├── .gitignore ├── Block ├── Categories.php ├── Cmspage.php ├── System │ └── Config │ │ └── Form │ │ └── Field │ │ └── Snippet.php └── Widget │ └── Categories.php ├── Controller └── Adminhtml │ └── Category │ └── Thumbnail │ └── Upload.php ├── Helper └── Data.php ├── Model ├── Category │ └── Attribute │ │ └── Backend │ │ └── Image.php └── Config │ ├── Category.php │ ├── Layout.php │ ├── SortAttribute.php │ └── Source │ ├── Col.php │ ├── Responsive.php │ ├── Row.php │ ├── Status.php │ └── Truefalse.php ├── README.md ├── Setup └── InstallData.php ├── composer.json ├── etc ├── acl.xml ├── adminhtml │ ├── di.xml │ ├── routes.xml │ └── system.xml ├── config.xml ├── module.xml └── widget.xml ├── media ├── Mgento-2-category-4.jpg ├── frontend_category.png ├── frontend_home.png ├── magento-2-categories-10.jpg ├── magento-2-categories-11.jpg ├── magento-2-categories-3.jpg ├── magento-2-categories-5.png ├── magento-2-categories-6.jpg ├── magento-2-categories-7.jpg ├── magento-2-categories-8.jpg └── magento-2-categories-9.jpg ├── registration.php └── view ├── adminhtml └── ui_component │ └── category_form.xml └── frontend ├── layout ├── catalog_category_view.xml └── cms_index_index.xml ├── templates ├── categories.phtml ├── categories_widget.phtml └── cmspage.phtml └── web └── css └── source └── _module.less /.gitignore: -------------------------------------------------------------------------------- 1 | # General 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Icon must end with two \r 7 | Icon 8 | 9 | # Thumbnails 10 | ._* 11 | 12 | # Files that might appear in the root of a volume 13 | .DocumentRevisions-V100 14 | .fseventsd 15 | .Spotlight-V100 16 | .TemporaryItems 17 | .Trashes 18 | .VolumeIcon.icns 19 | .com.apple.timemachine.donotpresent 20 | 21 | # Directories potentially created on remote AFP share 22 | .AppleDB 23 | .AppleDesktop 24 | Network Trash Folder 25 | Temporary Items 26 | .apdisk -------------------------------------------------------------------------------- /Block/Categories.php: -------------------------------------------------------------------------------- 1 | helper->getConfigModule(self::XML_PATH); 50 | //$dataConvert = array('infinite', 'vertical', 'autoplay', 'centerMode'); 51 | if($data['slide']){ 52 | $data['vertical-Swiping'] = $data['vertical']; 53 | $breakpoints = $this->getResponsiveBreakpoints(); 54 | $responsive = '['; 55 | $num = count($breakpoints); 56 | foreach ($breakpoints as $size => $opt) { 57 | $item = (int) $data[$opt]; 58 | $responsive .= '{"breakpoint": '.$size.', "settings": {"slidesToShow": '.$item.'}}'; 59 | $num--; 60 | if($num) $responsive .= ', '; 61 | } 62 | $responsive .= ']'; 63 | $data['slides-To-Show'] = $data['visible']; 64 | $data['autoplay-Speed'] = $data['autoplay_speed']; 65 | $data['swipe-To-Slide'] = 'true'; 66 | $data['responsive'] = $responsive; 67 | } 68 | 69 | $this->addData($data); 70 | 71 | parent::_construct(); 72 | 73 | } 74 | 75 | public function __construct( 76 | \Magento\Framework\View\Element\Template\Context $context, 77 | \Magento\Framework\Image\AdapterFactory $imageFactory, 78 | \Magento\Framework\Registry $coreRegistry, 79 | \Magento\Catalog\Model\CategoryFactory $categoryFactory, 80 | \Magento\Catalog\Helper\Image $helperImage, 81 | \Magento\Catalog\Helper\Output $catalogHelperOutput, 82 | \Magento\Store\Model\StoreManagerInterface $storeManager, 83 | \Magepow\Categories\Helper\Data $helper, 84 | array $data = [] 85 | ) { 86 | $this->storeManager = $storeManager; 87 | $this->coreRegistry = $coreRegistry; 88 | $this->categoryFactory = $categoryFactory; 89 | $this->catalogHelperOutput = $catalogHelperOutput; 90 | $this->helperImage = $helperImage; 91 | $this->_imageFactory = $imageFactory; 92 | $this->_filesystem = $context->getFilesystem(); 93 | $this->_directoryPub = $this->_filesystem->getDirectoryRead(\Magento\Framework\App\Filesystem\DirectoryList::PUB); 94 | $this->helper = $helper; 95 | 96 | parent::__construct($context, $data); 97 | 98 | $this->attributesToSelect = [ 99 | 'name', 100 | 'url_key', 101 | 'url_path', 102 | 'image', 103 | 'description' 104 | ]; 105 | if($this->isShowThumbnail()) { 106 | $this->attributesToSelect[] = 'magepow_thumbnail'; 107 | unset($this->attributesToSelect['image']); 108 | } 109 | 110 | } 111 | 112 | protected function getCacheLifetime() 113 | { 114 | return parent::getCacheLifetime() ?: 86400; 115 | } 116 | 117 | public function getCacheKeyInfo() 118 | { 119 | $keyInfo = parent::getCacheKeyInfo(); 120 | $categoryId = $this->getCurrentCategory() ? $this->getCurrentCategory()->getId() : 0; 121 | $keyInfo[] = $categoryId; 122 | return $keyInfo; 123 | } 124 | 125 | /** 126 | * @return array 127 | */ 128 | public function getIdentities() 129 | { 130 | $categoryId = $this->getCurrentCategory() ? $this->getCurrentCategory()->getId() : 0; 131 | return [self::DEFAULT_CACHE_TAG, self::DEFAULT_CACHE_TAG . '_' . $categoryId]; 132 | } 133 | 134 | public function getLayout() 135 | { 136 | return $this->helper->getConfigModule(self::XML_PATH . '/layout'); 137 | } 138 | 139 | public function getHeading() 140 | { 141 | return $this->helper->getConfigModule(self::XML_PATH . '/heading'); 142 | } 143 | 144 | public function isShowDescription() 145 | { 146 | return $this->helper->getConfigModule(self::XML_PATH . '/description'); 147 | } 148 | 149 | public function isShowThumbnail() 150 | { 151 | return $this->helper->getConfigModule(self::XML_PATH . '/thumbnail'); 152 | } 153 | 154 | public function getItemAmount() 155 | { 156 | return $this->helper->getConfigModule(self::XML_PATH . '/item_amount'); 157 | } 158 | 159 | public function getSortAttribute() 160 | { 161 | return $this->helper->getConfigModule(self::XML_PATH . '/sort_attribute'); 162 | } 163 | 164 | public function getExcludeCategory() 165 | { 166 | return $this->helper->getConfigModule(self::XML_PATH . '/exclude_category'); 167 | } 168 | 169 | public function getCurrentCategory() 170 | { 171 | return $this->coreRegistry->registry('current_category'); 172 | } 173 | 174 | public function getCategories() 175 | { 176 | $category = $this->getCurrentCategory(); 177 | if(!$category) return; 178 | 179 | $categoryId = $category->getId(); 180 | 181 | if ($this->isExcluded($categoryId)) return; 182 | 183 | $sortAttribute = $this->getSortAttribute(); 184 | $categories = $this->categoryFactory->create()->getCollection() 185 | ->addAttributeToSelect($this->attributesToSelect) 186 | ->addAttributeToFilter('parent_id', $categoryId) 187 | ->addIsActiveFilter(); 188 | 189 | if($sortAttribute == "position") { 190 | $categories->addAttributeToSort('level'); 191 | } 192 | 193 | $categories->addAttributeToSort($sortAttribute); 194 | 195 | return $categories; 196 | } 197 | 198 | public function getDescription($category) 199 | { 200 | $description = $category->getDescription(); 201 | if ($description) { 202 | $categoryDescription = $this->catalogHelperOutput->categoryAttribute($category, $description, 'description'); 203 | } else { 204 | $categoryDescription = ''; 205 | } 206 | return trim($categoryDescription); 207 | } 208 | 209 | public function getImage($category) 210 | { 211 | if($this->isShowThumbnail()){ 212 | $image = ($category->getData('magepow_thumbnail')) ? $category->getData('magepow_thumbnail') : ''; 213 | return $this->getImageUrl($image); 214 | } 215 | 216 | return $this->getImageUrl($category); 217 | } 218 | 219 | public function getImageInfo($image) 220 | { 221 | if(is_object($image)){ 222 | $img = $this->isShowThumbnail() ? $image->getData('magepow_thumbnail'): $image->getImage(); 223 | if(!$img) return $image; 224 | } else { 225 | $img = $image; 226 | } 227 | $_image = $this->_imageFactory->create(); 228 | $mediaPath = $this->_directoryPub->getAbsolutePath(); 229 | $mediaPath = explode(DIRECTORY_SEPARATOR, $mediaPath); 230 | $img = explode(DIRECTORY_SEPARATOR, $img); 231 | $imagePath = array_unique(array_merge($mediaPath, $img)); 232 | $imagePath = implode(DIRECTORY_SEPARATOR, $imagePath); 233 | if(file_exists($imagePath) ){ 234 | $_image->open($imagePath); 235 | return $_image; 236 | } 237 | return $image; 238 | } 239 | 240 | public function getImageUrl($image) 241 | { 242 | if(is_object($image)){ 243 | $image = $image->getImage(); 244 | } 245 | if(strpos($image ?? '', "media/"))$image = strstr($image,'/media'); 246 | elseif($image!=NULL){ 247 | $image = 'catalog/category/'.$image; 248 | } 249 | $image = str_replace('media/', '', $image ?? ''); 250 | 251 | if($image) { 252 | $url = $this->storeManager->getStore()->getBaseUrl( \Magento\Framework\UrlInterface::URL_TYPE_MEDIA ) . $image; 253 | } else { 254 | $url = $this->helperImage->getDefaultPlaceholderUrl('small_image'); 255 | } 256 | 257 | return $url; 258 | } 259 | 260 | public function isExcluded($id) 261 | { 262 | $excluded = explode(',', $this->getExcludeCategory() ?? ''); 263 | if (!$excluded) return; 264 | return in_array($id, $excluded); 265 | } 266 | 267 | public function getResponsiveBreakpoints() 268 | { 269 | return Responsive::getBreakpoints(); 270 | } 271 | 272 | public function getSlideOptions() 273 | { 274 | return array('autoplay', 'arrows', 'autoplay-Speed', 'dots', 'infinite', 'padding', 'vertical', 'vertical-Swiping', 'responsive', 'rows', 'slides-To-Show'); 275 | } 276 | 277 | public function getFrontendCfg() 278 | { 279 | if($this->getSlide()) return $this->getSlideOptions(); 280 | 281 | $this->addData(array('responsive' =>json_encode($this->getGridOptions()))); 282 | return array('padding', 'responsive'); 283 | 284 | } 285 | 286 | public function getGridOptions() 287 | { 288 | $options = array(); 289 | $breakpoints = $this->getResponsiveBreakpoints(); ksort($breakpoints); 290 | foreach ($breakpoints as $size => $screen) { 291 | $options[]= array($size-1 => $this->getData($screen)); 292 | } 293 | return $options; 294 | } 295 | 296 | } 297 | -------------------------------------------------------------------------------- /Block/Cmspage.php: -------------------------------------------------------------------------------- 1 | helper->getConfigModule(self::XML_PATH . '/layout'); 24 | } 25 | 26 | public function getHeading() 27 | { 28 | return $this->helper->getConfigModule(self::XML_PATH . '/heading'); 29 | } 30 | 31 | public function isShowDescription() 32 | { 33 | return $this->helper->getConfigModule(self::XML_PATH . '/description'); 34 | } 35 | 36 | public function isShowThumbnail() 37 | { 38 | return $this->helper->getConfigModule(self::XML_PATH . '/thumbnail'); 39 | } 40 | 41 | public function getItemAmount() 42 | { 43 | return $this->helper->getConfigModule(self::XML_PATH . '/item_amount'); 44 | } 45 | 46 | public function getSortAttribute() 47 | { 48 | return $this->helper->getConfigModule(self::XML_PATH . '/sort_attribute'); 49 | } 50 | 51 | public function getCategorySelect() 52 | { 53 | return $this->helper->getConfigModule(self::XML_PATH . '/category_select'); 54 | } 55 | 56 | public function getCategories() 57 | { 58 | $categoryIds = $this->getCategorySelect(); 59 | if(!$categoryIds) return; 60 | 61 | $sortAttribute = $this->getSortAttribute(); 62 | $categories = $this->categoryFactory->create()->getCollection() 63 | ->addAttributeToSelect($this->attributesToSelect) 64 | ->addIdFilter($categoryIds) 65 | ->addIsActiveFilter(); 66 | 67 | switch ($sortAttribute) { 68 | case 'position': 69 | $categories->addAttributeToSort('level'); 70 | $categories->addAttributeToSort($sortAttribute); 71 | break; 72 | case 'custom': 73 | // will sort as per order of Id's set in config value: magepow_categories/home_page/category_select 74 | $categories->getSelect()->order(new \Zend_Db_Expr('FIELD(e.entity_id,' . $categoryIds . ')')); 75 | break; 76 | default: 77 | $categories->addAttributeToSort($sortAttribute); 78 | break; 79 | } 80 | 81 | return $categories; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Block/System/Config/Form/Field/Snippet.php: -------------------------------------------------------------------------------- 1 | _getElementHtml($element); 24 | } 25 | 26 | protected function _getElementHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element) 27 | { 28 | // $html = $element->getElementHtml(); 29 | $html = ''; 30 | $value = $element->getData('value'); 31 | $shortcodeWidget = '{{block class="Magepow\Categories\Block\Widget\Categories" title="Magepow Categories Widget" subtitle="Magepow Categories Widget" template="categories_widget.phtml" sort_attribute="name" description="1" thumbnail="1" item_amount="1" categories="25,11,22,33" slide="1" vertical="false" infinite="true" autoplay="true" arrows="true" dots="false" speed="300" autoplaySpeed="3000" padding="15" rows="1" mobile="1" portrait="1" landscape="2" tablet="3" notebook="3" laptop="4" desktop="4" widescreen="4" visible="5"}}'; 32 | 33 | $html = ''; 40 | 41 | return $html; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Block/Widget/Categories.php: -------------------------------------------------------------------------------- 1 | getResponsiveBreakpoints(); 19 | $total = count($breakpoints); 20 | $responsive = '['; 21 | foreach ($breakpoints as $size => $screen) { 22 | if ($this->getData($screen)){ 23 | $responsive .= '{"breakpoint": '.$size.', "settings": {"slidesToShow": '.$this->getData($screen).'}}'; 24 | } 25 | if($total-- > 1) $responsive .= ', '; 26 | } 27 | $responsive .= ']'; 28 | $data['responsive'] = $responsive; 29 | $data['autoplay-Speed'] = $this->getData('autoplaySpeed'); 30 | $data['slides-To-Show'] = $this->getData('visible'); 31 | // $data['swipe-To-Slide'] = 'true'; 32 | $data['vertical-Swiping'] = $this->getData('vertical'); 33 | $data['slide'] = 1; 34 | //$data['lazy-Load'] = 'progressive'; 35 | $this->addData($data); 36 | parent::_construct(); 37 | } 38 | 39 | public function getCacheKeyInfo() 40 | { 41 | $keyInfo = parent::getCacheKeyInfo(); 42 | $uniqueId = $this->getUniqueId(); 43 | $keyInfo[] = $uniqueId; 44 | return $keyInfo; 45 | } 46 | 47 | public function getUniqueId() 48 | { 49 | $categories = $this->getData('categories'); 50 | $categories = str_replace(" ", "", $categories); 51 | $categories = str_replace(",", "_", $categories); 52 | return $categories; 53 | } 54 | 55 | public function isShowThumbnail(){ 56 | return $this->getData('thumbnail'); 57 | } 58 | 59 | public function getLayout() 60 | { 61 | return 'grid'; 62 | } 63 | 64 | public function getHeading() 65 | { 66 | return $this->getData('title'); 67 | } 68 | 69 | public function isShowDescription() 70 | { 71 | return $this->getData('description'); 72 | } 73 | 74 | public function getItemAmount(){ 75 | return $this->getData('item_amount'); 76 | } 77 | 78 | public function getSortAttribute() 79 | { 80 | return $this->getData('sort_attribute'); 81 | } 82 | 83 | public function getCategories() 84 | { 85 | 86 | $categoryIds = $this->getData('categories'); 87 | if(!$categoryIds) return; 88 | $sortAttribute = $this->getSortAttribute(); 89 | 90 | $attributesSelect = ['name', 'url_key', 'url_path', 'image','description']; 91 | if($this->isShowThumbnail()) $attributesSelect[] = 'magepow_thumbnail'; 92 | $categories = $this->categoryFactory->create(); 93 | $categories = $categories->getCollection() 94 | ->addAttributeToSelect($attributesSelect) 95 | ->addIdFilter($categoryIds); 96 | 97 | if($sortAttribute == "position") { 98 | $categories->addAttributeToSort('level'); 99 | }elseif($sortAttribute=='custom'){ 100 | $custom_sort= $this->getData('custom_sort'); 101 | if(preg_match('/^(\d+,)+\d+$/', (string) $custom_sort)){ 102 | $custom_sort_arr = []; 103 | $categoryIds = explode(',', (string) $categoryIds); 104 | $custom_sort_arr = explode(',',(string) $custom_sort); 105 | $custom_sort_arr2 = array_merge(array_diff($custom_sort_arr, $categoryIds), array_diff($categoryIds,$custom_sort_arr)); 106 | $custom_sort_arr = array_merge($custom_sort_arr,$custom_sort_arr2); 107 | $categories->getSelect()->order(new \Zend_Db_Expr('FIELD(entity_id,' . implode(',', $custom_sort_arr).')')); 108 | }else{ 109 | $categories->addAttributeToSort('level'); 110 | } 111 | }else{ 112 | $categories->addAttributeToSort($sortAttribute); 113 | } 114 | 115 | return $categories; 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Category/Thumbnail/Upload.php: -------------------------------------------------------------------------------- 1 | imageUploader = $imageUploader; 18 | parent::__construct($context); 19 | 20 | } 21 | public function execute() { 22 | try { 23 | $result = $this->imageUploader->saveFileToTmpDir('magepow_thumbnail'); 24 | $result['cookie'] = [ 25 | 'name' => $this->_getSession()->getName(), 26 | 'value' => $this->_getSession()->getSessionId(), 27 | 'lifetime' => $this->_getSession()->getCookieLifetime(), 28 | 'path' => $this->_getSession()->getCookiePath(), 29 | 'domain' => $this->_getSession()->getCookieDomain(), 30 | ]; 31 | } catch (\Exception $e) { 32 | $result = ['error' => $e->getMessage(), 'errorcode' => $e->getCode()]; 33 | } 34 | return $this->resultFactory->create(ResultFactory::TYPE_JSON)->setData($result); 35 | } 36 | } -------------------------------------------------------------------------------- /Helper/Data.php: -------------------------------------------------------------------------------- 1 | configModule = $this->getConfig(strtolower($this->_getModuleName())); 28 | } 29 | 30 | public function getConfig($cfg='') 31 | { 32 | if($cfg) return $this->scopeConfig->getValue( $cfg, \Magento\Store\Model\ScopeInterface::SCOPE_STORE ); 33 | return $this->scopeConfig; 34 | } 35 | 36 | public function getConfigModule($cfg='', $value=null) 37 | { 38 | $values = $this->configModule; 39 | if( !$cfg ) return $values; 40 | $config = explode('/', (string) $cfg); 41 | $end = count($config) - 1; 42 | foreach ($config as $key => $vl) { 43 | if( isset($values[$vl]) ){ 44 | if( $key == $end ) { 45 | $value = $values[$vl]; 46 | }else { 47 | $values = $values[$vl]; 48 | } 49 | } 50 | 51 | } 52 | return $value; 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /Model/Category/Attribute/Backend/Image.php: -------------------------------------------------------------------------------- 1 | _filesystem = $filesystem; 81 | $this->_fileUploaderFactory = $fileUploaderFactory; 82 | $this->_logger = $logger; 83 | $this->storeManager = $storeManager ?? 84 | ObjectManager::getInstance()->get(StoreManagerInterface::class); 85 | $this->imageUploader = $imageUploader ?? 86 | ObjectManager::getInstance()->get(ImageUploader::class); 87 | } 88 | 89 | /** 90 | * Gets image name from $value array. 91 | * 92 | * Will return empty string in a case when $value is not an array. 93 | * 94 | * @param array $value Attribute value 95 | * @return string 96 | */ 97 | private function getUploadedImageName($value) 98 | { 99 | if (is_array($value) && isset($value[0]['name'])) { 100 | // var_dump($value[0]['name']); 101 | // die('zxcvzx'); 102 | return $value[0]['name']; 103 | } 104 | 105 | return ''; 106 | } 107 | 108 | /** 109 | * Check that image name exists in catalog/category directory and return new image name if it already exists. 110 | * 111 | * @param string $imageName 112 | * @return string 113 | */ 114 | private function checkUniqueImageName(string $imageName): string 115 | { 116 | $mediaDirectory = $this->_filesystem->getDirectoryWrite(DirectoryList::MEDIA); 117 | $imageAbsolutePath = $mediaDirectory->getAbsolutePath( 118 | $this->imageUploader->getBasePath() . DIRECTORY_SEPARATOR . $imageName 119 | ); 120 | 121 | // phpcs:ignore Magento2.Functions.DiscouragedFunction 122 | $imageName = call_user_func([Uploader::class, 'getNewFilename'], $imageAbsolutePath); 123 | 124 | return $imageName; 125 | } 126 | 127 | /** 128 | * Avoiding saving potential upload data to DB. 129 | * 130 | * Will set empty image attribute value if image was not uploaded. 131 | * 132 | * @param \Magento\Framework\DataObject $object 133 | * @return $this 134 | * @since 101.0.8 135 | */ 136 | public function beforeSave($object) 137 | { 138 | $attributeName = $this->getAttribute()->getName(); 139 | 140 | $value = $object->getData($attributeName); 141 | 142 | if ($this->isTmpFileAvailable($value) && $imageName = $this->getUploadedImageName($value)) { 143 | try { 144 | /** @var StoreInterface $store */ 145 | $store = $this->storeManager->getStore(); 146 | $baseMediaDir = $store->getBaseMediaDir(); 147 | $newImgRelativePath = $this->imageUploader->moveFileFromTmp($imageName, true); 148 | $value[0]['url'] = '/' . $baseMediaDir . '/' . $newImgRelativePath; 149 | $value[0]['name'] = $value[0]['url']; 150 | } catch (\Exception $e) { 151 | $this->_logger->critical($e); 152 | } 153 | } elseif ($this->fileResidesOutsideCategoryDir($value)) { 154 | // use relative path for image attribute so we know it's outside of category dir when we fetch it 155 | // phpcs:ignore Magento2.Functions.DiscouragedFunction 156 | $value[0]['url'] = parse_url($value[0]['url'], PHP_URL_PATH); 157 | // $value[0]['name'] = $value[0]['url']; 158 | } 159 | 160 | if ($imageName = $this->getUploadedImageName($value)) { 161 | if (!$this->fileResidesOutsideCategoryDir($value)) { 162 | $imageName = $this->checkUniqueImageName($imageName); 163 | } 164 | $object->setData($this->additionalData . $attributeName, $value); 165 | 166 | $object->setData($attributeName, $imageName); 167 | 168 | } elseif (!is_string($value)) { 169 | $object->setData($attributeName, null); 170 | } 171 | return parent::beforeSave($object); 172 | } 173 | 174 | /** 175 | * Check if temporary file is available for new image upload. 176 | * 177 | * @param array $value 178 | * @return bool 179 | */ 180 | private function isTmpFileAvailable($value) 181 | { 182 | return is_array($value) && isset($value[0]['tmp_name']); 183 | } 184 | 185 | /** 186 | * Check for file path resides outside of category media dir. The URL will be a path including pub/media if true 187 | * 188 | * @param array|null $value 189 | * @return bool 190 | */ 191 | private function fileResidesOutsideCategoryDir($value) 192 | { 193 | if (!is_array($value) || !isset($value[0]['url'])) { 194 | return false; 195 | } 196 | 197 | $fileUrl = ltrim($value[0]['url'], '/'); 198 | $baseMediaDir = $this->_filesystem->getUri(DirectoryList::MEDIA); 199 | 200 | if (!$baseMediaDir) { 201 | return false; 202 | } 203 | 204 | return strpos($fileUrl, $baseMediaDir) !== false; 205 | } 206 | 207 | /** 208 | * Save uploaded file and set its name to category 209 | * 210 | * @param \Magento\Framework\DataObject $object 211 | * @return \Magento\Catalog\Model\Category\Attribute\Backend\Image 212 | * @SuppressWarnings(PHPMD.UnusedFormalParameter) 213 | */ 214 | public function afterSave($object) 215 | { 216 | return $this; 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /Model/Config/Category.php: -------------------------------------------------------------------------------- 1 | request = $request; 45 | $this->storeManager = $storeManager; 46 | $this->categoryTree = $categoryTree; 47 | } 48 | 49 | public function toOptionArray() 50 | { 51 | if(!$this->options){ 52 | $store = $this->request->getParam('store'); 53 | $categories = $this->categoryTree->getTree(); 54 | $options = [['label' => __('All'), 'value' => '0']]; 55 | foreach ($categories as $category) { 56 | $this->options = []; 57 | if(isset($category['cls']) && str_contains($category['cls'] , 'no-active')) continue; 58 | if($category['id']) { 59 | $this->options[] = ['label' => __('All in "%1"', $category['text']), 'value' => $category['id']]; 60 | $_categories = isset($category['children']) ? $category['children'] : '' ; 61 | if($_categories){ 62 | // $rootOption = ['label' => $category['label']]; 63 | foreach ($_categories as $cat) { 64 | $this->options[] = [ 65 | 'label' => self::PREFIX_ROOT .$cat['text'], 66 | 'value' => $cat['id'] 67 | ]; 68 | if(isset($cat['cls']) && str_contains($cat['cls'] , 'no-active')) continue; 69 | if (isset($cat['children'])) $this->_getChildOptions($cat['children']); 70 | } 71 | // $rootOption['value'] = $this->options; 72 | // $options[] = $rootOption; 73 | if($this->options){ 74 | $options[] = [ 75 | 'label' => $category['text'], 76 | 'value' => $this->options 77 | ]; 78 | } 79 | } 80 | } 81 | } 82 | $this->options = $options; 83 | } 84 | return $this->options; 85 | } 86 | 87 | protected function _getChildOptions($categories) 88 | { 89 | foreach ($categories as $category) { 90 | $prefix = str_repeat(self::REPEATER, count(explode("/", $category['path'])) * 1) . self::PREFIX_END; 91 | $this->options[] = [ 92 | 'label' => $prefix . $category['text'], 93 | 'value' => $category['id'] 94 | ]; 95 | if(isset($category['cls']) && str_contains($category['cls'] , 'no-active')) continue; 96 | if (isset($category['children'])) $this->_getChildOptions($category['children']); 97 | } 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /Model/Config/Layout.php: -------------------------------------------------------------------------------- 1 | 'grid', 'label' => __('Grid')], 27 | ['value' => 'list', 'label' => __('List')] 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Model/Config/SortAttribute.php: -------------------------------------------------------------------------------- 1 | 'name', 'label' => __('Name')], 27 | ['value' => 'meta_title', 'label' => __('Page Title')], 28 | ['value' => 'position', 'label' => __('Position')], 29 | ['value' => 'created_at', 'label' => __('Created Date')], 30 | ['value' => 'custom', 'label' => __('Custom Sort')] 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Model/Config/Source/Col.php: -------------------------------------------------------------------------------- 1 | 1, 'label'=>__('1 item(s) /row')), 24 | array('value' => 2, 'label'=>__('2 item(s) /row')), 25 | array('value' => 3, 'label'=>__('3 item(s) /row')), 26 | array('value' => 4, 'label'=>__('4 item(s) /row')), 27 | array('value' => 5, 'label'=>__('5 item(s) /row')), 28 | array('value' => 6, 'label'=>__('6 item(s) /row')), 29 | array('value' => 7, 'label'=>__('7 item(s) /row')), 30 | array('value' => 8, 'label'=>__('8 item(s) /row')), 31 | array('value' => 9, 'label'=>__('9 item(s) /row')), 32 | array('value' => 10, 'label'=>__('10 item(s) /row')), 33 | array('value' => 11, 'label'=>__('11 item(s) /row')), 34 | array('value' => 12, 'label'=>__('12 item(s) /row')), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Model/Config/Source/Responsive.php: -------------------------------------------------------------------------------- 1 | 'visible', 18 | 1920 =>'widescreen', 19 | 1480 =>'desktop', 20 | 1200 =>'laptop', 21 | 992 =>'notebook', 22 | 768 =>'tablet', 23 | 576 =>'landscape', 24 | 481 =>'portrait', 25 | 361 =>'mobile', 26 | 1 =>'mobile' 27 | ); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Model/Config/Source/Row.php: -------------------------------------------------------------------------------- 1 | __('1 row(s) /slider'), 18 | '2'=> __('2 row(s) /slider'), 19 | '3'=> __('3 row(s) /slider'), 20 | '4'=> __('4 row(s) /slider'), 21 | '5'=> __('5 row(s) /slider'), 22 | '6'=> __('6 row(s) /slider'), 23 | ]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Model/Config/Source/Status.php: -------------------------------------------------------------------------------- 1 | __('Enabled') 26 | , self::STATUS_DISABLED => __('Disabled'), 27 | ]; 28 | } 29 | 30 | public static function getOptionArray() 31 | { 32 | return self::getAvailableStatuses(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Model/Config/Source/Truefalse.php: -------------------------------------------------------------------------------- 1 | 'true', 'label' => __('True')], ['value' => 'false', 'label' => __('False')]]; 22 | } 23 | 24 | /** 25 | * Get options in "key-value" format 26 | * 27 | * @return array 28 | */ 29 | public function toArray() 30 | { 31 | return ['false' => __('No'), 'true' => __('Yes')]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [](https://shopify.pxf.io/VyL446) 2 | 3 | ## Magento 2 Categories Extension Free 4 | **Magento 2 Categories Extension Free** allows you to take the shortest way to lead customers to their target pages. With this extension, you can show subcategories on category pages and choose the layout to display them as the grid or list. Aside from that, you also can show the hot categories or simply the chosen categories on the Homepage or any CMS page. 5 | 6 | **Categories extension free by Magepow** is very easy to configure and manage, with no coding needed and responsive ready. With this extension, you can suggest to customers more content/products you have on your store and make an eye-catching look. 7 | 8 | For example, your online store is selling a wide range of subcategories such as Tops, bottoms, pants, bags, jackets... might dozens of categories but you want when your customers come to your store, you want them to buy or know most of some products types that you concentrate more than normal products. 9 | 10 | ![Magento 2 Categories Free](https://github.com/magepow/magento-2-categories/blob/master/media/magento-2-categories-5.png) 11 | 12 | So this extension can help you show on the top of the page the hot categories are chosen from categories collection or show them on the top of the category pages to recommend to customers. 13 | 14 | [![Latest Stable Version](https://poser.pugx.org/magepow/categories/v/stable)](https://packagist.org/packages/magepow/categories) 15 | [![Total Downloads](https://poser.pugx.org/magepow/categories/downloads)](https://packagist.org/packages/magepow/categories) 16 | [![Daily Downloads](https://poser.pugx.org/magepow/categories/d/daily)](https://packagist.org/packages/magepow/categories) 17 | 18 | ### 1. Highlight Features 19 | | Features | Free Version | Pro Version | 20 | | :------------ |:---------------:| :-----:| 21 | |Display optional subcategories on **Home page**|:white_check_mark:|:white_check_mark:| 22 | |Display the subcategories as slider layout on the Home page|X|:white_check_mark:| 23 | |Display optional subcategories on **Category page**|:white_check_mark:|:white_check_mark:| 24 | |Display the subcategories as slider layout on the Categories page|X|:white_check_mark:| 25 | |Display optional subcategories on **Product page**|X|:white_check_mark:| 26 | |Display optional subcategories on **Shopping Cart page**|X|:white_check_mark:| 27 | |Add or remove categories for the home pape and category pages as desired|:white_check_mark:|:white_check_mark:| 28 | |Add or remove categories on each page as desired|X|:white_check_mark:| 29 | |Multiple positions show categories|X|:white_check_mark:| 30 | |Subcategory characteristics on homepage and category page vary with 2
independent installers|:white_check_mark:|:white_check_mark:| 31 | |Subcategory block characteristics on each page can be individually
customized using 'Category Pro Rule'|X|:white_check_mark:| 32 | |**Grid layout**|:white_check_mark:|:white_check_mark:| 33 | |**List layout**|:white_check_mark:|:white_check_mark:| 34 | |**Slider layout**|X|:white_check_mark:| 35 | |Sort the subcategories by **Name**|:white_check_mark:|:white_check_mark:| 36 | |Sort the subcategories by **Page Title**|:white_check_mark:|:white_check_mark:| 37 | |Sort the subcategories by **Location**|:white_check_mark:|:white_check_mark:| 38 | |Sort the subcategories by **Creation Date**|:white_check_mark:|:white_check_mark:| 39 | |Sort the subcategories by **Admin tree**|X|:white_check_mark:| 40 | |Display subcategory with **Block Title**|:white_check_mark:|:white_check_mark:| 41 | |Display subcategory with **Description**|:white_check_mark:|:white_check_mark:| 42 | |Display subcategory with **Thumbnail**|:white_check_mark:|:white_check_mark:| 43 | |Display subcategory with **Item Amount**|:white_check_mark:|:white_check_mark:| 44 | |Full responsive design|:white_check_mark:|:white_check_mark:| 45 | |Customize Responsive Information|X|:white_check_mark:| 46 | |Display different categories with customer groups
(Not logged in, General, Wholesale, Retailer)|X|:white_check_mark:| 47 | |Free Support|X|:white_check_mark:| 48 | 49 | ![Magento 2 Categories Free](https://github.com/magepow/magento-2-categories/blob/master/media/magento-2-categories-7.jpg) 50 | 51 | Display optional subcategories on Home page 52 | 53 | ![Magento 2 Categories Free](https://github.com/magepow/magento-2-categories/blob/master/media/magento-2-categories-9.jpg) 54 | 55 | Display optional subcategories on Category page 56 | 57 | ![Magento 2 Categories Free](https://github.com/magepow/magento-2-categories/blob/master/media/magento-2-categories-8.jpg) 58 | 59 | Display optional subcategories on Product page 60 | 61 | ![Magento 2 Categories Free](https://github.com/magepow/magento-2-categories/blob/master/media/magento-2-categories-6.jpg) 62 | 63 | Display optional subcategories on Shopping Cart page 64 | 65 | See more: [Demo free version](https://demo.magepow.com/categories/) - [Demo Pro version](https://demo.magepow.com/categoriespro/) 66 | 67 | [![Magento 2 Categories Free](https://github.com/magepow/magento-2-categories/blob/master/media/Mgento-2-category-4.jpg)](https://magepow.com/magento-2-categories-extension.html) [![Magento 2 Categories Pro](https://github.com/magepow/magento-2-categories/blob/master/media/magento-2-categories-3.jpg)](https://magepow.com/magento-2-categories-extension.html) 68 | 69 | ### 2. How to install Magento 2 Categories extension Free 70 | #### ✓ Install Magepow Categories via composer (recommend) 71 | Run the following command in Magento 2 root folder: 72 | 73 | ``` 74 | composer require magepow/categories 75 | php bin/magento setup:upgrade 76 | php bin/magento setup:static-content:deploy -f 77 | ``` 78 | 79 | ### 3. Magepow Categories user guide 80 | **SubCategories extension free for Magento** allows customers access the categories quickly and conveniently, stimulating users to click on the categories because of the beautiful interface. 81 | 82 | #### Enable Magepow Categories 83 | Go to `Admin Panel > Stores > Settings > Configuration > Magepow > Categories` 84 | 85 | Select `Yes` to enable module. 86 | #### Setting Magepow SubCategories 87 | Go to `Admin Panel > Stores > Settings > Configuration > Magepow > Categories` 88 | 89 | * Two layouts available (Grid or List). 90 | * Ability to sort subcategories by "Name", "Page Title", "Position", and "Created Date". 91 | * Ability to show subcategories heading or not and to type in the heading text. 92 | * Ability to show or not category description. 93 | * Select categories that do not display subcategories. 94 | 95 | ![config-module-img](https://github.com/magepow/magento-2-categories/blob/master/media/magento-2-categories-10.jpg) 96 | 97 | The home page also has the same settings as the category page, except that: 98 | 99 | * The home page can choose the display categories instead of excluding the display category. 100 | * The home page can order the categories by 'custom sort', which will display in the order ids appear in the config value. 101 | You can curate this by manually setting the ids in the env.php file to override admin based config. 102 | ``` 103 | ./bin/magento config:set -e magepow_categories/home_page/category_select "64,72,73,1052,68,69,70,1046,65,88,311" 104 | ``` 105 | * Select the categories displayed on the home page. 106 | 107 | ![config-module-img](https://github.com/magepow/magento-2-categories/blob/master/media/magento-2-categories-11.jpg) 108 | 109 | ### This Is Result In Frontend 110 | #### In homepage 111 | 112 | ![config-module-img](https://github.com/magepow/magento2-categories/blob/master/media/frontend_home.png) 113 | 114 | #### In categories page 115 | 116 | ![config-module-img](https://github.com/magepow/magento2-categories/blob/master/media/frontend_category.png) 117 | 118 | ### [How does Magento 2 Categories work?](https://www.youtube.com/watch?v=k3A7PBh-NbQ&lc=UgzCFSLUqlD6cl__PH54AaABAg) 119 | ## Donation 120 | 121 | If this project help you reduce time to develop, you can give me a cup of coffee :) 122 | 123 | [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/paypalme/alopay) 124 | 125 | 126 | **[Our Magento 2 Extensions](https://magepow.com/magento-2-extensions.html)** 127 | 128 | * [Magento 2 Recent Sales Notification](https://magepow.com/magento-2-recent-order-notification.html) 129 | 130 | * [Magento 2 Categories Extension](https://magepow.com/magento-categories-extension.html) 131 | 132 | * [Magento 2 Sticky Cart](https://magepow.com/magento-sticky-cart.html) 133 | 134 | * [Magento 2 Ajax Contact](https://magepow.com/magento-ajax-contact-form.html) 135 | 136 | * [Magento 2 Lazy Load](https://magepow.com/magento-lazy-load.html) 137 | 138 | * [Magento 2 Mutil Translate](https://magepow.com/magento-multi-translate.html) 139 | 140 | * [Magento 2 Instagram Integration](https://magepow.com/magento-2-instagram.html) 141 | 142 | * [Magento 2 Lookbook Pin Products](https://magepow.com/lookbook-pin-products.html) 143 | 144 | * [Magento 2 Product Slider](https://magepow.com/magento-product-slider.html) 145 | 146 | * [Magento 2 Product Banner](https://magepow.com/magento-2-banner-slider.html) 147 | 148 | **[Our Magento 2 services](https://magepow.com/magento-services.html)** 149 | 150 | * [PSD to Magento 2 Theme Conversion](https://alothemes.com/psd-to-magento-theme-conversion.html) 151 | 152 | * [Magento 2 Speed Optimization Service](https://magepow.com/magento-speed-optimization-service.html) 153 | 154 | * [Magento 2 Security Patch Installation](https://magepow.com/magento-security-patch-installation.html) 155 | 156 | * [Magento 2 Website Maintenance Service](https://magepow.com/website-maintenance-service.html) 157 | 158 | * [Magento 2 Professional Installation Service](https://magepow.com/professional-installation-service.html) 159 | 160 | * [Magento 2 Upgrade Service](https://magepow.com/magento-upgrade-service.html) 161 | 162 | * [Magento 2 Customization Service](https://magepow.com/customization-service.html) 163 | 164 | * [Hire Magento 2 Developer](https://magepow.com/hire-magento-developer.html) 165 | 166 | **[Our Magento 2 Themes](https://alothemes.com/)** 167 | 168 | * [Expert Multipurpose Responsive Magento 2 Theme](https://1.envato.market/c/1314680/275988/4415?u=https://themeforest.net/item/expert-premium-responsive-magento-2-and-1-support-rtl-magento-2-/21667789) 169 | 170 | * [Gecko Premium Responsive Magento 2 Theme](https://1.envato.market/c/1314680/275988/4415?u=https://themeforest.net/item/gecko-responsive-magento-2-theme-rtl-supported/24677410) 171 | 172 | * [Milano Fashion Responsive Magento 2 Theme](https://1.envato.market/c/1314680/275988/4415?u=https://themeforest.net/item/milano-fashion-responsive-magento-1-2-theme/12141971) 173 | 174 | * [Electro 2 Responsive Magento 2 Theme](https://1.envato.market/c/1314680/275988/4415?u=https://themeforest.net/item/electro2-premium-responsive-magento-2-rtl-supported/26875864) 175 | 176 | * [Electro Responsive Magento 2 Theme](https://1.envato.market/c/1314680/275988/4415?u=https://themeforest.net/item/electro-responsive-magento-1-2-theme/17042067) 177 | 178 | * [Pizzaro Food responsive Magento 2 Theme](https://1.envato.market/c/1314680/275988/4415?u=https://themeforest.net/item/pizzaro-food-responsive-magento-1-2-theme/19438157) 179 | 180 | * [Biolife organic responsive Magento 2 Theme](https://1.envato.market/c/1314680/275988/4415?u=https://themeforest.net/item/biolife-organic-food-magento-2-theme-rtl-supported/25712510) 181 | 182 | * [Market responsive Magento 2 Theme](https://1.envato.market/c/1314680/275988/4415?u=https://themeforest.net/item/market-responsive-magento-2-theme/22997928) 183 | 184 | * [Kuteshop responsive Magento 2 Theme](https://1.envato.market/c/1314680/275988/4415?u=https://themeforest.net/item/kuteshop-multipurpose-responsive-magento-1-2-theme/12985435) 185 | 186 | * [Bencher - Responsive Magento 2 Theme](https://1.envato.market/c/1314680/275988/4415?u=https://themeforest.net/item/bencher-responsive-magento-1-2-theme/15787772) 187 | 188 | * [Supermarket Responsive Magento 2 Theme](https://1.envato.market/c/1314680/275988/4415?u=https://themeforest.net/item/supermarket-responsive-magento-1-2-theme/18447995) 189 | 190 | **[Our Shopify Themes](https://themeforest.net/user/alotheme)** 191 | 192 | * [Dukamarket - Multipurpose Shopify Theme](https://1.envato.market/c/1314680/275988/4415?u=https://themeforest.net/item/dukamarket-multipurpose-shopify-theme/36158349) 193 | 194 | * [Ohey - Multipurpose Shopify Theme](https://1.envato.market/c/1314680/275988/4415?u=https://themeforest.net/item/ohey-multipurpose-shopify-theme/34624195) 195 | 196 | * [Flexon - Multipurpose Shopify Theme](https://1.envato.market/c/1314680/275988/4415?u=https://themeforest.net/item/flexon-multipurpose-shopify-theme/33461048) 197 | 198 | **[Our Shopify App](https://apps.shopify.com/partners/maggicart)** 199 | 200 | * [Magepow Infinite Scroll](https://apps.shopify.com/magepow-infinite-scroll) 201 | 202 | * [Magepow Promotionbar](https://apps.shopify.com/magepow-promotionbar) 203 | 204 | * [Magepow Size Chart](https://apps.shopify.com/magepow-size-chart) 205 | 206 | **[Our WordPress Theme](https://themeforest.net/user/alotheme/portfolio)** 207 | 208 | * [SadesMarket - Multipurpose WordPress Theme](https://1.envato.market/c/1314680/275988/4415?u=https://themeforest.net/item/sadesmarket-multipurpose-wordpress-theme/35369933) 209 | -------------------------------------------------------------------------------- /Setup/InstallData.php: -------------------------------------------------------------------------------- 1 | categorySetupFactory = $categorySetupFactory; 21 | } 22 | 23 | public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) 24 | { 25 | $installer = $setup; 26 | $installer->startSetup(); 27 | 28 | $categorySetup = $this->categorySetupFactory->create(['setup' => $setup]); 29 | $entityTypeId = $categorySetup->getEntityTypeId(\Magento\Catalog\Model\Category::ENTITY); 30 | $attributeSetId = $categorySetup->getDefaultAttributeSetId($entityTypeId); 31 | $categorySetup->removeAttribute( 32 | \Magento\Catalog\Model\Category::ENTITY, 'magepow_thumbnail' ); 33 | $categorySetup->addAttribute( 34 | \Magento\Catalog\Model\Category::ENTITY, 'magepow_thumbnail', [ 35 | 'type' => 'varchar', 36 | 'label' => 'Thumbnail', 37 | 'input' => 'image', 38 | 'backend' => 'Magento\Catalog\Model\Category\Attribute\Backend\Image', 39 | 'required' => false, 40 | 'sort_order' => 5, 41 | 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, 42 | 'group' => 'General Information', 43 | ] 44 | ); 45 | $installer->endSetup(); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "magepow/categories", 3 | "description": "Shows categories in the form of a grid or list, on category pages, home page or any other page.", 4 | "require": { 5 | "magepow/core": "^1.0.0" 6 | }, 7 | "type": "magento2-module", 8 | "license": [ 9 | "OSL-3.0", 10 | "AFL-3.0" 11 | ], 12 | "authors": [ 13 | { 14 | "name": "Magepow", 15 | "email": "support@magepow.com", 16 | "homepage": "https://magepow.com", 17 | "role": "Technical Support" 18 | } 19 | ], 20 | "autoload": { 21 | "files": [ 22 | "registration.php" 23 | ], 24 | "psr-4": { 25 | "Magepow\\Categories\\": "" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /etc/acl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /etc/adminhtml/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Magento\Catalog\CategoryImageUpload 6 | 7 | 8 | 9 | 10 | 11 | jpg 12 | jpeg 13 | gif 14 | png 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /etc/adminhtml/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /etc/adminhtml/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | magepow 10 | Magepow_Categories::config 11 | 12 | 13 | 14 | 15 | Enables or disables extension. 16 | Magento\Config\Model\Config\Source\Yesno 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | The way categories are presented. Can be either "Grid" or "List". 25 | Magepow\Categories\Model\Config\Layout 26 | 27 | 28 | 29 | The way categories are sorted. 30 | Magepow\Categories\Model\Config\SortAttribute 31 | 32 | 33 | 34 | Categories heading text. 35 | validate-no-html-tags 36 | 37 | 38 | 39 | Enables or disables description. 40 | Magento\Config\Model\Config\Source\Yesno 41 | 42 | 43 | 44 | Enables to use Thumbnail set in Categories or disables to use Category Image. 45 | Magento\Config\Model\Config\Source\Yesno 46 | 47 | 48 | 49 | Enables to show number of items in each category. 50 | Magento\Config\Model\Config\Source\Yesno 51 | 52 | 53 | 54 | Use Ctrl+Click for check several values or uncheck value. Select categories that do not display subcategories. 55 | Magepow\Categories\Model\Config\Category 56 | 1 57 | 58 | 59 | 60 | Magento\Config\Block\System\Config\Form\Field\Heading 61 | 62 | 63 | 64 | Enabled Slide 65 | Magento\Config\Model\Config\Source\Yesno 66 | 67 | 68 | 69 | Mode Vertical 70 | Magepow\Categories\Model\Config\Source\Truefalse 71 | 1,3 72 | 73 | 74 | 75 | Infinite 76 | Magepow\Categories\Model\Config\Source\Truefalse 77 | 1 78 | 79 | 80 | 81 | Auto Play 82 | Magepow\Categories\Model\Config\Source\Truefalse 83 | 1 84 | 85 | 86 | 87 | Next/Back 88 | Magepow\Categories\Model\Config\Source\Truefalse 89 | 1 90 | 91 | 92 | 93 | Pager 94 | Magepow\Categories\Model\Config\Source\Truefalse 95 | 1 96 | 97 | 98 | 99 | Row Item 100 | Magepow\Categories\Model\Config\Source\Row 101 | 1 102 | 103 | 104 | 105 | Speed 106 | validate-zero-or-greater 107 | 1 108 | 109 | 110 | 111 | autoplay Speed 112 | validate-zero-or-greater 113 | 1 114 | 115 | 116 | 117 | Padding item Brand 118 | validate-zero-or-greater 119 | 120 | 121 | 122 | Magento\Config\Block\System\Config\Form\Field\Heading 123 | 124 | 125 | 126 | 127 | Magepow\Categories\Model\Config\Source\Col 128 | required-entry validate-greater-than-zero 129 | 130 | 131 | 132 | 133 | Magepow\Categories\Model\Config\Source\Col 134 | required-entry validate-greater-than-zero 135 | 136 | 137 | 138 | 139 | Magepow\Categories\Model\Config\Source\Col 140 | required-entry validate-greater-than-zero 141 | 142 | 143 | 144 | 145 | Magepow\Categories\Model\Config\Source\Col 146 | required-entry validate-greater-than-zero 147 | 148 | 149 | 150 | 151 | Magepow\Categories\Model\Config\Source\Col 152 | required-entry validate-greater-than-zero 153 | 154 | 155 | 156 | 157 | Magepow\Categories\Model\Config\Source\Col 158 | required-entry validate-greater-than-zero 159 | 160 | 161 | 162 | 163 | Magepow\Categories\Model\Config\Source\Col 164 | 165 | 166 | 167 | 168 | Magepow\Categories\Model\Config\Source\Col 169 | 170 | 171 | 172 | = 1920 ) ]]> 173 | Magepow\Categories\Model\Config\Source\Col 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | The way categories are presented. Can be either "Grid" or "List". 183 | Magepow\Categories\Model\Config\Layout 184 | 185 | 186 | 187 | The way categories are sorted. 188 | Magepow\Categories\Model\Config\SortAttribute 189 | 190 | 191 | 192 | Categories heading text. 193 | validate-no-html-tags 194 | 195 | 196 | 197 | Enables or disables description. 198 | Magento\Config\Model\Config\Source\Yesno 199 | 200 | 201 | 202 | Enables to use Thumbnail set in Categories or disables to use Category Image. 203 | Magento\Config\Model\Config\Source\Yesno 204 | 205 | 206 | 207 | Enables to show number of items in each category. 208 | Magento\Config\Model\Config\Source\Yesno 209 | 210 | 211 | 212 | Use Ctrl+Click for check several values or uncheck value. Select the categories displayed on the home page. 213 | Magepow\Categories\Model\Config\Category 214 | 1 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | Copy to code to page or block you want display categories 223 | Magepow\Categories\Block\System\Config\Form\Field\Snippet 224 | 225 | 226 |
227 |
228 |
229 | -------------------------------------------------------------------------------- /etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 1 7 | 8 | 9 | grid 10 | position 11 | 12 | 0 13 | 1 14 | 15 | 1 16 | false 17 | true 18 | true 19 | true 20 | false 21 | 0 22 | 300 23 | 3000 24 | 15 25 | 1 26 | 2 27 | 3 28 | 4 29 | 5 30 | 5 31 | 5 32 | 6 33 | 6 34 | 35 | 36 | grid 37 | position 38 | Categories 39 | 0 40 | 1 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /etc/widget.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | Magepow Categories Widget 17 | 18 | 19 | 20 | Magepow Categories Widget 21 | 22 | 23 | 24 | Magepow Categories Widget 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 47 | 48 | 49 | 50 | 51 | 52 | 55 | 58 | 59 | 60 | 61 | 62 | 63 | 66 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | Sort by typing down the category id and separating by comma.

77 |

Mentioned ids will be sorted from the top, unmentioned ids will queue at the back.

78 |

Wrong syntax won't sort.

79 |

Right syntax example: 1,2,3,4

]]>
80 | 81 | 82 | 83 |
84 | 85 | 86 | 87 | 90 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 104 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 118 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 132 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 146 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 160 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 300 171 | 172 | 173 | 174 | 175 | 176 | 177 | 3000 178 | 179 | 180 | 181 | 15 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 192 | 195 | 198 | 201 | 204 | 205 | 206 | 207 | 208 | 209 | 212 | 215 | 218 | 221 | 224 | 227 | 230 | 233 | 234 | 235 | 236 | 237 | 238 | 241 | 244 | 247 | 250 | 253 | 256 | 259 | 262 | 263 | 264 | 265 | 266 | 267 | 270 | 273 | 276 | 279 | 282 | 285 | 288 | 291 | 292 | 293 | 294 | 295 | 296 | 299 | 302 | 305 | 308 | 311 | 314 | 317 | 320 | 321 | 322 | 323 | 324 | 325 | 328 | 331 | 334 | 337 | 340 | 343 | 346 | 349 | 350 | 351 | 352 | 353 | 354 | 357 | 360 | 363 | 366 | 369 | 372 | 375 | 378 | 379 | 380 | 381 | 382 | 383 | 386 | 389 | 392 | 395 | 398 | 401 | 404 | 407 | 408 | 409 | 410 | 411 | 412 | 415 | 418 | 421 | 424 | 427 | 430 | 433 | 436 | 437 | 438 | 439 | 440 | 441 | 444 | 447 | 450 | 453 | 456 | 459 | 462 | 465 | 466 | 467 |
468 |
469 |
470 | -------------------------------------------------------------------------------- /media/Mgento-2-category-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magepow/magento-2-categories/1096b3388c0353da33213dce64f6e858a50813a7/media/Mgento-2-category-4.jpg -------------------------------------------------------------------------------- /media/frontend_category.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magepow/magento-2-categories/1096b3388c0353da33213dce64f6e858a50813a7/media/frontend_category.png -------------------------------------------------------------------------------- /media/frontend_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magepow/magento-2-categories/1096b3388c0353da33213dce64f6e858a50813a7/media/frontend_home.png -------------------------------------------------------------------------------- /media/magento-2-categories-10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magepow/magento-2-categories/1096b3388c0353da33213dce64f6e858a50813a7/media/magento-2-categories-10.jpg -------------------------------------------------------------------------------- /media/magento-2-categories-11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magepow/magento-2-categories/1096b3388c0353da33213dce64f6e858a50813a7/media/magento-2-categories-11.jpg -------------------------------------------------------------------------------- /media/magento-2-categories-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magepow/magento-2-categories/1096b3388c0353da33213dce64f6e858a50813a7/media/magento-2-categories-3.jpg -------------------------------------------------------------------------------- /media/magento-2-categories-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magepow/magento-2-categories/1096b3388c0353da33213dce64f6e858a50813a7/media/magento-2-categories-5.png -------------------------------------------------------------------------------- /media/magento-2-categories-6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magepow/magento-2-categories/1096b3388c0353da33213dce64f6e858a50813a7/media/magento-2-categories-6.jpg -------------------------------------------------------------------------------- /media/magento-2-categories-7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magepow/magento-2-categories/1096b3388c0353da33213dce64f6e858a50813a7/media/magento-2-categories-7.jpg -------------------------------------------------------------------------------- /media/magento-2-categories-8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magepow/magento-2-categories/1096b3388c0353da33213dce64f6e858a50813a7/media/magento-2-categories-8.jpg -------------------------------------------------------------------------------- /media/magento-2-categories-9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magepow/magento-2-categories/1096b3388c0353da33213dce64f6e858a50813a7/media/magento-2-categories-9.jpg -------------------------------------------------------------------------------- /registration.php: -------------------------------------------------------------------------------- 1 | 2 |
4 |
5 | 6 | 7 | 8 | string 9 | category 10 | Thumbnail 11 | true 12 | fileUploader 13 | ui/form/element/uploader/uploader 14 | Magento_Catalog/image-preview 15 | false 16 | 40 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |
-------------------------------------------------------------------------------- /view/frontend/layout/catalog_category_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /view/frontend/layout/cms_index_index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /view/frontend/templates/categories.phtml: -------------------------------------------------------------------------------- 1 | 12 | getCategories(); 20 | $layout = $block->getLayout(); 21 | $heading = $block->getHeading(); 22 | $description = $block->isShowDescription(); 23 | $itemAmount = $block->getItemAmount(); 24 | $selector = 'alo-content-' . uniqid(); 25 | ?> 26 | 27 | 28 | 29 |

30 | 31 |
32 |
33 |
67 | 68 | 69 | 70 | 71 |
72 | 73 | -------------------------------------------------------------------------------- /view/frontend/templates/categories_widget.phtml: -------------------------------------------------------------------------------- 1 | 12 | getCategories(); 20 | $heading = $block->getHeading(); 21 | $description = $block->isShowDescription(); 22 | $itemAmount = $block->getItemAmount(); 23 | if (empty($categories)) return; 24 | $selector = 'alo-content-' . uniqid(); 25 | ?> 26 | getData('visible'); ?> 27 | 30 | 31 |

32 |

getData('subtitle')); ?>

33 | 34 |
35 | 74 |
-------------------------------------------------------------------------------- /view/frontend/templates/cmspage.phtml: -------------------------------------------------------------------------------- 1 | 12 | getCategories(); 20 | $layout = $block->getLayout(); 21 | $heading = $block->getHeading(); 22 | $description = $block->isShowDescription(); 23 | $itemAmount = $block->getItemAmount(); 24 | ?> 25 | 26 | 27 |

28 | 29 | 66 | -------------------------------------------------------------------------------- /view/frontend/web/css/source/_module.less: -------------------------------------------------------------------------------- 1 | & when (@media-common = true) { 2 | .magepow-categories-grid, .magepow-categories-list { 3 | clear: both; 4 | display: block; 5 | margin: 0; 6 | padding: 0; 7 | border: none; 8 | box-sizing: content-box; 9 | width: 100%; 10 | list-style-type: none; 11 | text-align: left; 12 | } 13 | 14 | .magepow-categories-grid { 15 | display: flex; 16 | flex-wrap: wrap; 17 | } 18 | 19 | .magepow-categories-heading { 20 | margin: 16px 0; 21 | } 22 | 23 | 24 | /* Grid layout */ 25 | 26 | .magepow-categories-grid li { 27 | display: inline-block; 28 | text-align: left; 29 | margin: 0; 30 | padding: 0; 31 | border: none; 32 | box-sizing: content-box; 33 | width: 25%; 34 | vertical-align: top; 35 | } 36 | 37 | .magepow-categories-grid .category-item { 38 | display: block; 39 | margin: 16px; 40 | } 41 | 42 | .magepow-categories-grid .category-item-image img { 43 | margin: 0; 44 | padding: 0; 45 | border: none; 46 | width: 100%; 47 | } 48 | 49 | .magepow-categories-grid .category-item-name { 50 | text-align: center; 51 | } 52 | 53 | /* List layout */ 54 | 55 | .magepow-categories-list li { 56 | margin: 0; 57 | padding: 0; 58 | border: none; 59 | box-sizing: content-box; 60 | overflow: auto; 61 | } 62 | 63 | .magepow-categories-list .category-item { 64 | display: block; 65 | overflow: auto; 66 | margin: 16px; 67 | } 68 | 69 | .magepow-categories-list .category-item-image { 70 | float: left; 71 | width: 20%; /* These percentages must match 1/3 */ 72 | } 73 | 74 | .magepow-categories-list .category-item-image img { 75 | margin: 0; 76 | padding: 0; 77 | border: none; 78 | width: 100%; 79 | } 80 | 81 | .magepow-categories-list .category-item-name, 82 | .magepow-categories-list .category-item-description { 83 | margin: 0 0 16px 20%; 84 | padding: 0 0 0 32px; 85 | } 86 | 87 | .magepow-categories .category-item{ 88 | display: inline-block; 89 | float: left; 90 | } 91 | 92 | /* Media Queries */ 93 | 94 | @media only screen and (min-width: 320px) { 95 | 96 | .magepow-categories-grid li { 97 | width: 100%; 98 | } 99 | 100 | } 101 | 102 | @media only screen and (min-width: 360px) { 103 | 104 | .magepow-categories-grid li { 105 | width: 100%; 106 | } 107 | 108 | } 109 | 110 | @media only screen and (min-width: 400px) { 111 | 112 | .magepow-categories-grid li { 113 | width: 100%; 114 | } 115 | 116 | } 117 | 118 | @media only screen and (min-width: 480px) { 119 | 120 | .magepow-categories-grid li { 121 | width: 50%; 122 | } 123 | 124 | } 125 | 126 | @media only screen and (min-width: 540px) { 127 | 128 | .magepow-categories-grid li { 129 | width: 50%; 130 | } 131 | 132 | } 133 | 134 | @media only screen and (min-width: 600px) { 135 | 136 | .magepow-categories-grid li { 137 | width: 50%; 138 | } 139 | 140 | } 141 | 142 | @media only screen and (min-width: 640px) { 143 | 144 | .magepow-categories-grid li { 145 | width: 50%; 146 | } 147 | 148 | } 149 | 150 | @media only screen and (min-width: 720px) { 151 | 152 | .magepow-categories-grid li { 153 | width: 33.3%; 154 | } 155 | 156 | } 157 | 158 | @media only screen and (min-width: 768px) { 159 | 160 | .magepow-categories-grid li { 161 | width: 33.3%; 162 | } 163 | 164 | } 165 | 166 | @media only screen and (min-width: 800px) { 167 | 168 | .magepow-categories-grid li { 169 | width: 33.3%; 170 | } 171 | 172 | } 173 | 174 | @media only screen and (min-width: 960px) { 175 | 176 | .magepow-categories-grid li { 177 | width: 33.3%; 178 | } 179 | 180 | } 181 | 182 | @media only screen and (min-width: 1024px) { 183 | 184 | .magepow-categories-grid li { 185 | width: 25%; 186 | } 187 | 188 | } 189 | 190 | @media only screen and (min-width: 1280px) { 191 | 192 | .magepow-categories-grid li { 193 | width: 25%; 194 | } 195 | 196 | } 197 | } --------------------------------------------------------------------------------