PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 2.5.2
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v2.5.2
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.php +285 -8 2.2.42.5.2 View file →
@@ -66,18 +66,84 @@
66 66 * @since 1.9.6
67 67 */
68 68 public function __construct() {
69 69
70 - add_action( 'init', array( $this, 'get_subscriber_id_from_request' ), 1 );
70 + add_action( 'init', array( $this, 'get_subscriber_id_from_request' ) );
71 + add_action( 'wp', array( $this, 'maybe_tag_subscriber' ) );
71 72 add_action( 'template_redirect', array( $this, 'output_form' ) );
72 73 add_action( 'template_redirect', array( $this, 'page_takeover' ) );
73 74 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
74 75 add_filter( 'the_content', array( $this, 'append_form_to_content' ) );
76 + add_filter( 'hooked_block_types', array( $this, 'maybe_register_form_block_on_category_archive' ), 10, 4 );
77 + add_filter( 'hooked_block_convertkit/form', array( $this, 'append_form_block_to_category_archive' ), 10, 1 );
78 + add_action( 'wp_footer', array( $this, 'output_global_non_inline_form' ), 1 );
75 79 add_action( 'wp_footer', array( $this, 'output_scripts_footer' ) );
76 80
77 81 }
78 82
79 83 /**
84 + * Tags the subscriber, if:
85 + * - a subscriber ID exists in the cookie or URL,
86 + * - the WordPress Page has the "Add a Tag" setting specified
87 + *
88 + * @since 2.4.9.1
89 + */
90 + public function maybe_tag_subscriber() {
91 +
92 + // Bail if no subscriber ID detected.
93 + if ( ! $this->subscriber_id ) {
94 + return;
95 + }
96 +
97 + // Bail if not a singular Post Type supported by ConvertKit.
98 + if ( ! is_singular( convertkit_get_supported_post_types() ) ) {
99 + return;
100 + }
101 +
102 + // Get Post ID.
103 + $post_id = get_the_ID();
104 +
105 + // Bail if a Post ID couldn't be identified.
106 + if ( ! $post_id ) {
107 + return;
108 + }
109 +
110 + // Get Settings, if they have not yet been loaded.
111 + if ( ! $this->settings ) {
112 + $this->settings = new ConvertKit_Settings();
113 + }
114 +
115 + // Bail if the API if an API Key and Secret is not defined.
116 + if ( ! $this->settings->has_api_key_and_secret() ) {
117 + return;
118 + }
119 +
120 + // Get ConvertKit Post's Settings, if they have not yet been loaded.
121 + if ( ! $this->post_settings ) {
122 + $this->post_settings = new ConvertKit_Post( $post_id );
123 + }
124 +
125 + // Bail if no "Add a Tag" setting specified for this Page.
126 + if ( ! $this->post_settings->has_tag() ) {
127 + return;
128 + }
129 +
130 + // Initialize the API.
131 + $api = new ConvertKit_API_V4(
132 + CONVERTKIT_OAUTH_CLIENT_ID,
133 + CONVERTKIT_OAUTH_CLIENT_REDIRECT_URI,
134 + $this->settings->get_access_token(),
135 + $this->settings->get_refresh_token(),
136 + $this->settings->debug_enabled(),
137 + 'output'
138 + );
139 +
140 + // Tag subscriber.
141 + $api->tag_subscriber( $this->post_settings->get_tag(), $this->subscriber_id );
142 +
143 + }
144 +
145 + /**
80 146 * Runs the `convertkit_output_output_form` action for singular Post Types that don't use the_content()
81 147 * or apply_filters( 'the_content' ) to output a ConvertKit Form.
82 148 *
83 149 * @since 1.9.6
@@ -156,8 +222,26 @@
156 222 if ( is_wp_error( $landing_page ) ) {
157 223 return;
158 224 }
159 225
226 + // Replace the favicon with the WordPress site's favicon, if specified.
227 + $landing_page = $this->landing_pages->replace_favicon( $landing_page );
228 +
229 + /**
230 + * Perform any actions immediately prior to outputting the Landing Page.
231 + *
232 + * Caching and minification Plugins may need to hook here to prevent
233 + * CSS / JS minification and lazy loading images, which can interfere
234 + * with Landing Pages.
235 + *
236 + * @since 2.4.4
237 + *
238 + * @param string $landing_page ConvertKit Landing Page HTML.
239 + * @param int $landing_page_id ConvertKit Landing Page ID.
240 + * @param int $post_id WordPress Page ID.
241 + */
242 + do_action( 'convertkit_output_landing_page_before', $landing_page, $landing_page_id, $post_id );
243 +
160 244 // Output Landing Page.
161 245 // Output is supplied from ConvertKit's API, which is already sanitized.
162 246 echo $landing_page; // phpcs:ignore WordPress.Security.EscapeOutput
163 247 exit;
@@ -171,10 +255,10 @@
171 255 * @return string Post Content with Form Appended, if applicable
172 256 */
173 257 public function append_form_to_content( $content ) {
174 258
175 - // Bail if not a singular Post Type.
176 - if ( ! is_singular() ) {
259 + // Bail if not a singular Post Type supported by ConvertKit.
260 + if ( ! is_singular( convertkit_get_supported_post_types() ) ) {
177 261 return $content;
178 262 }
179 263
180 264 // Get Post ID and ConvertKit Form ID for the Post.
@@ -262,8 +346,108 @@
262 346
263 347 }
264 348
265 349 /**
350 + * Registers the ConvertKit Form block to before or after the Query Loop block, when viewing a Category archive.
351 + *
352 + * See append_form_block_on_category_archive() configures the block to display the applicable category's Form.
353 + *
354 + * @since 2.4.9.1
355 + *
356 + * @param array $hooked_blocks The list of hooked block types.
357 + * @param string $position The relative position of the hooked blocks.
358 + * @param string $anchor_block The anchor block type.
359 + * @param WP_Block_Template|WP_Post|array $context The block template, template part, wp_navigation post type, or pattern that the anchor block belongs to.
360 + * @return array
361 + */
362 + public function maybe_register_form_block_on_category_archive( $hooked_blocks, $position, $anchor_block, $context ) {
363 +
364 + // Don't append if we're not viewing a category archive.
365 + if ( ! is_category() ) {
366 + return $hooked_blocks;
367 + }
368 +
369 + if ( $context instanceof WP_Block_Template && $context->slug !== 'archive' ) {
370 + return $hooked_blocks;
371 + }
372 +
373 + // Don't append if the anchor block isn't the Query Loop block.
374 + if ( $anchor_block !== 'core/query' ) {
375 + return $hooked_blocks;
376 + }
377 +
378 + // Don't append if the Category's form position setting is not defined.
379 + $form_position = $this->get_term_form_position();
380 + if ( ! $form_position ) {
381 + // Unhook this function as we don't need to check again in this request, as we'll
382 + // never output a form on the Category archive.
383 + remove_filter( 'hooked_block_types', array( $this, 'maybe_register_form_block_on_category_archive' ), 10 );
384 +
385 + return $hooked_blocks;
386 + }
387 +
388 + // Don't append if the position doesn't match.
389 + if ( $form_position !== $position ) {
390 + return $hooked_blocks;
391 + }
392 +
393 + // Hook the ConvertKit Form block.
394 + $hooked_blocks[] = 'convertkit/form';
395 +
396 + // Unhook this function as we don't need to check again in this request, as
397 + // we have now appended the form.
398 + remove_filter( 'hooked_block_types', array( $this, 'maybe_register_form_block_on_category_archive' ), 10 );
399 +
400 + return $hooked_blocks;
401 +
402 + }
403 +
404 + /**
405 + * Configures the ConvertKit Form block that was hooked below the Query Loop block by maybe_register_form_block_on_category_archive,
406 + * defining the Form ID based on the current Category's Form ID.
407 + *
408 + * @since 2.4.9.1
409 + *
410 + * @param array $parsed_hooked_block The parsed block array for the given hooked block type, or null to suppress the block.
411 + * @return null|array
412 + */
413 + public function append_form_block_to_category_archive( $parsed_hooked_block ) {
414 +
415 + // Sanity check that we're still viewing a Category archive.
416 + if ( ! is_category() ) {
417 + // Returning null will unregister the Form block from displaying.
418 + return null;
419 + }
420 +
421 + // Get Category archive being viewed.
422 + $category = get_category( get_query_var( 'cat' ) );
423 +
424 + // Bail if the Category could be found.
425 + if ( is_wp_error( $category ) || is_null( $category ) ) {
426 + // Returning null will unregister the Form block from displaying.
427 + return null;
428 + }
429 +
430 + // Load Term Settings.
431 + $term_settings = new ConvertKit_Term( $category->term_id );
432 +
433 + // Bail if no Form specified for the Category.
434 + if ( ! $term_settings->has_form() ) {
435 + // Returning null will unregister the Form block from displaying.
436 + return null;
437 + }
438 +
439 + // Define the form block attributes to display the given Form ID.
440 + $parsed_hooked_block['attrs'] = array(
441 + 'id' => absint( $term_settings->get_form() ),
442 + );
443 +
444 + // Return the Form block with its attributes.
445 + return $parsed_hooked_block;
446 +
447 + }
448 +
449 + /**
266 450 * Returns the Post, Category or Plugin ConvertKit Form ID for the given Post.
267 451 *
268 452 * If the Post specifies a form to use, returns that Form ID.
269 453 * If the Post uses the 'Default' setting, and an assigned Category has a Form ID, uses the Category's Form ID.
@@ -337,8 +521,39 @@
337 521
338 522 }
339 523
340 524 /**
525 + * Returns the Form Position setting for the currently viewed Category.
526 + *
527 + * @since 2.4.9.1
528 + *
529 + * @return bool|string
530 + */
531 + private function get_term_form_position() {
532 +
533 + // Get Category archive being viewed.
534 + $category = get_category( get_query_var( 'cat' ) );
535 +
536 + // Bail if the Category could be found.
537 + if ( is_wp_error( $category ) || is_null( $category ) ) {
538 + return false;
539 + }
540 +
541 + // Load Term Settings.
542 + $term_settings = new ConvertKit_Term( $category->term_id );
543 +
544 + // Return false if no form position is defined i.e. we don't want to display
545 + // it on the Category archive.
546 + if ( ! $term_settings->has_form_position() ) {
547 + return false;
548 + }
549 +
550 + // Return form position.
551 + return $term_settings->get_form_position();
552 +
553 + }
554 +
555 + /**
341 556 * Enqueue scripts.
342 557 *
343 558 * @since 1.9.6
344 559 */
@@ -359,9 +574,9 @@
359 574 // Register scripts that we might use.
360 575 wp_register_script(
361 576 'convertkit-js',
362 577 CONVERTKIT_PLUGIN_URL . 'resources/frontend/js/convertkit.js',
363 - array( 'jquery' ),
578 + array(),
364 579 CONVERTKIT_PLUGIN_VERSION,
365 580 true
366 581 );
367 582 wp_localize_script(
@@ -371,10 +586,8 @@
371 586 'ajaxurl' => admin_url( 'admin-ajax.php' ),
372 587 'debug' => $settings->debug_enabled(),
373 588 'nonce' => wp_create_nonce( 'convertkit' ),
374 589 'subscriber_id' => $this->subscriber_id,
375 - 'tag' => ( ( is_singular() && $convertkit_post->has_tag() ) ? $convertkit_post->get_tag() : false ),
376 - 'post_id' => $post->ID,
377 590 )
378 591 );
379 592
380 593 // Bail if the no scripts setting is enabled.
@@ -407,8 +620,53 @@
407 620
408 621 }
409 622
410 623 /**
624 + * Outputs a non-inline form if defined in the Plugin's settings >
625 + * Default Non-Inline Form (Global) setting.
626 + *
627 + * @since 2.3.3
628 + */
629 + public function output_global_non_inline_form() {
630 +
631 + // Get Settings, if they have not yet been loaded.
632 + if ( ! $this->settings ) {
633 + $this->settings = new ConvertKit_Settings();
634 + }
635 +
636 + // Bail if no non-inline form setting is specified.
637 + if ( ! $this->settings->has_non_inline_form() ) {
638 + return;
639 + }
640 +
641 + // Get form.
642 + $convertkit_forms = new ConvertKit_Resource_Forms();
643 + $form = $convertkit_forms->get_by_id( (int) $this->settings->get_non_inline_form() );
644 +
645 + // Bail if the Form doesn't exist (this shouldn't happen, but you never know).
646 + if ( ! $form ) {
647 + return;
648 + }
649 +
650 + // Add the form to the scripts array so it is included in the output.
651 + add_filter(
652 + 'convertkit_output_scripts_footer',
653 + function ( $scripts ) use ( $form ) {
654 +
655 + $scripts[] = array(
656 + 'async' => true,
657 + 'data-uid' => $form['uid'],
658 + 'src' => $form['embed_js'],
659 + );
660 +
661 + return $scripts;
662 +
663 + }
664 + );
665 +
666 + }
667 +
668 + /**
411 669 * Outputs any JS <script> tags registered with the convertkit_output_scripts_footer
412 670 * filter
413 671 *
414 672 * @since 2.1.4
@@ -436,10 +694,19 @@
436 694 $output_scripts = array();
437 695
438 696 // Iterate through scripts, building the <script> tag for each.
439 697 foreach ( $scripts as $script ) {
698 + /**
699 + * Filter the form <script> key/value pairs immediately before the script is output.
700 + *
701 + * @since 2.4.5
702 + *
703 + * @param array $script Form script key/value pairs to output as <script> tag.
704 + */
705 + $script = apply_filters( 'convertkit_output_script_footer', $script );
706 +
707 + // Build output.
440 708 $output = '<script';
441 -
442 709 foreach ( $script as $attribute => $value ) {
443 710 // If the value is true, just output the attribute.
444 711 if ( $value === true ) {
445 712 $output .= ' ' . esc_attr( $attribute );
@@ -445,11 +712,21 @@
445 712 $output .= ' ' . esc_attr( $attribute );
446 713 continue;
447 714 }
448 715
716 + // Sanitize attribute and value.
717 + $attribute = esc_attr( $attribute );
718 + $value = ( $attribute === 'src' ? esc_url( $value ) : esc_attr( $value ) );
719 +
449 720 // Output the attribute and value.
450 - $output .= ' ' . esc_attr( $attribute ) . '="' . esc_attr( $value ) . '"';
721 + $output .= ' ' . $attribute;
722 +
723 + // Output the value, if it's not a blank string.
724 + if ( strlen( $value ) > 0 ) {
725 + $output .= '="' . $value . '"';
726 + }
451 727 }
728 +
452 729 $output .= '></script>';
453 730
454 731 // Add to array.
455 732 $output_scripts[] = $output;