PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.0.2
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.0.2
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 5 years ago MenuAbstract.php 5 years ago MenuAdmin.php 5 years ago MenuTop.php 5 years ago
MenuAbstract.php
362 lines
1 <?php
2 /**
3 * Matomo - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 *
8 */
9 namespace Piwik\Menu;
10
11 use Piwik\Cache;
12 use Piwik\Container\StaticContainer;
13 use Piwik\Plugins\SitesManager\API;
14 use Piwik\Singleton;
15 use Piwik\Plugin\Manager as PluginManager;
16
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
29 protected $menu = null;
30 protected $menuEntries = array();
31 protected $menuEntriesToRemove = array();
32 protected $edits = array();
33 protected $renames = array();
34 protected $orderingApplied = false;
35 protected $menuIcons = array();
36
37 /**
38 * Builds the menu, applies edits, renames
39 * and orders the entries.
40 *
41 * @return array
42 */
43 public function getMenu()
44 {
45 $this->buildMenu();
46 $this->applyEdits();
47 $this->applyRemoves();
48 $this->applyRenames();
49 $this->applyOrdering();
50 return $this->menu;
51 }
52
53 /**
54 * lets you register a menu icon for a certain menu category to replace the default arrow icon.
55 *
56 * @param string $menuName The translation key of a main menu category, eg 'Dashboard_Dashboard'
57 * @param string $iconCssClass The css class name of an icon, eg 'icon-user'
58 */
59 public function registerMenuIcon($menuName, $iconCssClass)
60 {
61 $this->menuIcons[$menuName] = $iconCssClass;
62 }
63
64 /**
65 * Returns a list of available plugin menu instances.
66 *
67 * @return \Piwik\Plugin\Menu[]
68 */
69 protected function getAllMenus()
70 {
71 $cacheId = 'Menus.all';
72 $cache = Cache::getTransientCache();
73
74 if ($cache->contains($cacheId)) {
75 return $cache->fetch($cacheId);
76 }
77
78 $components = PluginManager::getInstance()->findComponents('Menu', 'Piwik\\Plugin\\Menu');
79
80 $menus = array();
81 foreach ($components as $component) {
82 $menus[] = StaticContainer::get($component);
83 }
84
85 $cache->save($cacheId, $menus);
86
87 return $menus;
88 }
89
90 /**
91 * Adds a new entry to the menu.
92 *
93 * @param string $menuName The menu's category name. Can be a translation token.
94 * @param string $subMenuName The menu item's name. Can be a translation token.
95 * @param string|array $url The URL the admin menu entry should link to, or an array of query parameters
96 * that can be used to build the URL.
97 * @param int $order The order hint.
98 * @param bool|string $tooltip An optional tooltip to display or false to display the tooltip.
99 * @param bool|string $icon An icon classname, such as "icon-add". Only supported by admin menu
100 * @param bool|string $onclick Will execute the on click handler instead of executing the link. Only supported by admin menu.
101 * @since 2.7.0
102 * @api
103 */
104 public function addItem($menuName, $subMenuName, $url, $order = 50, $tooltip = false, $icon = false, $onclick = false)
105 {
106 // make sure the idSite value used is numeric (hack-y fix for #3426)
107 if (isset($url['idSite']) && !is_numeric($url['idSite'])) {
108 $idSites = API::getInstance()->getSitesIdWithAtLeastViewAccess();
109 $url['idSite'] = reset($idSites);
110 }
111
112 $this->menuEntries[] = array(
113 $menuName,
114 $subMenuName,
115 $url,
116 $order,
117 $tooltip,
118 $icon,
119 $onclick
120 );
121 }
122
123 /**
124 * Removes an existing entry from the menu.
125 *
126 * @param string $menuName The menu's category name. Can be a translation token.
127 * @param bool|string $subMenuName The menu item's name. Can be a translation token.
128 * @api
129 */
130 public function remove($menuName, $subMenuName = false)
131 {
132 $this->menuEntriesToRemove[] = array(
133 $menuName,
134 $subMenuName
135 );
136 }
137
138 /**
139 * Builds a single menu item
140 *
141 * @param string $menuName
142 * @param string $subMenuName
143 * @param string $url
144 * @param int $order
145 * @param bool|string $tooltip Tooltip to display.
146 */
147 private function buildMenuItem($menuName, $subMenuName, $url, $order = 50, $tooltip = false, $icon = false, $onclick = false)
148 {
149 if (!isset($this->menu[$menuName])) {
150 $this->menu[$menuName] = array(
151 '_hasSubmenu' => false,
152 '_order' => $order
153 );
154 }
155
156 if (empty($subMenuName)) {
157 $this->menu[$menuName]['_url'] = $url;
158 $this->menu[$menuName]['_order'] = $order;
159 $this->menu[$menuName]['_name'] = $menuName;
160 $this->menu[$menuName]['_tooltip'] = $tooltip;
161 if (!empty($this->menuIcons[$menuName])) {
162 $this->menu[$menuName]['_icon'] = $this->menuIcons[$menuName];
163 } else {
164 $this->menu[$menuName]['_icon'] = '';
165 }
166 }
167 if (!empty($subMenuName)) {
168 $this->menu[$menuName][$subMenuName]['_url'] = $url;
169 $this->menu[$menuName][$subMenuName]['_order'] = $order;
170 $this->menu[$menuName][$subMenuName]['_name'] = $subMenuName;
171 $this->menu[$menuName][$subMenuName]['_tooltip'] = $tooltip;
172 $this->menu[$menuName][$subMenuName]['_icon'] = $icon;
173 $this->menu[$menuName][$subMenuName]['_onclick'] = $onclick;
174 $this->menu[$menuName]['_hasSubmenu'] = true;
175
176 if (!array_key_exists('_tooltip', $this->menu[$menuName])) {
177 $this->menu[$menuName]['_tooltip'] = $tooltip;
178 }
179 }
180 }
181
182 /**
183 * Builds the menu from the $this->menuEntries variable.
184 */
185 private function buildMenu()
186 {
187 foreach ($this->menuEntries as $menuEntry) {
188 $this->buildMenuItem($menuEntry[0], $menuEntry[1], $menuEntry[2], $menuEntry[3], $menuEntry[4], $menuEntry[5], $menuEntry[6]);
189 }
190 }
191
192 /**
193 * Renames a single menu entry.
194 *
195 * @param $mainMenuOriginal
196 * @param $subMenuOriginal
197 * @param $mainMenuRenamed
198 * @param $subMenuRenamed
199 * @api
200 */
201 public function rename($mainMenuOriginal, $subMenuOriginal, $mainMenuRenamed, $subMenuRenamed)
202 {
203 $this->renames[] = array($mainMenuOriginal, $subMenuOriginal,
204 $mainMenuRenamed, $subMenuRenamed);
205 }
206
207 /**
208 * Edits a URL of an existing menu entry.
209 *
210 * @param $mainMenuToEdit
211 * @param $subMenuToEdit
212 * @param $newUrl
213 * @api
214 */
215 public function editUrl($mainMenuToEdit, $subMenuToEdit, $newUrl)
216 {
217 $this->edits[] = array($mainMenuToEdit, $subMenuToEdit, $newUrl);
218 }
219
220 /**
221 * Applies all edits to the menu.
222 */
223 private function applyEdits()
224 {
225 foreach ($this->edits as $edit) {
226 $mainMenuToEdit = $edit[0];
227 $subMenuToEdit = $edit[1];
228 $newUrl = $edit[2];
229
230 if ($subMenuToEdit === null) {
231 if (isset($this->menu[$mainMenuToEdit])) {
232 $menuDataToEdit = &$this->menu[$mainMenuToEdit];
233 } else {
234 $menuDataToEdit = null;
235 }
236 } else {
237 if (isset($this->menu[$mainMenuToEdit][$subMenuToEdit])) {
238 $menuDataToEdit = &$this->menu[$mainMenuToEdit][$subMenuToEdit];
239 } else {
240 $menuDataToEdit = null;
241 }
242 }
243
244 if (empty($menuDataToEdit)) {
245 $this->buildMenuItem($mainMenuToEdit, $subMenuToEdit, $newUrl);
246 } else {
247 $menuDataToEdit['_url'] = $newUrl;
248 }
249 }
250 }
251
252 private function applyRemoves()
253 {
254 foreach ($this->menuEntriesToRemove as $menuToDelete) {
255 if (empty($menuToDelete[1])) {
256 // Delete Main Menu
257 if (isset($this->menu[$menuToDelete[0]])) {
258 unset($this->menu[$menuToDelete[0]]);
259 }
260 } else {
261 // Delete Sub Menu
262 if (isset($this->menu[$menuToDelete[0]][$menuToDelete[1]])) {
263 unset($this->menu[$menuToDelete[0]][$menuToDelete[1]]);
264 }
265 }
266 }
267 }
268 /**
269 * Applies renames to the menu.
270 */
271 private function applyRenames()
272 {
273 foreach ($this->renames as $rename) {
274 $mainMenuOriginal = $rename[0];
275 $subMenuOriginal = $rename[1];
276 $mainMenuRenamed = $rename[2];
277 $subMenuRenamed = $rename[3];
278
279 // Are we changing a submenu?
280 if (!empty($subMenuOriginal)) {
281 if (isset($this->menu[$mainMenuOriginal][$subMenuOriginal])) {
282 $save = $this->menu[$mainMenuOriginal][$subMenuOriginal];
283 $save['_name'] = $subMenuRenamed;
284 unset($this->menu[$mainMenuOriginal][$subMenuOriginal]);
285 $this->menu[$mainMenuRenamed][$subMenuRenamed] = $save;
286 }
287 } // Changing a first-level element
288 elseif (isset($this->menu[$mainMenuOriginal])) {
289 $save = $this->menu[$mainMenuOriginal];
290 $save['_name'] = $mainMenuRenamed;
291 unset($this->menu[$mainMenuOriginal]);
292 $this->menu[$mainMenuRenamed] = $save;
293 }
294 }
295 }
296
297 /**
298 * Orders the menu according to their order.
299 */
300 private function applyOrdering()
301 {
302 if (empty($this->menu)
303 || $this->orderingApplied
304 ) {
305 return;
306 }
307
308 uasort($this->menu, array($this, 'menuCompare'));
309 foreach ($this->menu as $key => &$element) {
310 if (is_null($element)) {
311 unset($this->menu[$key]);
312 } elseif ($element['_hasSubmenu']) {
313 uasort($element, array($this, 'menuCompare'));
314 }
315 }
316
317 $this->orderingApplied = true;
318 }
319
320 /**
321 * Compares two menu entries. Used for ordering.
322 *
323 * @param array $itemOne
324 * @param array $itemTwo
325 * @return boolean
326 */
327 protected function menuCompare($itemOne, $itemTwo)
328 {
329 if (!is_array($itemOne) && !is_array($itemTwo)) {
330 return 0;
331 }
332
333 if (!is_array($itemOne) && is_array($itemTwo)) {
334 return -1;
335 }
336
337 if (is_array($itemOne) && !is_array($itemTwo)) {
338 return 1;
339 }
340
341 if (!isset($itemOne['_order']) && !isset($itemTwo['_order'])) {
342 return 0;
343 }
344
345 if (!isset($itemOne['_order']) && isset($itemTwo['_order'])) {
346 return -1;
347 }
348
349 if (isset($itemOne['_order']) && !isset($itemTwo['_order'])) {
350 return 1;
351 }
352
353 if ($itemOne['_order'] == $itemTwo['_order']) {
354 return strcmp(
355 @$itemOne['_name'],
356 @$itemTwo['_name']);
357 }
358
359 return ($itemOne['_order'] < $itemTwo['_order']) ? -1 : 1;
360 }
361 }
362