├── .gitignore
├── Api
├── BreezeThemeDetectionInterface.php
├── GetCategoryByProductInterface.php
├── GetModuleInfoInterface.php
├── GetModuleVersionInterface.php
├── GetParentProductIdsInterface.php
├── GetWebsitesMapInterface.php
├── HyvaThemeDetectionInterface.php
└── SecureHtmlRendererInterface.php
├── Block
├── Adminhtml
│ ├── Edit
│ │ ├── BackButton.php
│ │ ├── CreateButton.php
│ │ ├── DeleteButton.php
│ │ ├── DuplicateButton.php
│ │ ├── GenericButton.php
│ │ ├── PreviewButton.php
│ │ ├── ResetButton.php
│ │ ├── SaveAndContinueButton.php
│ │ └── SaveButton.php
│ ├── HyvaThemeChecker.php
│ ├── Linv.php
│ └── System
│ │ └── Config
│ │ └── Form
│ │ ├── ExtensionsInfo.php
│ │ ├── Info.php
│ │ └── ProductKeyField.php
└── JsScript.php
├── Controller
└── Adminhtml
│ ├── Actions.php
│ └── Activate
│ └── Extension.php
├── Cron
└── Sections.php
├── LICENSE.txt
├── Model
├── AbstractThemeDetection.php
├── AdminNotificationFeed.php
├── BreezeThemeDetection.php
├── Config.php
├── GetCategoryByProduct.php
├── GetModuleInfo.php
├── GetModuleVersion.php
├── GetParentProductIds.php
├── GetWebsitesMap.php
├── HyvaThemeDetection.php
├── Magento
│ ├── Framework
│ │ └── Mail
│ │ │ └── Template
│ │ │ └── TransportBuilder.php
│ ├── Product
│ │ └── CollectionOptimizedForSqlValidator.php
│ └── Rule
│ │ └── Model
│ │ └── Condition
│ │ └── Sql
│ │ └── Builder.php
├── Section.php
├── Section
│ └── Info.php
├── SetLinvFlag.php
├── UrlChecker.php
└── View
│ └── Helper
│ └── SecureHtmlRenderer.php
├── Observer
├── ConfigObserver.php
└── PredispathAdminActionControllerObserver.php
├── Plugin
└── Magento
│ ├── Backend
│ └── Model
│ │ └── Menu
│ │ └── BuilderPlugin.php
│ └── Framework
│ └── View
│ └── TemplateEngine
│ └── Php.php
├── README.md
├── Setup
└── Patch
│ └── Data
│ └── UpdateWelcomeBlogPost.php
├── composer.json
├── etc
├── acl.xml
├── adminhtml
│ ├── di.xml
│ ├── events.xml
│ ├── routes.xml
│ └── system.xml
├── config.xml
├── crontab.xml
├── csp_whitelist.xml
├── di.xml
└── module.xml
├── registration.php
└── view
├── adminhtml
├── layout
│ ├── default.xml
│ └── marketplace_index_index.xml
├── templates
│ ├── hyvathemechecker.phtml
│ ├── linv.phtml
│ ├── menu-magefan.phtml
│ └── vendors.phtml
└── web
│ ├── css
│ └── source
│ │ └── _module.less
│ ├── fonts
│ └── variable
│ │ └── LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko20yw.woff2
│ └── images
│ ├── logo-config-section.png
│ ├── logo-menu.png
│ └── magefan-logo.png
└── base
└── templates
└── js
├── ajax.phtml
├── getCookie.phtml
├── objToUrlParams.phtml
└── setCookie.phtml
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
--------------------------------------------------------------------------------
/Api/BreezeThemeDetectionInterface.php:
--------------------------------------------------------------------------------
1 | __('Back'),
23 | 'on_click' => sprintf("location.href = '%s';", $this->getBackUrl()),
24 | 'class' => 'back',
25 | 'sort_order' => 10
26 | ];
27 | }
28 |
29 | /**
30 | * Get URL for back (reset) button
31 | *
32 | * @return string
33 | */
34 | public function getBackUrl()
35 | {
36 | return $this->getUrl('*/*/');
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Edit/CreateButton.php:
--------------------------------------------------------------------------------
1 | __('Create'),
23 | 'class' => 'save primary',
24 | 'data_attribute' => [
25 | 'mage-init' => ['button' => ['event' => 'save']],
26 | 'form-role' => 'save',
27 | ],
28 | 'sort_order' => 10
29 | ];
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Edit/DeleteButton.php:
--------------------------------------------------------------------------------
1 | getObjectId()) {
24 | $data = [
25 | 'label' => __('Delete'),
26 | 'class' => 'delete',
27 | 'on_click' => 'deleteConfirm(\'' . __(
28 | 'Are you sure you want to do this?'
29 | ) . '\', \'' . $this->getDeleteUrl() . '\')',
30 | 'sort_order' => 20,
31 | ];
32 | }
33 | return $data;
34 | }
35 |
36 | /**
37 | * @return string
38 | */
39 | public function getDeleteUrl()
40 | {
41 | return $this->getUrl('*/*/delete', ['id' => $this->getObjectId()]);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Edit/DuplicateButton.php:
--------------------------------------------------------------------------------
1 | getObjectId()) {
23 | $data = [
24 | 'label' => __('Duplicate'),
25 | 'class' => 'duplicate',
26 | 'on_click' => 'window.location=\'' . $this->getDuplicateUrl() . '\'',
27 | 'sort_order' => 40,
28 | ];
29 | }
30 | return $data;
31 | }
32 |
33 | /**
34 | * @return string
35 | */
36 | public function getDuplicateUrl()
37 | {
38 | return $this->getUrl('*/*/duplicate', ['id' => $this->getObjectId()]);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Edit/GenericButton.php:
--------------------------------------------------------------------------------
1 | context = $context;
38 | $this->authorization = $authorization
39 | ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
40 | \Magento\Framework\AuthorizationInterface::class
41 | );
42 | }
43 |
44 | /**
45 | * Return CMS block ID
46 | *
47 | * @return int|null
48 | */
49 | public function getObjectId()
50 | {
51 | return $this->context->getRequest()->getParam('id');
52 | }
53 |
54 | /**
55 | * Generate URL by route and parameters
56 | *
57 | * @param string $route
58 | * @param array $params
59 | * @return string
60 | */
61 | public function getUrl($route = '', $params = [])
62 | {
63 | if ($storeId = $this->context->getRequest()->getParam('store')) {
64 | $params['store'] = (int)$storeId;
65 | }
66 | return $this->context->getUrlBuilder()->getUrl($route, $params);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Edit/PreviewButton.php:
--------------------------------------------------------------------------------
1 | getObjectId()) {
23 | $data = [
24 | 'label' => __('Preview'),
25 | 'class' => 'preview',
26 | 'on_click' => 'window.open(\'' . $this->getPreviewUrl() . '\');',
27 | 'sort_order' => 35,
28 | ];
29 | }
30 | return $data;
31 | }
32 |
33 | /**
34 | * @return string
35 | */
36 | public function getPreviewUrl()
37 | {
38 | return $this->getUrl('*/*/preview', ['id' => $this->getObjectId()]);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Edit/ResetButton.php:
--------------------------------------------------------------------------------
1 | __('Reset'),
23 | 'class' => 'reset',
24 | 'on_click' => 'location.reload();',
25 | 'sort_order' => 30
26 | ];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Edit/SaveAndContinueButton.php:
--------------------------------------------------------------------------------
1 | __('Save and Continue Edit'),
24 | 'class' => 'save',
25 | 'data_attribute' => [
26 | 'mage-init' => [
27 | 'button' => ['event' => 'saveAndContinueEdit'],
28 | ],
29 | ],
30 | 'sort_order' => 80,
31 | ];
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Edit/SaveButton.php:
--------------------------------------------------------------------------------
1 | __('Save'),
23 | 'class' => 'save primary',
24 | 'data_attribute' => [
25 | 'mage-init' => ['button' => ['event' => 'save']],
26 | 'form-role' => 'save',
27 | ],
28 | 'sort_order' => 90,
29 | ];
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Block/Adminhtml/HyvaThemeChecker.php:
--------------------------------------------------------------------------------
1 | moduleManager = $moduleManager;
44 | $this->hyvaThemeDetection =$hyvaThemeDetection;
45 | }
46 |
47 | /**
48 | * @return array
49 | */
50 | public function getWitchModuleIsInstalled(): array
51 | {
52 | $moduleGroups = [
53 | 'Blog' => [
54 | 'Magefan_BlogExtra' => 'magefan/hyva-theme-blog-extra',
55 | 'Magefan_BlogPlus' => 'magefan/hyva-theme-blog-plus',
56 | 'Magefan_Blog' => 'magefan/hyva-theme-blog'
57 | ],
58 | 'AutoRelatedProduct' => [
59 | 'Magefan_AutoRelatedProductPlus' => 'magefan/hyva-theme-auto-related-product-plus',
60 | 'Magefan_AutoRelatedProduct' => 'magefan/hyva-theme-auto-related-product'
61 | ],
62 | 'AutoLanguageSwitcher' => [
63 | 'Magefan_AutoLanguageSwitcher' => 'magefan/hyva-theme-auto-language-switcher'
64 | ]
65 | ];
66 |
67 | $hyvaModules = [];
68 | foreach ($moduleGroups as $groupKey => $modules) {
69 | foreach ($modules as $module => $packageName) {
70 | if ($this->moduleManager->isEnabled($module)) {
71 | $hyvaModule = 'Hyva_' . str_replace('_', '', $module);
72 | if (!$this->moduleManager->isEnabled($hyvaModule)) {
73 | $hyvaModules[$hyvaModule] = $packageName;
74 | break;
75 | }
76 | }
77 | }
78 | }
79 | return $hyvaModules;
80 | }
81 |
82 | /**
83 | * Produce and return block's html output
84 | *
85 | * This method should not be overridden. You can override _toHtml() method in descendants if needed.
86 | *
87 | * @return string
88 | */
89 | public function toHtml()
90 | {
91 | if (!$this->hyvaThemeDetection->execute()) {
92 | return '';
93 | }
94 |
95 | return parent::toHtml();
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Linv.php:
--------------------------------------------------------------------------------
1 | sectionFactory = $sectionFactory;
41 | $this->resource = $resource;
42 | }
43 |
44 | /**
45 | * @return array
46 | */
47 | public function getItems()
48 | {
49 | $connection = $this->resource->getConnection();
50 | $table = $this->resource->getTableName('core_config_data');
51 | $path = '/g'.'en'.'er'.'al'.'/l'.'in'.'v';
52 | $select = $connection->select()
53 | ->from([$table])
54 | ->where( 'path LIKE ?', '%' . $path )
55 | ->where('value = ?',1);
56 | $items = $connection->fetchAll($select);
57 | $result = [];
58 |
59 | foreach ($items as $config) {
60 | $configPath = explode('/', $config['path']);
61 | $moduleName = $configPath[0];
62 | $section = $this->sectionFactory->create([
63 | 'name' => $moduleName
64 | ]);
65 | $module = $section->getModule(true);
66 | if ($module && !$section->isEnabled()) {
67 | $result[] = $module;
68 | }
69 |
70 | }
71 | return $result;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Block/Adminhtml/System/Config/Form/ExtensionsInfo.php:
--------------------------------------------------------------------------------
1 | moduleList = $moduleList;
48 | $this->getModuleVersion = $getModuleVersion;
49 | $this->getModuleInfo = $getModuleInfo;
50 | }
51 |
52 | /**
53 | * @param AbstractElement $element
54 | * @return string
55 | */
56 | public function render(AbstractElement $element)
57 | {
58 | $modulesInfo = $this->getModuleInfo->execute();
59 | if (!$modulesInfo) {
60 | return '';
61 | }
62 |
63 | $lists = [
64 | 'need_update' => __('Extensions to Update'),
65 | 'up_to_date' => __('Up-to-Date Extensions'),
66 | 'new_extensions' => __('Available NEW Extensions'),
67 | ];
68 |
69 | $html = '';
70 | foreach ($lists as $listKey => $lable) {
71 | $html .= '
' . $this->escapeHtml($lable) . ' ';
72 | $html .= '';
73 | $html .= '';
74 | $html .= '';
75 | $html .= '' . $this->escapeHtml(__('Extension')) . ' ';
76 | $html .= '' . $this->escapeHtml(__('Version')) . ' ';
77 | $html .= '' . $this->escapeHtml(__('Change Log')) . ' ';
78 | $html .= '' . $this->escapeHtml(__('User Guide')) . ' ';
79 | $html .= ' ';
80 | $html .= ' ';
81 | $html .= '';
82 |
83 | foreach ($modulesInfo as $moduleKey => $moduleInfo) {
84 |
85 | $moduleName = 'Magefan_' . $moduleKey;
86 | $module = $this->moduleList->getOne($moduleName);
87 |
88 | if ((!$module && $listKey != 'new_extensions') || ($module && $listKey == 'new_extensions')) {
89 | continue;
90 | }
91 | if ($listKey == 'up_to_date' && version_compare($this->getModuleVersion->execute($moduleName), $moduleInfo->getVersion()) < 0) {
92 | continue;
93 | }
94 | if ($listKey == 'need_update' && version_compare($this->getModuleVersion->execute($moduleName), $moduleInfo->getVersion()) >= 0) {
95 | continue;
96 | }
97 |
98 | if ($listKey == 'need_update') {
99 | $version = $this->getModuleVersion->execute($moduleName) . ' -> ' . $moduleInfo->getVersion();
100 | } elseif ($listKey == 'new_extensions') {
101 | $version = $moduleInfo->getVersion();
102 | } else {
103 | $version = $this->getModuleVersion->execute($moduleName);
104 | }
105 |
106 |
107 | $html .= '';
108 | $html .= '' . $this->escapeHtml($moduleInfo->getProductName()) . ' ';
109 | $html .= '' . $this->escapeHtml($version) . ' ';
110 | $html .= '' . $this->escapeHtml(__('Change Log')) . ' ';
111 | $html .= ''. $this->escapeHtml(__('User Guide')). ' ';
112 | $html .= ' ';
113 | }
114 |
115 | $html .= ' ';
116 | $html .= '
';
117 | }
118 | return $html;
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/Block/Adminhtml/System/Config/Form/Info.php:
--------------------------------------------------------------------------------
1 | moduleList = $moduleList;
56 | $this->getModuleVersion = $getModuleVersion ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
57 | \Magefan\Community\Api\GetModuleVersionInterface::class
58 | );
59 | $this->mfSecureRenderer = $mfSecureRenderer ?: \Magento\Framework\App\ObjectManager::getInstance()
60 | ->get(SecureHtmlRendererInterface::class);
61 | $this->getModuleInfo = $getModuleInfo ?: \Magento\Framework\App\ObjectManager::getInstance()
62 | ->get(GetModuleInfoInterface::class);
63 | }
64 |
65 | /**
66 | * Return info block html
67 | * @param \Magento\Framework\Data\Form\Element\AbstractElement $element
68 | * @return string
69 | */
70 | public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element)
71 | {
72 | $moduleName = $this->getModuleName();
73 |
74 | $currentVersion = $this->getModuleVersion->execute($moduleName);
75 | $moduleInfo = $this->getModuleInfo->execute($moduleName);
76 |
77 | $plan = '';
78 | foreach (['Extra', 'Plus'] as $_plan) {
79 | if ($_currentVersion = $this->getModuleVersion->execute($moduleName . $_plan)) {
80 | $plan = $_plan;
81 | $currentVersion = $_currentVersion;
82 | break;
83 | }
84 | }
85 |
86 | if ($latestVersion = $moduleInfo->getVersion()) {
87 |
88 | $fullModuleTitle = $moduleInfo->getProductName();
89 | $moduleUrl = $moduleInfo->getProductUrl();
90 | $moduleImage = $moduleInfo->getProductImage();
91 |
92 | $newVersionAvailable = version_compare($latestVersion, $currentVersion) > 0;
93 | $moduleTitle = str_replace(['Magento 2', 'Magento'], ['', ''], (string)$fullModuleTitle);
94 | $moduleTitle = trim($moduleTitle);
95 |
96 | } else {
97 |
98 | $fullModuleTitle = $moduleTitle = $this->getModuleTitle();
99 | $newVersionAvailable = false;
100 | $moduleUrl = $this->getModuleUrl();
101 | $moduleImage = '';
102 | }
103 |
104 | $utmParam = '?utm_source=admin&utm_medium=config';
105 |
106 | if ($moduleInfo->getMaxPlan()) {
107 | $canUpgradeToMaxPlan = !$this->getModuleVersion->execute($moduleName . ucfirst($moduleInfo->getMaxPlan()));
108 | } else {
109 | $canUpgradeToMaxPlan = false;
110 | }
111 |
112 | $html = '
113 |
114 |
119 |
120 |
127 |
128 |
developed by
129 | Mage' . 'fan
130 | ' .
131 | ($latestVersion ? '
132 |
133 |
134 |
135 |
136 |
137 |
138 | User Guide
139 | ' : '') . '
140 |
141 |
142 |
143 |
144 |
145 |
';
146 | if ($canUpgradeToMaxPlan) {
147 | $html .= '
Upgrade Plan ';
148 | }
149 |
150 | if ($newVersionAvailable) {
151 | $html .= '
Upgrade to new Version
152 |
153 |
154 | ';
155 | }
156 | $html .= '
157 | ';
158 | if ($newVersionAvailable) {
159 | $html .= '
Version v' . $this->escapeHtml($latestVersion) . ' is available
';
160 | }
161 | $html .= '
162 |
163 |
198 | ';
199 |
200 | return $html;
201 | }
202 |
203 | /**
204 | * Return extension url
205 | * @return string
206 | */
207 | protected function getModuleUrl()
208 | {
209 | return 'https://magefan.com/';
210 | }
211 |
212 | /**
213 | * Return extension title
214 | * @return string
215 | */
216 | protected function getModuleTitle()
217 | {
218 | return ucwords(str_replace('_', ' ', $this->getModuleName())) . ' Extension';
219 | }
220 |
221 | }
222 |
--------------------------------------------------------------------------------
/Block/Adminhtml/System/Config/Form/ProductKeyField.php:
--------------------------------------------------------------------------------
1 | getFieldConfig();
29 | $path = explode('/', $fieldConfig['path']);
30 | $path = $path[0];
31 |
32 | $section = $objectManager->create(Section::class, ['name' => $path]);
33 | if ($section->getModule()) {
34 | if (!$element->getComment()) {
35 | $url = 'htt' . 'ps' . ':' . '/'. '/'. 'ma' . 'g' . 'ef' . 'an' . '.' . 'co'
36 | . 'm/' . 'down' . 'loa' . 'dab' . 'le/' . 'cus' . 'tomer' . '/' . 'pr' . 'od' . 'ucts' . '/';
37 | $element->setComment('You can find product key in your Magefan account .');
38 | }
39 | return parent::render($element);
40 | } else {
41 | $config = ObjectManager::getInstance()->get(\Magefan\Community\Model\Config::class);
42 | $bp = $section->getName() . '/' . 'g' . 'e' . 'n' . 'e' . 'r' . 'a' . 'l' . '/' ;
43 | if (!$config->getConfig( $bp . Section::ACTIVE) && !$section->getType()) {
44 | $url = 'ht' . 'tps'. ':' . '/'. '/'. 'ma' . 'g' . 'ef' . 'an' . '.' . 'c' . 'o' . 'm' . '/' . 'mp' . 'k/a' . 'cti' . 'vat' . 'e/e' . 'xte' . 'nsi' . 'on/' . 'ret' . 'urn_' . 'ur' . 'l/' .
45 | base64_encode($this->getUrl('m' . 'f' . 'co' . 'mm' . 'uni' . 'ty/' . 'act' . 'iva' . 'te/ext' . 'ens' . 'ion', ['section' => $section->getName()]))
46 | . '/mo' . 'dul' . 'e/' . $section->getModuleName() . '/se' . 'cti' . 'on/' . $section->getName();
47 | return '
48 |
49 |
50 |
51 |
52 | ' . __('Activate Extension') . '
53 |
54 |
55 |
56 | ' ;
57 | }
58 | }
59 | return '';
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Block/JsScript.php:
--------------------------------------------------------------------------------
1 | jsMethod = $method;
32 | return $this;
33 | }
34 |
35 | public function getTemplate()
36 | {
37 | if (!$this->_template) {
38 | $this->_template = 'Magefan_Community::js/' . $this->jsMethod . '.phtml';
39 | }
40 | return parent::getTemplate();
41 | }
42 |
43 | /**
44 | * @return string
45 | */
46 | public function toHtml()
47 | {
48 | if (isset(self::$rendered[$this->jsMethod])) {
49 | return '';
50 | }
51 | self::$rendered[$this->jsMethod] = 1;
52 | return parent::toHtml();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Actions.php:
--------------------------------------------------------------------------------
1 | dataPersistor = $dataPersistor;
93 | parent::__construct($context);
94 | }
95 |
96 | /**
97 | * Action execute
98 | * @return \Magento\Framework\Controller\ResultInterface
99 | */
100 | public function execute()
101 | {
102 | $_preparedActions = ['index', 'grid', 'new', 'edit', 'save', 'duplicate', 'delete', 'config', 'massStatus'];
103 | $_action = $this->getRequest()->getActionName();
104 | if (in_array($_action, $_preparedActions)) {
105 | $method = '_'.$_action.'Action';
106 |
107 | $this->_beforeAction();
108 | $this->$method();
109 | $this->_afterAction();
110 | }
111 | }
112 |
113 | /**
114 | * Index action
115 | * @return void
116 | */
117 | protected function _indexAction()
118 | {
119 | if ($this->getRequest()->getParam('ajax')) {
120 | $this->_forward('grid');
121 | return;
122 | }
123 |
124 | $this->_view->loadLayout();
125 | $this->_setActiveMenu($this->_activeMenu);
126 | $title = __('Manage %1', $this->_getModel(false)->getOwnTitle(true));
127 | $this->_view->getPage()->getConfig()->getTitle()->prepend($title);
128 | $this->_addBreadcrumb($title, $title);
129 | $this->_view->renderLayout();
130 | }
131 |
132 | /**
133 | * Grid action
134 | * @return void
135 | */
136 | protected function _gridAction()
137 | {
138 | $this->_view->loadLayout(false);
139 | $this->_view->renderLayout();
140 | }
141 |
142 | /**
143 | * New action
144 | * @return void
145 | */
146 | protected function _newAction()
147 | {
148 | $this->_forward('edit');
149 | }
150 |
151 | /**
152 | * Edit action
153 | * @return void
154 | */
155 | public function _editAction()
156 | {
157 |
158 | try {
159 | $model = $this->_getModel();
160 | $id = $this->getRequest()->getParam('id');
161 | if (!$model->getId() && $id) {
162 | throw new \Exception("Item is not longer exist.", 1);
163 | }
164 | $this->_getRegistry()->register('current_model', $model);
165 |
166 | $this->_view->loadLayout();
167 | $this->_setActiveMenu($this->_activeMenu);
168 |
169 | $title = $model->getOwnTitle();
170 | if ($model->getId()) {
171 | $breadcrumbTitle = __('Edit %1', $title);
172 | $breadcrumbLabel = $breadcrumbTitle;
173 | } else {
174 | $breadcrumbTitle = __('New %1', $title);
175 | $breadcrumbLabel = __('Create %1', $title);
176 | }
177 | $this->_view->getPage()->getConfig()->getTitle()->prepend(__($title));
178 | $this->_view->getPage()->getConfig()->getTitle()->prepend(
179 | $model->getId() ? $this->_getModelName($model) : __('New %1', $title)
180 | );
181 |
182 | $this->_addBreadcrumb($breadcrumbLabel, $breadcrumbTitle);
183 |
184 | // restore data
185 | $values = $this->_getSession()->getData($this->_formSessionKey, true);
186 | if ($this->_paramsHolder) {
187 | $values = isset($values[$this->_paramsHolder]) ? $values[$this->_paramsHolder] : null;
188 | }
189 |
190 | if ($values) {
191 | $model->addData($values);
192 | }
193 |
194 | $this->_view->renderLayout();
195 | } catch (\Exception $e) {
196 | $this->messageManager->addException(
197 | $e,
198 | __(
199 | 'Something went wrong: %1',
200 | $e->getMessage()
201 | )
202 | );
203 | $this->_redirect('*/*/');
204 | }
205 | }
206 |
207 | /**
208 | * Retrieve model name
209 | * @param boolean $plural
210 | * @return string
211 | */
212 | protected function _getModelName(\Magento\Framework\Model\AbstractModel $model)
213 | {
214 | return $model->getName() ?: $model->getTitle();
215 | }
216 |
217 | /**
218 | * Save action
219 | * @return void
220 | */
221 | public function _saveAction()
222 | {
223 | $request = $this->getRequest();
224 | if (!$request->isPost()) {
225 | $this->getResponse()->setRedirect($this->getUrl('*/*'));
226 | }
227 | $model = $this->_getModel();
228 |
229 | try {
230 | $params = $this->_paramsHolder ? $request->getParam($this->_paramsHolder) : $request->getParams();
231 | $params = $this->filterParams($params);
232 |
233 | $idFieldName = $model->getResource()->getIdFieldName();
234 | if (isset($params[$idFieldName]) && empty($params[$idFieldName])) {
235 | unset($params[$idFieldName]);
236 | }
237 | $model->addData($params);
238 |
239 | $this->_eventManager->dispatch('magefan_' . $this->getRequest()->getModuleName() . '_' . $this->getRequest()->getControllerName() . '_form_before_save', ['model' => $model]);
240 |
241 | $this->_beforeSave($model, $request);
242 | $model->save();
243 |
244 | $this->_afterSave($model, $request);
245 |
246 | $this->_eventManager->dispatch('magefan_' . $this->getRequest()->getModuleName() . '_' . $this->getRequest()->getControllerName() . '_form_after_save', ['model' => $model]);
247 |
248 | $this->messageManager->addSuccess(__('%1 has been saved.', $model->getOwnTitle()));
249 | $this->_setFormData(false);
250 | } catch (\Magento\Framework\Exception\LocalizedException $e) {
251 | $this->messageManager->addError(nl2br($e->getMessage()));
252 | $this->_setFormData($params);
253 | } catch (\Exception $e) {
254 | $this->messageManager->addException(
255 | $e,
256 | __(
257 | 'Something went wrong while saving this %1. %2',
258 | strtolower($model->getOwnTitle()),
259 | $e->getMessage()
260 | )
261 | );
262 | $this->_setFormData($params);
263 | }
264 |
265 | $hasError = (bool)$this->messageManager->getMessages()->getCountByType(
266 | \Magento\Framework\Message\MessageInterface::TYPE_ERROR
267 | );
268 |
269 | if ($request->getParam('isAjax')) {
270 | $block = $this->_objectManager->create(\Magento\Framework\View\Layout::class)->getMessagesBlock();
271 | $block->setMessages($this->messageManager->getMessages(true));
272 |
273 | $this->getResponse()->setBody(json_encode(
274 | [
275 | 'messages' => $block->getGroupedHtml(),
276 | 'error' => $hasError,
277 | 'model' => $model->toArray(),
278 | ]
279 | ));
280 | } else {
281 | if ($hasError || $request->getParam('back')) {
282 | if ($storeId = $request->getParam('store')) {
283 | $this->_redirect('*/*/edit', [$this->_idKey => $model->getId(), 'store' => (int)$storeId]);
284 | } else {
285 | $this->_redirect('*/*/edit', [$this->_idKey => $model->getId()]);
286 | }
287 | } else {
288 | if ($storeId = $request->getParam('store')) {
289 | $this->_redirect('*/*', ['store' => (int)$storeId]);
290 | } else {
291 | $this->_redirect('*/*');
292 | }
293 | }
294 | }
295 | }
296 |
297 | /**
298 | * Duplicat action
299 | * @return void
300 | */
301 | protected function _duplicateAction()
302 | {
303 | try {
304 | $originModel = $this->_getModel();
305 | if (!$originModel->getId()) {
306 | throw new \Exception("Item is not longer exist.", 1);
307 | }
308 |
309 | $model = $originModel->duplicate();
310 |
311 | $this->messageManager->addSuccess(__('%1 has been duplicated.', $model->getOwnTitle()));
312 | $this->_redirect('*/*/edit', [$this->_idKey => $model->getId()]);
313 | } catch (\Exception $e) {
314 | $this->messageManager->addException(
315 | $e,
316 | __(
317 | 'Something went wrong while saving this %1. %2',
318 | strtolower(isset($model) ? $model->getOwnTitle() : 'item'),
319 | $e->getMessage()
320 | )
321 | );
322 | $this->_redirect('*/*/edit', [$this->_idKey => $originModel->getId()]);
323 | }
324 | }
325 |
326 | /**
327 | * Before model Save action
328 | * @return void
329 | */
330 | protected function _beforeSave($model, $request)
331 | {
332 | }
333 |
334 | /**
335 | * After model action
336 | * @return void
337 | */
338 | protected function _afterSave($model, $request)
339 | {
340 | }
341 |
342 | /**
343 | * Before action
344 | * @return void
345 | */
346 | protected function _beforeAction()
347 | {
348 | }
349 |
350 | /**
351 | * After action
352 | * @return void
353 | */
354 | protected function _afterAction()
355 | {
356 | }
357 |
358 | /**
359 | * Delete action
360 | * @return void
361 | */
362 | protected function _deleteAction()
363 | {
364 | $ids = $this->getRequest()->getParam($this->_idKey);
365 |
366 | if (!is_array($ids)) {
367 | $ids = [$ids];
368 | }
369 |
370 | $error = false;
371 | try {
372 | foreach ($ids as $id) {
373 | $this->_objectManager->create($this->_modelClass)->load($id)->delete();
374 | }
375 | } catch (\Magento\Framework\Exception\LocalizedException $e) {
376 | $error = true;
377 | $this->messageManager->addError($e->getMessage());
378 | } catch (\Exception $e) {
379 | $error = true;
380 | $this->messageManager->addException(
381 | $e,
382 | __(
383 | "We can't delete %1 right now. %2",
384 | strtolower($this->_getModel(false)->getOwnTitle()),
385 | $e->getMessage()
386 | )
387 | );
388 | }
389 |
390 | if (!$error) {
391 | $this->messageManager->addSuccess(
392 | __('%1 have been deleted.', $this->_getModel(false)->getOwnTitle(count($ids) > 1))
393 | );
394 | }
395 |
396 | $this->_redirect('*/*');
397 | }
398 |
399 | /**
400 | * Change status action
401 | * @return void
402 | */
403 | protected function _massStatusAction()
404 | {
405 | $ids = $this->getRequest()->getParam($this->_idKey);
406 |
407 | if (!is_array($ids)) {
408 | $ids = [$ids];
409 | }
410 |
411 | $model = $this->_getModel(false);
412 |
413 | $error = false;
414 |
415 | try {
416 | $status = $this->getRequest()->getParam('status');
417 | $statusFieldName = $this->_statusField;
418 |
419 | if (is_null($status)) {
420 | throw new \Exception(__('Parameter "Status" missing in request data.'));
421 | }
422 |
423 | if (is_null($statusFieldName)) {
424 | throw new \Exception(__('Status Field Name is not specified.'));
425 | }
426 |
427 | foreach ($ids as $id) {
428 | $this->_objectManager->create($this->_modelClass)
429 | ->load($id)
430 | ->setData($this->_statusField, $status)
431 | ->save();
432 | }
433 | } catch (\Magento\Framework\Exception\LocalizedException $e) {
434 | $error = true;
435 | $this->messageManager->addError($e->getMessage());
436 | } catch (\Exception $e) {
437 | $error = true;
438 | $this->messageManager->addException(
439 | $e,
440 | __(
441 | "We can't change status of %1 right now. %2",
442 | strtolower($model->getOwnTitle()),
443 | $e->getMessage()
444 | )
445 | );
446 | }
447 |
448 | if (!$error) {
449 | $this->messageManager->addSuccess(
450 | __('%1 status have been changed.', $model->getOwnTitle(count($ids) > 1))
451 | );
452 | }
453 |
454 | $this->_redirect('*/*');
455 | }
456 |
457 | /**
458 | * Go to config section action
459 | * @return void
460 | */
461 | protected function _configAction()
462 | {
463 | $this->_redirect('admin/system_config/edit', ['section' => $this->_configSection()]);
464 | }
465 |
466 | /**
467 | * Set form data
468 | * @return $this
469 | */
470 | protected function _setFormData($data = null)
471 | {
472 | if (null === $data) {
473 | $data = $this->getRequest()->getParams();
474 | }
475 |
476 | if (false === $data) {
477 | $this->dataPersistor->clear($this->_formSessionKey);
478 | } else {
479 | $this->dataPersistor->set($this->_formSessionKey, $data);
480 | }
481 |
482 | /* deprecated save in session */
483 | $this->_getSession()->setData($this->_formSessionKey, $data);
484 |
485 | return $this;
486 | }
487 |
488 | /**
489 | * Filter request params
490 | * @param array $data
491 | * @return array
492 | */
493 | protected function filterParams($data)
494 | {
495 | return $data;
496 | }
497 |
498 | /**
499 | * Get core registry
500 | * @return void
501 | */
502 | protected function _getRegistry()
503 | {
504 | if (is_null($this->_coreRegistry)) {
505 | $this->_coreRegistry = $this->_objectManager->get(\Magento\Framework\Registry::class);
506 | }
507 | return $this->_coreRegistry;
508 | }
509 |
510 | /**
511 | * Check is allowed access
512 | *
513 | * @return bool
514 | */
515 | protected function _isAllowed()
516 | {
517 | return $this->_authorization->isAllowed($this->_allowedKey);
518 | }
519 |
520 | /**
521 | * Retrieve model object
522 | * @return \Magento\Framework\Model\AbstractModel
523 | */
524 | protected function _getModel($load = true)
525 | {
526 | if (is_null($this->_model)) {
527 | $this->_model = $this->_objectManager->create($this->_modelClass);
528 |
529 | $id = (int)$this->getRequest()->getParam($this->_idKey);
530 | $idFieldName = $this->_model->getResource()->getIdFieldName();
531 | if (!$id && $this->_idKey !== $idFieldName) {
532 | $id = (int)$this->getRequest()->getParam($idFieldName);
533 | }
534 |
535 | if ($id && $load) {
536 | $this->_model->load($id);
537 | $this->_eventManager->dispatch('magefan_' . $this->getRequest()->getModuleName() . '_' . $this->getRequest()->getControllerName() . '_form_load_model_after', ['model' => $this->_model]);
538 | }
539 | }
540 | return $this->_model;
541 | }
542 |
543 | /**
544 | * @param array $filterRules
545 | * @param array $validatorRules
546 | * @param array|null $data
547 | * @return mixed
548 | */
549 | protected function getFilterInput($filterRules, $validatorRules, $data)
550 | {
551 | if (class_exists('\Magento\Framework\Filter\FilterInput')) {
552 | $inputFilter = new \Magento\Framework\Filter\FilterInput(
553 | $filterRules,
554 | [],
555 | $data
556 | );
557 | } else {
558 | $inputFilter = new \Zend_Filter_Input(
559 | $filterRules,
560 | [],
561 | $data
562 | );
563 | }
564 |
565 | return $inputFilter;
566 | }
567 | }
568 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Activate/Extension.php:
--------------------------------------------------------------------------------
1 | configWriter = $configWriter;
51 | $this->cacheTypeList = $cacheTypeList;
52 | $this->date = $date;
53 | parent::__construct($context);
54 | }
55 |
56 | /**
57 | * @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\Result\Redirect|\Magento\Framework\Controller\ResultInterface
58 | * @throws NoSuchEntityException
59 | */
60 | public function execute()
61 | {
62 | try {
63 | $activationKey = (string)$this->getRequest()->getParam('activation_key');
64 | if (!$this->getRequest()->getParam('activation_key')) {
65 | throw new LocalizedException(__('Activation Key is missing. Please contact Magefan support.'));
66 | }
67 |
68 | $section = (string)$this->getRequest()->getParam('section');
69 | if (!$section) {
70 | throw new LocalizedException(__('Section param is missing. Please contact Magefan support.'));
71 | }
72 |
73 | $urlInfo = parse_url($this->_url->getCurrentUrl());
74 | $domain = isset($urlInfo['host']) ? $urlInfo['host'] : '';
75 |
76 | $date = $this->date->gmtDate();
77 | $key = sha1(date('y-m-d', strtotime($date)) . '_' . $section . '_' . $domain);
78 | if ($activationKey !== $key) {
79 | throw new LocalizedException(__('Invalid Activation Key. Please contact Magefan support.'));
80 | }
81 |
82 | $this->configWriter->save($section . '/g'.'e'.'n'.'e'.'r'.'a'.'l'.'/'.Section::ACTIVE, 1, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, 0);
83 | $this->cacheTypeList->cleanType(Config::TYPE_IDENTIFIER);
84 |
85 | $this->messageManager->addSuccess(__('Thank you. Extension has been activated.'));
86 | return $this->resultRedirectFactory->create()->setUrl($this->_url->getUrl('adminhtml/system_config/edit', ['section' => $section]));
87 | } catch (LocalizedException $e) {
88 | $this->messageManager->addError($e->getMessage());
89 | return $this->resultRedirectFactory->create()->setUrl($this->_url->getUrl('adminhtml'));
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/Cron/Sections.php:
--------------------------------------------------------------------------------
1 | resource = $resource;
53 | $this->sectionFactory = $sectionFactory;
54 | $this->info = $info;
55 | $this->setLinvFlag = $setLinvFlag;
56 | }
57 |
58 | /**
59 | * Execute cron job
60 | */
61 | public function execute()
62 | {
63 | $connection = $this->resource->getConnection();
64 | $table = $this->resource->getTableName('core_config_data');
65 | $path = 'gen' . 'er' . 'al'. '/' . 'ena' . 'bled';
66 |
67 | $select = $connection->select()->from(
68 | [$table]
69 | )->where(
70 | 'path LIKE ?',
71 | '%' . $path
72 | );
73 |
74 | $sections = [];
75 | foreach ($connection->fetchAll($select) as $config) {
76 | $matches = false;
77 | preg_match("/(.*)\/" . str_replace('/', '\/', $path) . "/", $config['path'], $matches);
78 | if (empty($matches[1])) {
79 | continue;
80 | }
81 | $section = $this->sectionFactory->create([
82 | 'name' => $matches[1]
83 | ]);
84 |
85 | if ($section->getModule()) {
86 | $sections[$section->getModule()] = $section;
87 | } else {
88 | unset($section);
89 | }
90 | }
91 |
92 | if (count($sections)) {
93 | $data = $this->info->load($sections);
94 |
95 | if ($data && is_array($data)) {
96 | foreach ($data as $module => $item) {
97 | $section = $sections[$module];
98 | $moduleName = $section->getName();
99 | if (!$section->validate($data)) {
100 | $connection->update(
101 | $table,
102 | [
103 | 'value' => 0
104 | ],
105 | ['path = ? ' => $section->getName() . '/' . $path]
106 | );
107 | $this->setLinvFlag->execute($moduleName, 1);
108 | } else {
109 | $this->setLinvFlag->execute($moduleName, 0);
110 | }
111 | }
112 | }
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Please visit Magefan.com for license details (https://magefan.com/end-user-license-agreement) or email Magefan (support@magefan.com) to get a copy of license agreement.
--------------------------------------------------------------------------------
/Model/AbstractThemeDetection.php:
--------------------------------------------------------------------------------
1 | moduleManager = $moduleManager;
59 | $this->storeManager = $storeManager;
60 | $this->scopeConfig = $scopeConfig;
61 | $this->themeProvider = $themeProvider;
62 | }
63 |
64 | /**
65 | * @return string
66 | */
67 | abstract public function getThemeModuleName(): string;
68 |
69 | /**
70 | * @return string
71 | */
72 | abstract public function getThemeName():string;
73 |
74 | /**
75 | * @param $storeId
76 | * @return bool
77 | * @throws NoSuchEntityException
78 | */
79 | public function execute($storeId = null): bool
80 | {
81 | $key = 'store_' . $storeId;
82 | if (isset($this->result[$key])) {
83 | return $this->result[$key];
84 | }
85 |
86 | $themeEnabled = $this->moduleManager->isEnabled($this->getThemeModuleName());
87 |
88 | if ($themeEnabled) {
89 |
90 | if (null === $storeId) {
91 | $storeId = $this->storeManager->getStore()->getId();
92 | }
93 |
94 | if (!$storeId){
95 | $stores = $this->storeManager->getStores();
96 | foreach ($stores as $store) {
97 | if ($this->isThemeInUse($store->getId())) {
98 | $this->result[$key] = true;
99 | return $this->result[$key];
100 | }
101 | }
102 | } else {
103 | $this->result[$key] = $this->isThemeInUse($storeId);
104 | return $this->result[$key];
105 | }
106 | }
107 | $this->result[$key] = false;
108 | return $this->result[$key];
109 | }
110 |
111 | /**
112 | * @param $storeId
113 | * @return bool
114 | */
115 | private function isThemeInUse($storeId)
116 | {
117 | $themeId = $this->scopeConfig->getValue(
118 | \Magento\Framework\View\DesignInterface::XML_PATH_THEME_ID,
119 | \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
120 | $storeId
121 | );
122 | if ($themeId) {
123 | try {
124 | $theme = $this->themeProvider->getThemeById($themeId);
125 | } catch (\Exception $e) {
126 | $theme = false;
127 | }
128 |
129 | while ($theme) {
130 | $themePath = $theme->getThemePath();
131 | if (false !== stripos($themePath, $this->getThemeName())) {
132 | return true;
133 | }
134 |
135 | $theme = $theme->getParentTheme();
136 | }
137 | }
138 | return false;
139 | }
140 | }
--------------------------------------------------------------------------------
/Model/AdminNotificationFeed.php:
--------------------------------------------------------------------------------
1 | curlFactory = $curlFactory;
123 | $this->_deploymentConfig = $deploymentConfig;
124 | $this->productMetadata = $productMetadata;
125 | $this->urlBuilder = $urlBuilder;
126 |
127 | $this->_backendAuthSession = $backendAuthSession;
128 | $this->_moduleList = $moduleList;
129 | $this->_moduleManager = $moduleManager;
130 | $this->config = $config;
131 | $this->getModuleVersion = $getModuleVersion;
132 | }
133 |
134 | /**
135 | * Init model
136 | *
137 | * @return void
138 | * phpcs:disable Magento2.CodeAnalysis.EmptyBlock
139 | */
140 | protected function _construct()
141 | {
142 | }
143 |
144 | /**
145 | * Retrieve feed url
146 | *
147 | * @return string
148 | */
149 | public function getFeedUrl()
150 | {
151 | if (is_null($this->_feedUrl)) {
152 | $this->_feedUrl = 'https://mage'.'fan'
153 | .'.c'.'om/community/notifications'.'/'.'feed/';
154 | }
155 | $urlInfo = parse_url($this->urlBuilder->getBaseUrl());
156 | $domain = isset($urlInfo['host']) ? $urlInfo['host'] : '';
157 | $url = $this->_feedUrl . 'domain/' . urlencode($domain);
158 | $modulesParams = [];
159 | foreach ($this->getMagefanModules() as $moduleName => $module) {
160 | $key = str_replace('Magefan_', '', $moduleName);
161 | $modulesParams[] = $key . ',' . $this->getModuleVersion->execute($moduleName);
162 | }
163 | if (count($modulesParams)) {
164 | $url .= '/modules/'.base64_encode(implode(';', $modulesParams));
165 | }
166 |
167 | $receiveNotifications = $this->config->receiveNotifications();
168 | $notificationsParams = [];
169 | foreach ($receiveNotifications as $notification => $notificationStatus) {
170 | $notificationsParams[] = $notification . ',' . $notificationStatus;
171 | }
172 |
173 | if (count($notificationsParams)) {
174 | $url .= '/notifications/' . base64_encode(implode(';', $notificationsParams));
175 | }
176 | return $url;
177 | }
178 |
179 | /**
180 | * Retrieve Magefan modules info
181 | *
182 | * @return $this
183 | */
184 | protected function getMagefanModules()
185 | {
186 | $modules = [];
187 | foreach ($this->_moduleList->getAll() as $moduleName => $module) {
188 | if (strpos($moduleName, 'Magefan_') !== false && $this->_moduleManager->isEnabled($moduleName)) {
189 | $modules[$moduleName] = $module;
190 | }
191 | }
192 | return $modules;
193 | }
194 |
195 | /**
196 | * Check feed for modification
197 | *
198 | * @return $this
199 | */
200 | public function checkUpdate()
201 | {
202 | $session = $this->_backendAuthSession;
203 | $time = time();
204 | $frequency = $this->getFrequency();
205 | if (($frequency + $session->getMfNoticeLastUpdate() > $time)
206 | || ($frequency + $this->getLastUpdate() > $time)
207 | ) {
208 | return $this;
209 | }
210 | $session->setMfNoticeLastUpdate($time);
211 |
212 | if ($this->_moduleManager->isEnabled('Magento_AdminNotification')) {
213 | return $this->parentCheckUpdate();
214 | } else {
215 | return $this;
216 | }
217 | }
218 |
219 | /**
220 | * Check feed for modification
221 | *
222 | * @return $this
223 | */
224 | protected function parentCheckUpdate()
225 | {
226 | if ($this->getFrequency() + $this->getLastUpdate() > time()) {
227 | return $this;
228 | }
229 |
230 | $feedData = [];
231 |
232 | $feedXml = $this->getFeedData();
233 |
234 | $installDate = strtotime($this->_deploymentConfig->get(ConfigOptionsListConstants::CONFIG_PATH_INSTALL_DATE));
235 |
236 | if ($feedXml && $feedXml->channel && $feedXml->channel->item) {
237 | foreach ($feedXml->channel->item as $item) {
238 | $itemPublicationDate = strtotime((string)$item->pubDate);
239 | if ($installDate <= $itemPublicationDate) {
240 | $feedData[] = [
241 | 'severity' => (int)$item->severity,
242 | 'date_added' => date('Y-m-d H:i:s', $itemPublicationDate),
243 | 'title' => $this->escapeString($item->title),
244 | 'description' => $this->escapeString($item->description),
245 | 'url' => $this->escapeString($item->link),
246 | ];
247 | }
248 | }
249 |
250 | if ($feedData) {
251 | $this->getInboxFactory()->create()->parse(array_reverse($feedData));
252 | }
253 | }
254 | $this->setLastUpdate();
255 |
256 | return $this;
257 | }
258 |
259 | /**
260 | * Retrieve update аrequency
261 | *
262 | * @return int
263 | */
264 | public function getFrequency()
265 | {
266 | return 86400 * 2;
267 | }
268 |
269 | /**
270 | * Retrieve Last update time
271 | *
272 | * @return int
273 | */
274 | public function getLastUpdate()
275 | {
276 | return $this->_cacheManager->load(self::MAGEFAN_CACHE_KEY);
277 | }
278 |
279 | /**
280 | * Set last update time (now)
281 | *
282 | * @return $this
283 | */
284 | public function setLastUpdate()
285 | {
286 | $this->_cacheManager->save(time(), self::MAGEFAN_CACHE_KEY);
287 | return $this;
288 | }
289 |
290 | /**
291 | * Retrieve feed data as XML element
292 | *
293 | * @return SimpleXMLElement
294 | */
295 | public function getFeedData()
296 | {
297 | $getNotification = false;
298 | foreach ($this->config->receiveNotifications() as $key => $value) {
299 | if ($value) {
300 | $getNotification = true;
301 | break;
302 | }
303 | }
304 |
305 | if (!$getNotification) {
306 | return new SimpleXMLElement('
307 |
308 |
309 | ');
310 | }
311 |
312 | return $this->parentGetFeedData();
313 | }
314 |
315 | /**
316 | * Retrieve feed data as XML element
317 | *
318 | * @return SimpleXMLElement
319 | */
320 | protected function parentGetFeedData()
321 | {
322 | /** @var Curl $curl */
323 | $curl = $this->curlFactory->create();
324 | $curl->setOptions(
325 | [
326 | 'timeout' => 2,
327 | 'useragent' => $this->productMetadata->getName()
328 | . '/' . $this->productMetadata->getVersion()
329 | . ' (' . $this->productMetadata->getEdition() . ')',
330 | 'referer' => $this->urlBuilder->getUrl('*/*/*')
331 | ]
332 | );
333 | $curl->write('GET', $this->getFeedUrl(), '1.0');
334 | $data = $curl->read();
335 | $data = preg_split('/^\r?$/m', $data, 2);
336 | $data = trim($data[1] ?? '');
337 | $curl->close();
338 |
339 | try {
340 | $xml = new SimpleXMLElement($data);
341 | } catch (\Exception $e) {
342 | return false;
343 | }
344 |
345 | return $xml;
346 | }
347 | /**
348 | * Retrieve feed as XML element
349 | *
350 | * @return SimpleXMLElement
351 | */
352 | public function getFeedXml()
353 | {
354 | try {
355 | $data = $this->getFeedData();
356 | $xml = new SimpleXMLElement($data);
357 | } catch (\Exception $e) {
358 | $xml = new SimpleXMLElement('');
359 | }
360 |
361 | return $xml;
362 | }
363 |
364 | /**
365 | * Converts incoming data to string format and escapes special characters.
366 | *
367 | * @param SimpleXMLElement $data
368 | * @return string
369 | */
370 | private function escapeString(SimpleXMLElement $data)
371 | {
372 | return htmlspecialchars((string)$data);
373 | }
374 |
375 | /**
376 | * @return mixed
377 | */
378 | private function getInboxFactory()
379 | {
380 | if (null === $this->_inboxFactory) {
381 | $this->_inboxFactory = \Magento\Framework\App\ObjectManager::getInstance()
382 | ->get(\Magento\AdminNotification\Model\InboxFactory::class);
383 | }
384 |
385 | return $this->_inboxFactory;
386 | }
387 | }
388 |
--------------------------------------------------------------------------------
/Model/BreezeThemeDetection.php:
--------------------------------------------------------------------------------
1 | scopeConfig = $scopeConfig;
41 | }
42 |
43 | /**
44 | * Receive Product Updates
45 | *
46 | * @param null $storeId
47 | * @return string
48 | */
49 | public function receiveProductUpdates($storeId = null)
50 | {
51 | return $this->getConfig(
52 | self::XML_PATH_RECEIVE_PRODUCT_UPDATES,
53 | $storeId
54 | );
55 | }
56 |
57 | /**
58 | * Receive Special Offers
59 | *
60 | * @param null $storeId
61 | * @return string
62 | */
63 | public function receiveSpecialOffers($storeId = null)
64 | {
65 | return $this->getConfig(
66 | self::XML_PATH_RECEIVE_SPECIAL_OFFERS,
67 | $storeId
68 | );
69 | }
70 |
71 | /**
72 | * Receive News
73 | *
74 | * @param null $storeId
75 | * @return string
76 | */
77 | public function receiveNews($storeId = null)
78 | {
79 | return $this->getConfig(
80 | self::XML_PATH_RECEIVE_NEWS,
81 | $storeId
82 | );
83 | }
84 |
85 | /**
86 | * Receive Tips & Tricks
87 | *
88 | * @param null $storeId
89 | * @return string
90 | */
91 | public function receiveTipsAndTricks($storeId = null)
92 | {
93 | return $this->getConfig(
94 | self::XML_PATH_RECEIVE_TIPS_AND_TRICKS,
95 | $storeId
96 | );
97 | }
98 |
99 | /**
100 | * Receive General Information
101 | *
102 | * @param null $storeId
103 | * @return string
104 | */
105 | public function receiveGeneralInformation($storeId = null)
106 | {
107 | return $this->getConfig(
108 | self::XML_PATH_RECEIVE_GENERAL_INFORMATION,
109 | $storeId
110 | );
111 | }
112 |
113 | /**
114 | * Receive Notifications
115 | *
116 | * @param null $storeId
117 | * @return array
118 | */
119 | public function receiveNotifications($storeId = null)
120 | {
121 | return [
122 | 'update' => $this->receiveProductUpdates(),
123 | 'offer' => $this->receiveSpecialOffers(),
124 | 'news' => $this->receiveNews(),
125 | 'tip_trick' => $this->receiveTipsAndTricks(),
126 | 'general' => $this->receiveGeneralInformation()
127 | ];
128 | }
129 |
130 | /**
131 | * Display Menu
132 | *
133 | * @param null $storeId
134 | * @return string
135 | */
136 | public function menuEnabled($storeId = null)
137 | {
138 | return $this->getConfig(
139 | self::XML_PATH_MENU_ENABLED,
140 | $storeId
141 | );
142 | }
143 |
144 | /**
145 | * Retrieve store config value
146 | *
147 | * @param string $path
148 | * @param null $storeId
149 | * @return mixed
150 | */
151 | public function getConfig($path, $storeId = null)
152 | {
153 | return $this->scopeConfig->getValue(
154 | $path,
155 | ScopeInterface::SCOPE_STORE,
156 | $storeId
157 | );
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/Model/GetCategoryByProduct.php:
--------------------------------------------------------------------------------
1 | categoryRepository = $categoryRepository;
42 | $this->storeManager = $storeManager;
43 | }
44 |
45 | /**
46 | * @param mixed $product
47 | * @param mixed $storeId
48 | * @returnmixed
49 | */
50 | public function execute($product, $storeId = null)
51 | {
52 | if (null === $storeId) {
53 | $storeId = $this->storeManager->getStore()->getId();
54 | }
55 |
56 | $key = $product->getId() . '_' . $storeId;
57 | if (!isset($this->productCategory[$key])) {
58 |
59 | $this->productCategory[$key] = false;
60 |
61 | $categoryIds = $product->getCategoryIds();
62 | if ($categoryIds) {
63 | $level = -1;
64 | $rootCategoryId = $this->storeManager->getStore($storeId)->getRootCategoryId();
65 |
66 | foreach ($categoryIds as $categoryId) {
67 | try {
68 | $category = $this->categoryRepository->get($categoryId, $storeId);
69 | if ($category->getIsActive()
70 | && $category->getLevel() > $level
71 | && in_array($rootCategoryId, $category->getPathIds())
72 | ) {
73 | $level = $category->getLevel();
74 | $this->productCategory[$key] = $category;
75 | }
76 | } catch (\Exception $e) { // phpcs:ignore
77 | /* Do nothing */
78 | }
79 | }
80 | }
81 | }
82 |
83 |
84 | return $this->productCategory[$key] ?: null;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/Model/GetModuleInfo.php:
--------------------------------------------------------------------------------
1 | curl = $curl;
45 | $this->cache = $cache;
46 | }
47 |
48 | /**
49 | * @param $moduleName
50 | * @return array|DataObject|mixed
51 | */
52 | public function execute($moduleName = null)
53 | {
54 | $modulesInfo = $this->getModulesInfo();
55 |
56 | if (!$moduleName) {
57 | return $modulesInfo;
58 | }
59 |
60 | $moduleKey = explode('_', $moduleName)[1];
61 |
62 | if (!isset($modulesInfo[$moduleKey])) {
63 | $modulesInfo[$moduleKey] = new DataObject();
64 | }
65 | return $modulesInfo[$moduleKey];
66 | }
67 |
68 | /**
69 | * @return array
70 | */
71 | public function getModulesInfo()
72 | {
73 | if (null === $this->modulesInfo) {
74 | $modulesInfo = $this->load();
75 | if (!$modulesInfo) {
76 | $modulesInfo = $this->loadFromCache();
77 | }
78 |
79 | foreach ($modulesInfo as $moduleKey => $moduleInfo) {
80 | $modulesInfo[$moduleKey] = new DataObject($moduleInfo);
81 | }
82 |
83 | $this->modulesInfo = $modulesInfo;
84 | }
85 |
86 | return $this->modulesInfo;
87 | }
88 |
89 | /**
90 | * @return array
91 | */
92 | private function load(): array
93 | {
94 | $data = [];
95 | try {
96 | $url = 'https://mage' . 'fan.com/media/product-versions-extended.json';
97 |
98 | // Make the request
99 | $this->curl->get($url);
100 |
101 | // Get the response
102 | $response = $this->curl->getBody();
103 |
104 | if ($response) {
105 | $this->cache->save($response, self::CACHE_KEY, [], self::CACHE_LIFETIME);
106 | $data = json_decode($response, true);
107 | }
108 | } catch (\Exception $e) {
109 |
110 | }
111 |
112 | return $data;
113 | }
114 |
115 | /**
116 | * @return array
117 | */
118 | private function loadFromCache(): array
119 | {
120 | $cachedData = $this->cache->load(self::CACHE_KEY);
121 | if ($cachedData) {
122 | return json_decode($cachedData, true);
123 | }
124 |
125 | return [];
126 | }
127 | }
--------------------------------------------------------------------------------
/Model/GetModuleVersion.php:
--------------------------------------------------------------------------------
1 | serializer = $serializer;
58 | $this->file = $file;
59 | $this->moduleReader = $moduleReader;
60 | $this->moduleList = $moduleList;
61 | }
62 |
63 | /**
64 | * @param string $moduleName
65 | * @return string
66 | */
67 | public function execute(string $moduleName): string
68 | {
69 | if (!isset($this->versions[$moduleName])) {
70 | $module = $this->moduleList->getOne($moduleName);
71 | if (!$module) {
72 | $this->versions[$moduleName] = '';
73 | } else {
74 | $fileDir = $this->moduleReader->getModuleDir('', $moduleName) . '/composer.json';
75 | $data = $this->file->read($fileDir);
76 | if ($data) {
77 | try {
78 | $data = $this->serializer->unserialize($data);
79 | } catch (\Exception $e) {
80 | $data = [];
81 | }
82 | if (empty($data['version'])) {
83 | return !empty($module['setup_version']) ? $module['setup_version'] : '';
84 | }
85 | }
86 |
87 | $this->versions[$moduleName] = !empty($data['version']) ? $data['version'] : '';
88 | }
89 | }
90 |
91 | return $this->versions[$moduleName];
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/Model/GetParentProductIds.php:
--------------------------------------------------------------------------------
1 | resourceConnection = $resourceConnection;
36 | $this->connection = $resourceConnection->getConnection();
37 | }
38 |
39 | /**
40 | * @param array $productIds
41 | * @return array
42 | */
43 | public function execute(array $productIds): array
44 | {
45 | $parentProductIds = [];
46 |
47 | /* Fix for configurable, bundle, grouped */
48 | if ($productIds) {
49 | $productTable = $this->resourceConnection->getTableName('catalog_product_entity');
50 | $entityIdColumn = $this->connection->tableColumnExists($productTable, 'row_id') ? 'row_id' : 'entity_id';
51 |
52 | $select = $this->connection->select()
53 | ->from(
54 | ['main_table' => $this->resourceConnection->getTableName('catalog_product_relation')],
55 | []
56 | )->join(
57 | ['e' => $productTable],
58 | 'e.' . $entityIdColumn . ' = main_table.parent_id',
59 | ['e.' .$entityIdColumn]
60 | )
61 | ->where('main_table.child_id IN (?)', $productIds)
62 | ->where('e.entity_id IS NOT NULL');
63 |
64 | foreach ($this->connection->fetchAll($select) as $product) {
65 | $parentProductIds[$product[$entityIdColumn]] = $product[$entityIdColumn];
66 | }
67 | }
68 | /* End fix */
69 |
70 | return $parentProductIds;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Model/GetWebsitesMap.php:
--------------------------------------------------------------------------------
1 | storeManager = $storeManager;
35 | }
36 |
37 | /**
38 | * @return array
39 | */
40 | public function execute(): array
41 | {
42 | if ($this->websitesMap === null) {
43 | $this->websitesMap = [];
44 | $websites = $this->storeManager->getWebsites();
45 | foreach ($websites as $website) {
46 | // Continue if website has no store to be able to create catalog rule for website without store
47 | if ($website->getDefaultStore() === null) {
48 | continue;
49 | }
50 | $this->websitesMap[$website->getId()] = $website->getDefaultStore()->getId();
51 | }
52 | }
53 |
54 | return $this->websitesMap;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Model/HyvaThemeDetection.php:
--------------------------------------------------------------------------------
1 | templateFactory = $templateFactory;
165 | $this->objectManager = $objectManager;
166 | $this->_senderResolver = $senderResolver;
167 | $this->mailTransportFactory = $mailTransportFactory;
168 | $this->productMetadata = $productMetadata;
169 | $this->emailMessageInterfaceFactory = $emailMessageInterfaceFactory ?: $this->objectManager
170 | ->get(EmailMessageInterfaceFactory::class);
171 | $this->mimeMessageInterfaceFactory = $mimeMessageInterfaceFactory ?: $this->objectManager
172 | ->get(MimeMessageInterfaceFactory::class);
173 | $this->mimePartInterfaceFactory = $mimePartInterfaceFactory ?: $this->objectManager
174 | ->get(MimePartInterfaceFactory::class);
175 | $this->addressConverter = $addressConverter ?: $this->objectManager
176 | ->get(AddressConverter::class);
177 | }
178 |
179 | /**
180 | * Add cc address
181 | *
182 | * @param array|string $address
183 | * @param string $name
184 | *
185 | * @return $this
186 | */
187 | public function addCc($address, $name = '')
188 | {
189 | $this->addAddressByType('cc', $address, $name);
190 |
191 | return $this;
192 | }
193 |
194 | /**
195 | * Add to address
196 | *
197 | * @param array|string $address
198 | * @param string $name
199 | *
200 | * @return $this
201 | * @throws InvalidArgumentException
202 | */
203 | public function addTo($address, $name = '')
204 | {
205 | $this->addAddressByType('to', $address, $name);
206 |
207 | return $this;
208 | }
209 |
210 | /**
211 | * Add bcc address
212 | *
213 | * @param array|string $address
214 | *
215 | * @return $this
216 | * @throws InvalidArgumentException
217 | */
218 | public function addBcc($address)
219 | {
220 | $this->addAddressByType('bcc', $address);
221 |
222 | return $this;
223 | }
224 |
225 | /**
226 | * Set Reply-To Header
227 | *
228 | * @param string $email
229 | * @param string|null $name
230 | *
231 | * @return $this
232 | * @throws InvalidArgumentException
233 | */
234 | public function setReplyTo($email, $name = null)
235 | {
236 | $this->addAddressByType('replyTo', $email, $name);
237 |
238 | return $this;
239 | }
240 |
241 | /**
242 | * Set mail from address
243 | *
244 | * @param string|array $from
245 | *
246 | * @return $this
247 | * @throws InvalidArgumentException
248 | * @see setFromByScope()
249 | *
250 | * @deprecated 102.0.1 This function sets the from address but does not provide
251 | * a way of setting the correct from addresses based on the scope.
252 | */
253 | public function setFrom($from)
254 | {
255 | return $this->setFromByScope($from);
256 | }
257 |
258 | /**
259 | * Set mail from address by scopeId
260 | *
261 | * @param string|array $from
262 | * @param string|int $scopeId
263 | *
264 | * @return $this
265 | * @throws InvalidArgumentException
266 | * @throws MailException
267 | * @since 102.0.1
268 | */
269 | public function setFromByScope($from, $scopeId = null)
270 | {
271 | $result = $this->_senderResolver->resolve($from, $scopeId);
272 | $this->addAddressByType('from', $result['email'], $result['name']);
273 |
274 | return $this;
275 | }
276 |
277 | /**
278 | * Set template identifier
279 | *
280 | * @param string $templateIdentifier
281 | *
282 | * @return $this
283 | */
284 | public function setTemplateIdentifier($templateIdentifier)
285 | {
286 | $this->templateIdentifier = $templateIdentifier;
287 |
288 | return $this;
289 | }
290 |
291 | /**
292 | * Set template model
293 | *
294 | * @param string $templateModel
295 | *
296 | * @return $this
297 | */
298 | public function setTemplateModel($templateModel)
299 | {
300 | $this->templateModel = $templateModel;
301 | return $this;
302 | }
303 |
304 | /**
305 | * Set template vars
306 | *
307 | * @param array $templateVars
308 | *
309 | * @return $this
310 | */
311 | public function setTemplateVars($templateVars)
312 | {
313 | $this->templateVars = $templateVars;
314 |
315 | return $this;
316 | }
317 |
318 | /**
319 | * Set template options
320 | *
321 | * @param array $templateOptions
322 | * @return $this
323 | */
324 | public function setTemplateOptions($templateOptions)
325 | {
326 | $this->templateOptions = $templateOptions;
327 |
328 | return $this;
329 | }
330 |
331 | /**
332 | * Get mail transport
333 | *
334 | * @return TransportInterface
335 | * @throws LocalizedException
336 | */
337 | public function getTransport()
338 | {
339 | try {
340 | $this->prepareMessage();
341 | $mailTransport = $this->mailTransportFactory->create(['message' => clone $this->message]);
342 | } finally {
343 | $this->reset();
344 | }
345 |
346 | return $mailTransport;
347 | }
348 |
349 | /**
350 | * @param string $content
351 | * @param string $name
352 | * @param string $type
353 | * @param $encoding
354 | * @param $disposition
355 | * @return $this
356 | */
357 | public function addAttachment(string $content, string $name, string $type, $encoding = null, $disposition = null)
358 | {
359 | $this->attachments[] = [
360 | 'content' => $content,
361 | 'name' => $name,
362 | 'type' => $type,
363 | 'encoding' => $encoding,
364 | 'disposition' => $disposition
365 | ];
366 |
367 | return $this;
368 | }
369 |
370 | /**
371 | * @return array
372 | */
373 | private function getLaminasParts()
374 | {
375 | $parts = [];
376 |
377 | foreach ($this->attachments as $attachmentData) {
378 |
379 | $attachment = new \Laminas\Mime\Part($attachmentData['content']);
380 | $attachment->filename = $attachmentData['name'];
381 | $attachment->type = $attachmentData['type'];
382 | $attachment->encoding = $attachmentData['encoding'] ?: \Laminas\Mime\Mime::ENCODING_BASE64;
383 | $attachment->disposition = $attachmentData['disposition'] ?: \Laminas\Mime\Mime::DISPOSITION_ATTACHMENT;
384 |
385 | $parts[] = $attachment;
386 | }
387 |
388 | return $parts;
389 | }
390 |
391 | /**
392 | * @return array
393 | */
394 | private function getSymfonyParts()
395 | {
396 | $parts = [];
397 |
398 | foreach ($this->attachments as $attachmentData) {
399 | $attachment = new \Symfony\Component\Mime\Part\DataPart($attachmentData['content'], $attachmentData['name'], $attachmentData['type']);
400 |
401 | $parts[] = $attachment;
402 | }
403 |
404 | return $parts;
405 | }
406 |
407 | /**
408 | * Reset object state
409 | *
410 | * @return $this
411 | */
412 | protected function reset()
413 | {
414 | $this->messageData = [];
415 | $this->templateIdentifier = null;
416 | $this->templateVars = null;
417 | $this->templateOptions = null;
418 | return $this;
419 | }
420 |
421 | /**
422 | * Get template
423 | *
424 | * @return TemplateInterface
425 | */
426 | protected function getTemplate()
427 | {
428 | return $this->templateFactory->get($this->templateIdentifier, $this->templateModel)
429 | ->setVars($this->templateVars)
430 | ->setOptions($this->templateOptions);
431 | }
432 |
433 | /**
434 | * Prepare message.
435 | *
436 | * @return $this
437 | * @throws LocalizedException if template type is unknown
438 | */
439 | protected function prepareMessage()
440 | {
441 | $template = $this->getTemplate();
442 | $content = $template->processTemplate();
443 |
444 | switch ($template->getType()) {
445 | case TemplateTypesInterface::TYPE_TEXT:
446 | $part['type'] = MimeInterface::TYPE_TEXT;
447 | break;
448 |
449 | case TemplateTypesInterface::TYPE_HTML:
450 | $part['type'] = MimeInterface::TYPE_HTML;
451 | break;
452 |
453 | default:
454 | throw new LocalizedException(
455 | new Phrase('Unknown template type')
456 | );
457 | }
458 |
459 | /** @var \Magento\Framework\Mail\MimePartInterface $mimePart */
460 | $mimePart = $this->mimePartInterfaceFactory->create(['content' => $content]);
461 | /* Custom code */
462 | $parts = [$mimePart];
463 |
464 | $attachmentParts = $this->isMagentoVersionLte248()
465 | ? $this->getLaminasParts()
466 | : $this->getSymfonyParts();
467 |
468 | $parts = array_merge($parts, $attachmentParts);
469 | /* End custom code */
470 |
471 | $this->messageData['encoding'] = $mimePart->getCharset();
472 | $this->messageData['body'] = $this->mimeMessageInterfaceFactory->create(
473 | ['parts' => $parts]
474 | );
475 |
476 | $this->messageData['subject'] = html_entity_decode(
477 | (string)$template->getSubject(),
478 | ENT_QUOTES
479 | );
480 |
481 | $this->message = $this->emailMessageInterfaceFactory->create($this->messageData);
482 |
483 | $this->addSymfonyAttachment($attachmentParts);
484 |
485 | return $this;
486 | }
487 |
488 | /**
489 | * @param array $attachmentParts
490 | * @return void
491 | */
492 | private function addSymfonyAttachment(array $attachmentParts): void
493 | {
494 | if ($this->message instanceof \Magento\Framework\Mail\EmailMessage && method_exists($this->message, 'getSymfonyMessage')) {
495 | $symfonyEmail = $this->message->getSymfonyMessage();
496 |
497 | // Decode the original HTML body (quoted-printable)
498 | $decodedBody = quoted_printable_decode($symfonyEmail->getBody()->bodyToString());
499 |
500 | // Create main HTML body part
501 | $htmlPart = new \Symfony\Component\Mime\Part\TextPart($decodedBody, 'utf-8', 'html');
502 |
503 | // Rebuild the email body with attachments
504 | $symfonyEmail->setBody(
505 | new \Symfony\Component\Mime\Part\Multipart\MixedPart($htmlPart, ...$attachmentParts)
506 | );
507 | }
508 | }
509 |
510 | /**
511 | * Handles possible incoming types of email (string or array)
512 | *
513 | * @param string $addressType
514 | * @param string|array $email
515 | * @param string|null $name
516 | *
517 | * @return void
518 | * @throws InvalidArgumentException
519 | */
520 | private function addAddressByType(string $addressType, $email, ?string $name = null): void
521 | {
522 | if (is_string($email)) {
523 | $this->messageData[$addressType][] = $this->addressConverter->convert($email, $name);
524 | return;
525 | }
526 | $convertedAddressArray = $this->addressConverter->convertMany($email);
527 | if (isset($this->messageData[$addressType])) {
528 | $this->messageData[$addressType] = array_merge(
529 | $this->messageData[$addressType],
530 | $convertedAddressArray
531 | );
532 | } else {
533 | $this->messageData[$addressType] = $convertedAddressArray;
534 | }
535 | }
536 |
537 | /**
538 | * @return bool
539 | */
540 | private function isMagentoVersionLte248(): bool
541 | {
542 | $version = $this->productMetadata->getVersion();
543 | return version_compare($version, '2.4.8', '<');
544 | }
545 | }
546 |
--------------------------------------------------------------------------------
/Model/Magento/Product/CollectionOptimizedForSqlValidator.php:
--------------------------------------------------------------------------------
1 | ';
22 | const IS_OPERATOR = '==';
23 |
24 | /**
25 | * @var array
26 | */
27 | private $stringConditionOperatorMap = [
28 | '{}' => ':field LIKE ?',
29 | '!{}' => ':field NOT LIKE ?',
30 | ];
31 |
32 | /**
33 | * @var AbstractCollection|null
34 | */
35 | private $collectionCopy;
36 |
37 | /**
38 | * @var AttributeRepositoryInterface
39 | */
40 | private $attributeRepository;
41 |
42 | public function __construct(
43 | ExpressionFactory $expressionFactory,
44 | AttributeRepositoryInterface $attributeRepository
45 | ) {
46 | parent::__construct($expressionFactory, $attributeRepository);
47 | $this->attributeRepository = $attributeRepository;
48 | }
49 |
50 | public function attachConditionToCollection(
51 | AbstractCollection $collection,
52 | Combine $combine
53 | ): void {
54 | $this->collectionCopy = $collection;
55 | parent::attachConditionToCollection($collection, $combine);
56 | $this->collectionCopy = null;
57 | }
58 |
59 | /**
60 | * Fixed issue with filter by default attribute value
61 | *
62 | * @param AbstractCondition $condition
63 | * @param string $value
64 | * @param bool $isDefaultStoreUsed
65 | * @return string
66 | * @throws \Magento\Framework\Exception\LocalizedException
67 | */
68 | protected function _getMappedSqlCondition(
69 | AbstractCondition $condition,
70 | string $value = '',
71 | bool $isDefaultStoreUsed = true
72 | ): string {
73 | $argument = $condition->getMappedSqlField();
74 |
75 | // If rule hasn't valid argument - prevent incorrect rule behavior.
76 | if (empty($argument)) {
77 | return (string) $this->_expressionFactory->create(['expression' => '1 = -1']);
78 | } elseif (preg_match('/[^a-z0-9\-_\.\`]/i', $argument) > 0 && !$argument instanceof \Zend_Db_Expr) {
79 | throw new \Magento\Framework\Exception\LocalizedException(__('Invalid field'));
80 | }
81 |
82 | if (self::UNDEFINED_OPERATOR === $condition->getOperatorForValidate()) {
83 | $condition->setOperator(self::IS_OPERATOR);
84 | $condition->setValue('');
85 | }
86 |
87 | $conditionOperator = $condition->getOperatorForValidate();
88 |
89 | if (!isset($this->_conditionOperatorMap[$conditionOperator])) {
90 | throw new \Magento\Framework\Exception\LocalizedException(__('Unknown condition operator'));
91 | }
92 |
93 | $defaultValue = $this->getDefaultValue($this->collectionCopy, $condition->getAttribute());
94 |
95 | //operator 'contains {}' is mapped to 'IN()' query that cannot work with substrings
96 | // adding mapping to 'LIKE %%'
97 | if ($condition->getInputType() === 'string'
98 | && array_key_exists($conditionOperator, $this->stringConditionOperatorMap)
99 | ) {
100 | $sql = str_replace(
101 | ':field',
102 | (string) $this->_connection->getIfNullSql(
103 | $this->_connection->quoteIdentifier($argument),
104 | $defaultValue
105 | ),
106 | $this->stringConditionOperatorMap[$conditionOperator]
107 | );
108 | $bindValue = $condition->getBindArgumentValue();
109 | $expression = $value . $this->_connection->quoteInto($sql, "%$bindValue%");
110 | } else {
111 | $sql = str_replace(
112 | ':field',
113 | (string) $this->_connection->getIfNullSql(
114 | $this->_connection->quoteIdentifier($argument),
115 | $defaultValue
116 | ),
117 | $this->_conditionOperatorMap[$conditionOperator]
118 | );
119 | $bindValue = $condition->getBindArgumentValue();
120 | $expression = $value . $this->_connection->quoteInto($sql, $bindValue);
121 | }
122 | // values for multiselect attributes can be saved in comma-separated format
123 | // below is a solution for matching such conditions with selected values
124 | if (is_array($bindValue) && \in_array($conditionOperator, ['()', '{}'], true)) {
125 | foreach ($bindValue as $item) {
126 | $ifNullSqlQuoteIdentifier = (string) $this->_connection->getIfNullSql(
127 | $this->_connection->quoteIdentifier($argument),
128 | $defaultValue
129 | );
130 |
131 | $expression .= ($e = $this->_connection->quoteInto(
132 | " OR (FIND_IN_SET (?, {$ifNullSqlQuoteIdentifier}) > 0)",
133 | $item
134 | ));
135 | }
136 | } elseif (is_array($bindValue) && \in_array($conditionOperator, ['!()', '!{}'], true)) {
137 | foreach ($bindValue as $item) {
138 | $ifNullSqlQuoteIdentifier = (string) $this->_connection->getIfNullSql(
139 | $this->_connection->quoteIdentifier($argument),
140 | $defaultValue
141 | );
142 |
143 | $expression .= ($e = $this->_connection->quoteInto(
144 | " AND (FIND_IN_SET (?, {$ifNullSqlQuoteIdentifier}) = 0)",
145 | $item
146 | ));
147 | }
148 | }
149 |
150 | return (string) $this->_expressionFactory->create(
151 | ['expression' => $expression]
152 | );
153 | }
154 |
155 | /**
156 | * @param AbstractCollection $collection
157 | * @param string $attributeCode
158 | * @return int|string
159 | */
160 | private function getDefaultValue(AbstractCollection $collection, string $attributeCode)
161 | {
162 | $isDefaultStoreUsed = (int) $collection->getStoreId() === (int) $collection->getDefaultStoreId();
163 |
164 | $defaultValue = 0;
165 |
166 | if (!$isDefaultStoreUsed && $this->isDefaultValueAvaibleForAttribute($attributeCode)) {
167 | $defaultField = 'at_' . $attributeCode . '_default.value';
168 | $defaultValue = $this->_connection->quoteIdentifier($defaultField);
169 | }
170 |
171 | return $defaultValue;
172 | }
173 |
174 | /**
175 | * @param string $attributeCode
176 | * @return bool
177 | */
178 | private function isDefaultValueAvaibleForAttribute(string $attributeCode): bool
179 | {
180 | try {
181 | $attribute = $this->attributeRepository->get(Product::ENTITY, $attributeCode);
182 | } catch (NoSuchEntityException $e) {
183 | return false;
184 | }
185 |
186 | return !$attribute->isScopeGlobal();
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/Model/Section.php:
--------------------------------------------------------------------------------
1 | scopeConfig = $scopeConfig;
78 | $this->metadata = $metadata;
79 | $this->getModuleVersion = $getModuleVersion;
80 | $this->hyvaThemeDetection = $hyvaThemeDetection;
81 | $this->name = $name;
82 | $this->key = $key;
83 | }
84 |
85 | /**
86 | * @return bool
87 | */
88 | final public function isEnabled()
89 | {
90 | return (bool)$this->getConfig(self::ENABLED);
91 | }
92 |
93 | /**
94 | * @param false $e
95 | * @return false|string
96 | */
97 | final public function getModuleName($e = false)
98 | {
99 | $fs = $e ? [self::MODULE] : [self::MODULE . 'e', self::MODULE . 'p', self::MODULE];
100 | foreach ($fs as $f) {
101 | $module = (string)$this->getConfig($f);
102 | if ($module) {
103 | break;
104 | }
105 | }
106 |
107 | return $module;
108 | }
109 |
110 | /**
111 | * @param false $e
112 | * @return false|string
113 | */
114 | final public function getModule($e = false)
115 | {
116 | $module = $this->getModuleName();
117 |
118 | $url = $this->scopeConfig->getValue(
119 | 'web/unsecure/base' . '_' . 'url',
120 | ScopeInterface::SCOPE_STORE,
121 | 0
122 | );
123 |
124 | if (\Magefan\Community\Model\UrlChecker::showUrl($url)) {
125 | if ($module && $this->getType()) {
126 | return $module;
127 | }
128 |
129 | if ($module == ('B' . 'l' . 'o' . 'g')
130 | && version_compare($this->getModuleVersion->execute('Ma' . 'ge' . 'fa' . 'n_' . $module), '2.' . '11' . '.4', '>=')
131 | && $this->hyvaThemeDetection->execute()
132 | ) {
133 | return $module;
134 | }
135 | }
136 | return false;
137 | }
138 |
139 | /**
140 | * @return bool
141 | */
142 | final public function getType()
143 | {
144 | return (!$this->getConfig(self::TYPE)
145 | || $this->getConfig(self::TYPE) && $this->metadata->getEdition() != 'C' . 'omm' . 'un' . 'ity'
146 | );
147 | }
148 |
149 | /**
150 | * @return string
151 | */
152 | final public function getKey()
153 | {
154 | if (null !== $this->key) {
155 | return $this->key;
156 | } else {
157 | return $this->getConfig(self::KEY);
158 | }
159 | }
160 |
161 | /**
162 | * @return string
163 | */
164 | final public function getName()
165 | {
166 | return (string) $this->name;
167 | }
168 |
169 | /**
170 | * @param $data
171 | * @param null $k
172 | * @return bool
173 | */
174 | final public function validate($data)
175 | {
176 | if (isset($data[$this->getModule()])) {
177 | return !empty($data[$this->getModule()]);
178 | }
179 |
180 | $k = $this->getKey();
181 |
182 | foreach ([$this->getModule(), $this->getModule(true)] as $id) {
183 | foreach (['', 'Plus', 'Extra'] as $e) {
184 | if ($result = $this->validateIDK($id . $e, $k)) {
185 | return true;
186 | }
187 | }
188 | }
189 |
190 | return false;
191 | }
192 |
193 | /**
194 | * @param string $id
195 | * @param string $k
196 | * @return bool
197 | */
198 | private function validateIDK($id, $k)
199 | {
200 | $l = substr($id, 1, 1);
201 | $d = (string) strlen($id);
202 |
203 | return (strlen($k) >= '3' . '2')
204 | && (strpos($k, $l, 5) == 5)
205 | && (strpos($k, $d, 19) == 19);
206 | }
207 |
208 | /**
209 | * @param string $field
210 | * @return mixed
211 | */
212 | private function getConfig($field)
213 | {
214 | $g = 'general';
215 | return $this->scopeConfig->getValue(
216 | implode('/', [$this->name, $g, $field]),
217 | ScopeInterface::SCOPE_STORE,
218 | 0
219 | );
220 | }
221 | }
222 |
--------------------------------------------------------------------------------
/Model/Section/Info.php:
--------------------------------------------------------------------------------
1 | metadata = $metadata;
47 | $this->storeManager = $storeManager;
48 | $this->curl = $curl;
49 | }
50 |
51 | /**
52 | * @param array $sections
53 | * @return bool|mixed
54 | */
55 | final public function load(array $sections)
56 | {
57 | /*$this->curl->setOption(CURLOPT_SSL_VERIFYPEER, false);*/
58 | try {
59 | $this->curl->post($u =
60 | implode('/', [
61 | 'htt' . 'ps' . ':',
62 | '',
63 | 'm' . 'ag' . 'ef' . 'an.c' . 'om',
64 | 'mpk',
65 | 'info'
66 | ]), $d = [
67 | 'version' => $this->metadata->getVersion(),
68 | 'edition' => $this->metadata->getEdition(),
69 | 'url' => $this->storeManager->getStore()->getBaseUrl(),
70 | 'sections' => $this->getSectionsParam($sections)
71 | ]);
72 | $body = $this->curl->getBody();
73 | return json_decode($body, true);
74 | } catch (\Exception $e) {
75 | return false;
76 | }
77 | }
78 |
79 | /**
80 | * @param array $sections
81 | * @return array
82 | */
83 | private function getSectionsParam(array $sections)
84 | {
85 | $result = [];
86 | foreach ($sections as $section) {
87 | $result[$section->getModule()] = [
88 | 'key' => $section->getKey(),
89 | 'section' => $section->getName()
90 | ];
91 | }
92 | return $result;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/Model/SetLinvFlag.php:
--------------------------------------------------------------------------------
1 | configWriter = $configWriter;
37 | $this->cacheTypeList = $cacheTypeList;
38 | }
39 |
40 | /**
41 | * @param $module
42 | * @param $value
43 | * @return void
44 | */
45 | public function execute($module, $value)
46 | {
47 | $this->configWriter->save($module . '/g'.'en'.'er'.'al'.'/l'.'in'.'v', $value, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, 0);
48 | $this->cacheTypeList->cleanType(Config::TYPE_IDENTIFIER);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Model/UrlChecker.php:
--------------------------------------------------------------------------------
1 | productMetadata = $productMetadata;
36 | $this->objectManager = $objectManager;
37 | }
38 |
39 | /**
40 | * @param string $tagName
41 | * @param array $attributes
42 | * @param string|null $content
43 | * @param bool $textContent
44 | * @return string
45 | */
46 | public function renderTag(
47 | string $tagName,
48 | array $attributes,
49 | ?string $content = null,
50 | bool $textContent = true
51 | )
52 | {
53 | $version = $this->productMetadata->getVersion();
54 | if (version_compare($version, '2.4.0',">")) {
55 | return $this->objectManager->get(\Magento\Framework\View\Helper\SecureHtmlRenderer::class)->renderTag($tagName, $attributes, $content, $textContent);
56 | } else {
57 | $attrs = [];
58 | if ($attributes) {
59 | foreach ($attributes as $key => $value) {
60 | $attrs[] = $key . '="' . $value . '"';
61 | }
62 | }
63 | return '<' . $tagName . ' ' . implode(' ', $attrs) . '>' . $content . '' . $tagName . '>';
64 | }
65 |
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Observer/ConfigObserver.php:
--------------------------------------------------------------------------------
1 | sectionFactory = $sectionFactory;
63 | $this->info = $info;
64 | $this->messageManager = $messageManager;
65 | $this->setLinvFlag = $setLinvFlag;
66 | $this->config = $config;
67 | }
68 |
69 | /**
70 | * @param \Magento\Framework\Event\Observer $observer
71 | */
72 | final public function execute(\Magento\Framework\Event\Observer $observer)
73 | {
74 | $request = $observer->getEvent()->getRequest();
75 | $groups = $request->getParam('groups');
76 | if (empty($groups['general']['fields']['enabled']['value'])) {
77 | return;
78 | }
79 |
80 | $key = isset($groups['general']['fields']['key']['value'])
81 | ? $groups['general']['fields']['key']['value']
82 | : null;
83 |
84 | $section = $this->sectionFactory->create([
85 | 'name' => $request->getParam('section'),
86 | 'key' => $key
87 | ]);
88 |
89 | if (!$section->getModule()) {
90 | $bp = $section->getName() . '/' . 'g' . 'e' . 'n' . 'e' . 'r' . 'a' . 'l' . '/' ;
91 | if (!$this->config->getConfig( $bp . Section::ACTIVE) && !$section->getType()) {
92 | $this->messageManager->addError(
93 | implode(array_reverse(
94 | [
95 | '.','e','g','a','s','u',' ','e','e','r','f',' ','y','o','j','n','e',' ',
96 | 'o','t',' ','t','i',' ','e','t','a','v','i','t','c','a',' ','e','s','a',
97 | 'e','l','P',' ','.','d','e','t','a','v','i','t','c','a',' ','t','o','n',
98 | ' ','s','i',' ','n','o','i','s','n','e','t','x','e',' ','e','h','T'
99 | ]
100 | ))
101 | );
102 | $groups['general']['fields']['enabled']['value'] = 0;
103 | $request->setPostValue('groups', $groups);
104 | }
105 | return;
106 | }
107 | $module = $section->getName();
108 | $data = $this->info->load([$section]);
109 |
110 | if (!$section->validate($data)) {
111 | $groups['general']['fields']['enabled']['value'] = 0;
112 | $this->setLinvFlag->execute($module, 1);
113 | $request->setPostValue('groups', $groups);
114 |
115 | $this->messageManager->addError(
116 | implode(array_reverse(
117 | [
118 | '.','d','e','l','b','a','s','i','d',' ','y','l','l','a','c','i','t','a','m',
119 | 'o','t','u','a',' ','n','e','e','b',' ','s','a','h',' ','n','o','i','s','n',
120 | 'e','t','x','e',' ','e','h','T',' ','.','d','i','l','a','v','n','i',' ','r',
121 | 'o',' ','y','t','p','m','e',' ','s','i',' ','y','e','K',' ','t','c','u','d',
122 | 'o','r','P'
123 | ]
124 | ))
125 | );
126 | } else {
127 | $this->setLinvFlag->execute($module, 0);
128 | }
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/Observer/PredispathAdminActionControllerObserver.php:
--------------------------------------------------------------------------------
1 | feedFactory = $feedFactory;
35 | $this->backendAuthSession = $backendAuthSession;
36 | }
37 |
38 | /**
39 | * Predispath admin action controller
40 | *
41 | * @param \Magento\Framework\Event\Observer $observer
42 | * @return void
43 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
44 | */
45 | public function execute(\Magento\Framework\Event\Observer $observer)
46 | {
47 | if ($this->backendAuthSession->isLoggedIn()) {
48 | $feedModel = $this->feedFactory->create();
49 | /* @var $feedModel \Magefan\Community\Model\AdminNotificationFeed */
50 | $feedModel->checkUpdate();
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Plugin/Magento/Backend/Model/Menu/BuilderPlugin.php:
--------------------------------------------------------------------------------
1 | menuItemFactory = $menuItemFactory;
71 | $this->config = $config;
72 | $this->structure = $structure;
73 | $this->moduleList = $moduleList;
74 | $this->moduleManager = $moduleManager;
75 | $this->magefanModules = $this->getMagefanModules();
76 | }
77 |
78 | /**
79 | * @param Builder $subject
80 | * @param Menu $menu
81 | * @param $result
82 | * @return mixed $result
83 | */
84 | public function afterGetResult(Builder $subject, Menu $menu, $result)
85 | {
86 | $menuEnabled = $this->config->menuEnabled();
87 | if ($menuEnabled) {
88 | $item = $this->menuItemFactory->create([
89 | 'data' => [
90 | 'id' => 'Magefan_Community::elements',
91 | 'title' => 'Magefan',
92 | 'module' => 'Magefan_Community',
93 | 'resource' => 'Magefan_Community::elements'
94 | ]
95 | ]);
96 | $menu->add($item, null, 61);
97 | $subItems = $this->getSubItem($menu->toArray());
98 | $this->createMenuItem($menu, $subItems, 'Magefan_Community::elements');
99 |
100 | $item = $this->menuItemFactory->create([
101 | 'data' => [
102 | 'id' => 'Magefan_Community::extension_and_notification',
103 | 'title' => 'Extensions & Notifications',
104 | 'module' => 'Magefan_Community',
105 | 'resource' => 'Magefan_Community::elements'
106 | ]
107 | ]);
108 | $menu->add($item, 'Magefan_Community::elements', 1000);
109 |
110 | $item = $this->menuItemFactory->create([
111 | 'data' => [
112 | 'id' => 'Magefan_Community::extension_and_notification_view',
113 | 'title' => 'Manage',
114 | 'module' => 'Magefan_Community',
115 | 'resource' => 'Magefan_Community::elements',
116 | 'action' => 'adminhtml/system_config/edit/section/mfextension',
117 | ]
118 | ]);
119 | $menu->add($item, 'Magefan_Community::extension_and_notification', 1000);
120 |
121 | unset($this->configSections['Magefan_Community']);
122 |
123 | foreach ($this->magefanModules as $moduleName) {
124 | $section = $this->getConfigSections($moduleName);
125 |
126 | if (isset($section['id']) && 'mfextension' != $section['id']) {
127 | $item = $this->menuItemFactory->create([
128 | 'data' => [
129 | 'id' => $section['resource'] . '_custom',
130 | 'title' => $section['label'],
131 | 'module' => $moduleName,
132 | 'resource' => $section['resource']
133 | ]
134 | ]);
135 | $menu->add($item, 'Magefan_Community::elements');
136 |
137 | $item = $this->menuItemFactory->create([
138 | 'data' => [
139 | 'id' => $section['resource'] . '_menu',
140 | 'title' => 'Configuration',
141 | 'resource' => $section['resource'],
142 | 'action' => 'adminhtml/system_config/edit/section/' . $section['key'],
143 | 'module' => $moduleName
144 | ]
145 | ]);
146 | $menu->add($item, $section['resource'] . '_custom', 1000);
147 | }
148 | }
149 | }
150 |
151 | return $result;
152 | }
153 |
154 | /**
155 | * @param $moduleName
156 | * @return mixed|null
157 | */
158 | private function getConfigSections($moduleName)
159 | {
160 | if (null === $this->configSections) {
161 | $sections = [];
162 | $this->configSections = [];
163 |
164 | try {
165 | $tabs = $this->structure->getTabs();
166 | } catch (\Exception $e) {
167 | $tabs = [];
168 | }
169 |
170 | foreach ($tabs as $tab) {
171 | if (in_array($tab->getId(), ['magefan', 'mf_extensions_list'])) {
172 | $sections = array_merge($sections, $tab->getData()['children']);
173 | }
174 | }
175 |
176 | foreach ($sections as $key => $section) {
177 | if (empty($section['resource']) || 0 !== strpos($section['resource'], 'Magefan_')) {
178 | continue;
179 | }
180 |
181 | $section['key'] = $key;
182 | $mName = $this->getModuleNameByResource($section['resource']);
183 | $this->configSections[$mName] = $section;
184 | }
185 | }
186 |
187 | return isset($this->configSections[$moduleName]) ? $this->configSections[$moduleName] : null;
188 | }
189 |
190 | /**
191 | * @param $resource
192 | * @return string
193 | */
194 | private function getModuleNameByResource($resource)
195 | {
196 | $moduleName = explode(':', $resource);
197 | $moduleName = $moduleName[0];
198 |
199 | return $moduleName;
200 | }
201 |
202 | /**
203 | * @param $menu
204 | * @param $items
205 | * @param $parentId
206 | */
207 | private function createMenuItem($menu, $items, $parentId)
208 | {
209 | foreach ($items as $item) {
210 | $moduleName = isset($item['module']) ? $item['module'] : null;
211 | $title = preg_replace('/(?menuItemFactory->create([
216 | 'data' => [
217 | 'id' => $item['id'] . '3',
218 | 'title' => $title,
219 | 'resource' => $item['resource'],
220 | 'module' => isset($item['module']) ? $item['module'] : null,
221 | ]
222 | ]);
223 | $menu->add($subItem, $parentId);
224 | }
225 |
226 | $subItem = $this->menuItemFactory->create([
227 | 'data' => [
228 | 'id' => $item['id'] . '2',
229 | 'title' => $item['title'],
230 | 'resource' => $item['resource'],
231 | 'action' => $item['action'],
232 | 'module' => isset($item['module']) ? $item['module'] : null,
233 | ]
234 | ]);
235 | if ($needCreateMenuItem) {
236 | $menu->add($subItem, $item['id'] . '3');
237 | } else {
238 | $menu->add($subItem, $parentId);
239 | }
240 |
241 | if (!empty($item['sub_menu'])) {
242 | $this->createMenuItem($menu, $item['sub_menu'], $item['id'] . '2');
243 | }
244 |
245 | if ('Magefan_Community::elements' == $parentId) {
246 | $addConfig = true;
247 | if (!empty($item['sub_menu'])) {
248 | foreach ($item['sub_menu'] as $subItem) {
249 | if ('Configuration' == $subItem['title']) {
250 | $addConfig = false;
251 | break;
252 | }
253 | }
254 | }
255 |
256 | if ($addConfig) {
257 | $section = $this->getConfigSections($moduleName);
258 | if ($section) {
259 | $subItem = $this->menuItemFactory->create([
260 | 'data' => [
261 | 'id' => $section['resource'] . '_menu',
262 | 'title' => 'Configuration',
263 | 'resource' => $section['resource'],
264 | 'action' => 'adminhtml/system_config/edit/section/' . $section['key'],
265 | 'module' => $moduleName
266 | ]
267 | ]);
268 | if ($needCreateMenuItem) {
269 | $menu->add($subItem, $item['id'] . '3');
270 | } else {
271 | $menu->add($subItem, $item['id'] . '2');
272 | }
273 | }
274 | }
275 | }
276 | unset($this->configSections[$moduleName]);
277 | $index = array_search($moduleName, $this->magefanModules);
278 | if (false !== $index) {
279 | unset($this->magefanModules[$index]);
280 | }
281 | }
282 | }
283 |
284 | /**
285 | * @param $items
286 | * @return array
287 | */
288 | private function getSubItem($items)
289 | {
290 | $subItems = [];
291 | if (!empty($items)) {
292 | foreach ($items as $item) {
293 | if (isset($item['module']) && 0 === strpos($item['module'], 'Magefan_')
294 | || !isset($item['module']) && isset($item['id']) && 0 === strpos($item['id'], 'Magefan_')
295 | ) {
296 | if ('Magefan_Community::elements' != $item['id']) {
297 | $subItems[] = $item;
298 | }
299 | } elseif (!empty($item['sub_menu'])) {
300 | $subItems = array_merge($subItems, $this->getSubItem($item['sub_menu']));
301 | }
302 | }
303 | }
304 |
305 | return $subItems;
306 | }
307 |
308 | /**
309 | * Retrieve Magefan modules info
310 | *
311 | * @return array
312 | */
313 | private function getMagefanModules()
314 | {
315 | $modules = [];
316 | foreach ($this->moduleList->getNames() as $moduleName) {
317 | if (strpos($moduleName, 'Magefan_') !== false && $this->moduleManager->isEnabled($moduleName)) {
318 | $modules[] = $moduleName;
319 | }
320 | }
321 | return $modules;
322 | }
323 | }
324 |
--------------------------------------------------------------------------------
/Plugin/Magento/Framework/View/TemplateEngine/Php.php:
--------------------------------------------------------------------------------
1 | mfSecureRenderer = $mfSecureRenderer;
39 | $this->mfHyvaThemeDetection = $mfHyvaThemeDetection;
40 | $this->mfBreezeThemeDetection = $mfBreezeThemeDetection;
41 | }
42 |
43 | /**
44 | * @param \Magento\Framework\View\TemplateEngine\Php $subject
45 | * @param \Magento\Framework\View\Element\BlockInterface $block
46 | * @param $fileName
47 | * @param array $dictionary
48 | * @return array
49 | */
50 | public function beforeRender(
51 | \Magento\Framework\View\TemplateEngine\Php $subject,
52 | \Magento\Framework\View\Element\BlockInterface $block,
53 | $fileName,
54 | array $dictionary = []
55 | ) {
56 | $dictionary['mfSecureRenderer'] = $this->mfSecureRenderer;
57 | $dictionary['mfHyvaThemeDetection'] = $this->mfHyvaThemeDetection;
58 | $dictionary['mfBreezeThemeDetection'] = $this->mfBreezeThemeDetection;
59 |
60 | return [$block, $fileName, $dictionary];
61 | }
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Magefan Community Extension by [Magefan](https://magefan.com/)
2 |
3 | [](https://packagist.org/packages/magefan/module-community)
4 | [](https://packagist.org/packages/magefan/module-community)
5 |
6 |
7 |
8 |
9 |
10 | This module is required for other Magefan extensions for Magento 2
11 |
12 | ## Requirements
13 | * Magento Community Edition 2.1.x-2.4.x or Magento Enterprise Edition 2.1.x-2.4.x
14 |
15 | ## Installation Method 1 - Installing via composer
16 | * Open command line
17 | * Using command "cd" navigate to your magento2 root directory
18 | * Run the commands:
19 |
20 | ```
21 | composer require magefan/module-community
22 | php bin/magento setup:upgrade
23 | php bin/magento setup:di:compile
24 | php bin/magento setup:static-content:deploy
25 | ```
26 |
27 | ## Installation Method 2 - Installing via FTP using archive
28 | * Download [ZIP Archive](https://github.com/magefan/module-community/archive/master.zip)
29 | * Extract files
30 | * In your Magento 2 root directory create folder app/code/Magefan/Community
31 | * Copy files and folders from archive to that folder
32 | * In command line, using "cd", navigate to your Magento 2 root directory
33 | * Run the commands:
34 | ```
35 | php bin/magento setup:upgrade
36 | php bin/magento setup:di:compile
37 | php bin/magento setup:static-content:deploy
38 | ```
39 |
40 | ## Support
41 | If you have any issues, please [contact us](https://magefan.com/contact)
42 | then if you still need help, open a bug report in GitHub's
43 | [issue tracker](https://github.com/magefan/module-community/issues).
44 |
45 | ## License
46 | The code is licensed under [EULA](https://magefan.com/end-user-license-agreement).
47 |
48 | ## [Magento 2 Extensions](https://magefan.com/magento-2-extensions) by Magefan
49 |
50 | ### [Magento 2 Google Extensions](https://magefan.com/magento-2-extensions/google-extensions)
51 |
52 | * [Magento 2 Google Indexing](https://magefan.com/magento-2-google-indexing-api)
53 | * [Magento 2 Google Analytics 4](https://magefan.com/magento-2-google-analytics-4)
54 | * [Magento 2 Google Tag Manager](https://magefan.com/magento-2-google-tag-manager)
55 | * [Magento 2 Google Shopping Feed](https://magefan.com/magento-2-google-shopping-feed-extension)
56 | * [Magento 2 Google Customer Reviews](https://magefan.com/magento-2-google-customer-reviews)
57 |
58 | ### Magento 2 SEO Extensions
59 |
60 | * [Magento 2 SEO Extension](https://magefan.com/magento-2-seo-extension)
61 | * [Magento 2 Rich Snippets](https://magefan.com/magento-2-rich-snippets)
62 | * [Magento 2 HTML Sitemap](https://magefan.com/magento-2-html-sitemap-extension)
63 | * [Magento 2 XML Sitemap](https://magefan.com/magento-2-xml-sitemap-extension)
64 | * [Magento 2 Facebook Open Graph](https://magefan.com/magento-2-open-graph-extension-og-tags)
65 | * [Magento 2 Twitter Cards](https://magefan.com/magento-2-twitter-cards-extension)
66 |
67 |
68 | ### [Magento 2 Speed Optimization Extensions](https://magefan.com/magento-2-extensions/speed-optimization)
69 |
70 | * [Magento 2 Google Page Speed Optimizer](https://magefan.com/magento-2-google-page-speed-optimizer)
71 | * [Magento 2 Full Page Cache Warmer](https://magefan.com/magento-2-full-page-cache-warmer)
72 | * [Magento 2 Image Lazy Load](https://magefan.com/magento-2-image-lazy-load-extension)
73 | * [Magento 2 WebP Images](https://magefan.com/magento-2-webp-optimized-images)
74 | * [Magento 2 Rocket JavaScript](https://magefan.com/rocket-javascript-deferred-javascript)
75 |
76 | ### [Magento 2 Admin Panel Extensions](https://magefan.com/magento-2-extensions/admin-extensions)
77 |
78 | * [Magento 2 Size Chart Extension](https://magefan.com/magento-2-size-chart)
79 | * [Magento 2 Security Extension](https://magefan.com/magento-2-security-extension)
80 | * [Magento 2 Admin Action Log](https://magefan.com/magento-2-admin-action-log)
81 | * [Magento 2 Order Editor](https://magefan.com/magento-2-edit-order-extension)
82 | * [Magento 2 Better Order Grid](https://magefan.com/magento-2-better-order-grid-extension)
83 | * [Magento 2 Extended Proruct Grid](https://magefan.com/magento-2-product-grid-inline-editor)
84 | * [Magento 2 Product Tabs](https://magefan.com/magento-2/extensions/product-tabs)
85 | * [Magento 2 Facebook Pixel](https://magefan.com/magento-2-facebook-pixel-extension)
86 | * [Magento 2 Email Attachments](https://magefan.com/magento-2-email-attachments)
87 | * [Magento 2 Admin View](https://magefan.com/magento-2-admin-view-extension)
88 | * [Magento 2 Admin Email Notifications](https://magefan.com/magento-2-admin-email-notifications)
89 | * [Magento 2 Login As Customer](https://magefan.com/login-as-customer-magento-2-extension)
90 |
91 | ### Magento 2 Blog Extensions
92 |
93 | * [Magento 2 Blog](https://magefan.com/magento2-blog-extension)
94 | * [Magento 2 Multi Blog](https://magefan.com/magento-2-multi-blog-extension)
95 | * [Magento 2 Product Widget](https://magefan.com/magento-2-product-widget)
96 |
97 | ### [Magento 2 Marketing Automation Extensions](https://magefan.com/magento-2-extensions/marketing-automation)
98 |
99 | * [Magento 2 Cookie Consent](https://magefan.com/magento-2-cookie-consent)
100 | * [Magento 2 Product Labels](https://magefan.com/magento-2-product-labels)
101 | * [Magento 2 Base Price](https://magefan.com/magento-2-base-price)
102 | * [Magento 2 Dynamic Categories](https://magefan.com/magento-2-dynamic-categories)
103 | * [Magento 2 Dynamic Blocks and Pages Extension](https://magefan.com/magento-2-cms-display-rules-extension)
104 | * [Magento 2 Automatic Related Products](https://magefan.com/magento-2-automatic-related-products)
105 | * [Magento 2 Price History](https://magefan.com/magento-2-price-history)
106 | * [Magento 2 Mautic Integration](https://magefan.com/magento-2-mautic-extension)
107 | * [Magento 2 YouTube Video](https://magefan.com/magento2-youtube-extension)
108 |
109 | ### [Magento 2 Cart Extensions](https://magefan.com/magento-2-extensions/cart-extensions)
110 |
111 | * [Magento 2 Checkout Extension](https://magefan.com/better-magento-2-checkout-extension)
112 | * [Magento 2 Coupon Code](https://magefan.com/magento-2-coupon-code-link)
113 | * [Magento 2 Guest to Customer](https://magefan.com/magento2-convert-guest-to-customer)
114 |
115 | ### [Magento 2 Multi-Language Extensions](https://magefan.com/magento-2-extensions/multi-language-extensions)
116 |
117 | * [Magento 2 Hreflang Tags](https://magefan.com/magento2-alternate-hreflang-extension)
118 | * [Magento 2 Auto Currency Switcher](https://magefan.com/magento-2-currency-switcher-auto-currency-by-country)
119 | * [Magento 2 Auto Language Switcher](https://magefan.com/magento-2-auto-language-switcher)
120 | * [Magento 2 GeoIP Store Switcher](https://magefan.com/magento-2-geoip-switcher-extension)
121 | * [Magento 2 Translation](https://magefan.com/magento-2-translation-extension)
122 |
123 | ### [Developers Tools](https://magefan.com/magento-2-extensions/developer-tools)
124 |
125 | * [Magento 2 Zero Downtime Deployment](https://magefan.com/blog/magento-2-zero-downtime-deployment)
126 | * [Magento 2 Cron Schedule](https://magefan.com/magento-2-cron-schedule)
127 | * [Magento 2 CLI Extension](https://magefan.com/magento2-cli-extension)
128 | * [Magento 2 Conflict Detector](https://magefan.com/magento2-conflict-detector)
129 |
130 | ## [Shopify Apps](https://magefan.com/shopify/apps) by Magefan
131 |
132 | * [Shopify Login As Customer](https://apps.shopify.com/login-as-customer)
133 | * [Shopify Blog](https://apps.shopify.com/magefan-blog)
134 | * [Shopify Size Chart](https://magefan.com/shopify/apps/size-chart)
135 | * [Shopify Google Indexer](https://magefan.com/shopify/apps/google-indexing)
136 | * [Shopify Product Feeds](https://magefan.com/shopify/apps/product-feed)
137 |
--------------------------------------------------------------------------------
/Setup/Patch/Data/UpdateWelcomeBlogPost.php:
--------------------------------------------------------------------------------
1 | moduleDataSetup = $moduleDataSetup;
25 | }
26 |
27 | /**
28 | * {@inheritdoc}
29 | */
30 | public function apply()
31 | {
32 | $this->moduleDataSetup->getConnection()->startSetup();
33 |
34 |
35 | $connection = $this->moduleDataSetup->getConnection();
36 | $tableName = $this->moduleDataSetup->getTable('magefan_blog_post');
37 |
38 | if ($connection->isTableExists($tableName)) {
39 |
40 | $replacesFrom = [
41 | '\'href="https://magefan.com/magento2-blog-extension"\'',
42 | '\'href="https://magefan.com/magento2-extensions"\'',
43 | '\'href="https://magefan.com/magento-2-extensions"\'',
44 | '\'href="https://magefan.com/blog/magento-2-blog-extension-documentation"\'',
45 | '\'href="https://magefan.com/blog/add-read-more-tag-to-blog-post-content"\'',
46 |
47 | '\'href="https://github.com/magefan/module-blog"\'',
48 | '\'href="https://twitter.com/magento2fan"\'',
49 | '\'href="https://www.facebook.com/magefan/"\''
50 | ];
51 |
52 | $replaceTo = '\'href="#" rel="nofollow"\'';
53 |
54 | foreach ($replacesFrom as $replaceFrom) {
55 | $connection->update(
56 | $tableName,
57 | [
58 | 'content' => new \Zend_Db_Expr(
59 | 'REPLACE(content, ' . $replaceFrom . ', ' . $replaceTo . ')'
60 | )
61 | ],
62 | ['content LIKE ?' => '%This is your first post. Edit or delete it%']
63 | );
64 | }
65 |
66 | $replacesFrom = [
67 | '\'Magefan\'',
68 | '\'Magento Blog\'',
69 | '\'Magento 2 Blog\''
70 | ];
71 |
72 | $replaceTo = '\'\'';
73 |
74 | foreach ($replacesFrom as $replaceFrom) {
75 | $connection->update(
76 | $tableName,
77 | [
78 | 'content' => new \Zend_Db_Expr(
79 | 'REPLACE(content, ' . $replaceFrom . ', ' . $replaceTo . ')'
80 | )
81 | ],
82 | ['content LIKE ?' => '%This is your first post. Edit or delete it%']
83 | );
84 | }
85 | }
86 |
87 | $this->moduleDataSetup->getConnection()->endSetup();
88 | }
89 |
90 | /**
91 | * {@inheritdoc}
92 | */
93 | public static function getDependencies()
94 | {
95 | return []; // Specify dependencies if any
96 | }
97 |
98 | /**
99 | * {@inheritdoc}
100 | */
101 | public function getAliases()
102 | {
103 | return [];
104 | }
105 | }
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "magefan/module-community",
3 | "description": "Magefan core module, required for other Magefan extensions",
4 | "require": {
5 | "magefan/module-admin-user-guide" : ">=2.0.6"
6 | },
7 | "version": "2.2.11",
8 | "type": "magento2-module",
9 | "autoload": {
10 | "files": [
11 | "registration.php"
12 | ],
13 | "psr-4": {
14 | "Magefan\\Community\\": ""
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/etc/acl.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/etc/adminhtml/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/etc/adminhtml/events.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/etc/adminhtml/routes.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/etc/adminhtml/system.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 | Magefan Extensions
12 |
13 |
14 | separator-top
15 | Extensions & Notifications
16 | magefan
17 | Magefan_Community::config_section
18 |
19 | Magefan Extensions
20 | 1
21 |
22 | Extensions Info
23 | Magefan\Community\Block\Adminhtml\System\Config\Form\ExtensionsInfo
24 |
25 |
26 |
27 | Magefan Notifications
28 | 1
29 |
30 | Product Updates
31 | Magento\Config\Model\Config\Source\Yesno
32 |
33 |
34 | Special Offers
35 | Magento\Config\Model\Config\Source\Yesno
36 |
37 |
38 | News
39 | Magento\Config\Model\Config\Source\Yesno
40 |
41 |
42 | Tips & Tricks
43 | Magento\Config\Model\Config\Source\Yesno
44 |
45 |
46 | General Information
47 | Magento\Config\Model\Config\Source\Yesno
48 |
49 |
50 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/etc/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
11 |
12 |
13 | 1
14 | 1
15 | 1
16 | 1
17 | 1
18 |
19 |
20 | 1
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/etc/crontab.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 | 1 1 1,10 * *
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/etc/csp_whitelist.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
11 |
12 |
13 | magefan.com
14 | cm.magefan.com
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/etc/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | - Magefan\Community\Model\View\Helper\SecureHtmlRenderer\Proxy
27 | - Magefan\Community\Model\HyvaThemeDetection\Proxy
28 | - Magefan\Community\Model\HyvaThemeDetection\Proxy
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/etc/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/registration.php:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/view/adminhtml/layout/marketplace_index_index.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/view/adminhtml/templates/hyvathemechecker.phtml:
--------------------------------------------------------------------------------
1 |
9 |
14 | getWitchModuleIsInstalled()) { ?>
15 |
16 |
17 |
18 | = $block->escapeHtml(__('It looks like you are using the Hyva theme, ' .
19 | 'but the Hyva Magefan extensions for Hyva compatibility are not installed. ' .
20 | 'Please install these packages for the proper functioning of the modules on the Hyva theme. Run the CLI commands:')) ?>
21 |
22 | $packageName) {
25 | $commands .= 'composer require hyva-themes/magento2-compat-module-fallback' . PHP_EOL;
26 | $commands .= 'composer require ' . $block->escapeHtml($packageName) . PHP_EOL;
27 | $commands .= 'bin/magento setup:upgrade' . PHP_EOL;
28 | $commands .= 'bin/magento setup:di:compile' . PHP_EOL;
29 | $commands .= 'bin/magento setup:static-content:deploy' . PHP_EOL;
30 | }
31 | ?>
32 |
= /* @noEscape */ $commands ?>
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/view/adminhtml/templates/linv.phtml:
--------------------------------------------------------------------------------
1 |
7 |
14 | getItems()) { ?>
15 |
16 |
17 |
18 |
19 | = 'Important! So' . 'me ' . 'Mag'.'efan'.' Ex'.'tensions'.' a'.'re'.' dis'.'abl'.'ed d'.'ue '.'to i'.'nva'.'lid'.' Product K'.'ey: ' ?>
20 |
21 |
22 |
23 | $name) { ?>
24 |
25 | = $block->escapeHtml($result = preg_replace('/([A-Z])/', ' $1', $name)); ?>
26 |
27 |
28 |
29 |
30 | = 'Ple' . 'ase che' . 'ck exten' . 'sions config' . 'uration' ?>.
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/view/adminhtml/templates/menu-magefan.phtml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
15 | ul[role=menu]');
24 | if (submenu.classList.contains('_show') && submenuDiv && submenuList) {
25 | submenuList.style.maxHeight = (document.documentElement.clientHeight - 120) + 'px';
26 | submenuDiv.style.position = 'fixed';
27 | submenuDiv.style.left = '88px';
28 | document.body.style.overflowY = 'hidden';
29 | } else {
30 | document.body.style.overflowY = 'auto';
31 | }
32 | }
33 |
34 | let menuElement = document.querySelector('#menu-magefan-community-elements');
35 | if (menuElement) {
36 | var observer = new MutationObserver(updateMenuHeight);
37 | observer.observe(menuElement, { attributes: true });
38 | }
39 | });
40 | "
41 | ?>
42 |
43 | = /* @noEscape */ $mfSecureRenderer->renderTag('script', [], $script, false) ?>
44 |
--------------------------------------------------------------------------------
/view/adminhtml/templates/vendors.phtml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 | = $block->escapeHtml(__('Extension Vendors')) ?>
10 |
11 |
12 |
13 |
14 |
15 |
Magefan
16 |
17 | Magefan is an eCommerce agency delivering top-notch extensions for Magento 2. We help eCommerce projects solve problems and reach their business goals faster.
18 | Magefan - eCommerce solutions you can trust.
19 |
20 | = $block->escapeHtml('Read More') ?>
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/view/adminhtml/web/css/source/_module.less:
--------------------------------------------------------------------------------
1 | .admin__menu {
2 |
3 | // Magefan Community Menu Lvl-0
4 | #menu-magefan-community-elements {
5 | &._show {
6 | > .submenu {
7 | width: calc(100vw - 8.800000000000001rem);
8 | > ul[role=menu] {
9 | display: grid;
10 | grid-template-columns: repeat(auto-fill, minmax(28rem, 1fr));
11 | overflow-x: hidden;
12 | overflow-y: auto;
13 | > .column {
14 | display: contents;
15 | > ul[role=menu] {
16 | display: contents;
17 | > li {
18 | display: flex;
19 | flex-direction: column;
20 | min-width: 24.8rem;
21 | border-bottom: 1px dotted rgba(255, 255, 255, 0.2);
22 | margin-bottom: 2rem;
23 | padding-bottom: 2.5rem;
24 | }
25 | }
26 | }
27 | }
28 | }
29 | }
30 |
31 | > a {
32 | &:before {
33 | content: '';
34 | background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8c3ZnIHZlcnNpb249IjEuMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogd2lkdGg9IjUwMC4wMDAwMDBwdCIgaGVpZ2h0PSI1MDAuMDAwMDAwcHQiIHZpZXdCb3g9IjAgMCA1MDAuMDAwMDAwIDUwMC4wMDAwMDAiCiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBtZWV0Ij4KCjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuMDAwMDAwLDUwMC4wMDAwMDApIHNjYWxlKDAuMTAwMDAwLC0wLjEwMDAwMCkiCmZpbGw9IiNhYWE2YTAiIHN0cm9rZT0ibm9uZSI+CjxwYXRoIGQ9Ik0zMjExIDQzOTkgYy0xMjIgLTM3IC0yMzUgLTE4OCAtMjkwIC0zODggbC0yMCAtNzMgMjIgNiBjMTIgNCA2MSAxMgoxMDkgMTggOTMgMTMgMjI0IDIgMjg3IC0yNCAzMCAtMTIgMjUgLTEzIC02NiAtMTMgLTI0OSAtMSAtNTAwIC0xNTMgLTYwMQotMzY1IC01NSAtMTE3IC02NyAtMTc0IC02NyAtMzIwIDEgLTEzNyAyMSAtMjMzIDcxIC0zMzMgMjggLTU2IDEwMCAtMTM3IDEyMQotMTM3IDcgMCAxMyAtNSAxMyAtMTEgMCAtMTcgLTgxIC00IC0xMjggMjAgLTIwMyAxMDMgLTI3MCA1MjggLTEyNyA4MDAgMjAgMzcKNTQgODYgNzUgMTA5IDIyIDIzIDQwIDQ0IDQwIDQ3IDAgMTAgLTU2IDUgLTExNSAtMTAgLTkyIC0yMyAtMjY3IC0xMTUgLTQwMAotMjExIC0xMzcgLTk4IC0yNDEgLTE1NCAtMzQ3IC0xODUgLTY2IC0yMCAtOTggLTIyIC0zMzggLTI0IC0yMzAgLTIgLTI3OSAtNQotMzcwIC0yNCAtMzM5IC03MiAtNjYwIC0zMzkgLTc3MCAtNjQwIC01NyAtMTU3IC03NCAtMzQyIC00NiAtNTAyIDEzIC03MiA3NwotMjg4IDM0OCAtMTE3NCAxMTYgLTM3OSAxMzQgLTQyMiAyMTAgLTQ5MSAxNDAgLTEyNiAzNjIgLTEyMiA1MTQgOSA4NSA3NCAxMzUKMjIzIDExNSAzNDYgLTUgMzMgLTYxIDIyNSAtMTIzIDQyOCAtMTExIDM2NCAtMTEzIDM2OSAtMTEzIDQ2OCAwIDkxIDMgMTA2IDMxCjE2NSAzNyA3OSA5NyAxNDAgMTcxIDE3NiA0NiAyMyA3MiAyOCAxNTcgMzIgODYgMyAxMDkgMSAxNTggLTE4IDYzIC0yMyAxNTMKLTk4IDE4OCAtMTU1IDEyIC0xOSA3OSAtMjIyIDE1MCAtNDUxIDExMSAtMzYzIDEzMyAtNDI0IDE2NyAtNDczIDE0NCAtMjA1CjM5OCAtMjI4IDU4NCAtNTQgNzQgNjkgMTAzIDEzNiAxMDcgMjUzIGwzIDk1IC0xMDYgMzUwIGMtNTggMTkzIC0xMDggMzc2Ci0xMTIgNDA3IC0xMSAxMDYgMjkgMjMzIDk3IDMxMSA0MCA0NiAxMzIgOTMgMjExIDEwOCA4MCAxNSAxNjggMiAyNDYgLTM2IDUxCi0yNiA3MiAtNDYgMTg2IC0xODUgMTEwIC0xMzQgMjgxIC0yNDcgNDMyIC0yODUgMTQyIC0zNiAzMDkgLTI5IDQ4MyAyMSAxMTMKMzIgMzMwIDE0MCA0MDcgMjAxIDc4IDY0IDg1IDg0IDU2IDE3MiAtMjYgNzkgLTQ0IDk5IC05MyAxMDcgLTM0IDYgLTM1IDUgLTYyCi00OSAtMzIgLTY3IC04OSAtMTIwIC0xNjUgLTE1NiAtNTEgLTI0IC02NyAtMjYgLTE3NiAtMjYgLTkwIDAgLTEzNCA1IC0xNzUKMTggLTEyNiA0MyAtMjIwIDEzOSAtMjYyIDI2NiAtMzIgMTAyIC0zNyAzMDQgLTggNDM2IDQ2IDIxNyAzNiAzODEgLTM1IDU1MAotMjYgNjMgLTM0IDk5IC0zOSAxNzAgLTIxIDM1OSAtMjY4IDcxMSAtNTExIDczMCAtMzMgMiAtNzUgMCAtOTQgLTZ6IG0xNDUKLTEwMzAgYzQxIC0zOSA1NyAtNzcgNTIgLTEyOSAtMyAtMjYgLTEzIC01OSAtMjQgLTczIC0xOCAtMjUgLTkzIC03MSAtMTAyCi02MyAtMiAyIDQgMTggMTIgMzUgMjEgNDAgMjAgOTkgLTMgMTM3IC0yMyAzNyAtODMgNjcgLTEyMiA2MiAtMzggLTYgLTMzIDEwCjEyIDQwIDQ3IDMyIDEzNiAyOCAxNzUgLTl6Ii8+CjwvZz4KPC9zdmc+Cg==") no-repeat center;
35 | background-size: 26px;
36 | margin: 0 auto .3rem auto;
37 | }
38 | &:hover {
39 | &:before {
40 | background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8c3ZnIHZlcnNpb249IjEuMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogd2lkdGg9IjUwMC4wMDAwMDBwdCIgaGVpZ2h0PSI1MDAuMDAwMDAwcHQiIHZpZXdCb3g9IjAgMCA1MDAuMDAwMDAwIDUwMC4wMDAwMDAiCiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBtZWV0Ij4KCjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuMDAwMDAwLDUwMC4wMDAwMDApIHNjYWxlKDAuMTAwMDAwLC0wLjEwMDAwMCkiCmZpbGw9IiNmN2YzZWIiIHN0cm9rZT0ibm9uZSI+CjxwYXRoIGQ9Ik0zMjExIDQzOTkgYy0xMjIgLTM3IC0yMzUgLTE4OCAtMjkwIC0zODggbC0yMCAtNzMgMjIgNiBjMTIgNCA2MSAxMgoxMDkgMTggOTMgMTMgMjI0IDIgMjg3IC0yNCAzMCAtMTIgMjUgLTEzIC02NiAtMTMgLTI0OSAtMSAtNTAwIC0xNTMgLTYwMQotMzY1IC01NSAtMTE3IC02NyAtMTc0IC02NyAtMzIwIDEgLTEzNyAyMSAtMjMzIDcxIC0zMzMgMjggLTU2IDEwMCAtMTM3IDEyMQotMTM3IDcgMCAxMyAtNSAxMyAtMTEgMCAtMTcgLTgxIC00IC0xMjggMjAgLTIwMyAxMDMgLTI3MCA1MjggLTEyNyA4MDAgMjAgMzcKNTQgODYgNzUgMTA5IDIyIDIzIDQwIDQ0IDQwIDQ3IDAgMTAgLTU2IDUgLTExNSAtMTAgLTkyIC0yMyAtMjY3IC0xMTUgLTQwMAotMjExIC0xMzcgLTk4IC0yNDEgLTE1NCAtMzQ3IC0xODUgLTY2IC0yMCAtOTggLTIyIC0zMzggLTI0IC0yMzAgLTIgLTI3OSAtNQotMzcwIC0yNCAtMzM5IC03MiAtNjYwIC0zMzkgLTc3MCAtNjQwIC01NyAtMTU3IC03NCAtMzQyIC00NiAtNTAyIDEzIC03MiA3NwotMjg4IDM0OCAtMTE3NCAxMTYgLTM3OSAxMzQgLTQyMiAyMTAgLTQ5MSAxNDAgLTEyNiAzNjIgLTEyMiA1MTQgOSA4NSA3NCAxMzUKMjIzIDExNSAzNDYgLTUgMzMgLTYxIDIyNSAtMTIzIDQyOCAtMTExIDM2NCAtMTEzIDM2OSAtMTEzIDQ2OCAwIDkxIDMgMTA2IDMxCjE2NSAzNyA3OSA5NyAxNDAgMTcxIDE3NiA0NiAyMyA3MiAyOCAxNTcgMzIgODYgMyAxMDkgMSAxNTggLTE4IDYzIC0yMyAxNTMKLTk4IDE4OCAtMTU1IDEyIC0xOSA3OSAtMjIyIDE1MCAtNDUxIDExMSAtMzYzIDEzMyAtNDI0IDE2NyAtNDczIDE0NCAtMjA1CjM5OCAtMjI4IDU4NCAtNTQgNzQgNjkgMTAzIDEzNiAxMDcgMjUzIGwzIDk1IC0xMDYgMzUwIGMtNTggMTkzIC0xMDggMzc2Ci0xMTIgNDA3IC0xMSAxMDYgMjkgMjMzIDk3IDMxMSA0MCA0NiAxMzIgOTMgMjExIDEwOCA4MCAxNSAxNjggMiAyNDYgLTM2IDUxCi0yNiA3MiAtNDYgMTg2IC0xODUgMTEwIC0xMzQgMjgxIC0yNDcgNDMyIC0yODUgMTQyIC0zNiAzMDkgLTI5IDQ4MyAyMSAxMTMKMzIgMzMwIDE0MCA0MDcgMjAxIDc4IDY0IDg1IDg0IDU2IDE3MiAtMjYgNzkgLTQ0IDk5IC05MyAxMDcgLTM0IDYgLTM1IDUgLTYyCi00OSAtMzIgLTY3IC04OSAtMTIwIC0xNjUgLTE1NiAtNTEgLTI0IC02NyAtMjYgLTE3NiAtMjYgLTkwIDAgLTEzNCA1IC0xNzUKMTggLTEyNiA0MyAtMjIwIDEzOSAtMjYyIDI2NiAtMzIgMTAyIC0zNyAzMDQgLTggNDM2IDQ2IDIxNyAzNiAzODEgLTM1IDU1MAotMjYgNjMgLTM0IDk5IC0zOSAxNzAgLTIxIDM1OSAtMjY4IDcxMSAtNTExIDczMCAtMzMgMiAtNzUgMCAtOTQgLTZ6IG0xNDUKLTEwMzAgYzQxIC0zOSA1NyAtNzcgNTIgLTEyOSAtMyAtMjYgLTEzIC01OSAtMjQgLTczIC0xOCAtMjUgLTkzIC03MSAtMTAyCi02MyAtMiAyIDQgMTggMTIgMzUgMjEgNDAgMjAgOTkgLTMgMTM3IC0yMyAzNyAtODMgNjcgLTEyMiA2MiAtMzggLTYgLTMzIDEwCjEyIDQwIDQ3IDMyIDEzNiAyOCAxNzUgLTl6Ii8+CjwvZz4KPC9zdmc+Cg==") no-repeat center;
41 | background-size: 26px;
42 | margin: 0 auto .3rem auto;
43 | }
44 | }
45 | }
46 | }
47 |
48 | // Content
49 | [data-ui-id^=menu-magento-].level-0 {
50 | [data-ui-id^=menu-magefan-].level-1 {
51 | .submenu-group-title {
52 | span {
53 | display: flex;
54 | justify-content: space-between;
55 | &:after {
56 | content: '';
57 | background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8c3ZnIHZlcnNpb249IjEuMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogd2lkdGg9IjUwMC4wMDAwMDBwdCIgaGVpZ2h0PSI1MDAuMDAwMDAwcHQiIHZpZXdCb3g9IjAgMCA1MDAuMDAwMDAwIDUwMC4wMDAwMDAiCiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBtZWV0Ij4KCjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuMDAwMDAwLDUwMC4wMDAwMDApIHNjYWxlKDAuMTAwMDAwLC0wLjEwMDAwMCkiCmZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSI+CjxwYXRoIGQ9Ik0zMjExIDQzOTkgYy0xMjIgLTM3IC0yMzUgLTE4OCAtMjkwIC0zODggbC0yMCAtNzMgMjIgNiBjMTIgNCA2MSAxMgoxMDkgMTggOTMgMTMgMjI0IDIgMjg3IC0yNCAzMCAtMTIgMjUgLTEzIC02NiAtMTMgLTI0OSAtMSAtNTAwIC0xNTMgLTYwMQotMzY1IC01NSAtMTE3IC02NyAtMTc0IC02NyAtMzIwIDEgLTEzNyAyMSAtMjMzIDcxIC0zMzMgMjggLTU2IDEwMCAtMTM3IDEyMQotMTM3IDcgMCAxMyAtNSAxMyAtMTEgMCAtMTcgLTgxIC00IC0xMjggMjAgLTIwMyAxMDMgLTI3MCA1MjggLTEyNyA4MDAgMjAgMzcKNTQgODYgNzUgMTA5IDIyIDIzIDQwIDQ0IDQwIDQ3IDAgMTAgLTU2IDUgLTExNSAtMTAgLTkyIC0yMyAtMjY3IC0xMTUgLTQwMAotMjExIC0xMzcgLTk4IC0yNDEgLTE1NCAtMzQ3IC0xODUgLTY2IC0yMCAtOTggLTIyIC0zMzggLTI0IC0yMzAgLTIgLTI3OSAtNQotMzcwIC0yNCAtMzM5IC03MiAtNjYwIC0zMzkgLTc3MCAtNjQwIC01NyAtMTU3IC03NCAtMzQyIC00NiAtNTAyIDEzIC03MiA3NwotMjg4IDM0OCAtMTE3NCAxMTYgLTM3OSAxMzQgLTQyMiAyMTAgLTQ5MSAxNDAgLTEyNiAzNjIgLTEyMiA1MTQgOSA4NSA3NCAxMzUKMjIzIDExNSAzNDYgLTUgMzMgLTYxIDIyNSAtMTIzIDQyOCAtMTExIDM2NCAtMTEzIDM2OSAtMTEzIDQ2OCAwIDkxIDMgMTA2IDMxCjE2NSAzNyA3OSA5NyAxNDAgMTcxIDE3NiA0NiAyMyA3MiAyOCAxNTcgMzIgODYgMyAxMDkgMSAxNTggLTE4IDYzIC0yMyAxNTMKLTk4IDE4OCAtMTU1IDEyIC0xOSA3OSAtMjIyIDE1MCAtNDUxIDExMSAtMzYzIDEzMyAtNDI0IDE2NyAtNDczIDE0NCAtMjA1CjM5OCAtMjI4IDU4NCAtNTQgNzQgNjkgMTAzIDEzNiAxMDcgMjUzIGwzIDk1IC0xMDYgMzUwIGMtNTggMTkzIC0xMDggMzc2Ci0xMTIgNDA3IC0xMSAxMDYgMjkgMjMzIDk3IDMxMSA0MCA0NiAxMzIgOTMgMjExIDEwOCA4MCAxNSAxNjggMiAyNDYgLTM2IDUxCi0yNiA3MiAtNDYgMTg2IC0xODUgMTEwIC0xMzQgMjgxIC0yNDcgNDMyIC0yODUgMTQyIC0zNiAzMDkgLTI5IDQ4MyAyMSAxMTMKMzIgMzMwIDE0MCA0MDcgMjAxIDc4IDY0IDg1IDg0IDU2IDE3MiAtMjYgNzkgLTQ0IDk5IC05MyAxMDcgLTM0IDYgLTM1IDUgLTYyCi00OSAtMzIgLTY3IC04OSAtMTIwIC0xNjUgLTE1NiAtNTEgLTI0IC02NyAtMjYgLTE3NiAtMjYgLTkwIDAgLTEzNCA1IC0xNzUKMTggLTEyNiA0MyAtMjIwIDEzOSAtMjYyIDI2NiAtMzIgMTAyIC0zNyAzMDQgLTggNDM2IDQ2IDIxNyAzNiAzODEgLTM1IDU1MAotMjYgNjMgLTM0IDk5IC0zOSAxNzAgLTIxIDM1OSAtMjY4IDcxMSAtNTExIDczMCAtMzMgMiAtNzUgMCAtOTQgLTZ6IG0xNDUKLTEwMzAgYzQxIC0zOSA1NyAtNzcgNTIgLTEyOSAtMyAtMjYgLTEzIC01OSAtMjQgLTczIC0xOCAtMjUgLTkzIC03MSAtMTAyCi02MyAtMiAyIDQgMTggMTIgMzUgMjEgNDAgMjAgOTkgLTMgMTM3IC0yMyAzNyAtODMgNjcgLTEyMiA2MiAtMzggLTYgLTMzIDEwCjEyIDQwIDQ3IDMyIDEzNiAyOCAxNzUgLTl6Ii8+CjwvZz4KPC9zdmc+Cg==") no-repeat center;background-size: contain;
58 | display: inline-block;
59 | width: 20px;
60 | min-width: 20px;
61 | height: 22px;
62 | margin-left: 15px;
63 | vertical-align: middle;
64 | padding: 0;
65 | }
66 | }
67 | }
68 | .submenu-group-title {
69 | + .submenu {
70 | [data-ui-id^=menu-magefan].level-2 {
71 | span {
72 | &:after {
73 | content: none;
74 | }
75 | }
76 | }
77 | }
78 | }
79 | }
80 | }
81 |
82 | [data-ui-id^=menu-magento-].level-0 {
83 | [data-ui-id^=menu-magento-].level-1 {
84 | [data-ui-id^=menu-magefan-].level-2 {
85 | span {
86 | display: flex;
87 | justify-content: space-between;
88 | &:after {
89 | content: '';
90 | background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8c3ZnIHZlcnNpb249IjEuMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogd2lkdGg9IjUwMC4wMDAwMDBwdCIgaGVpZ2h0PSI1MDAuMDAwMDAwcHQiIHZpZXdCb3g9IjAgMCA1MDAuMDAwMDAwIDUwMC4wMDAwMDAiCiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBtZWV0Ij4KCjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuMDAwMDAwLDUwMC4wMDAwMDApIHNjYWxlKDAuMTAwMDAwLC0wLjEwMDAwMCkiCmZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSI+CjxwYXRoIGQ9Ik0zMjExIDQzOTkgYy0xMjIgLTM3IC0yMzUgLTE4OCAtMjkwIC0zODggbC0yMCAtNzMgMjIgNiBjMTIgNCA2MSAxMgoxMDkgMTggOTMgMTMgMjI0IDIgMjg3IC0yNCAzMCAtMTIgMjUgLTEzIC02NiAtMTMgLTI0OSAtMSAtNTAwIC0xNTMgLTYwMQotMzY1IC01NSAtMTE3IC02NyAtMTc0IC02NyAtMzIwIDEgLTEzNyAyMSAtMjMzIDcxIC0zMzMgMjggLTU2IDEwMCAtMTM3IDEyMQotMTM3IDcgMCAxMyAtNSAxMyAtMTEgMCAtMTcgLTgxIC00IC0xMjggMjAgLTIwMyAxMDMgLTI3MCA1MjggLTEyNyA4MDAgMjAgMzcKNTQgODYgNzUgMTA5IDIyIDIzIDQwIDQ0IDQwIDQ3IDAgMTAgLTU2IDUgLTExNSAtMTAgLTkyIC0yMyAtMjY3IC0xMTUgLTQwMAotMjExIC0xMzcgLTk4IC0yNDEgLTE1NCAtMzQ3IC0xODUgLTY2IC0yMCAtOTggLTIyIC0zMzggLTI0IC0yMzAgLTIgLTI3OSAtNQotMzcwIC0yNCAtMzM5IC03MiAtNjYwIC0zMzkgLTc3MCAtNjQwIC01NyAtMTU3IC03NCAtMzQyIC00NiAtNTAyIDEzIC03MiA3NwotMjg4IDM0OCAtMTE3NCAxMTYgLTM3OSAxMzQgLTQyMiAyMTAgLTQ5MSAxNDAgLTEyNiAzNjIgLTEyMiA1MTQgOSA4NSA3NCAxMzUKMjIzIDExNSAzNDYgLTUgMzMgLTYxIDIyNSAtMTIzIDQyOCAtMTExIDM2NCAtMTEzIDM2OSAtMTEzIDQ2OCAwIDkxIDMgMTA2IDMxCjE2NSAzNyA3OSA5NyAxNDAgMTcxIDE3NiA0NiAyMyA3MiAyOCAxNTcgMzIgODYgMyAxMDkgMSAxNTggLTE4IDYzIC0yMyAxNTMKLTk4IDE4OCAtMTU1IDEyIC0xOSA3OSAtMjIyIDE1MCAtNDUxIDExMSAtMzYzIDEzMyAtNDI0IDE2NyAtNDczIDE0NCAtMjA1CjM5OCAtMjI4IDU4NCAtNTQgNzQgNjkgMTAzIDEzNiAxMDcgMjUzIGwzIDk1IC0xMDYgMzUwIGMtNTggMTkzIC0xMDggMzc2Ci0xMTIgNDA3IC0xMSAxMDYgMjkgMjMzIDk3IDMxMSA0MCA0NiAxMzIgOTMgMjExIDEwOCA4MCAxNSAxNjggMiAyNDYgLTM2IDUxCi0yNiA3MiAtNDYgMTg2IC0xODUgMTEwIC0xMzQgMjgxIC0yNDcgNDMyIC0yODUgMTQyIC0zNiAzMDkgLTI5IDQ4MyAyMSAxMTMKMzIgMzMwIDE0MCA0MDcgMjAxIDc4IDY0IDg1IDg0IDU2IDE3MiAtMjYgNzkgLTQ0IDk5IC05MyAxMDcgLTM0IDYgLTM1IDUgLTYyCi00OSAtMzIgLTY3IC04OSAtMTIwIC0xNjUgLTE1NiAtNTEgLTI0IC02NyAtMjYgLTE3NiAtMjYgLTkwIDAgLTEzNCA1IC0xNzUKMTggLTEyNiA0MyAtMjIwIDEzOSAtMjYyIDI2NiAtMzIgMTAyIC0zNyAzMDQgLTggNDM2IDQ2IDIxNyAzNiAzODEgLTM1IDU1MAotMjYgNjMgLTM0IDk5IC0zOSAxNzAgLTIxIDM1OSAtMjY4IDcxMSAtNTExIDczMCAtMzMgMiAtNzUgMCAtOTQgLTZ6IG0xNDUKLTEwMzAgYzQxIC0zOSA1NyAtNzcgNTIgLTEyOSAtMyAtMjYgLTEzIC01OSAtMjQgLTczIC0xOCAtMjUgLTkzIC03MSAtMTAyCi02MyAtMiAyIDQgMTggMTIgMzUgMjEgNDAgMjAgOTkgLTMgMTM3IC0yMyAzNyAtODMgNjcgLTEyMiA2MiAtMzggLTYgLTMzIDEwCjEyIDQwIDQ3IDMyIDEzNiAyOCAxNzUgLTl6Ii8+CjwvZz4KPC9zdmc+Cg==") no-repeat center;background-size: contain;
91 | display: inline-block;
92 | width: 20px;
93 | min-width: 20px;
94 | height: 22px;
95 | margin-left: 15px;
96 | vertical-align: middle;
97 | padding: 0;
98 | }
99 | }
100 | }
101 | }
102 | }
103 |
104 | }
105 |
106 |
107 |
108 | // Store Configuration Magefan Extension
109 | .config-nav .magefan-tab .admin__page-nav-title:before {
110 | content: '';
111 | background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8c3ZnIHZlcnNpb249IjEuMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogd2lkdGg9IjUwMC4wMDAwMDBwdCIgaGVpZ2h0PSI1MDAuMDAwMDAwcHQiIHZpZXdCb3g9IjAgMCA1MDAuMDAwMDAwIDUwMC4wMDAwMDAiCiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBtZWV0Ij4KCjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuMDAwMDAwLDUwMC4wMDAwMDApIHNjYWxlKDAuMTAwMDAwLC0wLjEwMDAwMCkiCmZpbGw9IiMzMDMwMzAiIHN0cm9rZT0ibm9uZSI+CjxwYXRoIGQ9Ik0zMjExIDQzOTkgYy0xMjIgLTM3IC0yMzUgLTE4OCAtMjkwIC0zODggbC0yMCAtNzMgMjIgNiBjMTIgNCA2MSAxMgoxMDkgMTggOTMgMTMgMjI0IDIgMjg3IC0yNCAzMCAtMTIgMjUgLTEzIC02NiAtMTMgLTI0OSAtMSAtNTAwIC0xNTMgLTYwMQotMzY1IC01NSAtMTE3IC02NyAtMTc0IC02NyAtMzIwIDEgLTEzNyAyMSAtMjMzIDcxIC0zMzMgMjggLTU2IDEwMCAtMTM3IDEyMQotMTM3IDcgMCAxMyAtNSAxMyAtMTEgMCAtMTcgLTgxIC00IC0xMjggMjAgLTIwMyAxMDMgLTI3MCA1MjggLTEyNyA4MDAgMjAgMzcKNTQgODYgNzUgMTA5IDIyIDIzIDQwIDQ0IDQwIDQ3IDAgMTAgLTU2IDUgLTExNSAtMTAgLTkyIC0yMyAtMjY3IC0xMTUgLTQwMAotMjExIC0xMzcgLTk4IC0yNDEgLTE1NCAtMzQ3IC0xODUgLTY2IC0yMCAtOTggLTIyIC0zMzggLTI0IC0yMzAgLTIgLTI3OSAtNQotMzcwIC0yNCAtMzM5IC03MiAtNjYwIC0zMzkgLTc3MCAtNjQwIC01NyAtMTU3IC03NCAtMzQyIC00NiAtNTAyIDEzIC03MiA3NwotMjg4IDM0OCAtMTE3NCAxMTYgLTM3OSAxMzQgLTQyMiAyMTAgLTQ5MSAxNDAgLTEyNiAzNjIgLTEyMiA1MTQgOSA4NSA3NCAxMzUKMjIzIDExNSAzNDYgLTUgMzMgLTYxIDIyNSAtMTIzIDQyOCAtMTExIDM2NCAtMTEzIDM2OSAtMTEzIDQ2OCAwIDkxIDMgMTA2IDMxCjE2NSAzNyA3OSA5NyAxNDAgMTcxIDE3NiA0NiAyMyA3MiAyOCAxNTcgMzIgODYgMyAxMDkgMSAxNTggLTE4IDYzIC0yMyAxNTMKLTk4IDE4OCAtMTU1IDEyIC0xOSA3OSAtMjIyIDE1MCAtNDUxIDExMSAtMzYzIDEzMyAtNDI0IDE2NyAtNDczIDE0NCAtMjA1CjM5OCAtMjI4IDU4NCAtNTQgNzQgNjkgMTAzIDEzNiAxMDcgMjUzIGwzIDk1IC0xMDYgMzUwIGMtNTggMTkzIC0xMDggMzc2Ci0xMTIgNDA3IC0xMSAxMDYgMjkgMjMzIDk3IDMxMSA0MCA0NiAxMzIgOTMgMjExIDEwOCA4MCAxNSAxNjggMiAyNDYgLTM2IDUxCi0yNiA3MiAtNDYgMTg2IC0xODUgMTEwIC0xMzQgMjgxIC0yNDcgNDMyIC0yODUgMTQyIC0zNiAzMDkgLTI5IDQ4MyAyMSAxMTMKMzIgMzMwIDE0MCA0MDcgMjAxIDc4IDY0IDg1IDg0IDU2IDE3MiAtMjYgNzkgLTQ0IDk5IC05MyAxMDcgLTM0IDYgLTM1IDUgLTYyCi00OSAtMzIgLTY3IC04OSAtMTIwIC0xNjUgLTE1NiAtNTEgLTI0IC02NyAtMjYgLTE3NiAtMjYgLTkwIDAgLTEzNCA1IC0xNzUKMTggLTEyNiA0MyAtMjIwIDEzOSAtMjYyIDI2NiAtMzIgMTAyIC0zNyAzMDQgLTggNDM2IDQ2IDIxNyAzNiAzODEgLTM1IDU1MAotMjYgNjMgLTM0IDk5IC0zOSAxNzAgLTIxIDM1OSAtMjY4IDcxMSAtNTExIDczMCAtMzMgMiAtNzUgMCAtOTQgLTZ6IG0xNDUKLTEwMzAgYzQxIC0zOSA1NyAtNzcgNTIgLTEyOSAtMyAtMjYgLTEzIC01OSAtMjQgLTczIC0xOCAtMjUgLTkzIC03MSAtMTAyCi02MyAtMiAyIDQgMTggMTIgMzUgMjEgNDAgMjAgOTkgLTMgMTM3IC0yMyAzNyAtODMgNjcgLTEyMiA2MiAtMzggLTYgLTMzIDEwCjEyIDQwIDQ3IDMyIDEzNiAyOCAxNzUgLTl6Ii8+CjwvZz4KPC9zdmc+Cg==") no-repeat 0 0;background-size: contain;
112 | display: block;
113 | width: 30px;
114 | height: 30px;
115 | position: absolute;
116 | top: 11px;
117 | }
118 | .config-nav .magefan-tab .admin__page-nav-title strong {
119 | margin-left: 40px;
120 | }
121 |
122 | .accordion .form-inline .config .data-grid .magefan-section td {
123 | padding: 1rem;
124 | }
125 | .accordion .form-inline .config .magefan-section tr:nth-child(even) td {
126 | background-color: #f5f5f5;
127 | }
128 |
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/variable/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko20yw.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/magefan/module-community/6315f33cf02f80829bc7316775b59f4d63d8c538/view/adminhtml/web/fonts/variable/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko20yw.woff2
--------------------------------------------------------------------------------
/view/adminhtml/web/images/logo-config-section.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/magefan/module-community/6315f33cf02f80829bc7316775b59f4d63d8c538/view/adminhtml/web/images/logo-config-section.png
--------------------------------------------------------------------------------
/view/adminhtml/web/images/logo-menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/magefan/module-community/6315f33cf02f80829bc7316775b59f4d63d8c538/view/adminhtml/web/images/logo-menu.png
--------------------------------------------------------------------------------
/view/adminhtml/web/images/magefan-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/magefan/module-community/6315f33cf02f80829bc7316775b59f4d63d8c538/view/adminhtml/web/images/magefan-logo.png
--------------------------------------------------------------------------------
/view/base/templates/js/ajax.phtml:
--------------------------------------------------------------------------------
1 |
7 |
13 |
37 | = /* @noEscape */ $mfSecureRenderer->renderTag('script', [], $script, false) ?>
38 |
--------------------------------------------------------------------------------
/view/base/templates/js/getCookie.phtml:
--------------------------------------------------------------------------------
1 |
7 |
13 |
31 | = /* @noEscape */ $mfSecureRenderer->renderTag('script', [], $script, false) ?>
32 |
--------------------------------------------------------------------------------
/view/base/templates/js/objToUrlParams.phtml:
--------------------------------------------------------------------------------
1 |
7 |
13 | `[${a}]`).join(\'\')}=${value}`)';
15 | ?>
16 |
20 | Object.entries(obj).reduce((pairs, [key, value]) => {
21 | if (typeof value === 'object')
22 | pairs.push(...getPairs(value, [...keys, key]));
23 | else
24 | pairs.push([[...keys, key], value]);
25 | return pairs;
26 | }, []);
27 |
28 | let x = getPairs(obj)
29 | .map(([[key0, ...keysRest], value]) =>
30 | {$mapCodeLine}
31 | .join('&');
32 |
33 | return x;
34 | };
35 | "; ?>
36 | = /* @noEscape */ $mfSecureRenderer->renderTag('script', [], $script, false) ?>
37 |
--------------------------------------------------------------------------------
/view/base/templates/js/setCookie.phtml:
--------------------------------------------------------------------------------
1 |
7 |
13 |
37 | = /* @noEscape */ $mfSecureRenderer->renderTag('script', [], $script, false) ?>
38 |
--------------------------------------------------------------------------------