← 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 | } |