The file you are looking for it here:
vendor/magento/module-catalog-widget/view/frontend/templates/product/widget/content/grid.phtml
If you place some dummy text here, you will see if on your home page. So if you want to edit this file further, you can copy it over to your theme.
To answer your question, at this point I have not found a .phtml or .xml that controls the product grids, they are all controlled by the styles based on css breakpoints. If you take a look at this file vendor/magento/theme-frontend-blank/Magento_Catalog/web/css/source/module/_listings.less
you will see this:
.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
.page-products .products-grid .product-item { width: 100%/3 }
.page-products.page-layout-1column .products-grid .product-item { width: 100%/4 }
.page-products.page-layout-3columns .products-grid .product-item { width: 100%/2 }
}
.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__l) {
.products-grid .product-item { width: 100%/5 }
.page-layout-1column .products-grid .product-item { width: 100%/6 }
.page-layout-3columns .products-grid .product-item { width: 100%/4 }
.page-products .products-grid .product-items { margin: 0; }
.page-products .products-grid .product-item {
width: 23.233%;
margin-left: calc(~"(100% - 4 * 23.233%) / 3");
padding: 0;
&:nth-child(4n+1) {
margin-left: 0;
}
}
.page-products.page-layout-1column .products-grid .product-item { width: 100%/5 }
.page-products.page-layout-3columns .products-grid .product-item { width: 100%/4 }
}
which defines the breakpoints at when the grid will shift from 5 to 4 to 3. When I have had to change this around, I just do it in the styles, based on what I need, just change the math around to work with the design.
Try bellow block code
<?php
/**
* Copyright © 2016 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Catalog\Block\Product;
use Magento\Customer\Model\Context as CustomerContext;
/**
* New products block
*
* @SuppressWarnings(PHPMD.LongVariable)
*/
class Special extends \Magento\Catalog\Block\Product\AbstractProduct implements
\Magento\Framework\DataObject\IdentityInterface
{
/**
* Default value for products count that will be shown
*/
const DEFAULT_PRODUCTS_COUNT = 10;
/**
* Products count
*
* @var int
*/
protected $_productsCount;
/**
* @var \Magento\Framework\App\Http\Context
*/
protected $httpContext;
/**
* Catalog product visibility
*
* @var \Magento\Catalog\Model\Product\Visibility
*/
protected $_catalogProductVisibility;
/**
* Product collection factory
*
* @var \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory
*/
protected $_productCollectionFactory;
/**
* @param Context $context
* @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory
* @param \Magento\Catalog\Model\Product\Visibility $catalogProductVisibility
* @param \Magento\Framework\App\Http\Context $httpContext
* @param array $data
*/
public function __construct(
\Magento\Catalog\Block\Product\Context $context,
\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
\Magento\Catalog\Model\Product\Visibility $catalogProductVisibility,
\Magento\Framework\App\Http\Context $httpContext,
array $data = []
) {
$this->_productCollectionFactory = $productCollectionFactory;
$this->_catalogProductVisibility = $catalogProductVisibility;
$this->httpContext = $httpContext;
parent::__construct(
$context,
$data
);
}
/**
* Initialize block's cache
*
* @return void
*/
protected function _construct()
{
parent::_construct();
$this->addColumnCountLayoutDepend('empty', 6)
->addColumnCountLayoutDepend('1column', 5)
->addColumnCountLayoutDepend('2columns-left', 4)
->addColumnCountLayoutDepend('2columns-right', 4)
->addColumnCountLayoutDepend('3columns', 3);
$this->addData(
['cache_lifetime' => 86400, 'cache_tags' => [\Magento\Catalog\Model\Product::CACHE_TAG]]
);
}
/**
* Get Key pieces for caching block content
*
* @return array
*/
public function getCacheKeyInfo()
{
return [
'CATALOG_PRODUCT_SPECIAL',
$this->_storeManager->getStore()->getId(),
$this->_design->getDesignTheme()->getId(),
$this->httpContext->getValue(CustomerContext::CONTEXT_GROUP),
'template' => $this->getTemplate(),
$this->getProductsCount()
];
}
/**
* Prepare and return product collection
*
* @return \Magento\Catalog\Model\ResourceModel\Product\Collection|Object|\Magento\Framework\Data\Collection
*/
protected function _getProductCollection()
{
$todayStartOfDayDate = $this->_localeDate->date()->setTime(0, 0, 0)->format('Y-m-d H:i:s');
$todayEndOfDayDate = $this->_localeDate->date()->setTime(23, 59, 59)->format('Y-m-d H:i:s');
/** @var $collection \Magento\Catalog\Model\ResourceModel\Product\Collection */
$collection = $this->_productCollectionFactory->create();
$collection->setVisibility($this->_catalogProductVisibility->getVisibleInCatalogIds());
$collection = $this->_addProductAttributesAndPrices(
$collection
)->addStoreFilter()->addAttributeToFilter(
'news_from_date',
[
'or' => [
0 => ['date' => true, 'to' => $todayEndOfDayDate],
1 => ['is' => new \Zend_Db_Expr('null')],
]
],
'left'
)->addAttributeToFilter(
'news_to_date',
[
'or' => [
0 => ['date' => true, 'from' => $todayStartOfDayDate],
1 => ['is' => new \Zend_Db_Expr('null')],
]
],
'left'
)->addAttributeToFilter(
[
['attribute' => 'news_from_date', 'is' => new \Zend_Db_Expr('not null')],
['attribute' => 'news_to_date', 'is' => new \Zend_Db_Expr('not null')],
]
)->addAttributeToSort(
'news_from_date',
'desc'
)->setPageSize(
$this->getProductsCount()
)->setCurPage(
1
);
return $collection;
}
/**
* Prepare collection with new products
*
* @return \Magento\Framework\View\Element\AbstractBlock
*/
protected function _beforeToHtml()
{
$this->setProductCollection($this->_getProductCollection());
return parent::_beforeToHtml();
}
/**
* Set how much product should be displayed at once.
*
* @param int $count
* @return $this
*/
public function setProductsCount($count)
{
$this->_productsCount = $count;
return $this;
}
/**
* Get how much products should be displayed at once.
*
* @return int
*/
public function getProductsCount()
{
if (null === $this->_productsCount) {
$this->_productsCount = self::DEFAULT_PRODUCTS_COUNT;
}
return $this->_productsCount;
}
/**
* Return identifiers for produced content
*
* @return array
*/
public function getIdentities()
{
return [\Magento\Catalog\Model\Product::CACHE_TAG];
}
}
Note: after run bellow command
php bin/magento setup:upgrade –keep-generated
php bin/magento setup:static-content:deploy
Best Answer
toHtml()
return block's html outputProcess
\vendor\magento\framework\View\Element\AbstractBlock.php
Next this goes to \vendor\magento\framework\View\Element\Template.php
Renders block html. and
$this->fetchView
function retrieves the block view from file (template).Assume you know templates are using block functions and blocks extends core classes ( Template.php or AbstractBlock.php not in all cases ).
The data is populating by using toHtml()
Hope this helps.