PluginProbe
Metricool – Social media and site statistics / 2.1.1
Metricool – Social media and site statistics v2.1.1
2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.27 trunk
← All changes | app/Features/AbstractLoader.php +90 -0 2.0.1 → 2.1.1 View file →
@@ -1,0 +1,90 @@
1 +<?php
2 +
3 +declare(strict_types=1);
4 +
5 +namespace Metricool\Features;
6 +
7 +use Metricool\Support\Helpers\Storages\RequestStorage;
8 +use Metricool\Support\Helpers\Storages\EnvironmentConfig;
9 +
10 +/**
11 + * Each Feature should have a {FeatureName}Loader class that extends this
12 + * abstract loader. The {@see FeatureManager} will use the loader to determine
13 + * if a feature should be loaded.
14 + *
15 + * @internal Without loading all the feature classes, composer will prevent
16 + * requiring the files entirely. Even tho the Feature namespace falls
17 + * withing the psr-4 scope.
18 + */
19 +abstract class AbstractLoader
20 +{
21 + protected EnvironmentConfig $env;
22 + protected RequestStorage $request;
23 +
24 + public function __construct(EnvironmentConfig $env, RequestStorage $request)
25 + {
26 + $this->env = $env;
27 + $this->request = $request;
28 + }
29 +
30 + /**
31 + * Method should return true if the feature is enabled. This can check
32 + * setting values or user capabilities for example.
33 + */
34 + abstract public function isEnabled(): bool;
35 +
36 + /**
37 + * Method should return true if the context of the user is in the scope of
38 + * the feature to be loaded. For example: some features only need to load
39 + * on our dashboard and others also in each REST API request.
40 + */
41 + abstract public function inScope(): bool;
42 +
43 + /**
44 + * Check if the current user is on the Dashboard page.
45 + * @todo Responsibility for retrieving the dashboard "page" value should
46 + * be added somewhere and it should be globally accessible.
47 + */
48 + protected function userIsOnDashboard(): bool
49 + {
50 + $pageVisitedByUser = $this->request->getString('global.page');
51 + $dashboardUrl = $this->env->getString('plugin.dashboard_url');
52 +
53 + $pluginPageQueryString = wp_parse_url($dashboardUrl, PHP_URL_QUERY);
54 + parse_str($pluginPageQueryString, $parsedQuery);
55 + $pluginDashboardPage = ($parsedQuery['page'] ?? '');
56 +
57 + return $pageVisitedByUser === $pluginDashboardPage;
58 + }
59 +
60 + /**
61 + * Check if the current request is a WP JSON request. This is better than
62 + * the WordPress native function `wp_is_json_request()`, because that
63 + * returns false when visiting /wp-json/ or ?rest_route= (for plain
64 + * permalinks) endpoint. We need a true value there to activate
65 + * features that register REST routes. For example
66 + * {@see \Metricool\Features\Onboarding\OnboardingController}
67 + *
68 + * @internal Ignore the phpcs errors for this method, as they are false
69 + * positives. We do not actually use the $_GET or $_SERVER variables
70 + * directly, but we need to check if they are set and contain the
71 + * expected values.
72 + */
73 + protected function requestIsRestRequest(): bool
74 + {
75 + $pluginHttpNamespace = $this->env->getString('http.namespace');
76 + $restUrlPrefix = trailingslashit(rest_get_url_prefix());
77 +
78 + $currentRequestUri = isset($_SERVER['REQUEST_URI'])
79 + ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI']))
80 + : '';
81 + $isPlainPermalink = (
82 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is a REST route detection check, not form processing.
83 + isset($_GET['rest_route'])
84 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is a REST route detection check, not form processing.
85 + && (strpos(sanitize_text_field(wp_unslash($_GET['rest_route'])), $pluginHttpNamespace) !== false)
86 + );
87 +
88 + return (strpos($currentRequestUri, $restUrlPrefix) !== false) || $isPlainPermalink;
89 + }
90 +}