PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 3.4.6
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v3.4.6
3.4.6 3.4.5 3.4.4 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 All 199 releases
← All changes | includes/blocks/class-convertkit-block-form-builder.php +83 -23 3.4.4 → 3.4.6 View file →
@@ -35,9 +35,9 @@
35 35 public $error = false;
36 36
37 37 /**
38 38 * Holds the number of times this block has been rendered on the Post,
39 - * to ensure error notice IDs are unique.
39 + * used to identify each block on the page and ensure error notice IDs are unique.
40 40 *
41 41 * @since 3.4.4
42 42 *
43 43 * @var int
@@ -44,8 +44,18 @@
44 44 */
45 45 public $render_count = 0;
46 46
47 47 /**
48 + * Holds the index of the block that was submitted, so the error notice
49 + * is only displayed on that block.
50 + *
51 + * @since 3.4.6
52 + *
53 + * @var int
54 + */
55 + public $submitted_block_index = 0;
56 +
57 + /**
48 58 * Constructor
49 59 *
50 60 * @since 3.0.0
51 61 */
@@ -96,8 +106,13 @@
96 106 if ( ! array_key_exists( 'post_id', $_REQUEST['convertkit'] ) ) {
97 107 return;
98 108 }
99 109
110 + // Store the submitted block's index, so any error is only displayed on that block.
111 + if ( array_key_exists( 'block_index', $_REQUEST['convertkit'] ) ) {
112 + $this->submitted_block_index = absint( $_REQUEST['convertkit']['block_index'] );
113 + }
114 +
100 115 // Check spam protection.
101 116 $spam_protection = new ConvertKit_Spam_Protection();
102 117
103 118 // Bail if spam protection failed.
@@ -125,12 +140,15 @@
125 140 if ( array_key_exists( 'custom_fields', $form_data ) ) {
126 141 $custom_fields = $form_data['custom_fields'];
127 142 }
128 143
144 + // Get First Name, if the Name field was included in the form.
145 + $first_name = array_key_exists( 'first_name', $form_data ) ? $form_data['first_name'] : '';
146 +
129 147 // Get Form, Tag and Sequence IDs, if any were specified.
130 - $form_id = array_key_exists( 'form_id', $form_data ) ? $form_data['form_id'] : false;
131 - $tag_id = array_key_exists( 'tag_id', $form_data ) ? $form_data['tag_id'] : false;
132 - $sequence_id = array_key_exists( 'sequence_id', $form_data ) ? $form_data['sequence_id'] : false;
148 + $form_id = array_key_exists( 'form_id', $form_data ) ? absint( $form_data['form_id'] ) : 0;
149 + $tag_id = array_key_exists( 'tag_id', $form_data ) ? absint( $form_data['tag_id'] ) : 0;
150 + $sequence_id = array_key_exists( 'sequence_id', $form_data ) ? absint( $form_data['sequence_id'] ) : 0;
133 151
134 152 // Initialize classes that will be used.
135 153 $settings = new ConvertKit_Settings();
136 154 $entries = new ConvertKit_Form_Entries();
@@ -142,9 +160,9 @@
142 160 $entries->upsert(
143 161 array(
144 162 'post_id' => $form_data['post_id'],
145 163 'email' => $form_data['email'],
146 - 'first_name' => $form_data['first_name'],
164 + 'first_name' => $first_name,
147 165 'custom_fields' => $custom_fields,
148 166 'form_id' => $form_id,
149 167 'tag_id' => $tag_id,
150 168 'sequence_id' => $sequence_id,
@@ -173,14 +191,14 @@
173 191
174 192 // Determine the subscriber state.
175 193 // If a Form is specified, mark the subscriber as inactive, so the form's double optin is honored.
176 194 // If a Tag or Sequence is specified, mark the subscriber as active, as there's no double optin for tags or sequences.
177 - $subscriber_state = $form_id !== false ? 'inactive' : 'active';
195 + $subscriber_state = $form_id ? 'inactive' : 'active';
178 196
179 197 // Create subscriber.
180 198 $result = $api->create_subscriber(
181 199 sanitize_email( $form_data['email'] ),
182 - array_key_exists( 'first_name', $form_data ) ? $form_data['first_name'] : '',
200 + $first_name,
183 201 $subscriber_state,
184 202 $custom_fields
185 203 );
186 204
@@ -191,9 +209,9 @@
191 209 $entries->upsert(
192 210 array(
193 211 'post_id' => $form_data['post_id'],
194 212 'email' => $form_data['email'],
195 - 'first_name' => $form_data['first_name'],
213 + 'first_name' => $first_name,
196 214 'custom_fields' => $custom_fields,
197 215 'form_id' => $form_id,
198 216 'tag_id' => $tag_id,
199 217 'sequence_id' => $sequence_id,
@@ -212,9 +230,9 @@
212 230 $entries->upsert(
213 231 array(
214 232 'post_id' => $form_data['post_id'],
215 233 'email' => $form_data['email'],
216 - 'first_name' => $form_data['first_name'],
234 + 'first_name' => $first_name,
217 235 'custom_fields' => $custom_fields,
218 236 'form_id' => $form_id,
219 237 'tag_id' => $tag_id,
220 238 'sequence_id' => $sequence_id,
@@ -222,11 +240,14 @@
222 240 )
223 241 );
224 242 }
225 243
244 + // Get the subscriber ID, as $result is overwritten by the form, tag and sequence requests below.
245 + $subscriber_id = $result['subscriber']['id'];
246 +
226 247 // Store the subscriber ID in a cookie.
227 248 $subscriber = new ConvertKit_Subscriber();
228 - $subscriber->set( $result['subscriber']['id'] );
249 + $subscriber->set( $subscriber_id );
229 250
230 251 // If a form was specified, add the subscriber to the form.
231 252 if ( $form_id ) {
232 253 // For Legacy Forms, a different endpoint is used.
@@ -233,14 +254,14 @@
233 254 $forms = new ConvertKit_Resource_Forms();
234 255 if ( $forms->is_legacy( $form_id ) ) {
235 256 $result = $api->add_subscriber_to_legacy_form(
236 257 $form_id,
237 - $result['subscriber']['id']
258 + $subscriber_id
238 259 );
239 260 } else {
240 261 $result = $api->add_subscriber_to_form(
241 262 $form_id,
242 - $result['subscriber']['id'],
263 + $subscriber_id,
243 264 get_permalink( absint( $form_data['post_id'] ) )
244 265 );
245 266 }
246 267
@@ -248,9 +269,9 @@
248 269 $entries->upsert(
249 270 array(
250 271 'post_id' => $form_data['post_id'],
251 272 'email' => $form_data['email'],
252 - 'first_name' => $form_data['first_name'],
273 + 'first_name' => $first_name,
253 274 'custom_fields' => $custom_fields,
254 275 'form_id' => $form_id,
255 276 'tag_id' => $tag_id,
256 277 'sequence_id' => $sequence_id,
@@ -262,9 +283,9 @@
262 283 }
263 284
264 285 // If a tag was specified, add the subscriber to the tag.
265 286 if ( $tag_id ) {
266 - $result = $api->tag_subscriber( $tag_id, $result['subscriber']['id'] );
287 + $result = $api->tag_subscriber( $tag_id, $subscriber_id );
267 288
268 289 if ( $form_data['store_entries'] ) {
269 290 $entries->upsert(
270 291 array(
@@ -269,9 +290,9 @@
269 290 $entries->upsert(
270 291 array(
271 292 'post_id' => $form_data['post_id'],
272 293 'email' => $form_data['email'],
273 - 'first_name' => $form_data['first_name'],
294 + 'first_name' => $first_name,
274 295 'custom_fields' => $custom_fields,
275 296 'form_id' => $form_id,
276 297 'tag_id' => $tag_id,
277 298 'sequence_id' => $sequence_id,
@@ -283,9 +304,9 @@
283 304 }
284 305
285 306 // If a sequence was specified, add the subscriber to the sequence.
286 307 if ( $sequence_id ) {
287 - $result = $api->add_subscriber_to_sequence( $sequence_id, $result['subscriber']['id'] );
308 + $result = $api->add_subscriber_to_sequence( $sequence_id, $subscriber_id );
288 309
289 310 if ( $form_data['store_entries'] ) {
290 311 $entries->upsert(
291 312 array(
@@ -290,9 +311,9 @@
290 311 $entries->upsert(
291 312 array(
292 313 'post_id' => $form_data['post_id'],
293 314 'email' => $form_data['email'],
294 - 'first_name' => $form_data['first_name'],
315 + 'first_name' => $first_name,
295 316 'custom_fields' => $custom_fields,
296 317 'form_id' => $form_id,
297 318 'tag_id' => $tag_id,
298 319 'sequence_id' => $sequence_id,
@@ -308,10 +329,10 @@
308 329 if ( array_key_exists( 'redirect', $form_data ) && wp_http_validate_url( sanitize_url( $form_data['redirect'] ) ) ) {
309 330 // Redirect to the URL specified in the form.
310 331 $redirect = sanitize_url( $form_data['redirect'] );
311 332 } else {
312 - // Redirect to the Post the form was displayed on, to show a success message.
313 - $redirect = get_permalink( absint( $form_data['post_id'] ) );
333 + // Redirect to the page the form was displayed on, to show a success message.
334 + $redirect = $this->get_current_url( absint( $form_data['post_id'] ) );
314 335 }
315 336
316 337 // Redirect.
317 338 wp_redirect( $redirect ); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
@@ -714,8 +735,11 @@
714 735
715 736 // Get Post ID.
716 737 $post_id = is_a( $post, 'WP_Post' ) ? $post->ID : 0;
717 738
739 + // Increment the render count, used to identify this block on the page.
740 + ++$this->render_count;
741 +
718 742 // Parse attributes, defining fallback defaults if required
719 743 // and moving some attributes (such as Gutenberg's styles), if defined.
720 744 $atts = $this->sanitize_and_declare_atts( $atts );
721 745
@@ -825,9 +849,9 @@
825 849 }
826 850
827 851 // Create form element.
828 852 $form = $parser->html->createElement( 'form' );
829 - $form->setAttribute( 'action', esc_url( get_permalink( $post_id ) ) );
853 + $form->setAttribute( 'action', esc_url( $this->get_current_url( $post_id ) ) );
830 854 $form->setAttribute( 'method', 'post' );
831 855
832 856 // Move form builder div contents into form.
833 857 while ( $block_container->hasChildNodes() ) {
@@ -833,8 +857,22 @@
833 857 while ( $block_container->hasChildNodes() ) {
834 858 $form->appendChild( $block_container->firstChild ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
835 859 }
836 860
861 + // Suffix field IDs and labels with the block's index from the second block onwards,
862 + // so IDs are unique when multiple blocks are on the same page.
863 + if ( $this->render_count > 1 ) {
864 + foreach ( $parser->xpath->query( './/*[starts-with(@id, "kit-form-builder-")]', $form ) as $element ) {
865 + $id = $element->getAttribute( 'id' ); // @phpstan-ignore-line
866 + $new_id = $id . '-' . $this->render_count;
867 + $element->setAttribute( 'id', $new_id ); // @phpstan-ignore-line
868 +
869 + foreach ( $parser->xpath->query( './/label[@for="' . $id . '"]', $form ) as $label ) {
870 + $label->setAttribute( 'for', $new_id ); // @phpstan-ignore-line
871 + }
872 + }
873 + }
874 +
837 875 // Add subscribed message if required.
838 876 if ( $this->subscriber_id ) {
839 877 $subscribed_message = $parser->html->createElement( 'div' );
840 878 $subscribed_message->setAttribute( 'class', 'convertkit-form-builder-subscribed-message' );
@@ -841,11 +879,11 @@
841 879 $subscribed_message->appendChild( $parser->html->createTextNode( $atts['text_if_subscribed'] ) );
842 880 $form->insertBefore( $subscribed_message, $form->firstChild ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
843 881 }
844 882
845 - // Add error notice if the submission failed.
846 - if ( is_wp_error( $this->error ) ) {
847 - ++$this->render_count;
883 + // Add error notice if the submission failed, and this is the submitted block.
884 + // If no block index was submitted (e.g. a cached page from an older version), display it on all blocks.
885 + if ( is_wp_error( $this->error ) && ( ! $this->submitted_block_index || $this->submitted_block_index === $this->render_count ) ) {
848 886 $error_id = 'convertkit-form-builder-error-' . $this->render_count;
849 887
850 888 $error_notice = $parser->html->createElement( 'div' );
851 889 $error_notice->setAttribute( 'id', $error_id );
@@ -876,8 +914,9 @@
876 914 'convertkit[redirect]' => esc_url( $atts['redirect'] ),
877 915 'convertkit[form_id]' => absint( $atts['form_id'] ),
878 916 'convertkit[tag_id]' => absint( $atts['tag_id'] ),
879 917 'convertkit[sequence_id]' => absint( $atts['sequence_id'] ),
918 + 'convertkit[block_index]' => absint( $this->render_count ),
880 919 '_wpnonce' => wp_create_nonce( 'convertkit_block_form_builder' ),
881 920 );
882 921 foreach ( $fields as $name => $value ) {
883 922 $hidden = $parser->html->createElement( 'input' );
@@ -891,8 +930,29 @@
891 930 $block_container->appendChild( $form );
892 931
893 932 // Return modified content.
894 933 return $parser->get_body_html();
934 +
935 + }
936 +
937 + /**
938 + * Returns the URL of the page the form is displayed on, so the form submits
939 + * back to the same page, falling back to the Post's URL.
940 + *
941 + * @since 3.4.6
942 + *
943 + * @param int $post_id Post ID.
944 + * @return string
945 + */
946 + private function get_current_url( $post_id ) {
947 +
948 + // Fallback to the Post's URL if the request URI isn't available.
949 + if ( ! isset( $_SERVER['REQUEST_URI'] ) ) {
950 + return get_permalink( $post_id );
951 + }
952 +
953 + // Remove the subscriber ID, which is only used when visiting a link from a Kit email.
954 + return remove_query_arg( 'ck_subscriber_id', esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
895 955
896 956 }
897 957
898 958 }