PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.14.2
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.14.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 / classes / WpMatomo / API.php
matomo / classes / WpMatomo Last commit date
Admin 3 years ago Commands 4 years ago Db 4 years ago Ecommerce 3 years ago Report 4 years ago Site 3 years ago TrackingCode 4 years ago Updater 4 years ago User 3 years ago WpStatistics 4 years ago views 4 years ago API.php 4 years ago Access.php 4 years ago AjaxTracker.php 5 years ago Annotations.php 4 years ago Bootstrap.php 4 years ago Capabilities.php 4 years ago Compatibility.php 4 years ago Email.php 4 years ago Installer.php 4 years ago Logger.php 4 years ago OptOut.php 4 years ago Paths.php 4 years ago PrivacyBadge.php 4 years ago RedirectOnActivation.php 4 years ago Referral.php 4 years ago Roles.php 4 years ago ScheduledTasks.php 4 years ago Settings.php 4 years ago Site.php 3 years ago TrackingCode.php 4 years ago Uninstaller.php 4 years ago Updater.php 4 years ago User.php 4 years ago
API.php
239 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 * @package matomo
8 */
9
10 namespace WpMatomo;
11
12 use Exception;
13 use Piwik\API\Request;
14 use Piwik\Common;
15 use WP_Error;
16 use WP_REST_Request;
17
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit; // if accessed directly
20 }
21 /**
22 * phpcs:disable WordPress.Security.NonceVerification.Missing
23 */
24 class API {
25 const VERSION = 'matomo/v1';
26
27 const ROUTE_HIT = 'hit';
28
29 public function register_hooks() {
30 add_action( 'rest_api_init', [ $this, 'register_routes' ] );
31 }
32
33 public function register_routes() {
34 register_rest_route(
35 self::VERSION,
36 '/' . self::ROUTE_HIT . '/',
37 [
38 'methods' => [ 'GET', 'POST' ],
39 'permission_callback' => '__return_true',
40 'callback' => [ $this, 'hit' ],
41 ]
42 );
43 $this->register_route( 'API', 'getProcessedReport' );
44 $this->register_route( 'API', 'getReportMetadata' );
45 $this->register_route( 'API', 'getMatomoVersion' );
46 $this->register_route( 'API', 'getMetadata' );
47 $this->register_route( 'API', 'getSegmentsMetadata' );
48 $this->register_route( 'API', 'getWidgetMetadata' );
49 $this->register_route( 'API', 'getRowEvolution' );
50 $this->register_route( 'API', 'getSuggestedValuesForSegment' );
51 $this->register_route( 'API', 'getSettings' );
52 $this->register_route( 'Annotations', 'add' );
53 $this->register_route( 'Annotations', 'getAll' );
54 $this->register_route( 'CoreAdminHome', 'invalidateArchivedReports' );
55 $this->register_route( 'CoreAdminHome', 'runScheduledTasks' );
56 $this->register_route( 'Dashboard', 'getDashboards' );
57 $this->register_route( 'ImageGraph', 'get' );
58 $this->register_route( 'VisitsSummary', 'getVisits' );
59 $this->register_route( 'VisitsSummary', 'getUniqueVisitors' );
60 $this->register_route( 'LanguagesManager', 'getAvailableLanguages' );
61 $this->register_route( 'LanguagesManager', 'getAvailableLanguagesInfo' );
62 $this->register_route( 'LanguagesManager', 'getAvailableLanguageNames' );
63 $this->register_route( 'LanguagesManager', 'getLanguageForUser' );
64 $this->register_route( 'Live', 'getCounters' );
65 $this->register_route( 'Live', 'getLastVisitsDetails' );
66 $this->register_route( 'Live', 'getVisitorProfile' );
67 $this->register_route( 'Live', 'getMostRecentVisitorId' );
68 $this->register_route( 'PrivacyManager', 'deleteDataSubjects' );
69 $this->register_route( 'PrivacyManager', 'exportDataSubjects' );
70 $this->register_route( 'PrivacyManager', 'anonymizeSomeRawData' );
71 $this->register_route( 'ScheduledReports', 'getReports' );
72 $this->register_route( 'ScheduledReports', 'sendReport' );
73 $this->register_route( 'SegmentEditor', 'add' );
74 $this->register_route( 'SegmentEditor', 'update' );
75 $this->register_route( 'SegmentEditor', 'delete' );
76 $this->register_route( 'SegmentEditor', 'get' );
77 $this->register_route( 'SegmentEditor', 'getAll' );
78 $this->register_route( 'SitesManager', 'getAllSites' );
79 $this->register_route( 'SitesManager', 'getAllSitesId' );
80 $this->register_route( 'UsersManager', 'getUsers' );
81 $this->register_route( 'UsersManager', 'getUsersLogin' );
82 $this->register_route( 'UsersManager', 'getUser' );
83 $this->register_route( 'Goals', 'getGoals' );
84
85 // todo ideally we would make here work /goal/12345 to get goalId 12345
86 $this->register_route( 'Goals', 'getGoal' );
87 $this->register_route( 'Goals', 'addGoal' );
88 $this->register_route( 'Goals', 'updateGoal' );
89 $this->register_route( 'Goals', 'deleteGoal' );
90 }
91
92 public function hit() {
93 if ( ( empty( $_GET ) || isset( $_GET['rest_route'] ) ) && empty( $_POST ) && empty( $_POST['idsite'] ) && empty( $_GET['idsite'] ) ) {
94 // todo if uploads dir is not writable, we may want to generate the matomo.js here and save it as an
95 // option... then we could also save it compressed
96 $paths = new Paths();
97 $path = $paths->get_matomo_js_upload_path();
98 $wp_filesystem = $paths->get_file_system();
99 header( 'Content-Type: application/javascript' );
100 header( 'Content-Length: ' . ( filesize( $path ) ) );
101 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
102 echo $wp_filesystem->get_contents( $paths->get_upload_base_dir() . '/matomo.js' ); // Reading the file into the output buffer
103 exit;
104 }
105 include_once plugin_dir_path( MATOMO_ANALYTICS_FILE ) . 'app/piwik.php';
106 exit;
107 }
108
109 public function execute_api_method( WP_REST_Request $request ) {
110 $attributes = $request->get_attributes();
111 $method = $attributes['matomoModule'] . '.' . $attributes['matomoMethod'];
112
113 $with_idsite = true;
114
115 return $this->execute_request( $method, $with_idsite, $request->get_params() );
116 }
117
118 /**
119 * @param string $method
120 *
121 * @return string
122 * @internal
123 * for tests only
124 */
125 public function to_snake_case( $method ) {
126 preg_match_all( '!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $method, $matches );
127
128 $snake_case = $matches[0];
129
130 foreach ( $snake_case as &$match ) {
131 if ( strtoupper( $match ) === $match ) {
132 $match = strtolower( $match );
133 } else {
134 $match = lcfirst( $match );
135 }
136 }
137
138 return implode( '_', $snake_case );
139 }
140
141 /**
142 * @api
143 */
144 public function register_route( $api_module, $api_method ) {
145 $methods = [
146 'get' => 'GET',
147 'edit' => 'PUT',
148 'update' => 'PUT',
149 'create' => 'POST',
150 'add' => 'POST',
151 'anonymize' => 'POST',
152 'invalidate' => 'POST',
153 'run' => 'POST',
154 'send' => 'POST',
155 'delete' => 'DELETE',
156 'remove' => 'DELETE',
157 ];
158 $starts_with_keep_prefix = [ 'anonymize', 'invalidate', 'run', 'send' ];
159
160 $method = 'GET';
161 $wp_api_module = $this->to_snake_case( $api_module );
162 $wp_api_action = $this->to_snake_case( $api_method );
163
164 foreach ( $methods as $method_starts_with => $method_to_use ) {
165 if ( strpos( $api_method, $method_starts_with ) === 0 ) {
166 $method = $method_to_use;
167 if ( ! in_array( $method_starts_with, $starts_with_keep_prefix, true ) ) {
168 $new_action = trim( ltrim( substr( $wp_api_action, strlen( $method_starts_with ) ), '_' ) );
169 if ( ! empty( $new_action ) ) {
170 $wp_api_action = $new_action;
171 }
172 }
173 break;
174 }
175 }
176
177 register_rest_route(
178 self::VERSION,
179 '/' . $wp_api_module . '/' . $wp_api_action . '/',
180 [
181 'methods' => $method,
182 'callback' => [ $this, 'execute_api_method' ],
183 'permission_callback' => '__return_true', // permissions are checked in the method itself
184 'matomoModule' => $api_module,
185 'matomoMethod' => $api_method,
186 ]
187 );
188 }
189
190 private function execute_request( $api_method, $with_idsite, $params ) {
191 if ( $with_idsite ) {
192 $site = new Site();
193 $idsite = $site->get_current_matomo_site_id();
194
195 if ( ! $idsite ) {
196 return new WP_Error( 'Site not found. Make sure it is synced' );
197 }
198
199 $params['idSite'] = $idsite;
200 $params['idsite'] = $idsite;
201 $params['idsites'] = $idsite;
202 $params['idSites'] = $idsite;
203 }
204
205 // ensure user is authenticated through WordPress!
206 unset( $_GET['token_auth'] );
207 unset( $_POST['token_auth'] );
208
209 Bootstrap::do_bootstrap();
210
211 // refs https://github.com/matomo-org/wp-matomo/issues/370 ensuring segment will be used from default request when
212 // creating new request object and not the encoded segment
213 if ( isset( $params['segment'] ) ) {
214 if ( isset( $_GET['segment'] ) || isset( $_POST['segment'] ) ) {
215 unset( $params['segment'] ); // matomo will read the segment from default request
216 } elseif ( ! empty( $params['segment'] ) && is_string( $params['segment'] ) ) {
217 // manually unsanitize this value
218 $params['segment'] = Common::unsanitizeInputValue( $params['segment'] );
219 }
220 }
221
222 try {
223 $result = Request::processRequest( $api_method, $params );
224 } catch ( Exception $e ) {
225 $code = 'matomo_error';
226 if ( $e->getCode() ) {
227 $code .= '_' . $code;
228 }
229 if ( get_class( $e ) !== 'Exception' ) {
230 $code = str_replace( 'piwik', 'matomo', $this->to_snake_case( get_class( $e ) ) );
231 }
232
233 return new WP_Error( $code, $e->getMessage() );
234 }
235
236 return $result;
237 }
238 }
239