diff --git a/Block/Sitemap.php b/Block/Sitemap.php
index 04b6fde..8faed3c 100755
--- a/Block/Sitemap.php
+++ b/Block/Sitemap.php
@@ -21,20 +21,23 @@
namespace Mageplaza\Sitemap\Block;
+use Exception;
use Magento\Catalog\Helper\Category;
use Magento\Catalog\Model\CategoryRepository;
use Magento\Catalog\Model\Product\Visibility as ProductVisibility;
use Magento\Catalog\Model\ResourceModel\Category\Collection;
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory;
-use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection;
+use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollection;
use Magento\CatalogInventory\Helper\Stock;
use Magento\Cms\Model\Page;
use Magento\Cms\Model\ResourceModel\Page\Collection as PageCollection;
-use Magento\Framework\Data\Tree\Node\Collection as TreeCollection;
+use Magento\Framework\Data\Collection\AbstractDb;
+use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\View\Element\Template;
use Magento\Framework\View\Element\Template\Context;
use Mageplaza\Sitemap\Helper\Data as HelperConfig;
+use Mageplaza\Sitemap\Model\Source\SortProduct;
/**
* Class Sitemap
@@ -136,28 +139,160 @@ public function __construct(
public function getProductCollection()
{
$limit = $this->_helper->getProductLimit() ?: self::DEFAULT_PRODUCT_LIMIT;
- $collection = $this->productCollection
+ $collection = $this->productCollection->create()
->setVisibility($this->productVisibility->getVisibleInCatalogIds())
->addMinimalPrice()
->addFinalPrice()
->addTaxPercents()
- ->setPageSize($limit)
->addAttributeToSelect('*');
- if (!$this->_helper->getConfigValue('cataloginventory/options/show_out_of_stock')) {
+
+ $sortProductBy = $this->_helper->getHtmlSitemapConfig('product_sorting');
+ $sortProductDir = $this->_helper->getHtmlSitemapConfig('product_sorting_dir');
+
+ switch ($sortProductBy) {
+ case SortProduct::PRODUCT_NAME:
+ $collection->setOrder('name', $sortProductDir);
+ break;
+ case SortProduct::PRICE:
+ $collection->setOrder('minimal_price', $sortProductDir);
+ break;
+ default:
+ $collection->setOrder('entity_id', $sortProductDir);
+ break;
+ }
+
+ if ($this->_helper->getHtmlSitemapConfig('out_of_stock_products')) {
$this->_stockFilter->addInStockFilterToCollection($collection);
}
+ $collection->setPageSize($limit);
+
return $collection;
}
/**
- * Get category collection
- *
- * @return TreeCollection
+ * @return Collection|AbstractDb
+ * @throws NoSuchEntityException
+ * @throws LocalizedException
*/
public function getCategoryCollection()
{
- return $this->_categoryHelper->getStoreCategories(false, true);
+ $storeRootCategoryId = $this->_storeManager->getStore()->getRootCategoryId();
+ $storeRootCategory = $this->categoryRepository->get($storeRootCategoryId);
+ $categoryCollection = $this->_categoryCollection->create()->addAttributeToSelect('*')
+ ->addFieldToFilter('entity_id', ['in' => $storeRootCategory->getAllChildren(true)])
+ ->addFieldToFilter('is_active', 1)
+ ->addFieldToFilter('include_in_menu', 1)
+ ->addFieldToFilter('entity_id', ['nin' => [$storeRootCategoryId]]);
+
+ $excludeCategories = $this->_helper->getHtmlSitemapConfig('category_page');
+ if (!empty($excludeCategories)) {
+ $excludeCategories = array_map('trim', explode(
+ "\n",
+ $excludeCategories
+ ));
+
+ $allExcludeIds = '';
+ foreach ($excludeCategories as $excludeCategory) {
+ if (!empty($excludeCategory)) {
+ try {
+ $testRegex = preg_match($excludeCategory, '');
+ if ($testRegex) {
+ $allExcludeIds .= '-' . $this->filterCategoryWithRegex($excludeCategory);
+ } else {
+ $excludePath = $this->getExcludePath($excludeCategory);
+ $allExcludeIds .= '-' . $this->filterCategoryWithPath($excludePath, $categoryCollection);
+ }
+ } catch (Exception $e) {
+ $excludePath = $this->getExcludePath($excludeCategory);
+ $allExcludeIds .= '-' . $this->filterCategoryWithPath($excludePath, $categoryCollection);
+ }
+ }
+ }
+
+ $excludeIds = explode('-', $allExcludeIds);
+ $categoryCollection->addFieldToFilter('entity_id', ['nin' => $excludeIds]);
+ }
+
+ return $this->_categoryCollection->create()->addAttributeToSelect('*')
+ ->addFieldToFilter('entity_id', ['in' => $categoryCollection->getAllIds()])->setOrder('path');
+ }
+
+ /**
+ * @param $path
+ * @param $categoryCollection
+ *
+ * @return string
+ */
+ protected function filterCategoryWithPath($path, $categoryCollection)
+ {
+ $excludeIds = [];
+ foreach ($categoryCollection as $category) {
+ if ($this->isExcludeCategory($category, $path)) {
+ $excludeIds[] = $category->getData('entity_id');
+ }
+ }
+
+ return implode('-', $excludeIds);
+ }
+
+ /**
+ * @param $category
+ * @param $path
+ *
+ * @return bool
+ */
+ public function isExcludeCategory($category, $path)
+ {
+ $filterPath = explode('/', $path);
+ $categoryPath = $category->getUrlPath();
+ $categoryPath = explode('/', $categoryPath);
+
+ foreach ($filterPath as $pathInfo) {
+ if (!in_array($pathInfo, $categoryPath)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @param $regex
+ *
+ * @return string
+ * @throws LocalizedException
+ * @throws NoSuchEntityException
+ */
+ protected function filterCategoryWithRegex($regex)
+ {
+ $excludeCategoriesIds = [];
+ $categoryCollection = $this->_categoryCollection->create()->addAttributeToSelect('*')
+ ->setStoreId($this->_storeManager->getStore()->getId());
+ foreach ($categoryCollection as $category) {
+ if (!preg_match($regex, $category->getUrlPath())) {
+ $excludeCategoriesIds[] = $category->getId();
+ }
+ }
+
+ return implode('-', $excludeCategoriesIds);
+ }
+
+ /**
+ * @param $excludeCategory
+ *
+ * @return string
+ */
+ protected function getExcludePath($excludeCategory)
+ {
+ if ($excludeCategory[0] == '/') {
+ $excludeCategory = substr($excludeCategory, 1);
+ }
+ if ($excludeCategory[-1] == '/') {
+ $excludeCategory = substr($excludeCategory, 0, -1);
+ }
+
+ return $excludeCategory;
}
/**
@@ -223,16 +358,15 @@ public function getAdditionLinksCollection()
}
/**
- * Render link element
- *
- * @param string $link
- * @param string $title
+ * @param $link
+ * @param $title
+ * @param $level
*
* @return string
*/
- public function renderLinkElement($link, $title)
+ public function renderLinkElement($link, $title, $level = null)
{
- return '
' . __($title) . '';
+ return '' . __($title) . '';
}
// phpcs:disable Generic.Metrics.NestingLevel
@@ -260,7 +394,8 @@ public function renderSection($section, $config, $title, $collection)
if (!$category->getData('mp_exclude_sitemap')) {
$html .= $this->renderLinkElement(
$this->getCategoryUrl($item->getId()),
- $item->getName()
+ $item->getName(),
+ $item->getLevel()
);
}
break;
@@ -334,4 +469,12 @@ public function isEnableHtmlSitemap()
{
return $this->_helper->isEnableHtmlSiteMap();
}
+
+ /**
+ * @return array|bool|mixed
+ */
+ public function getCategoryDisplayType()
+ {
+ return $this->_helper->getHtmlSitemapConfig('display_type');
+ }
}
diff --git a/Model/Source/DisplayType.php b/Model/Source/DisplayType.php
new file mode 100644
index 0000000..85e6db4
--- /dev/null
+++ b/Model/Source/DisplayType.php
@@ -0,0 +1,63 @@
+toArray() as $value => $label) {
+ $options[] = [
+ 'value' => $value,
+ 'label' => $label
+ ];
+ }
+
+ return $options;
+ }
+
+ /**
+ * Get options in "key-value" format
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return [
+ self::LIST => __('List'),
+ self::DROPDOWN => __('Dropdown'),
+ ];
+ }
+}
diff --git a/Model/Source/SortDirection.php b/Model/Source/SortDirection.php
new file mode 100644
index 0000000..e543f53
--- /dev/null
+++ b/Model/Source/SortDirection.php
@@ -0,0 +1,63 @@
+toArray() as $value => $label) {
+ $options[] = [
+ 'value' => $value,
+ 'label' => $label
+ ];
+ }
+
+ return $options;
+ }
+
+ /**
+ * Get options in "key-value" format
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return [
+ self::ASC => __('Ascending'),
+ self::DESC => __('Descending'),
+ ];
+ }
+}
diff --git a/Model/Source/SortProduct.php b/Model/Source/SortProduct.php
new file mode 100644
index 0000000..e29f982
--- /dev/null
+++ b/Model/Source/SortProduct.php
@@ -0,0 +1,65 @@
+toArray() as $value => $label) {
+ $options[] = [
+ 'value' => $value,
+ 'label' => $label
+ ];
+ }
+
+ return $options;
+ }
+
+ /**
+ * Get options in "key-value" format
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return [
+ self::PRODUCT_IDS => __('Product IDs'),
+ self::PRODUCT_NAME => __('Product Name'),
+ self::PRICE => __('Price')
+ ];
+ }
+}
diff --git a/composer.json b/composer.json
index b54281c..cd1f86e 100755
--- a/composer.json
+++ b/composer.json
@@ -2,11 +2,11 @@
"name": "mageplaza/module-sitemap",
"description": "Magento 2 Google XML Sitemap extension",
"require": {
- "mageplaza/module-core": "^1.4.5",
- "mageplaza/magento-2-seo-extension": "^4.0.0"
+ "mageplaza/module-core": "^1.4.12",
+ "mageplaza/magento-2-seo-extension": "^4.2.0"
},
"type": "magento2-module",
- "version": "4.1.0",
+ "version": "4.2.0",
"license": "proprietary",
"authors": [
{
diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml
index affe70e..1091831 100755
--- a/etc/adminhtml/system.xml
+++ b/etc/adminhtml/system.xml
@@ -1,154 +1,203 @@
-
-
-
-
-
-
-
-
-
- Magento\Config\Model\Config\Source\Yesno
- Yes to enable this module.
- Default URL: http://your-domain.com/sitemap/; See this article
- 1. It helps to reduce abandonment cart with One Step Checkout.
- 2. How to setup abandoned cart email series]]>
-
-
-
- Magento\Config\Model\Config\Source\Yesno
-
- 1
-
-
-
-
- Magento\Config\Model\Config\Source\Yesno
-
- 1
-
-
-
-
- validate-digits validate-not-negative-number
-
-
- 1
- 1
-
-
-
-
- Magento\Config\Model\Config\Source\Yesno
-
- 1
-
-
-
-
- Magento\Config\Model\Config\Source\Yesno
-
- 1
- 1
-
-
-
-
- Mageplaza\Sitemap\Model\Source\Page
-
- 1
- 1
- 1
-
-
-
-
- Magento\Config\Model\Config\Source\Yesno
-
- 1
-
-
-
-
-
-
- - One link per line.
- Example:
-
- http://www.mageplaza.com/,Mageplaza
- https://magento.com/,Magento
-
- ]]>
-
-
- 1
- 1
-
-
-
-
-
-
-
-
- Magento\Config\Model\Config\Source\Yesno
- In sitemap file, it will remove the link of the CMS page using for homepage.
-
-
-
- Magento\Config\Model\Config\Source\Yesno
- Yes, if you want to add more custom links into sitemap XML file.
-
-
-
-
- 1
-
- One link per line.
-
-
-
- Magento\Sitemap\Model\Config\Source\Frequency
-
- 1
-
- always, hourly, daily, weekly, monthly, yearly, never. Learn more.]]>
-
-
-
- validate-number validate-digits-range digits-range-0-1
-
- 1
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+ Magento\Config\Model\Config\Source\Yesno
+ Yes to enable this module.
+ Default URL: http://your-domain.com/sitemap/; See this article
+ 1. It helps to reduce abandonment cart with One Step Checkout.
+ 2. How to setup abandoned cart email series]]>
+
+
+
+ Magento\Config\Model\Config\Source\Yesno
+
+ 1
+
+
+
+
+
+ E.g: Do not display with the category pages including /men/ such as:
+ /men/top
+ /men/top/t-shirt
+ /clothes/men/
+ Support Regular expression
+ ]]>
+
+
+ 1
+ 1
+
+
+
+
+ Mageplaza\Sitemap\Model\Source\DisplayType
+ Choose style to display categories in HTML Sitemap.
+
+ 1
+ 1
+
+
+
+
+ Magento\Config\Model\Config\Source\Yesno
+
+ 1
+
+
+
+
+ Mageplaza\Sitemap\Model\Source\SortProduct
+
+ 1
+
+ Choose how to arrange and display products in HTML Site Map.
+
+
+
+ Mageplaza\Sitemap\Model\Source\SortDirection
+
+ 1
+
+
+
+
+ Magento\Config\Model\Config\Source\Yesno
+ If yes, will hide out of stock products in HTML Site Map.
+
+ 1
+
+
+
+
+ validate-digits validate-not-negative-number
+
+
+ 1
+ 1
+
+
+
+
+ Magento\Config\Model\Config\Source\Yesno
+
+ 1
+
+
+
+
+ Magento\Config\Model\Config\Source\Yesno
+
+ 1
+ 1
+
+
+
+
+ Mageplaza\Sitemap\Model\Source\Page
+
+ 1
+ 1
+ 1
+
+
+
+
+ Magento\Config\Model\Config\Source\Yesno
+
+ 1
+
+
+
+
+
+
+ - One link per line.
+ Example:
+
+ http://www.mageplaza.com/,Mageplaza
+ https://magento.com/,Magento
+
+ ]]>
+
+
+ 1
+ 1
+
+
+
+
+
+
+
+
+ Magento\Config\Model\Config\Source\Yesno
+ In sitemap file, it will remove the link of the CMS page using for homepage.
+
+
+
+ Magento\Config\Model\Config\Source\Yesno
+ Yes, if you want to add more custom links into sitemap XML file.
+
+
+
+
+ 1
+
+ One link per line.
+
+
+
+ Magento\Sitemap\Model\Config\Source\Frequency
+
+ 1
+
+ always, hourly, daily, weekly, monthly, yearly, never. Learn more.]]>
+
+
+
+ validate-number validate-digits-range digits-range-0-1
+
+ 1
+
+
+
+
+
+
+
diff --git a/etc/config.xml b/etc/config.xml
index 3fe8201..4b18a8a 100755
--- a/etc/config.xml
+++ b/etc/config.xml
@@ -1,35 +1,40 @@
-
-
-
-
-
-
- 1
-
-
- 1
- daily
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+ 1
+ 0
+ list
+ product_ids
+ asc
+ 1
+
+
+ 1
+ daily
+
+
+
+
diff --git a/view/frontend/templates/sitemap.phtml b/view/frontend/templates/sitemap.phtml
index 5fad0f3..19b29ca 100755
--- a/view/frontend/templates/sitemap.phtml
+++ b/view/frontend/templates/sitemap.phtml
@@ -19,10 +19,30 @@
* @license https://www.mageplaza.com/LICENSE.txt
*/
-/** @var \Mageplaza\Sitemap\Block\Sitemap $block */
+use Mageplaza\Sitemap\Block\Sitemap;
+
+/** @var Sitemap $block */
?>
= $block->renderHtmlSiteMap() ?>
-
+getCategoryDisplayType() == 'dropdown') :
+?>
+
+