PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.0.3
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.0.3
5.13.0 5.12.1 5.12.0 5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Menu / MenuAbstract.php
matomo / app / core / Menu Last commit date
Group.php 2 years ago MenuAbstract.php 2 years ago MenuAdmin.php 2 years ago MenuTop.php 2 years ago
MenuAbstract.php
321 lines
1 <?php
2
3 /**
4 * Matomo - free/libre analytics platform
5 *
6 * @link https://matomo.org
7 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
8 *
9 */
10 namespace Piwik\Menu;
11
12 use Piwik\Cache;
13 use Piwik\Container\StaticContainer;
14 use Piwik\Plugins\SitesManager\API;
15 use Piwik\Singleton;
16 use Piwik\Plugin\Manager as PluginManager;
17 /**
18 * Base class for classes that manage one of Piwik's menus.
19 *
20 * There are three menus in Piwik, the main menu, the top menu and the admin menu.
21 * Each menu has a class that manages the menu's content. Each class invokes
22 * a different event to allow plugins to add new menu items.
23 *
24 * @static \Piwik\Menu\MenuAbstract getInstance()
25 */
26 abstract class MenuAbstract extends Singleton
27 {
28 protected $menu = null;
29 protected $menuEntries = array();
30 protected $menuEntriesToRemove = array();
31 protected $edits = array();
32 protected $renames = array();
33 protected $orderingApplied = false;
34 protected $menuIcons = array();
35 /**
36 * Builds the menu, applies edits, renames
37 * and orders the entries.
38 *
39 * @return array
40 */
41 public function getMenu()
42 {
43 $this->buildMenu();
44 $this->applyEdits();
45 $this->applyRemoves();
46 $this->applyRenames();
47 $this->applyOrdering();
48 return $this->menu;
49 }
50 /**
51 * lets you register a menu icon for a certain menu category to replace the default arrow icon.
52 *
53 * @param string $menuName The translation key of a main menu category, eg 'Dashboard_Dashboard'
54 * @param string $iconCssClass The css class name of an icon, eg 'icon-user'
55 */
56 public function registerMenuIcon($menuName, $iconCssClass)
57 {
58 $this->menuIcons[$menuName] = $iconCssClass;
59 }
60 /**
61 * Returns a list of available plugin menu instances.
62 *
63 * @return \Piwik\Plugin\Menu[]
64 */
65 protected function getAllMenus()
66 {
67 $cacheId = 'Menus.all';
68 $cache = Cache::getTransientCache();
69 if ($cache->contains($cacheId)) {
70 return $cache->fetch($cacheId);
71 }
72 $components = PluginManager::getInstance()->findComponents('Menu', 'Piwik\\Plugin\\Menu');
73 $menus = array();
74 foreach ($components as $component) {
75 $menus[] = StaticContainer::get($component);
76 }
77 $cache->save($cacheId, $menus);
78 return $menus;
79 }
80 /**
81 * Adds a new entry to the menu.
82 *
83 * @param string $menuName The menu's category name. Can be a translation token.
84 * @param string $subMenuName The menu item's name. Can be a translation token.
85 * @param string|array $url The URL the admin menu entry should link to, or an array of query parameters
86 * that can be used to build the URL.
87 * @param int $order The order hint.
88 * @param bool|string $tooltip An optional tooltip to display or false to display the tooltip.
89 * @param bool|string $icon An icon classname, such as "icon-add". Only supported by admin menu
90 * @param bool|string $onclick Will execute the on click handler instead of executing the link. Only supported by admin menu.
91 * @param string $attribute Will add this string as a link attribute.
92 * @param bool|string $help Will display a help icon that will pop a notification with help information.
93 * @param int $badgeCount If non-zero then a badge will be overlaid on the icon showing the provided count
94 * @since 2.7.0
95 * @api
96 */
97 public function addItem($menuName, $subMenuName, $url, $order = 50, $tooltip = false, $icon = false, $onclick = false, $attribute = false, $help = false, $badgeCount = 0)
98 {
99 // make sure the idSite value used is numeric (hack-y fix for #3426)
100 if (isset($url['idSite']) && !is_numeric($url['idSite'])) {
101 $idSites = API::getInstance()->getSitesIdWithAtLeastViewAccess();
102 $url['idSite'] = reset($idSites);
103 }
104 $this->menuEntries[] = array($menuName, $subMenuName, $url, $order, $tooltip, $icon, $onclick, $attribute, $help, $badgeCount);
105 }
106 /**
107 * Removes an existing entry from the menu.
108 *
109 * @param string $menuName The menu's category name. Can be a translation token.
110 * @param bool|string $subMenuName The menu item's name. Can be a translation token.
111 * @api
112 */
113 public function remove($menuName, $subMenuName = false)
114 {
115 $this->menuEntriesToRemove[] = array($menuName, $subMenuName);
116 }
117 /**
118 * Builds a single menu item
119 *
120 * @param string $menuName
121 * @param string $subMenuName
122 * @param string $url
123 * @param int $order
124 * @param bool|string $tooltip Tooltip to display.
125 */
126 private function buildMenuItem($menuName, $subMenuName, $url, $order = 50, $tooltip = false, $icon = false, $onclick = false, $attribute = false, $help = false, $badgeCount = 0)
127 {
128 if (!isset($this->menu[$menuName])) {
129 $this->menu[$menuName] = array('_hasSubmenu' => false, '_order' => $order);
130 }
131 if (empty($subMenuName)) {
132 $this->menu[$menuName]['_url'] = $url;
133 $this->menu[$menuName]['_order'] = $order;
134 $this->menu[$menuName]['_name'] = $menuName;
135 $this->menu[$menuName]['_tooltip'] = $tooltip;
136 $this->menu[$menuName]['_attribute'] = $attribute;
137 if (!empty($this->menuIcons[$menuName])) {
138 $this->menu[$menuName]['_icon'] = $this->menuIcons[$menuName];
139 } else {
140 $this->menu[$menuName]['_icon'] = '';
141 }
142 if (!empty($onclick)) {
143 $this->menu[$menuName]['_onclick'] = $onclick;
144 }
145 $this->menu[$menuName]['_help'] = $help ?: '';
146 $this->menu[$menuName]['_badgecount'] = $badgeCount;
147 }
148 if (!empty($subMenuName)) {
149 $this->menu[$menuName][$subMenuName]['_url'] = $url;
150 $this->menu[$menuName][$subMenuName]['_order'] = $order;
151 $this->menu[$menuName][$subMenuName]['_name'] = $subMenuName;
152 $this->menu[$menuName][$subMenuName]['_tooltip'] = $tooltip;
153 $this->menu[$menuName][$subMenuName]['_attribute'] = $attribute;
154 $this->menu[$menuName][$subMenuName]['_icon'] = $icon;
155 $this->menu[$menuName][$subMenuName]['_onclick'] = $onclick;
156 $this->menu[$menuName][$subMenuName]['_help'] = $help ?: '';
157 $this->menu[$menuName][$subMenuName]['_badgecount'] = $badgeCount;
158 $this->menu[$menuName]['_hasSubmenu'] = true;
159 if (!array_key_exists('_tooltip', $this->menu[$menuName])) {
160 $this->menu[$menuName]['_tooltip'] = $tooltip;
161 }
162 }
163 }
164 /**
165 * Builds the menu from the $this->menuEntries variable.
166 */
167 private function buildMenu()
168 {
169 foreach ($this->menuEntries as $menuEntry) {
170 $this->buildMenuItem($menuEntry[0], $menuEntry[1], $menuEntry[2], $menuEntry[3], $menuEntry[4], $menuEntry[5], $menuEntry[6], $menuEntry[7], $menuEntry[8], $menuEntry[9]);
171 }
172 }
173 /**
174 * Renames a single menu entry.
175 *
176 * @param $mainMenuOriginal
177 * @param $subMenuOriginal
178 * @param $mainMenuRenamed
179 * @param $subMenuRenamed
180 * @api
181 */
182 public function rename($mainMenuOriginal, $subMenuOriginal, $mainMenuRenamed, $subMenuRenamed)
183 {
184 $this->renames[] = array($mainMenuOriginal, $subMenuOriginal, $mainMenuRenamed, $subMenuRenamed);
185 }
186 /**
187 * Edits a URL of an existing menu entry.
188 *
189 * @param $mainMenuToEdit
190 * @param $subMenuToEdit
191 * @param $newUrl
192 * @api
193 */
194 public function editUrl($mainMenuToEdit, $subMenuToEdit, $newUrl)
195 {
196 $this->edits[] = array($mainMenuToEdit, $subMenuToEdit, $newUrl);
197 }
198 /**
199 * Applies all edits to the menu.
200 */
201 private function applyEdits()
202 {
203 foreach ($this->edits as $edit) {
204 $mainMenuToEdit = $edit[0];
205 $subMenuToEdit = $edit[1];
206 $newUrl = $edit[2];
207 if ($subMenuToEdit === null) {
208 if (isset($this->menu[$mainMenuToEdit])) {
209 $menuDataToEdit =& $this->menu[$mainMenuToEdit];
210 } else {
211 $menuDataToEdit = null;
212 }
213 } else {
214 if (isset($this->menu[$mainMenuToEdit][$subMenuToEdit])) {
215 $menuDataToEdit =& $this->menu[$mainMenuToEdit][$subMenuToEdit];
216 } else {
217 $menuDataToEdit = null;
218 }
219 }
220 if (empty($menuDataToEdit)) {
221 $this->buildMenuItem($mainMenuToEdit, $subMenuToEdit, $newUrl);
222 } else {
223 $menuDataToEdit['_url'] = $newUrl;
224 }
225 }
226 }
227 private function applyRemoves()
228 {
229 foreach ($this->menuEntriesToRemove as $menuToDelete) {
230 if (empty($menuToDelete[1])) {
231 // Delete Main Menu
232 if (isset($this->menu[$menuToDelete[0]])) {
233 unset($this->menu[$menuToDelete[0]]);
234 }
235 } else {
236 // Delete Sub Menu
237 if (isset($this->menu[$menuToDelete[0]][$menuToDelete[1]])) {
238 unset($this->menu[$menuToDelete[0]][$menuToDelete[1]]);
239 }
240 }
241 }
242 }
243 /**
244 * Applies renames to the menu.
245 */
246 private function applyRenames()
247 {
248 foreach ($this->renames as $rename) {
249 $mainMenuOriginal = $rename[0];
250 $subMenuOriginal = $rename[1];
251 $mainMenuRenamed = $rename[2];
252 $subMenuRenamed = $rename[3];
253 // Are we changing a submenu?
254 if (!empty($subMenuOriginal)) {
255 if (isset($this->menu[$mainMenuOriginal][$subMenuOriginal])) {
256 $save = $this->menu[$mainMenuOriginal][$subMenuOriginal];
257 $save['_name'] = $subMenuRenamed;
258 unset($this->menu[$mainMenuOriginal][$subMenuOriginal]);
259 $this->menu[$mainMenuRenamed][$subMenuRenamed] = $save;
260 }
261 } elseif (isset($this->menu[$mainMenuOriginal])) {
262 // Changing a first-level element
263 $save = $this->menu[$mainMenuOriginal];
264 $save['_name'] = $mainMenuRenamed;
265 unset($this->menu[$mainMenuOriginal]);
266 $this->menu[$mainMenuRenamed] = $save;
267 }
268 }
269 }
270 /**
271 * Orders the menu according to their order.
272 */
273 private function applyOrdering()
274 {
275 if (empty($this->menu) || $this->orderingApplied) {
276 return;
277 }
278 uasort($this->menu, array($this, 'menuCompare'));
279 foreach ($this->menu as $key => &$element) {
280 if (is_null($element)) {
281 unset($this->menu[$key]);
282 } elseif ($element['_hasSubmenu']) {
283 uasort($element, array($this, 'menuCompare'));
284 }
285 }
286 $this->orderingApplied = true;
287 }
288 /**
289 * Compares two menu entries. Used for ordering.
290 *
291 * @param array $itemOne
292 * @param array $itemTwo
293 * @return boolean
294 */
295 protected function menuCompare($itemOne, $itemTwo)
296 {
297 if (!is_array($itemOne) && !is_array($itemTwo)) {
298 return 0;
299 }
300 if (!is_array($itemOne) && is_array($itemTwo)) {
301 return -1;
302 }
303 if (is_array($itemOne) && !is_array($itemTwo)) {
304 return 1;
305 }
306 if (!isset($itemOne['_order']) && !isset($itemTwo['_order'])) {
307 return 0;
308 }
309 if (!isset($itemOne['_order']) && isset($itemTwo['_order'])) {
310 return -1;
311 }
312 if (isset($itemOne['_order']) && !isset($itemTwo['_order'])) {
313 return 1;
314 }
315 if ($itemOne['_order'] == $itemTwo['_order']) {
316 return strcmp($itemOne['_name'] ?? '', $itemTwo['_name'] ?? '');
317 }
318 return $itemOne['_order'] < $itemTwo['_order'] ? -1 : 1;
319 }
320 }
321