Submenu.php
289 lines
| 1 | <?php |
| 2 | |
| 3 | namespace AmeliaBooking\Infrastructure\WP\WPMenu; |
| 4 | |
| 5 | use AmeliaBooking\Domain\Services\Settings\SettingsService; |
| 6 | use AmeliaBooking\Infrastructure\Licence\Licence; |
| 7 | use AmeliaBooking\Infrastructure\WP\SettingsService\SettingsStorage; |
| 8 | |
| 9 | /** |
| 10 | * Class Submenu |
| 11 | * |
| 12 | * @package AmeliaBooking\Infrastructure\WPMenu |
| 13 | */ |
| 14 | class Submenu |
| 15 | { |
| 16 | /** @var SubmenuPageHandler $submenuHandler */ |
| 17 | private $submenuHandler; |
| 18 | |
| 19 | /** @var array $menu */ |
| 20 | private $menu; |
| 21 | |
| 22 | /** |
| 23 | * Submenu constructor. |
| 24 | * |
| 25 | * @param SubmenuPageHandler $submenuHandler |
| 26 | * @param array $menu |
| 27 | */ |
| 28 | public function __construct($submenuHandler, $menu) |
| 29 | { |
| 30 | $this->submenuHandler = $submenuHandler; |
| 31 | |
| 32 | $this->menu = $menu; |
| 33 | } |
| 34 | |
| 35 | /** |
| 36 | * Add options in WP menu |
| 37 | */ |
| 38 | public function addOptionsPages() |
| 39 | { |
| 40 | add_menu_page( |
| 41 | 'Amelia Booking', |
| 42 | 'Amelia', |
| 43 | 'amelia_read_menu', |
| 44 | 'amelia', |
| 45 | '', |
| 46 | AMELIA_URL . 'public/img/amelia-logo-admin-icon.svg' |
| 47 | ); |
| 48 | |
| 49 | foreach ($this->menu as $menu) { |
| 50 | $this->handleMenuItem($menu); |
| 51 | } |
| 52 | |
| 53 | $this->addSubmenuPage( |
| 54 | 'amelia', |
| 55 | 'Welcome', |
| 56 | 'Welcome', |
| 57 | 'amelia_read_menu', |
| 58 | 'wpamelia-welcome', |
| 59 | function () { |
| 60 | $this->submenuHandler->render('wpamelia-welcome'); |
| 61 | } |
| 62 | ); |
| 63 | |
| 64 | remove_submenu_page('amelia', 'amelia'); |
| 65 | |
| 66 | add_action('admin_head', function () { |
| 67 | remove_submenu_page('amelia', 'wpamelia-welcome'); |
| 68 | }); |
| 69 | |
| 70 | if (!Licence::isPremium() && current_user_can('manage_options')) { |
| 71 | $this->addUpgradeMenuItem(); |
| 72 | } |
| 73 | |
| 74 | add_action('admin_menu', [$this, 'applyWhiteLabelMenuBranding'], 999); |
| 75 | } |
| 76 | |
| 77 | /** |
| 78 | * Apply custom plugin name and logo to the top-level Amelia admin menu. |
| 79 | */ |
| 80 | public function applyWhiteLabelMenuBranding() |
| 81 | { |
| 82 | $settingsService = new SettingsService(new SettingsStorage()); |
| 83 | |
| 84 | $featuresIntegrations = $settingsService->getCategorySettings('featuresIntegrations'); |
| 85 | |
| 86 | if (!$this->isWhiteLabelFeatureEnabled($featuresIntegrations)) { |
| 87 | return; |
| 88 | } |
| 89 | |
| 90 | $whiteLabel = $settingsService->getCategorySettings('whiteLabel'); |
| 91 | |
| 92 | if (empty($whiteLabel['pluginName']) && empty($whiteLabel['pictureFullPath']) && empty($whiteLabel['pictureThumbPath'])) { |
| 93 | return; |
| 94 | } |
| 95 | |
| 96 | global $menu; |
| 97 | |
| 98 | foreach ($menu as $key => $item) { |
| 99 | if (!isset($item[2]) || $item[2] !== 'amelia') { |
| 100 | continue; |
| 101 | } |
| 102 | |
| 103 | if (!empty($whiteLabel['pluginName'])) { |
| 104 | $menu[$key][0] = esc_html($whiteLabel['pluginName']); |
| 105 | } |
| 106 | |
| 107 | $logoUrl = !empty($whiteLabel['pictureThumbPath']) |
| 108 | ? $whiteLabel['pictureThumbPath'] |
| 109 | : ($whiteLabel['pictureFullPath'] ?? ''); |
| 110 | |
| 111 | if (!empty($logoUrl)) { |
| 112 | $menu[$key][6] = 'none'; |
| 113 | add_action('admin_head', static function () use ($logoUrl) { |
| 114 | echo '<style>#toplevel_page_amelia .wp-menu-image{background-image:url(' |
| 115 | . esc_url($logoUrl) |
| 116 | . ')!important;background-size:20px 20px!important;background-position:center!important;' |
| 117 | . 'background-repeat:no-repeat!important;}</style>'; |
| 118 | }, 10, 0); |
| 119 | } |
| 120 | |
| 121 | break; |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | private function addUpgradeMenuItem() |
| 126 | { |
| 127 | $upgradeUrl = 'https://wpamelia.com/pricing/?utm_source=lite&utm_medium=dashboard&utm_content=amelia&utm_campaign=amelia-utm'; |
| 128 | |
| 129 | $this->addSubmenuPage( |
| 130 | 'amelia', |
| 131 | '', |
| 132 | esc_html__('Upgrade', 'wpamelia'), |
| 133 | 'amelia_read_menu', |
| 134 | 'wpamelia-upgrade', |
| 135 | '__return_null' |
| 136 | ); |
| 137 | |
| 138 | add_action('admin_init', function () use ($upgradeUrl) { |
| 139 | $page = isset($_GET['page']) ? sanitize_key($_GET['page']) : ''; |
| 140 | |
| 141 | if ('wpamelia-upgrade' === $page) { |
| 142 | wp_redirect($upgradeUrl); |
| 143 | exit; |
| 144 | } |
| 145 | }); |
| 146 | |
| 147 | add_action('admin_enqueue_scripts', function () { |
| 148 | wp_enqueue_style( |
| 149 | 'amelia-admin-menu', |
| 150 | AMELIA_URL . 'public/css/backend/admin-menu.css', |
| 151 | [], |
| 152 | AMELIA_VERSION |
| 153 | ); |
| 154 | |
| 155 | wp_enqueue_script( |
| 156 | 'amelia-admin-menu', |
| 157 | AMELIA_URL . 'public/js/backend/admin-menu.js', |
| 158 | ['jquery'], |
| 159 | AMELIA_VERSION, |
| 160 | true |
| 161 | ); |
| 162 | }); |
| 163 | } |
| 164 | |
| 165 | /** |
| 166 | * Get the inline SVG diamond icon for locked features |
| 167 | * |
| 168 | * @return string |
| 169 | */ |
| 170 | private function getDiamondIcon() |
| 171 | { |
| 172 | return '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" ' |
| 173 | . 'style="width: 17px; height: 16px; margin-left: 8px; vertical-align: middle; display: inline-block;">' |
| 174 | // phpcs:ignore Generic.Files.LineLength |
| 175 | . '<path fill="currentColor" d="M17.166 1c.113 0 .308-.006.498.046.149.04.29.107.415.195.16.114.28.27.352.357l4.84 5.869c.077.094.162.197.228.291.054.076.113.17.16.284l.041.122.037.178c.025.18.013.363-.037.54a1.32 1.32 0 0 1-.2.405 5.2 5.2 0 0 1-.23.291L13.265 21.712c-.11.133-.222.27-.327.377a1.316 1.316 0 0 1-.486.33 1.305 1.305 0 0 1-.903 0 1.327 1.327 0 0 1-.487-.33c-.105-.107-.217-.244-.327-.377L.73 9.577c-.078-.094-.163-.196-.23-.29a1.32 1.32 0 0 1-.2-.406 1.32 1.32 0 0 1 0-.717l.042-.122c.046-.114.105-.208.159-.284.066-.094.15-.197.229-.291l4.84-5.87c.072-.087.19-.242.35-.356l.098-.062c.099-.058.206-.103.317-.133.19-.052.386-.046.499-.046h10.332ZM12 19.198l3.416-9.925H8.584L12 19.198Zm-1.725-.402L6.997 9.273H2.422l7.853 9.523Zm3.449 0 7.854-9.523h-4.575l-3.28 9.523ZM17.01 7.773h4.568l-4.305-5.221-.043-.052h-1.959l1.739 5.273Zm-8.44 0h6.86L13.692 2.5H10.31L8.57 7.773ZM6.77 2.5l-.043.052-4.305 5.22H6.99L8.73 2.5H6.77Z"/>' |
| 176 | . '</svg>'; |
| 177 | } |
| 178 | |
| 179 | public function handleMenuItem(array $menu) |
| 180 | { |
| 181 | if (!isset($menu['menuSlug'])) { |
| 182 | return; |
| 183 | } |
| 184 | |
| 185 | // Hide locations if it shouldn't be shown based on license and hideUnavailableFeatures setting |
| 186 | if ($menu['menuSlug'] === 'wpamelia-locations' && !Licence::shouldShowFeature('locations')) { |
| 187 | return; |
| 188 | } |
| 189 | |
| 190 | // Hide custom fields if it shouldn't be shown based on license and hideUnavailableFeatures setting |
| 191 | if ($menu['menuSlug'] === 'wpamelia-customfields' && !Licence::shouldShowFeature('customFields')) { |
| 192 | return; |
| 193 | } |
| 194 | |
| 195 | if ($menu['menuSlug'] === 'wpamelia-whats-new' && $this->shouldHideExternalLinks()) { |
| 196 | return; |
| 197 | } |
| 198 | |
| 199 | // Add diamond icon for locked features |
| 200 | if ($menu['menuSlug'] === 'wpamelia-locations' && Licence::isFeatureLocked('locations')) { |
| 201 | $menu['menuTitle'] = '<span style="display: inline-flex; align-items: center;">' |
| 202 | . $menu['menuTitle'] . $this->getDiamondIcon() . '</span>'; |
| 203 | } |
| 204 | |
| 205 | if ($menu['menuSlug'] === 'wpamelia-customfields' && Licence::isFeatureLocked('customFields')) { |
| 206 | $menu['menuTitle'] = '<span style="display: inline-flex; align-items: center;">' |
| 207 | . $menu['menuTitle'] . $this->getDiamondIcon() . '</span>'; |
| 208 | } |
| 209 | |
| 210 | $this->addSubmenuPage( |
| 211 | $menu['parentSlug'], |
| 212 | $menu['pageTitle'], |
| 213 | $menu['menuTitle'], |
| 214 | $menu['capability'], |
| 215 | $menu['menuSlug'], |
| 216 | function () use ($menu) { |
| 217 | $this->submenuHandler->render($menu['menuSlug']); |
| 218 | } |
| 219 | ); |
| 220 | } |
| 221 | |
| 222 | /** |
| 223 | * @noinspection MoreThanThreeArgumentsInspection |
| 224 | * |
| 225 | * @param $parentSlug |
| 226 | * @param $pageTitle |
| 227 | * @param $menuTitle |
| 228 | * @param $capability |
| 229 | * @param $menuSlug |
| 230 | * @param string $function |
| 231 | */ |
| 232 | private function addSubmenuPage($parentSlug, $pageTitle, $menuTitle, $capability, $menuSlug, $function = '') |
| 233 | { |
| 234 | add_submenu_page( |
| 235 | $parentSlug, |
| 236 | $pageTitle, |
| 237 | $menuTitle, |
| 238 | $capability, |
| 239 | $menuSlug, |
| 240 | $function |
| 241 | ); |
| 242 | } |
| 243 | |
| 244 | /** |
| 245 | * Check whether white label settings hide external Amelia links. |
| 246 | * |
| 247 | * @return bool |
| 248 | */ |
| 249 | private function shouldHideExternalLinks() |
| 250 | { |
| 251 | $settingsService = new SettingsService(new SettingsStorage()); |
| 252 | |
| 253 | $featuresIntegrations = $settingsService->getCategorySettings('featuresIntegrations'); |
| 254 | |
| 255 | if (!$this->isWhiteLabelFeatureEnabled($featuresIntegrations)) { |
| 256 | return false; |
| 257 | } |
| 258 | |
| 259 | $whiteLabel = $settingsService->getCategorySettings('whiteLabel'); |
| 260 | |
| 261 | return !empty($whiteLabel['hideExternalLinks']); |
| 262 | } |
| 263 | |
| 264 | /** |
| 265 | * Check whether white label is enabled in settings and available in the current licence. |
| 266 | * |
| 267 | * @param array|null $featuresIntegrations |
| 268 | * |
| 269 | * @return bool |
| 270 | */ |
| 271 | private function isWhiteLabelFeatureEnabled($featuresIntegrations) |
| 272 | { |
| 273 | $whiteLabelFeature = isset($featuresIntegrations['whiteLabel']) ? $featuresIntegrations['whiteLabel'] : null; |
| 274 | |
| 275 | return $this->isFeatureToggleEnabled($whiteLabelFeature) && |
| 276 | Licence::isFeatureEnabledWithLicense('whiteLabel', $whiteLabelFeature); |
| 277 | } |
| 278 | |
| 279 | /** |
| 280 | * @param array|null $feature |
| 281 | */ |
| 282 | private function isFeatureToggleEnabled(?array $feature): bool |
| 283 | { |
| 284 | return is_array($feature) && |
| 285 | array_key_exists('enabled', $feature) && |
| 286 | in_array($feature['enabled'], [true, 1, '1'], true); |
| 287 | } |
| 288 | } |
| 289 |