PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 3.4.3
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v3.4.3
3.4.3 3.4.2 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 All 196 releases
← All changes | includes/class-convertkit-output-restrict-content.php +201 -61 3.3.73.4.3 View file →
@@ -98,8 +98,17 @@
98 98 */
99 99 public $token = false;
100 100
101 101 /**
102 + * Whether the login modal has been output.
103 + *
104 + * @since 3.4.2
105 + *
106 + * @var bool
107 + */
108 + public $login_modal_output = false;
109 +
110 + /**
102 111 * Constructor. Registers actions and filters to possibly limit output of a Page/Post/CPT's
103 112 * content on the frontend site.
104 113 *
105 114 * @since 2.1.0
@@ -108,8 +117,9 @@
108 117
109 118 add_action( 'rest_api_init', array( $this, 'register_routes' ) );
110 119 add_action( 'init', array( $this, 'initialize_classes' ), 2 );
111 120 add_action( 'init', array( $this, 'maybe_run_subscriber_authentication' ), 3 );
121 + add_action( 'wp', array( $this, 'maybe_run_subscriber_logout' ), 3 );
112 122 add_action( 'wp', array( $this, 'maybe_run_subscriber_verification' ), 4 );
113 123 add_action( 'wp', array( $this, 'register_content_filter' ), 5 );
114 124 add_filter( 'get_previous_post_where', array( $this, 'maybe_change_previous_post_where_clause' ), 10, 5 );
115 125 add_filter( 'get_next_post_where', array( $this, 'maybe_change_next_post_where_clause' ), 10, 5 );
@@ -154,11 +164,12 @@
154 164 },
155 165 'sanitize_callback' => 'absint',
156 166 ),
157 167
158 - // Resource Type: Validate resource type is included in the request and is a string.
168 + // Resource Type: Validate resource type is a string, if included in the request.
169 + // It's not included when logging in using the Member Content Login block.
159 170 'convertkit_resource_type' => array(
160 - 'required' => true,
171 + 'required' => false,
161 172 'validate_callback' => function ( $param ) {
162 173
163 174 return is_string( $param );
164 175
@@ -165,11 +176,12 @@
165 176 },
166 177 'sanitize_callback' => 'sanitize_text_field',
167 178 ),
168 179
169 - // Resource ID: Validate resource ID is included in the request and is an integer.
180 + // Resource ID: Validate resource ID is an integer, if included in the request.
181 + // It's not included when logging in using the Member Content Login block.
170 182 'convertkit_resource_id' => array(
171 - 'required' => true,
183 + 'required' => false,
172 184 'validate_callback' => function ( $param ) {
173 185
174 186 return is_numeric( $param );
175 187
@@ -175,8 +187,32 @@
175 187
176 188 },
177 189 'sanitize_callback' => 'absint',
178 190 ),
191 +
192 + // Spam protection response, if a spam protection provider is enabled.
193 + 'spam_protection_response' => array(
194 + 'required' => false,
195 + 'validate_callback' => function ( $param ) {
196 +
197 + return is_string( $param );
198 +
199 + },
200 + 'sanitize_callback' => 'sanitize_text_field',
201 + ),
202 +
203 + // Whether to display the heading above the login form.
204 + // It's not displayed by the Member Content Login block, as it refers to
205 + // reading the Member Content the subscriber is logging in to view.
206 + 'display_heading' => array(
207 + 'required' => false,
208 + 'default' => true,
209 + 'validate_callback' => function ( $param ) {
210 +
211 + return is_bool( $param );
212 +
213 + },
214 + ),
179 215 ),
180 216 'callback' => function ( $request ) {
181 217
182 218 // Initialize classes that will be used.
@@ -188,8 +224,26 @@
188 224 $post_id = $request->get_param( 'convertkit_post_id' );
189 225 $resource_type = $request->get_param( 'convertkit_resource_type' );
190 226 $resource_id = $request->get_param( 'convertkit_resource_id' );
191 227
228 + // Check spam protection (reCAPTCHA or Cloudflare Turnstile, depending on Plugin settings).
229 + $result = $output_restrict_content->verify_spam_protection( $request->get_param( 'spam_protection_response' ) );
230 +
231 + // If spam protection failed, build the email form view with the error message.
232 + if ( is_wp_error( $result ) ) {
233 + $output_restrict_content->error = $result;
234 +
235 + ob_start();
236 + include CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/' . ( $request->get_param( 'display_heading' ) ? 'login-modal-content-email.php' : 'login-email.php' );
237 + $output = trim( ob_get_clean() );
238 + return rest_ensure_response(
239 + array(
240 + 'success' => false,
241 + 'data' => $output,
242 + )
243 + );
244 + }
245 +
192 246 // Run subscriber authentication.
193 247 $result = $output_restrict_content->subscriber_authentication_send_code(
194 248 $email,
195 249 $post_id
@@ -201,9 +255,9 @@
201 255 $output_restrict_content->error = $result;
202 256
203 257 // Build email form view to return for output with error message.
204 258 ob_start();
205 - include CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/login-modal-content-email.php';
259 + include CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/' . ( $request->get_param( 'display_heading' ) ? 'login-modal-content-email.php' : 'login-email.php' );
206 260 $output = trim( ob_get_clean() );
207 261 return rest_ensure_response(
208 262 array(
209 263 'success' => false,
@@ -364,18 +418,12 @@
364 418 if ( ! wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'convertkit_restrict_content_login' ) ) {
365 419 return;
366 420 }
367 421
368 - // Bail if the expected email, resource type, resource ID or Post ID are missing from the request.
422 + // Bail if the expected email or Post ID are missing from the request.
369 423 if ( ! array_key_exists( 'convertkit_email', $_REQUEST ) ) {
370 424 return;
371 425 }
372 - if ( ! array_key_exists( 'convertkit_resource_type', $_REQUEST ) ) {
373 - return;
374 - }
375 - if ( ! array_key_exists( 'convertkit_resource_id', $_REQUEST ) ) {
376 - return;
377 - }
378 426 if ( ! array_key_exists( 'convertkit_post_id', $_REQUEST ) ) {
379 427 return;
380 428 }
381 429
@@ -385,10 +433,10 @@
385 433 }
386 434
387 435 // Sanitize inputs.
388 436 $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'] );
437 + $this->resource_type = ( array_key_exists( 'convertkit_resource_type', $_REQUEST ) ? sanitize_text_field( wp_unslash( $_REQUEST['convertkit_resource_type'] ) ) : '' );
438 + $this->resource_id = ( array_key_exists( 'convertkit_resource_id', $_REQUEST ) ? absint( $_REQUEST['convertkit_resource_id'] ) : 0 );
391 439 $this->post_id = absint( $_REQUEST['convertkit_post_id'] );
392 440
393 441 // If Restrict Content is by tag, tag the subscriber.
394 442 if ( $this->resource_type === 'tag' ) {
@@ -409,8 +457,17 @@
409 457 if ( is_wp_error( $result ) ) {
410 458 $this->error = $result;
411 459 return;
412 460 }
461 + } else {
462 + // Check spam protection (reCAPTCHA or Cloudflare Turnstile, depending on Plugin settings).
463 + $spam_check = $this->verify_spam_protection();
464 +
465 + // Bail if spam protection failed.
466 + if ( is_wp_error( $spam_check ) ) {
467 + $this->error = $spam_check;
468 + return;
469 + }
413 470 }
414 471
415 472 // Run subscriber authentication.
416 473 $result = $this->subscriber_authentication_send_code( $email, $this->post_id );
@@ -487,8 +544,133 @@
487 544
488 545 }
489 546
490 547 /**
548 + * Logs the subscriber out by deleting their subscriber ID cookie, when the
549 + * log out button is clicked in the Member Content Login block.
550 + *
551 + * @since 3.4.2
552 + */
553 + public function maybe_run_subscriber_logout() {
554 +
555 + // Bail if no logout request was made.
556 + if ( ! array_key_exists( 'convertkit_logout', $_REQUEST ) ) {
557 + return;
558 + }
559 +
560 + // Bail if no nonce was specified.
561 + if ( ! array_key_exists( '_wpnonce', $_REQUEST ) ) {
562 + return;
563 + }
564 +
565 + // Bail if the nonce failed validation.
566 + if ( ! wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'convertkit_member_content_logout' ) ) {
567 + return;
568 + }
569 +
570 + // Delete the subscriber ID cookie.
571 + $subscriber = new ConvertKit_Subscriber();
572 + $subscriber->forget();
573 +
574 + // Reload the Post, so the login form displays.
575 + wp_safe_redirect( $this->get_url( get_the_ID(), true ) );
576 + exit();
577 +
578 + }
579 +
580 + /**
581 + * Verifies the spam protection response for the login form, using the spam
582 + * protection provider enabled in the Plugin's settings.
583 + *
584 + * @since 3.4.2
585 + *
586 + * @param bool|string $response Spam protection response, if supplied by a REST API request.
587 + * @return bool|WP_Error
588 + */
589 + public function verify_spam_protection( $response = false ) {
590 +
591 + $spam_protection = new ConvertKit_Spam_Protection();
592 + $provider = $spam_protection->get_active_provider();
593 +
594 + // Return true if no spam protection provider is enabled.
595 + if ( $provider === false ) {
596 + return true;
597 + }
598 +
599 + // Verify the response included in the REST API request.
600 + if ( ! empty( $response ) ) {
601 + return $provider->verify( $response, 'convertkit_member_content_login' );
602 + }
603 +
604 + // Verify the response included in the form submission.
605 + return $spam_protection->verify( 'convertkit_member_content_login' );
606 +
607 + }
608 +
609 + /**
610 + * Enqueues the CSS and JS required by the login form and modal.
611 + *
612 + * @since 3.4.2
613 + */
614 + public function enqueue_scripts_and_styles() {
615 +
616 + // Only load styles if the Disable CSS option is off.
617 + if ( ! $this->settings->css_disabled() ) {
618 + convertkit_enqueue_frontend_css();
619 + }
620 +
621 + // Bail if scripts are disabled.
622 + if ( $this->settings->scripts_disabled() ) {
623 + return;
624 + }
625 +
626 + // Enqueue scripts.
627 + convertkit_enqueue_frontend_js();
628 +
629 + // Define variables.
630 + wp_localize_script(
631 + 'convertkit-js',
632 + 'convertkit_restrict_content',
633 + array(
634 + 'nonce' => wp_create_nonce( 'wp_rest' ),
635 + 'subscriber_authentication_url' => rest_url( 'kit/v1/restrict-content/subscriber-authentication' ),
636 + 'subscriber_verification_url' => rest_url( 'kit/v1/restrict-content/subscriber-verification' ),
637 + 'debug' => $this->settings->debug_enabled(),
638 + )
639 + );
640 +
641 + }
642 +
643 + /**
644 + * Outputs the login modal in the footer, ensuring it is only output once
645 + * when a Post contains multiple Member Content Login blocks.
646 + *
647 + * @since 3.4.2
648 + *
649 + * @param int $post_id Post ID.
650 + * @param bool|int $resource_id Resource ID.
651 + * @param bool|string $resource_type Resource Type.
652 + */
653 + public function output_login_modal( $post_id, $resource_id = 0, $resource_type = '' ) {
654 +
655 + if ( $this->login_modal_output ) {
656 + return;
657 + }
658 +
659 + $this->login_modal_output = true;
660 +
661 + add_action(
662 + 'wp_footer',
663 + function () use ( $post_id, $resource_id, $resource_type ) {
664 +
665 + include_once CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/login-modal.php';
666 +
667 + }
668 + );
669 +
670 + }
671 +
672 + /**
491 673 * Sends an email to the subscriber with a code and link to authenticate they have access to the email address submitted.
492 674 *
493 675 * @since 3.1.0
494 676 *
@@ -1344,32 +1526,11 @@
1344 1526 * @return string HTML
1345 1527 */
1346 1528 private function get_call_to_action( $post_id ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter
1347 1529
1348 - // Only load styles if the Disable CSS option is off.
1349 - if ( ! $this->settings->css_disabled() ) {
1350 - // Enqueue styles.
1351 - convertkit_enqueue_frontend_css();
1352 - }
1530 + // Enqueue CSS and JS.
1531 + $this->enqueue_scripts_and_styles();
1353 1532
1354 - // Only load scripts if the Disable Scripts option is off.
1355 - if ( ! $this->settings->scripts_disabled() ) {
1356 - // Enqueue scripts.
1357 - convertkit_enqueue_frontend_js();
1358 -
1359 - // Define variables.
1360 - wp_localize_script(
1361 - 'convertkit-js',
1362 - 'convertkit_restrict_content',
1363 - 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(),
1368 - )
1369 - );
1370 - }
1371 -
1372 1533 // Output code form if this request is after the user entered their email address,
1373 1534 // which means we're going through the authentication flow.
1374 1535 if ( $this->in_authentication_flow() ) {
1375 1536 ob_start();
@@ -1402,16 +1563,9 @@
1402 1563
1403 1564 // If scripts are enabled, output the email login form in a modal, which will be displayed
1404 1565 // when the 'log in' link is clicked.
1405 1566 if ( ! $this->settings->scripts_disabled() ) {
1406 - add_action(
1407 - 'wp_footer',
1408 - function () use ( $post_id, $resource_id, $resource_type ) {
1409 -
1410 - include_once CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/login-modal.php';
1411 -
1412 - }
1413 - );
1567 + $this->output_login_modal( $post_id, $resource_id, $resource_type );
1414 1568 }
1415 1569
1416 1570 // Output.
1417 1571 ob_start();
@@ -1432,16 +1586,9 @@
1432 1586
1433 1587 // If scripts are enabled, output the email login form in a modal, which will be displayed
1434 1588 // when the 'log in' link is clicked.
1435 1589 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 - );
1590 + $this->output_login_modal( $post_id, $resource_id, $resource_type );
1444 1591 }
1445 1592
1446 1593 // Output.
1447 1594 ob_start();
@@ -1455,16 +1602,9 @@
1455 1602
1456 1603 // If scripts are enabled, output the email login form in a modal, which will be displayed
1457 1604 // when the 'log in' link is clicked.
1458 1605 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 - );
1606 + $this->output_login_modal( $post_id, $resource_id, $resource_type );
1467 1607 }
1468 1608
1469 1609 // Enqueue the active spam protection provider's client-side script.
1470 1610 $spam = new ConvertKit_Spam_Protection();