PluginProbe ʕ •ᴥ•ʔ
Popup Builder & Popup Maker for WordPress – OptinMonster Email Marketing and Lead Generation / 2.16.5
Popup Builder & Popup Maker for WordPress – OptinMonster Email Marketing and Lead Generation v2.16.5
2.16.24 trunk 2.13.8 2.14.0 2.14.1 2.15.0 2.15.1 2.15.2 2.15.3 2.16.0 2.16.1 2.16.10 2.16.11 2.16.12 2.16.13 2.16.14 2.16.15 2.16.16 2.16.17 2.16.18 2.16.19 2.16.2 2.16.20 2.16.21 2.16.22 2.16.3 2.16.4 2.16.5 2.16.6 2.16.7 2.16.8 2.16.9
optinmonster / OMAPI / Api.php
optinmonster / OMAPI Last commit date
EasyDigitalDownloads 3 years ago Elementor 2 years ago Integrations 3 years ago MemberPress 2 years ago Plugins 2 years ago Promos 3 years ago Rules 2 years ago Shortcodes 2 years ago WPForms 1 year ago WooCommerce 1 year ago Actions.php 1 year ago Ajax.php 4 years ago Api.php 1 year ago ApiAuth.php 4 years ago ApiKey.php 1 year ago AssetLoader.php 5 years ago BaseRestApi.php 3 years ago Blocks.php 1 year ago ClassicEditor.php 3 years ago ConstantContact.php 1 year ago Debug.php 1 year ago EasyDigitalDownloads.php 1 year ago Elementor.php 3 years ago Inserter.php 3 years ago InstallSkin.php 5 years ago InstallSkinCompat.php 5 years ago MailPoet.php 1 year ago MemberPress.php 2 years ago Menu.php 1 year ago Notifications.php 1 year ago OmuApi.php 4 years ago Output.php 1 year ago Pages.php 1 year ago Partners.php 1 year ago Plugins.php 2 years ago Promos.php 3 years ago Refresh.php 1 year ago RestApi.php 1 year ago RevenueAttribution.php 4 years ago Review.php 4 years ago Rules.php 1 year ago Save.php 2 years ago Shortcode.php 4 years ago Sites.php 1 year ago Support.php 1 year ago Type.php 3 years ago Urls.php 1 year ago Utils.php 1 year ago Validate.php 2 years ago WPForms.php 2 years ago Welcome.php 4 years ago Widget.php 4 years ago WooCommerce.php 1 year ago Wordfence.php 3 years ago WpErrorException.php 5 years ago
Api.php
560 lines
1 <?php
2 /**
3 * Api class.
4 *
5 * @since 1.0.0
6 *
7 * @package OMAPI
8 * @author Thomas Griffin
9 */
10
11 // Exit if accessed directly.
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit;
14 }
15
16 /**
17 * Api class.
18 *
19 * @since 1.0.0
20 */
21 class OMAPI_Api {
22
23 /**
24 * Holds the last instantiated instance of this class.
25 *
26 * @var OMAPI_Api
27 */
28 protected static $instance = null;
29
30 /**
31 * Base API route.
32 *
33 * @since 1.0.0
34 *
35 * @var string
36 */
37 public $base = OPTINMONSTER_APP_URL;
38
39 /**
40 * Current API route.
41 *
42 * @since 1.0.0
43 *
44 * @var bool|string
45 */
46 public $route = false;
47
48 /**
49 * Full API URL endpoint.
50 *
51 * @since 1.0.0
52 *
53 * @var bool|string
54 */
55 public $url = false;
56
57 /**
58 * Current API method.
59 *
60 * @since 1.0.0
61 *
62 * @var bool|string
63 */
64 public $method = false;
65
66 /**
67 * API Username.
68 *
69 * @since 1.0.0
70 *
71 * @var bool|string
72 */
73 public $user = false;
74
75 /**
76 * API Key.
77 *
78 * @since 1.0.0
79 *
80 * @var bool|string
81 */
82 public $key = false;
83
84 /**
85 * New API Key.
86 *
87 * @since 1.3.4
88 *
89 * @var bool|string
90 */
91 public $apikey = false;
92
93 /**
94 * Plugin slug.
95 *
96 * @since 1.0.0
97 *
98 * @var bool|string
99 */
100 public $plugin = false;
101
102 /**
103 * The Api Version (v1 or v2) for this request.
104 *
105 * @since 1.8.0
106 *
107 * @var string
108 */
109 public $version = 'v1';
110
111 /**
112 * Additional data to add to request body
113 *
114 * @since 1.0.0
115 *
116 * @var array
117 */
118 protected $additional_data = array();
119
120 /**
121 * The HTTP response array.
122 *
123 * @since 1.6.5
124 *
125 * @var null|array
126 */
127 public $response = null;
128
129 /**
130 * The HTTP response code.
131 *
132 * @since 1.6.5
133 *
134 * @var int
135 */
136 public $response_code = 0;
137
138 /**
139 * The parsed HTTP response body.
140 *
141 * @since 1.6.5
142 *
143 * @var mixed
144 */
145 public $response_body = null;
146
147 /**
148 * JSON decode error from decoding the response, if found.
149 *
150 * @since 2.6.6
151 *
152 * @var mixed
153 */
154 public $decode_error = null;
155
156 /**
157 * Builds the API Object
158 *
159 * @since 1.8.0
160 *
161 * @param string $version The Api Version (v1 or v2).
162 * @param string $route The Api Endpoint/route.
163 * @param string $method The Request method.
164 * @param array $creds Array of API credentials.
165 *
166 * @return self
167 */
168 public static function build( $version, $route, $method = 'POST', $creds = array() ) {
169 if ( empty( $creds ) ) {
170 $creds = OMAPI::get_instance()->get_api_credentials();
171
172 if ( ! empty( $creds ) ) {
173
174 // Check if we have the new API and if so only use it.
175 $creds = ! empty( $creds['apikey'] )
176 ? array( 'apikey' => $creds['apikey'] )
177 : array(
178 'user' => ! empty( $creds['user'] ) ? $creds['user'] : '',
179 'key' => ! empty( $creds['key'] ) ? $creds['key'] : '',
180 );
181 }
182 }
183
184 return new self( $route, $creds, $method, $version );
185 }
186
187 /**
188 * Primary class constructor.
189 *
190 * @since 1.0.0
191 *
192 * @param string $route The API route to target.
193 * @param array $creds Array of API credentials.
194 * @param string $method The API method.
195 * @param string $version The version number of our API.
196 */
197 public function __construct( $route, $creds, $method = 'POST', $version = 'v1' ) {
198 // Set class properties.
199 $this->route = $route;
200 $this->version = $version;
201 $this->method = $method;
202 $this->user = ! empty( $creds['user'] ) ? $creds['user'] : '';
203 $this->key = ! empty( $creds['key'] ) ? $creds['key'] : '';
204 $this->apikey = ! empty( $creds['apikey'] ) ? $creds['apikey'] : '';
205 $this->plugin = OMAPI::get_instance()->plugin_slug;
206
207 self::$instance = $this;
208 }
209
210 /**
211 * Processes the API request.
212 *
213 * @since 1.0.0
214 *
215 * @param array $args Request args.
216 *
217 * @return mixed $value The response to the API call.
218 */
219 public function request( $args = array() ) {
220 // Build the body of the request.
221 $body = array(
222 'omapi-user' => $this->user,
223 'omapi-key' => $this->key,
224 );
225 $body = array_filter( $body );
226
227 // If a plugin API request, add the data.
228 if ( 'info' === $this->route || 'update' === $this->route ) {
229 $body['omapi-plugin'] = $this->plugin;
230 }
231
232 // Add in additional data if needed.
233 if ( ! empty( $this->additional_data ) ) {
234 $body['omapi-data'] = maybe_serialize( $this->additional_data );
235 }
236
237 $body = wp_parse_args( $args, $body );
238 $url = in_array( $this->method, array( 'GET', 'DELETE' ), true )
239 ? add_query_arg( array_map( 'urlencode', $body ), $this->get_url() )
240 : $this->get_url();
241
242 $url = esc_url_raw( $url );
243 $plugins = new OMAPI_Plugins();
244
245 // Build the headers of the request.
246 $headers = array(
247 'Content-Type' => 'application/x-www-form-urlencoded',
248 'Cache-Control' => 'no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0',
249 'Pragma' => 'no-cache',
250 'Expires' => 0,
251 'Origin' => site_url(),
252 'OMAPI-Referer' => site_url(),
253 'OMAPI-Sender' => 'WordPress',
254 'OMAPI-Site' => esc_attr( get_option( 'blogname' ) ),
255 'OMAPI-Version' => esc_attr( OMAPI::get_instance()->version ),
256 'OMAPI-Plugins' => $plugins->get_active_plugins_header_value(),
257 );
258
259 if ( $this->apikey ) {
260 $headers['X-OptinMonster-ApiKey'] = $this->apikey;
261 }
262 // Setup data to be sent to the API.
263 $data = array(
264 'headers' => $headers,
265 'body' => $body,
266 'timeout' => 3000,
267 'sslverify' => false,
268 'method' => $this->method,
269 );
270
271 // Perform the query and retrieve the response.
272 $this->handle_response( wp_remote_request( $url, $data ) );
273
274 // Bail out early if there are any errors.
275 if ( is_wp_error( $this->response ) ) {
276 return $this->response;
277 }
278
279 // If we used the legacy api-creds, we'll get back a new api key.
280 if (
281 empty( $this->apikey )
282 && ! empty( $this->response['headers']['x-optinmonster-apikey'] )
283 ) {
284 $this->apikey = sanitize_text_field( $this->response['headers']['x-optinmonster-apikey'] );
285 }
286
287 $error = $this->check_response_error();
288
289 // Bail out early if there are any errors.
290 if ( is_wp_error( $error ) ) {
291 return $error;
292 }
293
294 // Return the json decoded content.
295 return $this->response_body;
296 }
297
298 /**
299 * Handle setting up the object properties from the response.
300 *
301 * @since 2.6.6
302 *
303 * @param object $response The response object from wp_remote_request.
304 *
305 * @return void
306 */
307 public function handle_response( $response ) {
308 $this->response = $response;
309
310 // Get the response code and response body.
311 $this->response_code = wp_remote_retrieve_response_code( $response );
312 $this->response_body = json_decode( wp_remote_retrieve_body( $response ) );
313 $this->decode_error = json_last_error();
314 }
315
316 /**
317 * Check for an error response, and return an applicable WP_Error instance.
318 *
319 * @since 2.6.6
320 *
321 * @return boolean|WP_Error False if no errors, and WP_Error object if found.
322 */
323 public function check_response_error() {
324 $code = (int) $this->response_code;
325
326 if ( $code < 400 ) {
327 return false;
328 }
329
330 // If not successful status header, send back error.
331 $type = ! empty( $this->response_body->type ) ? $this->response_body->type : 'api-error';
332 $message = ! empty( $this->response_body->message ) ? stripslashes( $this->response_body->message ) : '';
333 if ( empty( $message ) ) {
334 $message = ! empty( $this->response_body->status_message ) ? stripslashes( $this->response_body->status_message ) : '';
335 }
336
337 if ( empty( $message ) ) {
338 $message = ! empty( $this->response_body->error ) ? stripslashes( $this->response_body->error ) : 'unknown';
339 }
340
341 $message = sprintf(
342 /* translators: %1$s - API response code, %2$s - returned error from API. */
343 __( 'The API returned a <strong>%1$s</strong> response with this message: <strong>%2$s</strong>', 'optin-monster-api' ),
344 $this->response_code,
345 $message
346 );
347
348 return new WP_Error( $type, $message, $this->response_code );
349 }
350
351 /**
352 * The gets the URL based on our base, endpoint and version
353 *
354 * @since 1.8.0
355 *
356 * @return string The API url.
357 */
358 public function get_url() {
359 return $this->base . '/' . $this->version . '/' . $this->route;
360 }
361
362 /**
363 * Sets a class property.
364 *
365 * @since 1.0.0
366 *
367 * @param string $key The property to set.
368 * @param string $val The value to set for the property.
369 * @return mixed $value The response to the API call.
370 */
371 public function set( $key, $val ) {
372 $this->{$key} = $val;
373 }
374
375 /**
376 * Allow additional data to be passed in the request
377 *
378 * @since 1.0.0
379 *
380 * @param array $data The data to set.
381 *
382 * @return void
383 */
384 public function set_additional_data( array $data ) {
385 $this->additional_data = array_merge( $this->additional_data, $data );
386 }
387
388 /**
389 * Clear additional data
390 *
391 * @since 1.9.0
392 *
393 * return void
394 */
395 public function clear_additional_data() {
396 $this->additional_data = null;
397
398 return $this;
399 }
400
401 /**
402 * Get the request credentials for this API object.
403 *
404 * @since 2.3.0
405 *
406 * @return array Array containing API credentials.
407 */
408 public function get_creds() {
409 return ! empty( $this->apikey )
410 ? array( 'apikey' => $this->apikey )
411 : array(
412 'user' => $this->user,
413 'key' => $this->key,
414 );
415 }
416
417 /**
418 * Returns the last instantiated instance of this class.
419 *
420 * @since 1.9.10
421 *
422 * @return A single instance of this class.
423 */
424 public static function instance() {
425 return self::$instance;
426 }
427
428 /**
429 * Fetch from the OM /me route, and cache results if no error..
430 *
431 * @since 2.6.6
432 *
433 * @param bool $refresh Whether to refresh the cache.
434 * @param array $creds Existing credentials array.
435 *
436 * @return array Requested /me data.
437 */
438 public static function fetch_me_cached( $refresh = false, $creds = array() ) {
439 $api = self::build( 'v2', 'me?includeOnboarding=true', 'GET', $creds );
440
441 $creds = array( $api->user, $api->key, $api->apikey );
442 $creds = array_filter( $creds );
443 $creds = array_values( $creds );
444 $cache_key = 'omapp_me_cached' . md5( implode( ':', $creds ) );
445 $result = get_transient( $cache_key );
446
447 if ( empty( $result ) || $refresh ) {
448 $result = $api->request();
449
450 if ( ! is_wp_error( $result ) ) {
451 set_transient( $cache_key, $result, DAY_IN_SECONDS );
452
453 // Force the option to be updated when we gather new data from the API.
454 self::return_option_from_fetch( $result, array(), $creds, true );
455 }
456 }
457
458 return $result;
459 }
460
461 /**
462 * Fetch from the OM /me route, and store data to our options.
463 *
464 * @since 2.0.0
465 *
466 * @param array $option Existing options array.
467 * @param array $creds Existing credentials array.
468 *
469 * @return array Updated options array.
470 */
471 public static function fetch_me( $option = array(), $creds = array() ) {
472 $result = self::fetch_me_cached( true, $creds );
473 if ( is_wp_error( $result ) ) {
474 return $result;
475 }
476
477 return self::return_option_from_fetch( $result, $option, $creds, empty( $option ) );
478 }
479
480 /**
481 * Return the option after fetching data from the /me route, potentially
482 * updating it in the database as well.
483 *
484 * @since 2.6.13
485 *
486 * @param stdClass $result The /me route result.
487 * @param array $option Possible option to be passed.
488 * @param array $creds Possible creds to be passed.
489 * @param bool $should_update Flag to update the option in the database or not.
490 *
491 * @return array Updated options array.
492 */
493 public static function return_option_from_fetch( $result, $option = array(), $creds = array(), $should_update = false ) {
494 $api = self::instance();
495 if ( $should_update ) {
496 $option = OMAPI::get_instance()->get_option();
497 }
498
499 // Make sure to set the new api key, if we have it.
500 if ( empty( $option['api']['apikey'] ) && ! empty( $api->apikey ) ) {
501 $option['api'] = array( 'apikey' => $api->apikey );
502
503 if ( $api->user && $api->key ) {
504 // Notify user of credentials replacement.
505 OMAPI::get_instance()->notifications->add_event(
506 array(
507 'type' => 'success',
508 'title' => 'Your API Access Credentials have been updated',
509 'content' => 'We have automatically replaced your deprecated user/key OptinMonster connection credentials with a new API key.',
510 'btns' => array(
511 'main' => array(
512 'text' => 'Manage API Keys',
513 'url' => esc_url_raw( OPTINMONSTER_APP_URL . '/account/api/' ),
514 ),
515 ),
516 )
517 );
518 }
519 }
520
521 if ( isset( $result->id ) ) {
522 /*
523 * The user id connecting the plugin. It could be the owner or any sub-account.
524 * This key should not be used to embed codes or other API usage.
525 * In those cases, the owner's id (accountUserId) would be the one to use.
526 */
527 $option['userId'] = $result->id;
528 }
529
530 $to_store = array( 'accountId', 'accountUserId', 'currentLevel', 'plan', 'revenueAttribution' );
531 foreach ( $to_store as $key ) {
532 if ( isset( $result->{$key} ) ) {
533 $option[ $key ] = is_object( $result->{$key} ) ? (array) $result->{$key} : $result->{$key};
534 }
535 }
536
537 if ( $should_update ) {
538 OMAPI::get_instance()->save->update_option( $option, $creds );
539 }
540
541 return $option;
542 }
543
544 /**
545 * Get the home/rest/admin url args.
546 *
547 * @since 2.13.0
548 *
549 * @return array
550 */
551 public static function get_url_args() {
552 return array(
553 'homeUrl' => esc_url_raw( home_url() ),
554 'restUrl' => esc_url_raw( get_rest_url() ),
555 'adminUrl' => esc_url_raw( get_admin_url() ),
556 );
557 }
558
559 }
560