MenuController::setCustomPermissions()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 0
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Controllers;
4
5
use GeminiLabs\SiteReviews\Api;
6
use GeminiLabs\SiteReviews\Database\Cache;
7
use GeminiLabs\SiteReviews\Database\Tables;
8
use GeminiLabs\SiteReviews\Defaults\AddonDefaults;
9
use GeminiLabs\SiteReviews\Defaults\FeatureDefaults;
10
use GeminiLabs\SiteReviews\Helper;
11
use GeminiLabs\SiteReviews\Helpers\Arr;
12
use GeminiLabs\SiteReviews\Helpers\Str;
13
use GeminiLabs\SiteReviews\License;
14
use GeminiLabs\SiteReviews\Modules\Console;
15
use GeminiLabs\SiteReviews\Modules\Html\Builder;
16
use GeminiLabs\SiteReviews\Modules\Html\SettingForm;
17
use GeminiLabs\SiteReviews\Modules\Notice;
18
use GeminiLabs\SiteReviews\Overrides\ScheduledActionsTable;
19
20
class MenuController extends AbstractController
21
{
22
    /**
23
     * This is necessary because the ActionScheduler table is rendered late
24
     * after request headers have already be set which breaks redirects.
25
     *
26
     * @action load-site-review_page_glsr-tools
27
     */
28
    public function processPageActions(): void
29
    {
30
        glsr(ScheduledActionsTable::class)->process_actions();
31
    }
32
33
    /**
34
     * @action admin_menu
35
     */
36
    public function registerMenuCount(): void
37
    {
38
        global $menu, $typenow;
39
        foreach ($menu as $key => $value) {
40
            if (!isset($value[2]) || $value[2] != 'edit.php?post_type='.glsr()->post_type) {
41
                continue;
42
            }
43
            $postCount = wp_count_posts(glsr()->post_type);
44
            $pendingCount = glsr(Builder::class)->span(number_format_i18n($postCount->pending), [
45
                'class' => 'unapproved-count',
46
            ]);
47
            $awaitingModeration = glsr(Builder::class)->span($pendingCount, [
48
                'class' => "awaiting-mod count-{$postCount->pending}",
49
            ]);
50
            $menu[$key][0] .= " {$awaitingModeration}";
51
            if (glsr()->post_type === $typenow) {
52
                $menu[$key][4] .= ' current';
53
            }
54
            break;
55
        }
56
    }
57
58
    /**
59
     * @action admin_menu
60
     */
61
    public function registerSubMenus(): void
62
    {
63
        global $submenu;
64
        $pages = $this->parseWithFilter('submenu/pages', [
65
            'settings' => _x('Settings', 'admin-text', 'site-reviews'),
66
            'tools' => _x('Tools', 'admin-text', 'site-reviews'),
67
            'documentation' => _x('Help & Support', 'admin-text', 'site-reviews'),
68
            'premium' => _x('Upgrade to Premium', 'admin-text', 'site-reviews'),
69
        ]);
70
        $parentSlug = 'edit.php?post_type='.glsr()->post_type;
71
        $slugPrefix = Str::dashCase(glsr()->prefix);
72
        foreach ($pages as $slug => $title) {
73
            $method = Helper::buildMethodName('render', $slug, 'menu', 'callback');
74 8
            if (!method_exists($this, $method)) {
75
                continue;
76 8
            }
77
            $callback = glsr()->filter('addon/submenu/callback', [$this, $method], $slug);
78
            if (!is_callable($callback)) {
79 8
                continue;
80 8
            }
81 8
            add_submenu_page($parentSlug, $title, $title, glsr()->getPermission($slug), $slugPrefix.$slug, $callback);
0 ignored issues
show
Bug introduced by
It seems like $callback can also be of type GeminiLabs\SiteReviews\Controllers\MenuController; however, parameter $callback of add_submenu_page() does only seem to accept callable, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

81
            add_submenu_page($parentSlug, $title, $title, glsr()->getPermission($slug), $slugPrefix.$slug, /** @scrutinizer ignore-type */ $callback);
Loading history...
82 8
        }
83
        foreach ($submenu[$parentSlug] as $index => $menu) {
84
            $slug = $menu[2] ?? '';
85
            if (!str_starts_with($slug, $slugPrefix)) {
86
                continue;
87
            }
88
            $submenu[$parentSlug][$index][4] = "submenu_{$slug}"; // add submenu class
89
        }
90
    }
91
92
    /**
93
     * We don't use admin_menu because it breaks the privilege check which runs
94
     * after the admin_menu hook is triggered in wp-admin/includes/menu.php.
95
     *
96
     * @action admin_init
97
     */
98
    public function removeSubMenu(): void
99
    {
100
        if (!function_exists('remove_submenu_page')) {
101
            require_once ABSPATH.'wp-admin/includes/plugin.php';
102
        }
103
        remove_submenu_page(
104
            'edit.php?post_type='.glsr()->post_type,
105
            'post-new.php?post_type='.glsr()->post_type
106
        );
107
    }
108
109
    /**
110
     * @see registerSubMenus
111
     */
112
    public function renderDocumentationMenuCallback(): void
113
    {
114
        $tabs = $this->parseWithFilter('documentation/tabs', [
115
            'support' => _x('Support', 'admin-text', 'site-reviews'),
116
            'faq' => _x('FAQ', 'admin-text', 'site-reviews'),
117
            'shortcodes' => _x('Shortcodes', 'admin-text', 'site-reviews'),
118
            'hooks' => _x('Hooks', 'admin-text', 'site-reviews'),
119
            'functions' => _x('Functions', 'admin-text', 'site-reviews'),
120
            'api' => _x('API', 'admin-text', 'site-reviews'),
121
            'integrations' => _x('Integrations', 'admin-text', 'site-reviews'),
122
            'addons' => _x('Addons', 'admin-text', 'site-reviews'),
123
        ]);
124
        $addons = glsr()->filterArray('addon/documentation', []);
125
        uksort($addons, fn ($a, $b) => strnatcasecmp(glsr($a)->name, glsr($b)->name));
126
        if (empty($addons)) {
127
            unset($tabs['addons']);
128
        }
129
        $this->renderPage('documentation', [
130
            'addons' => $addons,
131
            'tabs' => $tabs,
132
        ]);
133
    }
134
135
    /**
136
     * @see registerSubMenus
137
     */
138
    public function renderPremiumMenuCallback(): void
139
    {
140
        $addons = [];
141
        $features = [];
142
        $isPremium = glsr(License::class)->isPremium();
143
        if ($isPremium) {
144
            $data = glsr(Api::class)->get('addons')->data();
145
            foreach ($data as $values) {
146
                $context = glsr(AddonDefaults::class)->restrict($values);
147
                $addons[] = array_merge($context, compact('context'));
148
            }
149
        } else {
150
            $data = glsr(Api::class)->get('features')->data();
151
            foreach ($data as $values) {
152
                $features[] = glsr(FeatureDefaults::class)->restrict($values);
153
            }
154
            $feature = array_column($features, 'feature');
155
            $premium = array_column($features, 'premium');
156
            array_multisort(
157
                $premium, \SORT_DESC,
0 ignored issues
show
Bug introduced by
SORT_DESC cannot be passed to array_multisort() as the parameter $rest expects a reference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

157
                $premium, /** @scrutinizer ignore-type */ \SORT_DESC,
Loading history...
158
                $feature, \SORT_ASC | \SORT_NATURAL,
0 ignored issues
show
Bug introduced by
SORT_ASC | SORT_NATURAL cannot be passed to array_multisort() as the parameter $rest expects a reference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

158
                $feature, /** @scrutinizer ignore-type */ \SORT_ASC | \SORT_NATURAL,
Loading history...
159
                $features
160
            );
161
        }
162
        $this->renderPage('premium', [
163
            'addons' => $addons,
164
            'features' => $features,
165
            'is_premium' => $isPremium,
166
        ]);
167
    }
168
169
    /**
170
     * @see registerSubMenus
171
     */
172
    public function renderSettingsMenuCallback(): void
173
    {
174
        $tabs = $this->parseWithFilter('settings/tabs', [ // order is intentional
175
            'general' => _x('General', 'admin-text', 'site-reviews'),
176
            'reviews' => _x('Reviews', 'admin-text', 'site-reviews'),
177
            'forms' => _x('Forms', 'admin-text', 'site-reviews'),
178
            'schema' => _x('Schema', 'admin-text', 'site-reviews'),
179
            'strings' => _x('Strings', 'admin-text', 'site-reviews'),
180
            'integrations' => _x('Integrations', 'admin-text', 'site-reviews'),
181
            'addons' => _x('Addons', 'admin-text', 'site-reviews'),
182
            'licenses' => _x('Licenses', 'admin-text', 'site-reviews'),
183
        ]);
184
        if (empty(Arr::get(glsr()->defaults(), 'settings.addons'))) {
185
            unset($tabs['addons']);
186
        }
187 8
        if (empty(Arr::get(glsr()->defaults(), 'settings.licenses'))) {
188
            unset($tabs['licenses']);
189 8
        }
190 8
        $this->renderPage('settings', [
191
            'fields' => glsr(SettingForm::class, ['groups' => $tabs])->build(),
192
            'tabs' => $tabs,
193
        ]);
194
    }
195
196
    /**
197
     * @see registerSubMenus
198
     */
199
    public function renderToolsMenuCallback(): void
200
    {
201
        $tabs = $this->parseWithFilter('tools/tabs', [
202
            'general' => _x('General', 'admin-text', 'site-reviews'),
203
            'scheduled' => _x('Scheduled Actions', 'admin-text', 'site-reviews'),
204
            'sync' => _x('Sync Reviews', 'admin-text', 'site-reviews'),
205
            'console' => _x('Console', 'admin-text', 'site-reviews'),
206
            'system-info' => _x('System Info', 'admin-text', 'site-reviews'),
207
        ]);
208
        if (!glsr()->filterBool('addon/sync/enable', false)) {
209
            unset($tabs['sync']);
210
        }
211
        $this->renderPage('tools', [
212
            'data' => [
213
                'console_level' => glsr(Console::class)->getLevel(),
214
                'context' => [
215
                    'base_url' => glsr_admin_url(),
216
                    'console' => glsr(Console::class)->get(),
217
                    'id' => glsr()->id,
218
                ],
219
                'myisam_tables' => Arr::get(glsr(Tables::class)->tableEngines(), 'MyISAM', []),
220
                'rollback_script' => file_get_contents(glsr()->path('assets/scripts/rollback.js')),
221
                'rollback_versions' => glsr(Cache::class)->getPluginVersions(),
222
                'services' => glsr()->filterArray('addon/sync/services', []),
223
            ],
224
            'tabs' => $tabs,
225
        ]);
226
    }
227
228
    /**
229
     * @action admin_init
230
     */
231
    public function setCustomPermissions(): void
232
    {
233
        foreach (wp_roles()->roles as $role => $value) {
234
            wp_roles()->remove_cap($role, 'create_'.glsr()->post_type);
235
        }
236
    }
237
238
    protected function getNotices(): string
239
    {
240
        return glsr(Builder::class)->div(glsr(Notice::class)->get(), [
241
            'id' => 'glsr-notices',
242
        ]);
243
    }
244
245
    protected function parseWithFilter(string $hookSuffix, array $args = []): array
246
    {
247
        if (str_ends_with($hookSuffix, '/tabs')) {
248
            $page = str_replace('/tabs', '', $hookSuffix);
249
            foreach ($args as $tab => $title) {
250
                if (!glsr()->hasPermission($page, $tab)) {
251
                    unset($args[$tab]);
252
                }
253
            }
254
        } elseif (array_key_exists('premium', $args) && glsr(License::class)->isPremium()) {
255
            $args['premium'] = _x('Premium Addons', 'admin-text', 'site-reviews');
256
        }
257
        return glsr()->filterArray("addon/{$hookSuffix}", $args);
258
    }
259
260
    protected function renderPage(string $page, array $data = []): void
261
    {
262
        $data['http_referer'] = (string) wp_get_referer();
263
        $data['notices'] = $this->getNotices();
264
        glsr()->render("pages/{$page}/index", $data);
265
    }
266
}
267