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 +282 -8 2.3.02.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
@@ -159,8 +225,23 @@
159 225
160 226 // Replace the favicon with the WordPress site's favicon, if specified.
161 227 $landing_page = $this->landing_pages->replace_favicon( $landing_page );
162 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 +
163 244 // Output Landing Page.
164 245 // Output is supplied from ConvertKit's API, which is already sanitized.
165 246 echo $landing_page; // phpcs:ignore WordPress.Security.EscapeOutput
166 247 exit;
@@ -174,10 +255,10 @@
174 255 * @return string Post Content with Form Appended, if applicable
175 256 */
176 257 public function append_form_to_content( $content ) {
177 258
178 - // Bail if not a singular Post Type.
179 - if ( ! is_singular() ) {
259 + // Bail if not a singular Post Type supported by ConvertKit.
260 + if ( ! is_singular( convertkit_get_supported_post_types() ) ) {
180 261 return $content;
181 262 }
182 263
183 264 // Get Post ID and ConvertKit Form ID for the Post.
@@ -265,8 +346,108 @@
265 346
266 347 }
267 348
268 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 + /**
269 450 * Returns the Post, Category or Plugin ConvertKit Form ID for the given Post.
270 451 *
271 452 * If the Post specifies a form to use, returns that Form ID.
272 453 * If the Post uses the 'Default' setting, and an assigned Category has a Form ID, uses the Category's Form ID.
@@ -340,8 +521,39 @@
340 521
341 522 }
342 523
343 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 + /**
344 556 * Enqueue scripts.
345 557 *
346 558 * @since 1.9.6
347 559 */
@@ -362,9 +574,9 @@
362 574 // Register scripts that we might use.
363 575 wp_register_script(
364 576 'convertkit-js',
365 577 CONVERTKIT_PLUGIN_URL . 'resources/frontend/js/convertkit.js',
366 - array( 'jquery' ),
578 + array(),
367 579 CONVERTKIT_PLUGIN_VERSION,
368 580 true
369 581 );
370 582 wp_localize_script(
@@ -374,10 +586,8 @@
374 586 'ajaxurl' => admin_url( 'admin-ajax.php' ),
375 587 'debug' => $settings->debug_enabled(),
376 588 'nonce' => wp_create_nonce( 'convertkit' ),
377 589 'subscriber_id' => $this->subscriber_id,
378 - 'tag' => ( ( is_singular() && $convertkit_post->has_tag() ) ? $convertkit_post->get_tag() : false ),
379 - 'post_id' => $post->ID,
380 590 )
381 591 );
382 592
383 593 // Bail if the no scripts setting is enabled.
@@ -410,8 +620,53 @@
410 620
411 621 }
412 622
413 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 + /**
414 669 * Outputs any JS <script> tags registered with the convertkit_output_scripts_footer
415 670 * filter
416 671 *
417 672 * @since 2.1.4
@@ -439,10 +694,19 @@
439 694 $output_scripts = array();
440 695
441 696 // Iterate through scripts, building the <script> tag for each.
442 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.
443 708 $output = '<script';
444 -
445 709 foreach ( $script as $attribute => $value ) {
446 710 // If the value is true, just output the attribute.
447 711 if ( $value === true ) {
448 712 $output .= ' ' . esc_attr( $attribute );
@@ -448,11 +712,21 @@
448 712 $output .= ' ' . esc_attr( $attribute );
449 713 continue;
450 714 }
451 715
716 + // Sanitize attribute and value.
717 + $attribute = esc_attr( $attribute );
718 + $value = ( $attribute === 'src' ? esc_url( $value ) : esc_attr( $value ) );
719 +
452 720 // Output the attribute and value.
453 - $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 + }
454 727 }
728 +
455 729 $output .= '></script>';
456 730
457 731 // Add to array.
458 732 $output_scripts[] = $output;