PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 2.5.1
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v2.5.1
3.4.1 3.4.0 3.3.9 3.3.8 3.3.7 3.3.6 3.3.5 3.3.4 3.3.3 3.3.2 3.3.1 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 2.3.0 2.3.1 2.3.2 2.3.3 All 194 releases
← All changes | includes/class-convertkit-output-restrict-content.php +193 -919 3.3.82.5.1 View file →
@@ -105,13 +105,22 @@
105 105 * @since 2.1.0
106 106 */
107 107 public function __construct() {
108 108
109 - add_action( 'rest_api_init', array( $this, 'register_routes' ) );
110 - add_action( 'init', array( $this, 'initialize_classes' ), 2 );
111 - add_action( 'init', array( $this, 'maybe_run_subscriber_authentication' ), 3 );
112 - add_action( 'wp', array( $this, 'maybe_run_subscriber_verification' ), 4 );
113 - add_action( 'wp', array( $this, 'register_content_filter' ), 5 );
109 + // Initialize classes that will be used.
110 + $this->settings = new ConvertKit_Settings();
111 + $this->restrict_content_settings = new ConvertKit_Settings_Restrict_Content();
112 +
113 + // Don't register any hooks if this is an AJAX request, otherwise
114 + // maybe_run_subscriber_authentication() and maybe_run_subscriber_verification() will run
115 + // twice in an AJAX request (once here, and once when called by the ConvertKit_AJAX class).
116 + if ( wp_doing_ajax() ) {
117 + return;
118 + }
119 +
120 + add_action( 'init', array( $this, 'maybe_run_subscriber_authentication' ), 1 );
121 + add_action( 'init', array( $this, 'maybe_run_subscriber_verification' ), 2 );
122 + add_filter( 'the_content', array( $this, 'maybe_restrict_content' ) );
114 123 add_filter( 'get_previous_post_where', array( $this, 'maybe_change_previous_post_where_clause' ), 10, 5 );
115 124 add_filter( 'get_next_post_where', array( $this, 'maybe_change_next_post_where_clause' ), 10, 5 );
116 125 add_filter( 'get_previous_post_sort', array( $this, 'maybe_change_previous_next_post_order_by_clause' ), 10, 3 );
117 126 add_filter( 'get_next_post_sort', array( $this, 'maybe_change_previous_next_post_order_by_clause' ), 10, 3 );
@@ -118,255 +127,29 @@
118 127
119 128 }
120 129
121 130 /**
122 - * Register REST API routes.
123 - *
124 - * @since 3.1.0
125 - */
126 - public function register_routes() {
127 -
128 - // Register route to run subscriber authentication.
129 - register_rest_route(
130 - 'kit/v1',
131 - '/restrict-content/subscriber-authentication',
132 - array(
133 - 'methods' => WP_REST_Server::CREATABLE,
134 - 'args' => array(
135 - // Email: Validate email is included in the request, is a valid email address
136 - // and sanitize the email address.
137 - 'convertkit_email' => array(
138 - 'required' => true,
139 - 'validate_callback' => function ( $param ) {
140 -
141 - return is_string( $param ) && is_email( $param );
142 -
143 - },
144 - 'sanitize_callback' => 'sanitize_email',
145 - ),
146 -
147 - // Post ID: Validate post ID is included in the request and is an integer.
148 - 'convertkit_post_id' => array(
149 - 'required' => true,
150 - 'validate_callback' => function ( $param ) {
151 -
152 - return is_numeric( $param );
153 -
154 - },
155 - 'sanitize_callback' => 'absint',
156 - ),
157 -
158 - // Resource Type: Validate resource type is included in the request and is a string.
159 - 'convertkit_resource_type' => array(
160 - 'required' => true,
161 - 'validate_callback' => function ( $param ) {
162 -
163 - return is_string( $param );
164 -
165 - },
166 - 'sanitize_callback' => 'sanitize_text_field',
167 - ),
168 -
169 - // Resource ID: Validate resource ID is included in the request and is an integer.
170 - 'convertkit_resource_id' => array(
171 - 'required' => true,
172 - 'validate_callback' => function ( $param ) {
173 -
174 - return is_numeric( $param );
175 -
176 - },
177 - 'sanitize_callback' => 'absint',
178 - ),
179 - ),
180 - 'callback' => function ( $request ) {
181 -
182 - // Initialize classes that will be used.
183 - $output_restrict_content = WP_ConvertKit()->get_class( 'output_restrict_content' );
184 - $output_restrict_content->initialize_classes();
185 -
186 - // Fetch Post ID, Resource Type and Resource ID for the view.
187 - $email = $request->get_param( 'convertkit_email' );
188 - $post_id = $request->get_param( 'convertkit_post_id' );
189 - $resource_type = $request->get_param( 'convertkit_resource_type' );
190 - $resource_id = $request->get_param( 'convertkit_resource_id' );
191 -
192 - // Run subscriber authentication.
193 - $result = $output_restrict_content->subscriber_authentication_send_code(
194 - $email,
195 - $post_id
196 - );
197 -
198 - // If an error occurred, build the email form view with the error message.
199 - if ( is_wp_error( $result ) ) {
200 - // Set error to display on screen.
201 - $output_restrict_content->error = $result;
202 -
203 - // Build email form view to return for output with error message.
204 - ob_start();
205 - include CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/login-modal-content-email.php';
206 - $output = trim( ob_get_clean() );
207 - return rest_ensure_response(
208 - array(
209 - 'success' => false,
210 - 'data' => $output,
211 - )
212 - );
213 - }
214 -
215 - // Set token and Post ID for authentication code view.
216 - $output_restrict_content->token = $result;
217 - $output_restrict_content->post_id = $post_id;
218 -
219 - // Build authentication code view to return for output.
220 - ob_start();
221 - include CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/login-modal-content-code.php';
222 - $output = trim( ob_get_clean() );
223 - return rest_ensure_response(
224 - array(
225 - 'success' => true,
226 - 'data' => $output,
227 - )
228 - );
229 - },
230 -
231 - // No authentication required, as this is on the frontend site.
232 - 'permission_callback' => '__return_true',
233 - )
234 - );
235 -
236 - // Register route to run subscriber verification.
237 - register_rest_route(
238 - 'kit/v1',
239 - '/restrict-content/subscriber-verification',
240 - array(
241 - 'methods' => WP_REST_Server::CREATABLE,
242 - 'args' => array(
243 - // Post ID: Validate post ID is an integer if included in the request.
244 - 'convertkit_post_id' => array(
245 - 'required' => false,
246 - 'validate_callback' => function ( $param ) {
247 -
248 - return is_numeric( $param );
249 -
250 - },
251 - 'sanitize_callback' => 'absint',
252 - ),
253 -
254 - // Token: Validate token is included in the request and is a string.
255 - 'token' => array(
256 - 'required' => true,
257 - 'validate_callback' => function ( $param ) {
258 -
259 - return is_string( $param );
260 -
261 - },
262 - 'sanitize_callback' => 'sanitize_text_field',
263 - ),
264 -
265 - // Subscriber Code: Validate subscriber code is included in the request and is a string.
266 - 'subscriber_code' => array(
267 - 'required' => true,
268 - 'validate_callback' => function ( $param ) {
269 -
270 - return is_string( $param );
271 -
272 - },
273 - 'sanitize_callback' => 'sanitize_text_field',
274 - ),
275 - ),
276 - 'callback' => function ( $request ) {
277 -
278 - // Initialize classes that will be used.
279 - $output_restrict_content = WP_ConvertKit()->get_class( 'output_restrict_content' );
280 - $output_restrict_content->initialize_classes();
281 -
282 - // Fetch Post ID, Resource Type and Resource ID for the view.
283 - $post_id = $request->get_param( 'convertkit_post_id' );
284 - $token = $request->get_param( 'token' );
285 - $subscriber_code = $request->get_param( 'subscriber_code' );
286 -
287 - // Run subscriber authentication.
288 - $result = $output_restrict_content->subscriber_authentication_verify( $post_id, $token, $subscriber_code );
289 -
290 - // If an error occurred, build the code form view with the error message.
291 - if ( is_wp_error( $result ) ) {
292 - // Set error to display on screen.
293 - $output_restrict_content->error = $result;
294 -
295 - // Set token and post ID for authentication code view.
296 - $output_restrict_content->token = $token;
297 - $output_restrict_content->post_id = $post_id;
298 -
299 - // Build code form view to return for output with error message.
300 - ob_start();
301 - include CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/login-modal-content-code.php';
302 - $output = trim( ob_get_clean() );
303 - return rest_ensure_response(
304 - array(
305 - 'success' => false,
306 - 'data' => $output,
307 - )
308 - );
309 - }
310 -
311 - // Return success with the URL to the Post, including the `ck-cache-bust` parameter.
312 - return rest_ensure_response(
313 - array(
314 - 'success' => true,
315 - 'url' => $output_restrict_content->get_url( $post_id, true ),
316 - )
317 - );
318 - },
319 -
320 - // No authentication required, as this is on the frontend site.
321 - 'permission_callback' => '__return_true',
322 - )
323 - );
324 - }
325 -
326 - /**
327 - * Initialize classes that will be used.
328 - *
329 - * @since 3.1.0
330 - */
331 - public function initialize_classes() {
332 -
333 - $this->settings = new ConvertKit_Settings();
334 - $this->restrict_content_settings = new ConvertKit_Settings_Restrict_Content();
335 - $this->api = new ConvertKit_API_V4(
336 - CONVERTKIT_OAUTH_CLIENT_ID,
337 - CONVERTKIT_OAUTH_CLIENT_REDIRECT_URI,
338 - $this->settings->get_access_token(),
339 - $this->settings->get_refresh_token(),
340 - $this->settings->debug_enabled(),
341 - 'restrict_content'
342 - );
343 -
344 - }
345 -
346 - /**
347 - * If the user isn't using JavaScript, or the Plugin's Disable JS is enabled, checks if the request is a Restrict Content request with an email address.
131 + * Checks if the request is a Restrict Content request with an email address.
348 132 * If so, calls the API depending on the Restrict Content resource that's required:
349 - * - tag: subscribes the email address to the tag, and calls the API to send the subscriber a magic link by email containing a code.
350 - * - form + product: calls the API to send the subscriber a magic link by email containing a code.
133 + * - tag: subscribes the email address to the tag, storing the subscriber ID in a cookie and redirecting
134 + * - product: calls the API to send the subscriber a magic link by email containing a code. See maybe_run_subscriber_verification()
135 + * for logic once they click the link in the email or enter the code on screen.
351 136 *
352 - * See maybe_run_subscriber_verification() for logic once they click the link in the email or enter the code on screen.
353 - *
354 137 * @since 2.1.0
355 138 */
356 139 public function maybe_run_subscriber_authentication() {
357 140
358 - // Bail if no nonce was specified via form submission.
141 + // Bail if no nonce was specified.
359 142 if ( ! array_key_exists( '_wpnonce', $_REQUEST ) ) {
360 143 return;
361 144 }
362 145
363 - // Bail if the request is a form submission and the nonce failed validation.
146 + // Bail if the nonce failed validation.
364 147 if ( ! wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'convertkit_restrict_content_login' ) ) {
365 148 return;
366 149 }
367 150
368 - // Bail if the expected email, resource type, resource ID or Post ID are missing from the request.
151 + // Bail if the expected email, resource ID or Post ID are missing.
369 152 if ( ! array_key_exists( 'convertkit_email', $_REQUEST ) ) {
370 153 return;
371 154 }
372 155 if ( ! array_key_exists( 'convertkit_resource_type', $_REQUEST ) ) {
@@ -383,55 +166,80 @@
383 166 if ( ! $this->settings->has_access_and_refresh_token() ) {
384 167 return;
385 168 }
386 169
170 + // Initialize the API.
171 + $this->api = new ConvertKit_API_V4(
172 + CONVERTKIT_OAUTH_CLIENT_ID,
173 + CONVERTKIT_OAUTH_CLIENT_REDIRECT_URI,
174 + $this->settings->get_access_token(),
175 + $this->settings->get_refresh_token(),
176 + $this->settings->debug_enabled(),
177 + 'restrict_content'
178 + );
179 +
387 180 // Sanitize inputs.
388 - $email = sanitize_text_field( wp_unslash( $_REQUEST['convertkit_email'] ) );
389 - $this->resource_type = sanitize_text_field( wp_unslash( $_REQUEST['convertkit_resource_type'] ) );
390 - $this->resource_id = absint( $_REQUEST['convertkit_resource_id'] );
391 - $this->post_id = absint( $_REQUEST['convertkit_post_id'] );
181 + $email = sanitize_text_field( $_REQUEST['convertkit_email'] );
182 + $this->resource_type = sanitize_text_field( $_REQUEST['convertkit_resource_type'] );
183 + $this->resource_id = absint( sanitize_text_field( $_REQUEST['convertkit_resource_id'] ) );
184 + $this->post_id = absint( sanitize_text_field( $_REQUEST['convertkit_post_id'] ) );
392 185
393 - // If Restrict Content is by tag, tag the subscriber.
394 - if ( $this->resource_type === 'tag' ) {
395 - // Check spam protection (reCAPTCHA or Cloudflare Turnstile, depending on Plugin settings).
396 - $spam_protection = new ConvertKit_Spam_Protection();
397 - $spam_check = $spam_protection->verify( 'convertkit_restrict_content_tag' );
186 + // Run subscriber authentication / subscription depending on the resource type.
187 + switch ( $this->resource_type ) {
188 + case 'product':
189 + // Send email to subscriber with a link to authenticate they have access to the email address submitted.
190 + $result = $this->api->subscriber_authentication_send_code(
191 + $email,
192 + $this->get_url()
193 + );
398 194
399 - // Bail if spam protection failed.
400 - if ( is_wp_error( $spam_check ) ) {
401 - $this->error = $spam_check;
402 - return;
403 - }
195 + // Bail if an error occured.
196 + if ( is_wp_error( $result ) ) {
197 + $this->error = $result;
198 + return;
199 + }
404 200
405 - // Tag subscriber.
406 - $result = $this->api->tag_subscribe( $this->resource_id, $email );
201 + // Clear any existing subscriber ID cookie, as the authentication flow has started by sending the email.
202 + $subscriber = new ConvertKit_Subscriber();
203 + $subscriber->forget();
407 204
408 - // Bail if an error occurred.
409 - if ( is_wp_error( $result ) ) {
410 - $this->error = $result;
411 - return;
412 - }
413 - }
205 + // Store the token so it's included in the subscriber code form.
206 + $this->token = $result;
207 + break;
414 208
415 - // Run subscriber authentication.
416 - $result = $this->subscriber_authentication_send_code( $email, $this->post_id );
209 + case 'tag':
210 + // Tag the subscriber.
211 + $result = $this->api->tag_subscribe( $this->resource_id, $email );
417 212
418 - // Bail if an error occurred.
419 - if ( is_wp_error( $result ) ) {
420 - $this->error = $result;
421 - return;
213 + // Bail if an error occured.
214 + if ( is_wp_error( $result ) ) {
215 + $this->error = $result;
216 + return;
217 + }
218 +
219 + // Clear any existing subscriber ID cookie, as the authentication flow has started by sending the email.
220 + $subscriber = new ConvertKit_Subscriber();
221 + $subscriber->forget();
222 +
223 + // Fetch the subscriber ID from the result.
224 + $subscriber_id = $result['subscriber']['id'];
225 +
226 + // Store subscriber ID in cookie.
227 + $this->store_subscriber_id_in_cookie( $subscriber_id );
228 +
229 + // If this isn't an AJAX request, redirect now to reload the Post.
230 + if ( ! wp_doing_ajax() ) {
231 + $this->redirect();
232 + }
233 + break;
234 +
422 235 }
423 236
424 - // Store the token so it's included in the subscriber code form.
425 - $this->token = $result;
426 -
427 237 }
428 238
429 239 /**
430 - * If the user isn't using JavaScript, or the Plugin's Disable JS is enabled, checks if the request contains a token and subscriber_code,
431 - * which happens when the subscriber either:
432 - * - clicked the link in the email sent by run_subscriber_authentication(), or
433 - * - entered the code from the email on the screen
240 + * Checks if the request contains a token and subscriber_code i.e. the subscriber clicked
241 + * the link in the email sent by the maybe_run_subscriber_authentication() function above.
434 242 *
435 243 * This calls the API to verify the token and subscriber code, which tells us that the email
436 244 * address supplied truly belongs to the user, and that we can safely trust their subscriber ID
437 245 * to be valid.
@@ -439,8 +247,18 @@
439 247 * @since 2.1.0
440 248 */
441 249 public function maybe_run_subscriber_verification() {
442 250
251 + // Bail if no nonce was specified.
252 + if ( ! array_key_exists( '_wpnonce', $_REQUEST ) ) {
253 + return;
254 + }
255 +
256 + // Bail if the nonce failed validation.
257 + if ( ! wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'convertkit_restrict_content_subscriber_code' ) ) {
258 + return;
259 + }
260 +
443 261 // Bail if the expected token and subscriber code is missing.
444 262 if ( ! array_key_exists( 'token', $_REQUEST ) ) {
445 263 return;
446 264 }
@@ -447,16 +265,8 @@
447 265 if ( ! array_key_exists( 'subscriber_code', $_REQUEST ) ) {
448 266 return;
449 267 }
450 268
451 - // If a nonce was specified, validate it now.
452 - // It won't be provided if clicking the link in the magic link email.
453 - if ( array_key_exists( '_wpnonce', $_REQUEST ) && ! is_null( $_REQUEST['_wpnonce'] ) ) {
454 - if ( ! wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'convertkit_restrict_content_subscriber_code' ) ) {
455 - return;
456 - }
457 - }
458 -
459 269 // If the Plugin Access Token has not been configured, we can't get this subscriber's ID by email.
460 270 if ( ! $this->settings->has_access_and_refresh_token() ) {
461 271 return;
462 272 }
@@ -461,119 +271,44 @@
461 271 return;
462 272 }
463 273
464 274 // Store the token so it's included in the subscriber code form if verification fails.
465 - $this->token = sanitize_text_field( wp_unslash( $_REQUEST['token'] ) );
275 + $this->token = sanitize_text_field( $_REQUEST['token'] );
276 + $this->post_id = absint( sanitize_text_field( $_REQUEST['convertkit_post_id'] ) );
466 277
467 - // Store the post ID if this is an AJAX request.
468 - // This won't be included if clicking the link in the magic link email, so fall back to using
469 - // get_the_ID() to get the post ID.
470 - if ( array_key_exists( 'convertkit_post_id', $_REQUEST ) ) {
471 - $this->post_id = absint( wp_unslash( $_REQUEST['convertkit_post_id'] ) );
472 - } else {
473 - $this->post_id = get_the_ID();
474 - }
278 + // Initialize the API.
279 + $this->api = new ConvertKit_API_V4(
280 + CONVERTKIT_OAUTH_CLIENT_ID,
281 + CONVERTKIT_OAUTH_CLIENT_REDIRECT_URI,
282 + $this->settings->get_access_token(),
283 + $this->settings->get_refresh_token(),
284 + $this->settings->debug_enabled(),
285 + 'restrict_content'
286 + );
475 287
476 - // Run subscriber verification.
477 - $subscriber_id = $this->subscriber_authentication_verify( $this->post_id, sanitize_text_field( wp_unslash( $_REQUEST['token'] ) ), sanitize_text_field( wp_unslash( $_REQUEST['subscriber_code'] ) ) );
288 + // Verify the token and subscriber code.
289 + $subscriber_id = $this->api->subscriber_authentication_verify(
290 + sanitize_text_field( $_REQUEST['token'] ),
291 + sanitize_text_field( $_REQUEST['subscriber_code'] )
292 + );
478 293
479 - // Bail if an error occurred.
294 + // Bail if an error occured.
480 295 if ( is_wp_error( $subscriber_id ) ) {
481 296 $this->error = $subscriber_id;
482 297 return;
483 298 }
484 299
485 - // Redirect now to reload the Post.
486 - $this->redirect( $this->post_id );
487 -
488 - }
489 -
490 - /**
491 - * Sends an email to the subscriber with a code and link to authenticate they have access to the email address submitted.
492 - *
493 - * @since 3.1.0
494 - *
495 - * @param string $email Email address.
496 - * @param int $post_id Post ID.
497 - *
498 - * @return WP_Error|string Error or Token.
499 - */
500 - public function subscriber_authentication_send_code( $email, $post_id ) {
501 -
502 - // Send email to subscriber with a link to authenticate they have access to the email address submitted.
503 - $token = $this->api->subscriber_authentication_send_code(
504 - $email,
505 - $this->get_url( $post_id )
506 - );
507 -
508 - // Bail if an error occurred.
509 - if ( is_wp_error( $token ) ) {
510 - return $token;
511 - }
512 -
513 - // Clear any existing subscriber ID cookie, as the authentication flow has started by sending the email.
514 - $subscriber = new ConvertKit_Subscriber();
515 - $subscriber->forget();
516 -
517 - // Return the token.
518 - return $token;
519 -
520 - }
521 -
522 - /**
523 - * Verifies the token and subscriber code, which tells us that the email
524 - * address supplied truly belongs to the user, and that we can safely
525 - * trust their subscriber ID to be valid.
526 - *
527 - * @since 3.1.0
528 - *
529 - * @param int $post_id Post ID.
530 - * @param string $token Token.
531 - * @param string $subscriber_code Subscriber code.
532 - *
533 - * @return WP_Error|string Error or Signed Subscriber ID.
534 - */
535 - public function subscriber_authentication_verify( $post_id, $token, $subscriber_code ) {
536 -
537 - // Verify the token and subscriber code.
538 - $subscriber_id = $this->api->subscriber_authentication_verify( $token, $subscriber_code );
539 -
540 - // Bail if an error occurred.
541 - if ( is_wp_error( $subscriber_id ) ) {
542 - return $subscriber_id;
543 - }
544 -
545 300 // Store subscriber ID in cookie.
546 301 $this->store_subscriber_id_in_cookie( $subscriber_id );
547 302
548 - // Return signed subscriber ID.
549 - return $subscriber_id;
303 + // If this isn't an AJAX request, redirect now to reload the Post.
304 + if ( ! wp_doing_ajax() ) {
305 + $this->redirect();
306 + }
550 307
551 308 }
552 309
553 310 /**
554 - * Registers the applicable content filter for maybe restricting content, depending
555 - * on the Theme or Page Builder used.
556 - *
557 - * @since 2.7.7
558 - */
559 - public function register_content_filter() {
560 -
561 - // Use the standard `the_content` filter, which works for most Themes
562 - // and Page Builders.
563 - add_filter( 'the_content', array( $this, 'maybe_restrict_content' ) );
564 -
565 - /**
566 - * Allow specific Themes and Page Builders to use a different filter
567 - * for Restrict Content functionality.
568 - *
569 - * @since 2.7.7
570 - */
571 - do_action( 'convertkit_restrict_content_register_content_filter' );
572 -
573 - }
574 -
575 - /**
576 311 * Displays (or hides) content on a singular Page, Post or Custom Post Type's Content,
577 312 * depending on whether the visitor is an authenticated ConvertKit subscriber and has
578 313 * subscribed to the ConvertKit Product or Tag.
579 314 *
@@ -636,27 +371,11 @@
636 371 // If the subscriber is not subscribed to the product, restrict the content.
637 372 if ( ! $this->subscriber_has_access( $subscriber_id ) ) {
638 373 // Show an error before the call to action, to tell the subscriber why they still cannot
639 374 // view the content.
640 - switch ( $this->resource_type ) {
641 - case 'form':
642 - $message = $this->restrict_content_settings->get_by_key( 'no_access_text_form' );
643 - break;
644 -
645 - case 'tag':
646 - $message = $this->restrict_content_settings->get_by_key( 'no_access_text_tag' );
647 - break;
648 -
649 - case 'product':
650 - default:
651 - $message = $this->restrict_content_settings->get_by_key( 'no_access_text' );
652 - break;
653 - }
654 -
655 - // Define error for output.
656 375 $this->error = new WP_Error(
657 376 'convertkit_restrict_content_subscriber_no_access',
658 - esc_html( $message )
377 + esc_html( $this->restrict_content_settings->get_by_key( 'no_access_text' ) )
659 378 );
660 379
661 380 return $this->restrict_content( $content );
662 381 }
@@ -698,9 +417,9 @@
698 417 // Build replacement where statement.
699 418 $new_where = 'p.post_parent = ' . $post->post_parent . ' AND p.menu_order < ' . $post->menu_order;
700 419
701 420 // Replace existing where statement with new statement.
702 - $where = 'WHERE ' . $new_where . ' ' . substr( $where, strpos( $where, 'AND p.post_type = \'' . $post->post_type . '\' ' ) );
421 + $where = 'WHERE ' . $new_where . ' ' . substr( $where, strpos( $where, 'AND' ) );
703 422
704 423 // Return.
705 424 return $where;
706 425
@@ -737,9 +456,9 @@
737 456 // Build replacement where statement.
738 457 $new_where = 'p.post_parent = ' . $post->post_parent . ' AND p.menu_order > ' . $post->menu_order;
739 458
740 459 // Replace existing where statement with new statement.
741 - $where = 'WHERE ' . $new_where . ' ' . substr( $where, strpos( $where, 'AND p.post_type = \'' . $post->post_type . '\' ' ) );
460 + $where = 'WHERE ' . $new_where . ' ' . substr( $where, strpos( $where, 'AND' ) );
742 461
743 462 // Return.
744 463 return $where;
745 464
@@ -797,18 +516,16 @@
797 516 * Redirects to the current URL, removing any query parameters (such as tokens), and appending
798 517 * a ck-cache-bust query parameter to beat caching plugins.
799 518 *
800 519 * @since 2.3.7
801 - *
802 - * @param int $post_id Post ID.
803 520 */
804 - private function redirect( $post_id ) {
521 + private function redirect() {
805 522
806 523 // Redirect to the Post, appending a query parameter to the URL to prevent caching plugins and
807 524 // aggressive cache hosting configurations from serving a cached page, which would
808 525 // result in maybe_restrict_content() not showing an error message or permitting
809 526 // access to the content.
810 - wp_safe_redirect( $this->get_url( $post_id, true ) );
527 + wp_safe_redirect( $this->get_url( true ) );
811 528 exit;
812 529
813 530 }
814 531
@@ -816,16 +533,15 @@
816 533 * Returns the URL for the current request, excluding any query parameters.
817 534 *
818 535 * @since 2.1.0
819 536 *
820 - * @param int $post_id Post ID.
821 537 * @param bool $cache_bust Include `ck-cache-bust` parameter in URL.
822 - * @return string URL.
538 + * @return string URL.
823 539 */
824 - public function get_url( $post_id, $cache_bust = false ) {
540 + public function get_url( $cache_bust = false ) {
825 541
826 542 // Get URL of Post.
827 - $url = get_permalink( $post_id );
543 + $url = get_permalink( $this->post_id );
828 544
829 545 // If no cache busting required, return the URL now.
830 546 if ( ! $cache_bust ) {
831 547 return $url;
@@ -1011,21 +727,8 @@
1011 727
1012 728 // Product exists in ConvertKit.
1013 729 return true;
1014 730
1015 - case 'form':
1016 - // Get Form.
1017 - $forms = new ConvertKit_Resource_Forms( 'restrict_content' );
1018 - $form = $forms->get_by_id( $this->resource_id );
1019 -
1020 - // If the Form does not exist, return false.
1021 - if ( ! $form ) {
1022 - return false;
1023 - }
1024 -
1025 - // Form exists in ConvertKit.
1026 - return true;
1027 -
1028 731 case 'tag':
1029 732 // Get Tag.
1030 733 $tags = new ConvertKit_Resource_Tags( 'restrict_content' );
1031 734 $tag = $tags->get_by_id( $this->resource_id );
@@ -1055,116 +758,76 @@
1055 758 * @return bool Can view restricted content
1056 759 */
1057 760 private function subscriber_has_access( $subscriber_id ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter
1058 761
762 + // Initialize the API.
763 + $this->api = new ConvertKit_API_V4(
764 + CONVERTKIT_OAUTH_CLIENT_ID,
765 + CONVERTKIT_OAUTH_CLIENT_REDIRECT_URI,
766 + $this->settings->get_access_token(),
767 + $this->settings->get_refresh_token(),
768 + $this->settings->debug_enabled(),
769 + 'restrict_content'
770 + );
771 +
772 + // Depending on the resource type, determine if the subscriber has access to it.
773 + // This is deliberately a switch statement, because we will likely add in support
774 + // for restrict by tag and form later.
1059 775 switch ( $this->resource_type ) {
1060 776 case 'product':
1061 - return $this->subscriber_has_access_to_product_by_signed_subscriber_id( $subscriber_id, absint( $this->resource_id ) );
777 + // Get products that the subscriber has access to.
778 + $result = $this->api->profile( $subscriber_id );
1062 779
1063 - case 'form':
1064 - return $this->subscriber_has_access_to_form_by_signed_subscriber_id( $subscriber_id, absint( $this->resource_id ) );
780 + // If an error occured, the subscriber ID is invalid.
781 + if ( is_wp_error( $result ) ) {
782 + return false;
783 + }
1065 784
1066 - case 'tag':
1067 - return $this->subscriber_has_access_to_tag_by_signed_subscriber_id( $subscriber_id, absint( $this->resource_id ) );
785 + // If no products exist, there's no access.
786 + if ( ! $result['products'] || ! count( $result['products'] ) ) {
787 + return false;
788 + }
1068 789
1069 - }
790 + // Return if the subscriber is not subscribed to the product.
791 + if ( ! in_array( absint( $this->resource_id ), $result['products'], true ) ) {
792 + return false;
793 + }
1070 794
1071 - // If here, the subscriber does not have access.
1072 - return false;
795 + // If here, the subscriber is subscribed to the product.
796 + return true;
1073 797
1074 - }
798 + case 'tag':
799 + // Get tags that the subscriber has been assigned.
800 + $tags = $this->api->get_subscriber_tags( $subscriber_id );
1075 801
1076 - /**
1077 - * Determines if the given signed subscriber ID has an active subscription to
1078 - * the given product.
1079 - *
1080 - * @since 2.7.1
1081 - *
1082 - * @param string $signed_subscriber_id Signed Subscriber ID.
1083 - * @param int $product_id Product ID.
1084 - * @return bool Has access to product
1085 - */
1086 - private function subscriber_has_access_to_product_by_signed_subscriber_id( $signed_subscriber_id, $product_id ) {
802 + // If an error occured, the subscriber ID is invalid.
803 + if ( is_wp_error( $tags ) ) {
804 + return false;
805 + }
1087 806
1088 - // Get products that the subscriber has access to.
1089 - $result = $this->api->profile( $signed_subscriber_id );
807 + // If no tags exist, there's no access.
808 + if ( ! count( $tags['tags'] ) ) {
809 + return false;
810 + }
1090 811
1091 - // If an error occurred, the subscriber ID is invalid.
1092 - if ( is_wp_error( $result ) ) {
1093 - return false;
1094 - }
812 + // Iterate through the subscriber's tags to see if they have the required tag.
813 + foreach ( $tags['tags'] as $tag ) {
814 + if ( $tag['id'] === absint( $this->resource_id ) ) {
815 + // Subscriber has the required tag assigned to them - grant access.
816 + return true;
817 + }
818 + }
1095 819
1096 - // If no products exist, there's no access.
1097 - if ( ! $result['products'] || ! count( $result['products'] ) ) {
1098 - return false;
820 + // If here, the subscriber does not have the tag.
821 + return false;
1099 822 }
1100 823
1101 - // Return if the subscriber is subscribed to the product or not.
1102 - return in_array( $product_id, $result['products'], true );
824 + // If here, the subscriber does not have access.
825 + return false;
1103 826
1104 827 }
1105 828
1106 829 /**
1107 - * Determines if the given signed subscriber ID has an active subscription to
1108 - * the given form.
1109 - *
1110 - * @since 2.7.3
1111 - *
1112 - * @param string $signed_subscriber_id Signed Subscriber ID.
1113 - * @param int $form_id Form ID.
1114 - * @return bool Has access to form
1115 - */
1116 - private function subscriber_has_access_to_form_by_signed_subscriber_id( $signed_subscriber_id, $form_id ) {
1117 -
1118 - // Get products that the subscriber has access to.
1119 - $result = $this->api->profile( $signed_subscriber_id );
1120 -
1121 - // If an error occurred, the subscriber ID is invalid.
1122 - if ( is_wp_error( $result ) ) {
1123 - return false;
1124 - }
1125 -
1126 - // If no forms exist, there's no access.
1127 - if ( ! $result['forms'] || ! count( $result['forms'] ) ) {
1128 - return false;
1129 - }
1130 -
1131 - // Return if the subscriber is subscribed to the form or not.
1132 - return in_array( $form_id, $result['forms'], true );
1133 -
1134 - }
1135 -
1136 - /**
1137 - * Determines if the given signed subscriber ID has an active subscription to
1138 - * the given tag.
1139 - *
1140 - * @since 2.7.1
1141 - *
1142 - * @param string $signed_subscriber_id Signed Subscriber ID.
1143 - * @param int $tag_id Tag ID.
1144 - * @return bool Has access to tag
1145 - */
1146 - private function subscriber_has_access_to_tag_by_signed_subscriber_id( $signed_subscriber_id, $tag_id ) {
1147 -
1148 - // Get products that the subscriber has access to.
1149 - $result = $this->api->profile( $signed_subscriber_id );
1150 -
1151 - // If an error occurred, the subscriber ID is invalid.
1152 - if ( is_wp_error( $result ) ) {
1153 - return false;
1154 - }
1155 -
1156 - // If no tags exist, there's no access.
1157 - if ( ! $result['tags'] || ! count( $result['tags'] ) ) {
1158 - return false;
1159 - }
1160 -
1161 - // Return if the subscriber is subscribed to the tag or not.
1162 - return in_array( $tag_id, $result['tags'], true );
1163 -
1164 - }
1165 -
1166 - /**
1167 830 * Gets the subscriber ID from the request (either the cookie or the URL).
1168 831 *
1169 832 * @since 2.1.0
1170 833 *
@@ -1175,9 +838,9 @@
1175 838 // Use ConvertKit_Subscriber class to fetch and validate the subscriber ID.
1176 839 $subscriber = new ConvertKit_Subscriber();
1177 840 $subscriber_id = $subscriber->get_subscriber_id();
1178 841
1179 - // If an error occurred, the subscriber ID in the request/cookie is not a valid subscriber.
842 + // If an error occured, the subscriber ID in the request/cookie is not a valid subscriber.
1180 843 if ( is_wp_error( $subscriber_id ) ) {
1181 844 return 0;
1182 845 }
1183 846
@@ -1232,29 +895,8 @@
1232 895 * @param int $post_id Post ID.
1233 896 */
1234 897 $call_to_action = apply_filters( 'convertkit_output_restrict_content_call_to_action', $call_to_action, $this->post_id );
1235 898
1236 - // Fetch container CSS classes.
1237 - $container_css_classes = explode( ' ', $this->restrict_content_settings->get_by_key( 'container_css_classes' ) );
1238 -
1239 - /**
1240 - * Define the container CSS classes to wrap the content preview and call to action within.
1241 - *
1242 - * @since 3.1.4
1243 - *
1244 - * @param array $container_css_classes Container CSS classes.
1245 - * @param int $post_id Post ID.
1246 - */
1247 - $container_css_classes = apply_filters( 'convertkit_output_restrict_content_container_css_classes', $container_css_classes, $this->post_id );
1248 -
1249 - // Remove empty CSS classes.
1250 - $container_css_classes = array_filter( $container_css_classes );
1251 -
1252 - // If container CSS classes are set, return the content preview and call to action wrapped in the container.
1253 - if ( count( $container_css_classes ) ) {
1254 - return '<div class="' . trim( implode( ' ', map_deep( $container_css_classes, 'sanitize_html_class' ) ) ) . '">' . $content_preview . $call_to_action . '</div>';
1255 - }
1256 -
1257 899 // Return the content preview and its call to action.
1258 900 return $content_preview . $call_to_action;
1259 901
1260 902 }
@@ -1347,53 +989,42 @@
1347 989
1348 990 // Only load styles if the Disable CSS option is off.
1349 991 if ( ! $this->settings->css_disabled() ) {
1350 992 // Enqueue styles.
1351 - convertkit_enqueue_frontend_css();
993 + wp_enqueue_style( 'convertkit-restrict-content', CONVERTKIT_PLUGIN_URL . 'resources/frontend/css/restrict-content.css', array(), CONVERTKIT_PLUGIN_VERSION );
1352 994 }
1353 995
1354 996 // Only load scripts if the Disable Scripts option is off.
1355 997 if ( ! $this->settings->scripts_disabled() ) {
1356 998 // Enqueue scripts.
1357 - convertkit_enqueue_frontend_js();
1358 -
1359 - // Define variables.
999 + wp_enqueue_script( 'convertkit-restrict-content', CONVERTKIT_PLUGIN_URL . 'resources/frontend/js/restrict-content.js', array(), CONVERTKIT_PLUGIN_VERSION, true );
1360 1000 wp_localize_script(
1361 - 'convertkit-js',
1001 + 'convertkit-restrict-content',
1362 1002 'convertkit_restrict_content',
1363 1003 array(
1364 - 'nonce' => wp_create_nonce( 'wp_rest' ),
1365 - 'subscriber_authentication_url' => rest_url( 'kit/v1/restrict-content/subscriber-authentication' ),
1366 - 'subscriber_verification_url' => rest_url( 'kit/v1/restrict-content/subscriber-verification' ),
1367 - 'debug' => $this->settings->debug_enabled(),
1004 + 'ajaxurl' => admin_url( 'admin-ajax.php' ),
1005 + 'debug' => $this->settings->debug_enabled(),
1368 1006 )
1369 1007 );
1370 - }
1371 1008
1372 - // Output code form if this request is after the user entered their email address,
1373 - // which means we're going through the authentication flow.
1374 - if ( $this->in_authentication_flow() ) {
1375 - ob_start();
1376 - include CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/code.php';
1377 - return trim( ob_get_clean() );
1378 1009 }
1379 1010
1380 - // Get resource type and id.
1381 - $resource_type = $this->resource_type;
1382 - $resource_id = $this->resource_id;
1383 -
1384 1011 // This is deliberately a switch statement, because we will likely add in support
1385 1012 // for restrict by tag and form later.
1386 - switch ( $resource_type ) {
1013 + switch ( $this->resource_type ) {
1387 1014 case 'product':
1388 - // Get header and text from settings for Products.
1389 - $heading = $this->restrict_content_settings->get_by_key( 'subscribe_heading' );
1390 - $text = $this->restrict_content_settings->get_by_key( 'subscribe_text' );
1015 + // Output product code form if this request is after the user entered their email address,
1016 + // which means we're going through the authentication flow.
1017 + if ( $this->in_authentication_flow() ) { // phpcs:ignore WordPress.Security.NonceVerification
1018 + ob_start();
1019 + include CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/product-code.php';
1020 + return trim( ob_get_clean() );
1021 + }
1391 1022
1392 1023 // Output product restricted message and email form.
1393 1024 // Get Product.
1394 1025 $products = new ConvertKit_Resource_Products( 'restrict_content' );
1395 - $product = $products->get_by_id( $resource_id );
1026 + $product = $products->get_by_id( $this->resource_id );
1396 1027
1397 1028 // Get commerce.js URL and enqueue.
1398 1029 $url = $products->get_commerce_js_url();
1399 1030 if ( $url ) {
@@ -1404,11 +1035,11 @@
1404 1035 // when the 'log in' link is clicked.
1405 1036 if ( ! $this->settings->scripts_disabled() ) {
1406 1037 add_action(
1407 1038 'wp_footer',
1408 - function () use ( $post_id, $resource_id, $resource_type ) {
1039 + function () {
1409 1040
1410 - include_once CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/login-modal.php';
1041 + include_once CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/product-modal.php';
1411 1042
1412 1043 }
1413 1044 );
1414 1045 }
@@ -1414,66 +1045,13 @@
1414 1045 }
1415 1046
1416 1047 // Output.
1417 1048 ob_start();
1418 - $button = $products->get_html(
1419 - $resource_id,
1420 - $this->restrict_content_settings->get_by_key( 'subscribe_button_label' ),
1421 - array(
1422 - 'css_classes' => array( 'wp-block-button__link', 'wp-element-button' ),
1423 - )
1424 - );
1049 + $button = $products->get_html( $this->resource_id, $this->restrict_content_settings->get_by_key( 'subscribe_button_label' ) );
1425 1050 include CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/product.php';
1426 1051 return trim( ob_get_clean() );
1427 1052
1428 - case 'form':
1429 - // Display the Form.
1430 - $forms = new ConvertKit_Resource_Forms( 'restrict_content' );
1431 - $form = $forms->get_html( $resource_id, $post_id );
1432 -
1433 - // If scripts are enabled, output the email login form in a modal, which will be displayed
1434 - // when the 'log in' link is clicked.
1435 - if ( ! $this->settings->scripts_disabled() ) {
1436 - add_action(
1437 - 'wp_footer',
1438 - function () use ( $post_id, $resource_id, $resource_type ) {
1439 -
1440 - include_once CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/login-modal.php';
1441 -
1442 - }
1443 - );
1444 - }
1445 -
1446 - // Output.
1447 - ob_start();
1448 - include CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/form.php';
1449 - return trim( ob_get_clean() );
1450 -
1451 1053 case 'tag':
1452 - // Get header and text from settings for Tags.
1453 - $heading = $this->restrict_content_settings->get_by_key( 'subscribe_heading_tag' );
1454 - $text = $this->restrict_content_settings->get_by_key( 'subscribe_text_tag' );
1455 -
1456 - // If scripts are enabled, output the email login form in a modal, which will be displayed
1457 - // when the 'log in' link is clicked.
1458 - if ( ! $this->settings->scripts_disabled() ) {
1459 - add_action(
1460 - 'wp_footer',
1461 - function () use ( $post_id, $resource_id, $resource_type ) {
1462 -
1463 - include_once CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/login-modal.php';
1464 -
1465 - }
1466 - );
1467 - }
1468 -
1469 - // Enqueue the active spam protection provider's client-side script.
1470 - $spam = new ConvertKit_Spam_Protection();
1471 - $spam_provider = $spam->get_active_provider();
1472 - if ( $spam_provider !== false ) {
1473 - $spam_provider->enqueue_scripts();
1474 - }
1475 -
1476 1054 // Output.
1477 1055 ob_start();
1478 1056 include CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/tag.php';
1479 1057 return trim( ob_get_clean() );
@@ -1497,9 +1075,9 @@
1497 1075 // Define permitted user agent crawlers and their IP addresses.
1498 1076 $permitted_user_agent_ip_ranges = array(
1499 1077 // Google.
1500 1078 // https://developers.google.com/static/search/apis/ipranges/googlebot.json.
1501 - 'Googlebot' => array(
1079 + 'Googlebot' => array(
1502 1080 '192.178.5.0/27',
1503 1081 '34.100.182.96/28',
1504 1082 '34.101.50.144/28',
1505 1083 '34.118.254.0/28',
@@ -1628,28 +1206,11 @@
1628 1206 '66.249.79.64/27',
1629 1207 '66.249.79.96/27',
1630 1208 ),
1631 1209
1632 - // Applebot.
1633 - // http://search.developer.apple.com/applebot.json.
1634 - 'Applebot' => array(
1635 - '17.241.208.160/27',
1636 - '17.241.193.160/27',
1637 - '17.241.200.160/27',
1638 - '17.22.237.0/24',
1639 - '17.22.245.0/24',
1640 - '17.22.253.0/24',
1641 - '17.241.75.0/24',
1642 - '17.241.219.0/24',
1643 - '17.241.227.0/24',
1644 - '17.246.15.0/24',
1645 - '17.246.19.0/24',
1646 - '17.246.23.0/24',
1647 - ),
1648 -
1649 1210 // Bing.
1650 1211 // https://www.bing.com/toolbox/bingbot.json.
1651 - 'Bingbot' => array(
1212 + 'Bingbot' => array(
1652 1213 '157.55.39.0/24',
1653 1214 '207.46.13.0/24',
1654 1215 '40.77.167.0/24',
1655 1216 '13.66.139.0/24',
@@ -1677,295 +1238,8 @@
1677 1238 '20.15.133.160/27',
1678 1239 '40.77.177.0/24',
1679 1240 '40.77.178.0/23',
1680 1241 ),
1681 -
1682 - // DuckDuckGo.
1683 - // https://duckduckgo.com/duckduckgo-help-pages/results/duckduckbot.
1684 - 'DuckDuckBot' => array(
1685 - '57.152.72.128',
1686 - '51.8.253.152',
1687 - '40.80.242.63',
1688 - '20.12.141.99',
1689 - '20.49.136.28',
1690 - '51.116.131.221',
1691 - '51.107.40.209',
1692 - '20.40.133.240',
1693 - '20.50.168.91',
1694 - '51.120.48.122',
1695 - '20.193.45.113',
1696 - '40.76.173.151',
1697 - '40.76.163.7',
1698 - '20.185.79.47',
1699 - '52.142.26.175',
1700 - '20.185.79.15',
1701 - '52.142.24.149',
1702 - '40.76.162.208',
1703 - '40.76.163.23',
1704 - '40.76.162.191',
1705 - '40.76.162.247',
1706 - '40.88.21.235',
1707 - '20.191.45.212',
1708 - '52.146.59.12',
1709 - '52.146.59.156',
1710 - '52.146.59.154',
1711 - '52.146.58.236',
1712 - '20.62.224.44',
1713 - '51.104.180.53',
1714 - '51.104.180.47',
1715 - '51.104.180.26',
1716 - '51.104.146.225',
1717 - '51.104.146.235',
1718 - '20.73.202.147',
1719 - '20.73.132.240',
1720 - '20.71.12.143',
1721 - '20.56.197.58',
1722 - '20.56.197.63',
1723 - '20.43.150.93',
1724 - '20.43.150.85',
1725 - '20.44.222.1',
1726 - '40.89.243.175',
1727 - '13.89.106.77',
1728 - '52.143.242.6',
1729 - '52.143.241.111',
1730 - '52.154.60.82',
1731 - '20.197.209.11',
1732 - '20.197.209.27',
1733 - '20.226.133.105',
1734 - '191.234.216.4',
1735 - '191.234.216.178',
1736 - '20.53.92.211',
1737 - '20.53.91.2',
1738 - '20.207.99.197',
1739 - '20.207.97.190',
1740 - '40.81.250.205',
1741 - '40.64.106.11',
1742 - '40.64.105.247',
1743 - '20.72.242.93',
1744 - '20.99.255.235',
1745 - '20.113.3.121',
1746 - '52.224.16.221',
1747 - '52.224.21.53',
1748 - '52.224.20.204',
1749 - '52.224.21.19',
1750 - '52.224.20.249',
1751 - '52.224.20.203',
1752 - '52.224.20.190',
1753 - '52.224.16.229',
1754 - '52.224.21.20',
1755 - '52.146.63.80',
1756 - '52.224.20.227',
1757 - '52.224.20.193',
1758 - '52.190.37.160',
1759 - '52.224.21.23',
1760 - '52.224.20.223',
1761 - '52.224.20.181',
1762 - '52.224.21.49',
1763 - '52.224.21.55',
1764 - '52.224.21.61',
1765 - '52.224.19.152',
1766 - '52.224.20.186',
1767 - '52.224.21.27',
1768 - '52.224.21.51',
1769 - '52.224.20.174',
1770 - '52.224.21.4',
1771 - '51.104.164.109',
1772 - '51.104.167.71',
1773 - '51.104.160.177',
1774 - '51.104.162.149',
1775 - '51.104.167.95',
1776 - '51.104.167.54',
1777 - '51.104.166.111',
1778 - '51.104.167.88',
1779 - '51.104.161.32',
1780 - '51.104.163.250',
1781 - '51.104.164.189',
1782 - '51.104.167.19',
1783 - '51.104.160.167',
1784 - '51.104.167.110',
1785 - '20.191.44.119',
1786 - '51.104.167.104',
1787 - '20.191.44.234',
1788 - '51.104.164.215',
1789 - '51.104.167.52',
1790 - '20.191.44.22',
1791 - '51.104.167.87',
1792 - '51.104.167.96',
1793 - '20.191.44.16',
1794 - '51.104.167.61',
1795 - '51.104.164.147',
1796 - '20.50.48.159',
1797 - '40.114.182.172',
1798 - '20.50.50.130',
1799 - '20.50.50.163',
1800 - '20.50.50.46',
1801 - '40.114.182.153',
1802 - '20.50.50.118',
1803 - '20.50.49.55',
1804 - '20.50.49.25',
1805 - '40.114.183.251',
1806 - '20.50.50.123',
1807 - '20.50.49.237',
1808 - '20.50.48.192',
1809 - '20.50.50.134',
1810 - '51.138.90.233',
1811 - '40.114.183.196',
1812 - '20.50.50.146',
1813 - '40.114.183.88',
1814 - '20.50.50.145',
1815 - '20.50.50.121',
1816 - '20.50.49.40',
1817 - '51.138.90.206',
1818 - '40.114.182.45',
1819 - '51.138.90.161',
1820 - '20.50.49.0',
1821 - '40.119.232.215',
1822 - '104.43.55.167',
1823 - '40.119.232.251',
1824 - '40.119.232.50',
1825 - '40.119.232.146',
1826 - '40.119.232.218',
1827 - '104.43.54.127',
1828 - '104.43.55.117',
1829 - '104.43.55.116',
1830 - '104.43.55.166',
1831 - '52.154.169.50',
1832 - '52.154.171.70',
1833 - '52.154.170.229',
1834 - '52.154.170.113',
1835 - '52.154.171.44',
1836 - '52.154.172.2',
1837 - '52.143.244.81',
1838 - '52.154.171.87',
1839 - '52.154.171.250',
1840 - '52.154.170.28',
1841 - '52.154.170.122',
1842 - '52.143.243.117',
1843 - '52.143.247.235',
1844 - '52.154.171.235',
1845 - '52.154.171.196',
1846 - '52.154.171.0',
1847 - '52.154.170.243',
1848 - '52.154.170.26',
1849 - '52.154.169.200',
1850 - '52.154.170.96',
1851 - '52.154.170.88',
1852 - '52.154.171.150',
1853 - '52.154.171.205',
1854 - '52.154.170.117',
1855 - '52.154.170.209',
1856 - '191.235.202.48',
1857 - '191.233.3.202',
1858 - '191.235.201.214',
1859 - '191.233.3.197',
1860 - '191.235.202.38',
1861 - '20.53.78.144',
1862 - '20.193.24.10',
1863 - '20.53.78.236',
1864 - '20.53.78.138',
1865 - '20.53.78.123',
1866 - '20.53.78.106',
1867 - '20.193.27.215',
1868 - '20.193.25.197',
1869 - '20.193.12.126',
1870 - '20.193.24.251',
1871 - '20.204.242.101',
1872 - '20.207.72.113',
1873 - '20.204.242.19',
1874 - '20.219.45.67',
1875 - '20.207.72.11',
1876 - '20.219.45.190',
1877 - '20.204.243.55',
1878 - '20.204.241.148',
1879 - '20.207.72.110',
1880 - '20.204.240.172',
1881 - '20.207.72.21',
1882 - '20.204.246.81',
1883 - '20.207.107.181',
1884 - '20.204.246.254',
1885 - '20.219.43.246',
1886 - '52.149.25.43',
1887 - '52.149.61.51',
1888 - '52.149.58.139',
1889 - '52.149.60.38',
1890 - '52.148.165.38',
1891 - '52.143.95.162',
1892 - '52.149.56.151',
1893 - '52.149.30.45',
1894 - '52.149.58.173',
1895 - '52.143.95.204',
1896 - '52.149.28.83',
1897 - '52.149.58.69',
1898 - '52.148.161.87',
1899 - '52.149.58.27',
1900 - '52.149.28.18',
1901 - '20.79.226.26',
1902 - '20.79.239.66',
1903 - '20.79.238.198',
1904 - '20.113.14.159',
1905 - '20.75.144.152',
1906 - '20.43.172.120',
1907 - '20.53.134.160',
1908 - '20.201.15.208',
1909 - '20.93.28.24',
1910 - '20.61.34.40',
1911 - '52.242.224.168',
1912 - '20.80.129.80',
1913 - '20.195.108.47',
1914 - '4.195.133.120',
1915 - '4.228.76.163',
1916 - '4.182.131.108',
1917 - '4.209.224.56',
1918 - '108.141.83.74',
1919 - '4.213.46.14',
1920 - '172.169.17.165',
1921 - '51.8.71.117',
1922 - '20.3.1.178',
1923 - ),
1924 -
1925 - // OpenAI Search Bot.
1926 - // https://platform.openai.com/docs/bots/overview-of-openai-crawlers.
1927 - // https://openai.com/searchbot.json.
1928 - 'OAI-SearchBot' => array(
1929 - '20.42.10.176/28',
1930 - '172.203.190.128/28',
1931 - '104.210.140.128/28',
1932 - '51.8.102.0/24',
1933 - '135.234.64.0/24',
1934 - ),
1935 -
1936 - // Perplexity Search Bot.
1937 - // https://www.perplexity.com/perplexitybot.json.
1938 - 'PerplexityBot' => array(
1939 - '107.20.236.150/32',
1940 - '3.224.62.45/32',
1941 - '18.210.92.235/32',
1942 - '3.222.232.239/32',
1943 - '3.211.124.183/32',
1944 - '3.231.139.107/32',
1945 - '18.97.1.228/30',
1946 - '18.97.9.96/29',
1947 - ),
1948 -
1949 - // YandexBot.
1950 - // https://yandex.com/support/webmaster/en/robot-workings/check-yandex-robots.html.
1951 - 'YandexBot' => array(
1952 - '5.45.192.0/18',
1953 - '5.255.192.0/18',
1954 - '37.9.64.0/18',
1955 - '37.140.128.0/18',
1956 - '77.88.0.0/18',
1957 - '84.252.160.0/19',
1958 - '87.250.224.0/19',
1959 - '90.156.176.0/22',
1960 - '93.158.128.0/18',
1961 - '95.108.128.0/17',
1962 - '141.8.128.0/18',
1963 - '178.154.128.0/18',
1964 - '213.180.192.0/19',
1965 - '185.32.187.0/24',
1966 - ),
1967 -
1968 1242 );
1969 1243
1970 1244 /**
1971 1245 * Define the permitted user agents and their IP address ranges that can bypass
@@ -1984,15 +1258,15 @@
1984 1258
1985 1259 // Iterate through permitted crawler IP addresses.
1986 1260 foreach ( $permitted_user_agent_ip_ranges as $permitted_user_agent => $permitted_ip_addresses ) {
1987 1261 // Skip this user agent's IP addresses if the client user agent doesn't contain this user agent.
1988 - if ( stripos( sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ), $permitted_user_agent ) === false ) {
1262 + if ( stripos( $_SERVER['HTTP_USER_AGENT'], $permitted_user_agent ) === false ) {
1989 1263 continue;
1990 1264 }
1991 1265
1992 1266 // Check IP address.
1993 1267 foreach ( $permitted_ip_addresses as $permitted_ip_range ) {
1994 - if ( ! $this->ip_in_range( sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ), $permitted_ip_range ) ) {
1268 + if ( ! $this->ip_in_range( $_SERVER['REMOTE_ADDR'], $permitted_ip_range ) ) {
1995 1269 continue;
1996 1270 }
1997 1271
1998 1272 // The client user agent and IP address match a known crawler and its IP address.