File size: 4,586 Bytes
7929f62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<?php

/**
 * Matomo - free/libre analytics platform
 *
 * @link    https://matomo.org
 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 */

namespace Piwik\Plugins\CoreHome;

use Piwik\Category\Category;
use Piwik\Category\CategoryList;
use Piwik\Menu\MenuTop;
use Piwik\Piwik;
use Piwik\Plugins\UsersManager\UserPreferences;
use Piwik\Request;

class Menu extends \Piwik\Plugin\Menu
{
    public function configureTopMenu(MenuTop $menu)
    {
        $this->configureReportingGroupMenuItems($menu);

        $module = $this->getLoginModule();
        if (Piwik::isUserIsAnonymous()) {
            $menu->registerMenuIcon('Login_LogIn', 'icon-sign-in');
            $menu->addItem('Login_LogIn', null, array('module' => $module, 'action' => false), 1000, Piwik::translate('Login_LogIn'));
        } else {
            $menu->registerMenuIcon('General_Logout', 'icon-sign-out');
            $menu->addItem('General_Logout', null, array('module' => $module, 'action' => 'logout', 'idSite' => null), 1000, Piwik::translate('General_Logout'));
        }
    }

    /**
     * Adds a top menu entry for each non-default reporting menu group (e.g. "AI Insights"). Each entry
     * leads into the regular reporting single-page-app, which filters the reporting menu to the active
     * group. This keeps every reporting section within the same SPA (no full page reloads when navigating
     * within a section) and lets categories opt into sections via Category::setGroups() instead of any
     * plugin scraping another plugin's reports.
     *
     * The reporting SPA reads the section from the hash, filters the menu to it and selects its first
     * page. The `data-reporting-group` attribute lets the active top-menu highlight be kept in sync
     * client-side (the server cannot read the hash).
     */
    private function configureReportingGroupMenuItems(MenuTop $menu): void
    {
        $idSite = $this->getMenuIdSite();
        if (null === $idSite) {
            return;
        }

        foreach ($this->getReportingMenuGroups() as $group => $order) {
            $params = $this->urlForModuleActionWithDefaultUserParams('CoreHome', 'index', ['idSite' => $idSite]);
            if (empty($params)) {
                continue;
            }

            $url = $this->urlForReportingSection($params, $group);

            $menu->addItem($group, null, $url, $order, false, false, false, 'data-reporting-group="' . $group . '"');
        }
    }

    /**
     * Resolves the site id to use for the reporting group menu entries. Mirrors the Analytics top-menu
     * entry: the entry stays visible (linking to the user's default site) even on pages without an idSite
     * in the URL, such as the All Websites page or admin pages.
     */
    private function getMenuIdSite(): ?int
    {
        $userPreferences = new UserPreferences();
        $idSite = (int) $userPreferences->getDefaultWebsiteId();
        $idSite = Request::fromRequest()->getIntegerParameter('idSite', $idSite);

        if (!$idSite || !Piwik::isUserHasViewAccess($idSite)) {
            return null;
        }

        return $idSite;
    }

    /**
     * Returns the reporting menu groups (excluding the default Analytics group) that have at least one
     * category with reporting pages, mapped to the order of the resulting top-menu entry. Sections are
     * ordered by their lowest category order and placed right after the Analytics entry.
     *
     * @return array<string, int> map of group id => top-menu order
     */
    private function getReportingMenuGroups(): array
    {
        $categoryOrderByGroup = [];

        foreach (CategoryList::get()->getCategories() as $category) {
            if (!$category->hasSubCategories()) {
                continue;
            }

            foreach ($category->getGroups() as $group) {
                if (Category::DEFAULT_GROUP === $group) {
                    continue;
                }

                $order = (int) $category->getOrder();
                if (!isset($categoryOrderByGroup[$group]) || $order < $categoryOrderByGroup[$group]) {
                    $categoryOrderByGroup[$group] = $order;
                }
            }
        }

        asort($categoryOrderByGroup);

        $groups = [];
        $order = 2; // right after the Analytics entry (order 1)
        foreach (array_keys($categoryOrderByGroup) as $group) {
            $groups[$group] = $order++;
        }

        return $groups;
    }

    private function getLoginModule()
    {
        return Piwik::getLoginPluginName();
    }
}