PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.0.1
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.0.1
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
320 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 $save = $this->menu[$mainMenuOriginal];
263 $save['_name'] = $mainMenuRenamed;
264 unset($this->menu[$mainMenuOriginal]);
265 $this->menu[$mainMenuRenamed] = $save;
266 }
267 }
268 }
269 /**
270 * Orders the menu according to their order.
271 */
272 private function applyOrdering()
273 {
274 if (empty($this->menu) || $this->orderingApplied) {
275 return;
276 }
277 uasort($this->menu, array($this, 'menuCompare'));
278 foreach ($this->menu as $key => &$element) {
279 if (is_null($element)) {
280 unset($this->menu[$key]);
281 } elseif ($element['_hasSubmenu']) {
282 uasort($element, array($this, 'menuCompare'));
283 }
284 }
285 $this->orderingApplied = true;
286 }
287 /**
288 * Compares two menu entries. Used for ordering.
289 *
290 * @param array $itemOne
291 * @param array $itemTwo
292 * @return boolean
293 */
294 protected function menuCompare($itemOne, $itemTwo)
295 {
296 if (!is_array($itemOne) && !is_array($itemTwo)) {
297 return 0;
298 }
299 if (!is_array($itemOne) && is_array($itemTwo)) {
300 return -1;
301 }
302 if (is_array($itemOne) && !is_array($itemTwo)) {
303 return 1;
304 }
305 if (!isset($itemOne['_order']) && !isset($itemTwo['_order'])) {
306 return 0;
307 }
308 if (!isset($itemOne['_order']) && isset($itemTwo['_order'])) {
309 return -1;
310 }
311 if (isset($itemOne['_order']) && !isset($itemTwo['_order'])) {
312 return 1;
313 }
314 if ($itemOne['_order'] == $itemTwo['_order']) {
315 return strcmp($itemOne['_name'] ?? '', $itemTwo['_name'] ?? '');
316 }
317 return $itemOne['_order'] < $itemTwo['_order'] ? -1 : 1;
318 }
319 }
320