diff --git a/Block/Adminhtml/System/Config/Form/Info.php b/Block/Adminhtml/System/Config/Form/Info.php
index 29b9141..ae39606 100755
--- a/Block/Adminhtml/System/Config/Form/Info.php
+++ b/Block/Adminhtml/System/Config/Form/Info.php
@@ -11,6 +11,7 @@
use Magefan\Community\Api\GetModuleVersionInterface;
use Magefan\Community\Api\SecureHtmlRendererInterface;
use Magefan\Community\Api\GetModuleInfoInterface;
+use Magefan\Community\Model\SectionFactory;
use Magento\Backend\Block\Template\Context;
use Magento\Framework\Data\Form\Element\AbstractElement;
use Magento\Framework\Module\ModuleListInterface;
@@ -40,6 +41,11 @@ class Info extends \Magento\Config\Block\System\Config\Form\Field
*/
protected $getModuleInfo;
+ /**
+ * @var SectionFactory
+ */
+ protected $sectionFactory;
+
/**
* @param ModuleListInterface $moduleList
* @param Context $context
@@ -47,6 +53,7 @@ class Info extends \Magento\Config\Block\System\Config\Form\Field
* @param GetModuleVersionInterface|null $getModuleVersion
* @param SecureHtmlRendererInterface|null $mfSecureRenderer
* @param ModuleInfoInterface|null $getModuleInfo
+ * @param SectionFactory|null $sectionFactory
*/
public function __construct(
ModuleListInterface $moduleList,
@@ -54,7 +61,8 @@ public function __construct(
array $data = [],
?GetModuleVersionInterface $getModuleVersion = null,
?SecureHtmlRendererInterface $mfSecureRenderer = null,
- ?GetModuleInfoInterface $getModuleInfo = null
+ ?GetModuleInfoInterface $getModuleInfo = null,
+ ?SectionFactory $sectionFactory = null
) {
parent::__construct($context, $data);
$this->moduleList = $moduleList;
@@ -65,6 +73,8 @@ public function __construct(
->get(SecureHtmlRendererInterface::class);
$this->getModuleInfo = $getModuleInfo ?: \Magento\Framework\App\ObjectManager::getInstance()
->get(GetModuleInfoInterface::class);
+ $this->sectionFactory = $sectionFactory ?: \Magento\Framework\App\ObjectManager::getInstance()
+ ->get(SectionFactory::class);
}
/**
@@ -206,12 +216,20 @@ public function render(AbstractElement $element)
';
if ($canUpgradeToMaxPlan) {
- $escapedUrl = $this->escapeHtml($moduleUrl . '/pricing' . $utmParam);
+ $productKey = $this->getProductKey($element);
+
+ if ($productKey) {
+ $upgradeUrl = 'https://magefan.com/mfplanupgrade/upgrade/index?product_key=' . urlencode($productKey);
+ } else {
+ $upgradeUrl = $moduleUrl . '/pricing' . $utmParam . '&utm_campaign=upgrade-plan';
+ }
+
+ $escapedUrl = $this->escapeHtml($upgradeUrl);
$html .= '';
@@ -351,6 +369,26 @@ class="action-update"
return $html;
}
+ /**
+ * Get configured product key for the current section, if any
+ *
+ * @param AbstractElement $element
+ * @return string|null
+ */
+ protected function getProductKey(AbstractElement $element)
+ {
+ $fieldConfig = $element->getFieldConfig();
+ $sectionName = !empty($fieldConfig['path']) ? explode('/', $fieldConfig['path'])[0] : '';
+
+ if (!$sectionName) {
+ return null;
+ }
+
+ $productKey = $this->sectionFactory->create(['name' => $sectionName])->getKey();
+
+ return $productKey ?: null;
+ }
+
/**
* Return extension url
*
diff --git a/Plugin/Magento/Backend/Model/Menu/BuilderPlugin.php b/Plugin/Magento/Backend/Model/Menu/BuilderPlugin.php
index c371647..016d7e7 100644
--- a/Plugin/Magento/Backend/Model/Menu/BuilderPlugin.php
+++ b/Plugin/Magento/Backend/Model/Menu/BuilderPlugin.php
@@ -9,10 +9,12 @@
namespace Magefan\Community\Plugin\Magento\Backend\Model\Menu;
use Magefan\Community\Api\GetModuleInfoInterface;
+use Magefan\Community\Api\GetModuleVersionInterface;
use Magento\Backend\Model\Menu\Builder;
use Magento\Backend\Model\Menu;
use Magento\Backend\Model\Menu\ItemFactory;
use Magefan\Community\Model\Config;
+use Magefan\Community\Model\SectionFactory;
use Magento\Config\Model\Config\Structure;
use Magento\Framework\Module\Manager;
use Magento\Framework\Module\ModuleListInterface;
@@ -49,6 +51,11 @@ class BuilderPlugin
*/
private $configSections;
+ /**
+ * @var array
+ */
+ private $allConfigSections;
+
/**
* @var array
*/
@@ -59,6 +66,16 @@ class BuilderPlugin
*/
private $getModuleInfo;
+ /**
+ * @var GetModuleVersionInterface
+ */
+ private $getModuleVersion;
+
+ /**
+ * @var SectionFactory
+ */
+ private $sectionFactory;
+
/**
* BuilderPlugin constructor.
* @param ItemFactory $menuItemFactory
@@ -67,6 +84,8 @@ class BuilderPlugin
* @param ModuleListInterface $moduleList
* @param Manager $moduleManager
* @param GetModuleInfoInterface $getModuleInfo
+ * @param GetModuleVersionInterface|null $getModuleVersion
+ * @param SectionFactory|null $sectionFactory
*/
public function __construct(
ItemFactory $menuItemFactory,
@@ -74,7 +93,9 @@ public function __construct(
Structure $structure,
ModuleListInterface $moduleList,
Manager $moduleManager,
- GetModuleInfoInterface $getModuleInfo
+ GetModuleInfoInterface $getModuleInfo,
+ ?GetModuleVersionInterface $getModuleVersion = null,
+ ?SectionFactory $sectionFactory = null
) {
$this->menuItemFactory = $menuItemFactory;
$this->config = $config;
@@ -83,6 +104,12 @@ public function __construct(
$this->moduleManager = $moduleManager;
$this->magefanModules = $this->getMagefanModules();
$this->getModuleInfo = $getModuleInfo;
+ $this->getModuleVersion = $getModuleVersion ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
+ GetModuleVersionInterface::class
+ );
+ $this->sectionFactory = $sectionFactory ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
+ SectionFactory::class
+ );
}
/**
@@ -236,32 +263,12 @@ private function addUserGuideLinks(Menu $menu): void
$added[] = $id;
// extract module name from id e.g. Magefan_Blog::elements -> Magefan_Blog
- $module = explode('::', $id)[0];
- $module = explode('_', $module)[1];
- $url = !empty($modulesInfo[$module]) ? $modulesInfo[$module]->getDocumentationUrl() : '';
- // unique id per module to avoid conflicts
- $newItemId = $id . '_user_guides';
- if (!$url) {
- continue;
- }
-
- try {
- $encodedUrl = 'mf-ug-url-start' . rtrim(strtr(base64_encode($url), '+/', '-_'), '=') . 'mf-ug-url-end';
-
- $userGuideItem = $this->menuItemFactory->create([
- 'data' => [
- 'id' => $newItemId,
- 'title' => 'User Guides',
- 'module' => 'Magefan_Community',
- 'resource' => 'Magefan_Community::elements',
- 'action' => $encodedUrl,
- ]
- ]);
-
- $menu->add($userGuideItem, $id, 6000);
+ $moduleFullName = explode('::', $id)[0];
+ $module = explode('_', $moduleFullName)[1];
+ $moduleInfo = !empty($modulesInfo[$module]) ? $modulesInfo[$module] : null;
- } catch (\Exception $e) {
- }
+ $this->addUserGuideLink($menu, $id, $moduleInfo);
+ $this->addUpgradePlanLink($menu, $id, $moduleFullName, $moduleInfo);
}
}
}
@@ -270,6 +277,90 @@ private function addUserGuideLinks(Menu $menu): void
}
}
+ /**
+ * Add "User Guides" sub menu item for a module
+ *
+ * @param Menu $menu
+ * @param string $id
+ * @param \Magento\Framework\DataObject|null $moduleInfo
+ * @return void
+ */
+ private function addUserGuideLink(Menu $menu, string $id, $moduleInfo): void
+ {
+ $url = $moduleInfo ? $moduleInfo->getDocumentationUrl() : '';
+ if (!$url) {
+ return;
+ }
+
+ try {
+ $encodedUrl = 'mf-ug-url-start' . rtrim(strtr(base64_encode($url), '+/', '-_'), '=') . 'mf-ug-url-end';
+
+ $userGuideItem = $this->menuItemFactory->create([
+ 'data' => [
+ 'id' => $id . '_user_guides',
+ 'title' => 'User Guides',
+ 'module' => 'Magefan_Community',
+ 'resource' => 'Magefan_Community::elements',
+ 'action' => $encodedUrl,
+ ]
+ ]);
+
+ $menu->add($userGuideItem, $id, 6000);
+ } catch (\Exception $e) {
+ }
+ }
+
+ /**
+ * Add "Upgrade Plan" sub menu item for a module, if a higher paid plan is available for it
+ *
+ * @param Menu $menu
+ * @param string $id
+ * @param string $moduleFullName
+ * @param \Magento\Framework\DataObject|null $moduleInfo
+ * @return void
+ */
+ private function addUpgradePlanLink(Menu $menu, string $id, string $moduleFullName, $moduleInfo): void
+ {
+ if (!$moduleInfo || !$moduleInfo->getMaxPlan()) {
+ return;
+ }
+
+ $canUpgradeToMaxPlan = !$this->getModuleVersion->execute(
+ $moduleFullName . ucfirst($moduleInfo->getMaxPlan())
+ );
+
+ if (!$canUpgradeToMaxPlan) {
+ return;
+ }
+
+ $productKey = $this->getProductKeyForModule($moduleFullName);
+
+ if ($productKey) {
+ $url = 'https://magefan.com/mfplanupgrade/upgrade/index?product_key=' . urlencode($productKey);
+ } else {
+ $moduleUrl = $moduleInfo->getProductUrl() ?: 'https://magefan.com/';
+ $url = rtrim($moduleUrl, '/') . '/pricing'
+ . '?utm_source=admin&utm_medium=menu&utm_campaign=upgrade-plan';
+ }
+
+ try {
+ $encodedUrl = 'mf-upg-url-start' . rtrim(strtr(base64_encode($url), '+/', '-_'), '=') . 'mf-upg-url-end';
+
+ $upgradePlanItem = $this->menuItemFactory->create([
+ 'data' => [
+ 'id' => $id . '_upgrade_plan',
+ 'title' => 'Upgrade Plan',
+ 'module' => 'Magefan_Community',
+ 'resource' => 'Magefan_Community::elements',
+ 'action' => $encodedUrl,
+ ]
+ ]);
+
+ $menu->add($upgradePlanItem, $id, 6001);
+ } catch (\Exception $e) {
+ }
+ }
+
/**
* Ge config by module name
*
@@ -304,11 +395,34 @@ private function getConfigSections($moduleName)
$mName = $this->getModuleNameByResource($section['resource']);
$this->configSections[$mName] = $section;
}
+
+ $this->allConfigSections = $this->configSections;
}
return isset($this->configSections[$moduleName]) ? $this->configSections[$moduleName] : null;
}
+ /**
+ * Get configured product key for a Magefan module, if any
+ *
+ * @param string $moduleFullName
+ * @return string|null
+ */
+ private function getProductKeyForModule(string $moduleFullName): ?string
+ {
+ // ensure sections are loaded, regardless of whether createMenuItem() already consumed them
+ $this->getConfigSections($moduleFullName);
+
+ $sectionKey = $this->allConfigSections[$moduleFullName]['key'] ?? null;
+ if (!$sectionKey) {
+ return null;
+ }
+
+ $productKey = $this->sectionFactory->create(['name' => $sectionKey])->getKey();
+
+ return $productKey ?: null;
+ }
+
/**
* Get module by resource
*
diff --git a/view/adminhtml/web/js/magefan-menu.js b/view/adminhtml/web/js/magefan-menu.js
index 6e91d50..e9634ae 100644
--- a/view/adminhtml/web/js/magefan-menu.js
+++ b/view/adminhtml/web/js/magefan-menu.js
@@ -119,7 +119,7 @@ var MagefanMenuManager = {
if (groupTitleParent && groupTitleParent.nodeName === 'STRONG') {
var link = document.createElement('a');
link.href = "#";
- link.className = 'mf-submenu-group-title';
+ link.className = 'mf-submenu-group-title';
link.innerHTML = groupTitleParent.innerHTML;
groupTitleParent.replaceWith(link);
@@ -182,7 +182,7 @@ var MagefanMenuManager = {
}
var titleEl = parent.querySelector('.mf-submenu-group-title span') ||
- parent.querySelector('.submenu-group-title span');
+ parent.querySelector('.submenu-group-title span');
var titleText = titleEl ? titleEl.textContent.trim() : '';
self.addSubmenuHeader(submenu, titleText);
@@ -355,7 +355,7 @@ var MagefanMenuManager = {
var getItemText = function(item) {
var span = item.querySelector('.mf-submenu-group-title span') ||
- item.querySelector('.submenu-group-title span');
+ item.querySelector('.submenu-group-title span');
return (span ? span.textContent : '').trim();
};
@@ -407,7 +407,7 @@ var MagefanMenuManager = {
if (baseItem) {
var titleEl = baseItem.querySelector('.submenu-group-title span') ||
- baseItem.querySelector('.mf-submenu-group-title span');
+ baseItem.querySelector('.mf-submenu-group-title span');
if (titleEl) {
titleEl.textContent = 'General';
titleEl.setAttribute('data-original-text', 'General');
@@ -733,10 +733,11 @@ var MagefanMenuManager = {
});
}
- function addUserGuideLinks() {
- document.querySelectorAll('a[href*="mf-ug-url-start"]').forEach(function(link) {
- var match = link.getAttribute('href')
- .match(/mf-ug-url-start(.+?)mf-ug-url-end/);
+ function addEncodedMenuLinks(marker, endMarker, utmCampaign) {
+ var regex = new RegExp(marker + '(.+?)' + endMarker);
+
+ document.querySelectorAll('a[href*="' + marker + '"]').forEach(function(link) {
+ var match = link.getAttribute('href').match(regex);
if (!match) return;
var encoded = match[1];
@@ -753,7 +754,8 @@ var MagefanMenuManager = {
if (!decoded) return;
- link.href = decoded + '?utm_source=admin&utm_medium=menu&utm_campaign=sub-guide';
+ var separator = decoded.indexOf('?') !== -1 ? '&' : '?';
+ link.href = decoded + separator + 'utm_source=admin&utm_medium=menu&utm_campaign=' + utmCampaign;
link.target = '_blank';
link.addEventListener('click', function(e) {
e.preventDefault();
@@ -762,6 +764,15 @@ var MagefanMenuManager = {
});
}
+ function addUserGuideLinks() {
+ addEncodedMenuLinks('mf-ug-url-start', 'mf-ug-url-end', 'sub-guide');
+ }
+
+ function addUpgradePlanLinks() {
+ addEncodedMenuLinks('mf-upg-url-start', 'mf-upg-url-end', 'upgrade-plan');
+ }
+
addMainUserGuideAndMarketplaceLinks();
addUserGuideLinks();
+ addUpgradePlanLinks();
})();