| @@ -26,8 +26,11 @@ | ||
| 26 | 26 | |
| 27 | 27 | // Register this as a Gutenberg block in the ConvertKit Plugin. |
| 28 | 28 | add_filter( 'convertkit_blocks', array( $this, 'register' ) ); |
| 29 | 29 | |
| 30 | + // Register this block's MCP abilities. | |
| 31 | + add_filter( 'convertkit_abilities', array( $this, 'register_abilities' ) ); | |
| 32 | + | |
| 30 | 33 | // Enqueue scripts for this Gutenberg Block in the editor view. |
| 31 | 34 | add_action( 'convertkit_gutenberg_enqueue_scripts', array( $this, 'enqueue_scripts_editor' ) ); |
| 32 | 35 | |
| 33 | 36 | // Enqueue styles for this Gutenberg Block in the editor view. |
| @@ -32,8 +35,11 @@ | ||
| 32 | 35 | |
| 33 | 36 | // Enqueue styles for this Gutenberg Block in the editor view. |
| 34 | 37 | add_action( 'convertkit_gutenberg_enqueue_styles', array( $this, 'enqueue_styles_editor' ) ); |
| 35 | 38 | |
| 39 | + // Enqueue scripts and styles for this Gutenberg Block in the editor and frontend views. | |
| 40 | + add_action( 'convertkit_gutenberg_enqueue_styles_editor_and_frontend', array( $this, 'enqueue_styles' ) ); | |
| 41 | + | |
| 36 | 42 | } |
| 37 | 43 | |
| 38 | 44 | /** |
| 39 | 45 | * Enqueues scripts for this Gutenberg Block in the editor view. |
| @@ -57,8 +63,19 @@ | ||
| 57 | 63 | |
| 58 | 64 | } |
| 59 | 65 | |
| 60 | 66 | /** |
| 67 | + * Enqueues styles for this Gutenberg Block in the editor and frontend views. | |
| 68 | + * | |
| 69 | + * @since 2.3.3 | |
| 70 | + */ | |
| 71 | + public function enqueue_styles() { | |
| 72 | + | |
| 73 | + convertkit_enqueue_frontend_css(); | |
| 74 | + | |
| 75 | + } | |
| 76 | + | |
| 77 | + /** | |
| 61 | 78 | * Returns this block's programmatic name, excluding the convertkit- prefix. |
| 62 | 79 | * |
| 63 | 80 | * @since 1.9.6 |
| 64 | 81 | * |
| @@ -76,8 +93,43 @@ | ||
| 76 | 93 | |
| 77 | 94 | } |
| 78 | 95 | |
| 79 | 96 | /** |
| 97 | + * Returns this block's title. | |
| 98 | + * | |
| 99 | + * @since 3.1.1 | |
| 100 | + */ | |
| 101 | + public function get_title() { | |
| 102 | + | |
| 103 | + return __( 'Kit Form', 'convertkit' ); | |
| 104 | + | |
| 105 | + } | |
| 106 | + | |
| 107 | + /** | |
| 108 | + * Returns this block's plural title. | |
| 109 | + * | |
| 110 | + * @since 3.4.0 | |
| 111 | + * | |
| 112 | + * @return string | |
| 113 | + */ | |
| 114 | + public function get_title_plural() { | |
| 115 | + | |
| 116 | + return __( 'Kit Forms', 'convertkit' ); | |
| 117 | + | |
| 118 | + } | |
| 119 | + | |
| 120 | + /** | |
| 121 | + * Returns this block's icon. | |
| 122 | + * | |
| 123 | + * @since 3.1.1 | |
| 124 | + */ | |
| 125 | + public function get_icon() { | |
| 126 | + | |
| 127 | + return 'resources/backend/images/block-icon-form.svg'; | |
| 128 | + | |
| 129 | + } | |
| 130 | + | |
| 131 | + /** | |
| 80 | 132 | * Returns this block's Title, Icon, Categories, Keywords and properties. |
| 81 | 133 | * |
| 82 | 134 | * @since 1.9.6 |
| 83 | 135 | * |
| @@ -88,14 +140,15 @@ | ||
| 88 | 140 | $convertkit_forms = new ConvertKit_Resource_Forms( 'block_edit' ); |
| 89 | 141 | $settings = new ConvertKit_Settings(); |
| 90 | 142 | |
| 91 | 143 | return array( |
| 92 | - 'title' => __( 'ConvertKit Form', 'convertkit' ), | |
| 93 | - 'description' => __( 'Displays a ConvertKit Form.', 'convertkit' ), | |
| 94 | - 'icon' => 'resources/backend/images/block-icon-form.svg', | |
| 144 | + 'title' => $this->get_title(), | |
| 145 | + 'description' => __( 'Displays a Kit Form.', 'convertkit' ), | |
| 146 | + 'icon' => $this->get_icon(), | |
| 95 | 147 | 'category' => 'convertkit', |
| 96 | 148 | 'keywords' => array( |
| 97 | 149 | __( 'ConvertKit', 'convertkit' ), |
| 150 | + __( 'Kit', 'convertkit' ), | |
| 98 | 151 | __( 'Form', 'convertkit' ), |
| 99 | 152 | ), |
| 100 | 153 | |
| 101 | 154 | // Function to call when rendering as a block or a shortcode on the frontend web site. |
| @@ -103,9 +156,9 @@ | ||
| 103 | 156 | |
| 104 | 157 | // Shortcode: TinyMCE / QuickTags Modal Width and Height. |
| 105 | 158 | 'modal' => array( |
| 106 | 159 | 'width' => 500, |
| 107 | - 'height' => 106, | |
| 160 | + 'height' => 55, | |
| 108 | 161 | ), |
| 109 | 162 | |
| 110 | 163 | // Shortcode: Include a closing [/shortcode] tag when using TinyMCE or QuickTag Modals. |
| 111 | 164 | 'shortcode_include_closing_tag' => false, |
| @@ -116,17 +169,19 @@ | ||
| 116 | 169 | // Gutenberg: Example image showing how this block looks when choosing it in Gutenberg. |
| 117 | 170 | 'gutenberg_example_image' => CONVERTKIT_PLUGIN_URL . 'resources/backend/images/block-example-form.png', |
| 118 | 171 | |
| 119 | 172 | // Help descriptions, displayed when no API key / resources exist and this block/shortcode is added. |
| 120 | - 'no_api_key' => array( | |
| 121 | - 'notice' => __( 'No API Key specified.', 'convertkit' ), | |
| 122 | - 'link' => convertkit_get_setup_wizard_plugin_link(), | |
| 123 | - 'link_text' => __( 'Click here to add your API Key.', 'convertkit' ), | |
| 173 | + 'no_access_token' => array( | |
| 174 | + 'notice' => __( 'Not connected to Kit.', 'convertkit' ), | |
| 175 | + 'link' => convertkit_get_setup_wizard_plugin_link(), | |
| 176 | + 'link_text' => __( 'Click here to connect your Kit account.', 'convertkit' ), | |
| 177 | + 'instruction_text' => __( 'Connect your Kit account at Settings > Kit, and then refresh this page to select a form.', 'convertkit' ), | |
| 124 | 178 | ), |
| 125 | 179 | 'no_resources' => array( |
| 126 | - 'notice' => __( 'No forms exist in ConvertKit.', 'convertkit' ), | |
| 127 | - 'link' => convertkit_get_new_form_url(), | |
| 128 | - 'link_text' => __( 'Click here to create your first form.', 'convertkit' ), | |
| 180 | + 'notice' => __( 'No forms exist in Kit.', 'convertkit' ), | |
| 181 | + 'link' => convertkit_get_new_form_url(), | |
| 182 | + 'link_text' => __( 'Click here to create your first form.', 'convertkit' ), | |
| 183 | + 'instruction_text' => __( 'Add a form to your Kit account, and then refresh this page to select a form.', 'convertkit' ), | |
| 129 | 184 | ), |
| 130 | 185 | |
| 131 | 186 | // Gutenberg: Help descriptions, displayed when no settings defined for a newly added Block. |
| 132 | 187 | 'gutenberg_help_description' => __( 'Select a Form using the Form option in the Gutenberg sidebar.', 'convertkit' ), |
| @@ -148,9 +203,9 @@ | ||
| 148 | 203 | ), |
| 149 | 204 | |
| 150 | 205 | // Whether an API Key exists in the Plugin, and are the required resources (forms) available. |
| 151 | 206 | // If no API Key is specified in the Plugin's settings, render the "No API Key" output. |
| 152 | - 'has_api_key' => $settings->has_api_key_and_secret(), | |
| 207 | + 'has_access_token' => $settings->has_access_and_refresh_token(), | |
| 153 | 208 | 'has_resources' => $convertkit_forms->exist(), |
| 154 | 209 | ); |
| 155 | 210 | |
| 156 | 211 | } |
| @@ -168,8 +223,19 @@ | ||
| 168 | 223 | 'form' => array( |
| 169 | 224 | 'type' => 'string', |
| 170 | 225 | ), |
| 171 | 226 | |
| 227 | + // get_supports() style, color and typography attributes. | |
| 228 | + 'align' => array( | |
| 229 | + 'type' => 'string', | |
| 230 | + ), | |
| 231 | + 'style' => array( | |
| 232 | + 'type' => 'object', | |
| 233 | + ), | |
| 234 | + 'backgroundColor' => array( | |
| 235 | + 'type' => 'string', | |
| 236 | + ), | |
| 237 | + | |
| 172 | 238 | // Always required for Gutenberg. |
| 173 | 239 | 'is_gutenberg_example' => array( |
| 174 | 240 | 'type' => 'boolean', |
| 175 | 241 | 'default' => false, |
| @@ -178,8 +244,33 @@ | ||
| 178 | 244 | |
| 179 | 245 | } |
| 180 | 246 | |
| 181 | 247 | /** |
| 248 | + * Returns this block's supported built-in Attributes. | |
| 249 | + * | |
| 250 | + * @since 1.9.7.4 | |
| 251 | + * | |
| 252 | + * @return array Supports | |
| 253 | + */ | |
| 254 | + public function get_supports() { | |
| 255 | + | |
| 256 | + return array( | |
| 257 | + 'align' => true, | |
| 258 | + 'className' => true, | |
| 259 | + 'color' => array( | |
| 260 | + 'link' => false, | |
| 261 | + 'background' => true, | |
| 262 | + 'text' => false, | |
| 263 | + ), | |
| 264 | + 'spacing' => array( | |
| 265 | + 'margin' => true, | |
| 266 | + 'padding' => true, | |
| 267 | + ), | |
| 268 | + ); | |
| 269 | + | |
| 270 | + } | |
| 271 | + | |
| 272 | + /** | |
| 182 | 273 | * Returns this block's Fields |
| 183 | 274 | * |
| 184 | 275 | * @since 1.9.6 |
| 185 | 276 | * |
| @@ -186,31 +277,44 @@ | ||
| 186 | 277 | * @return bool|array |
| 187 | 278 | */ |
| 188 | 279 | public function get_fields() { |
| 189 | 280 | |
| 190 | - // Bail if the request is not for the WordPress Administration or frontend editor. | |
| 191 | - if ( ! WP_ConvertKit()->is_admin_or_frontend_editor() ) { | |
| 192 | - return false; | |
| 193 | - } | |
| 194 | - | |
| 195 | - // Get ConvertKit Forms. | |
| 281 | + // Get ConvertKit Forms. Non-legacy forms populate the sidebar dropdown; | |
| 282 | + // legacy forms are exposed separately as a fallback so the sidebar can | |
| 283 | + // keep displaying a previously-saved legacy form as the current | |
| 284 | + // selection without offering other legacy forms as new choices. | |
| 196 | 285 | $forms = array(); |
| 286 | + $legacy_forms = array(); | |
| 197 | 287 | $convertkit_forms = new ConvertKit_Resource_Forms( 'block_edit' ); |
| 198 | 288 | if ( $convertkit_forms->exist() ) { |
| 199 | 289 | foreach ( $convertkit_forms->get() as $form ) { |
| 200 | - $forms[ absint( $form['id'] ) ] = sanitize_text_field( $form['name'] ); | |
| 290 | + $label = sprintf( | |
| 291 | + '%s [%s]', | |
| 292 | + sanitize_text_field( $form['name'] ), | |
| 293 | + // Legacy forms don't include a `format` key, so define them as inline. | |
| 294 | + ( ! empty( $form['format'] ) ? sanitize_text_field( $form['format'] ) : 'inline' ) | |
| 295 | + ); | |
| 296 | + | |
| 297 | + if ( ! empty( $form['format'] ) ) { | |
| 298 | + $forms[ absint( $form['id'] ) ] = $label; | |
| 299 | + } else { | |
| 300 | + $legacy_forms[ absint( $form['id'] ) ] = $label; | |
| 301 | + } | |
| 201 | 302 | } |
| 202 | 303 | } |
| 203 | 304 | |
| 204 | 305 | return array( |
| 205 | 306 | 'form' => array( |
| 206 | - 'label' => __( 'Form', 'convertkit' ), | |
| 207 | - 'type' => 'select', | |
| 208 | - 'values' => $forms, | |
| 209 | - 'data' => array( | |
| 307 | + 'label' => __( 'Form', 'convertkit' ), | |
| 308 | + 'type' => 'resource', | |
| 309 | + 'resource' => 'forms', | |
| 310 | + 'values' => $forms, | |
| 311 | + 'legacy_values' => $legacy_forms, | |
| 312 | + 'data' => array( | |
| 210 | 313 | // Used by resources/backend/js/gutenberg-block-form.js to determine the selected form's format |
| 211 | 314 | // (modal, slide in, sticky bar) and output a message in the block editor for the preview to explain |
| 212 | - // why some formats cannot be previewed. | |
| 315 | + // why some formats cannot be previewed. Includes legacy forms so the preview code can still find | |
| 316 | + // them when a saved block references a legacy form. | |
| 213 | 317 | 'forms' => ( $convertkit_forms->exist() ? $convertkit_forms->get() : array() ), |
| 214 | 318 | ), |
| 215 | 319 | ), |
| 216 | 320 | ); |
| @@ -225,13 +329,8 @@ | ||
| 225 | 329 | * @return bool|array |
| 226 | 330 | */ |
| 227 | 331 | public function get_panels() { |
| 228 | 332 | |
| 229 | - // Bail if the request is not for the WordPress Administration or frontend editor. | |
| 230 | - if ( ! WP_ConvertKit()->is_admin_or_frontend_editor() ) { | |
| 231 | - return false; | |
| 232 | - } | |
| 233 | - | |
| 234 | 333 | return array( |
| 235 | 334 | 'general' => array( |
| 236 | 335 | 'label' => __( 'General', 'convertkit' ), |
| 237 | 336 | 'fields' => array( |
| @@ -267,8 +366,19 @@ | ||
| 267 | 366 | * @return string Output |
| 268 | 367 | */ |
| 269 | 368 | public function render( $atts ) { |
| 270 | 369 | |
| 370 | + global $post; | |
| 371 | + | |
| 372 | + $post_id = is_a( $post, 'WP_Post' ) ? $post->ID : 0; | |
| 373 | + | |
| 374 | + // Check if the Block Visibility Plugin permits displaying this block. | |
| 375 | + if ( ! $this->is_block_visible( $atts ) ) { | |
| 376 | + // Block should not be displayed due to Block Visibility Plugin conditions. | |
| 377 | + // Return a blank string now. | |
| 378 | + return ''; | |
| 379 | + } | |
| 380 | + | |
| 271 | 381 | // Parse shortcode attributes, defining fallback defaults if required. |
| 272 | 382 | $atts = shortcode_atts( |
| 273 | 383 | $this->get_default_values(), |
| 274 | 384 | $this->sanitize_atts( $atts ), |
| @@ -297,22 +407,32 @@ | ||
| 297 | 407 | } |
| 298 | 408 | |
| 299 | 409 | // Get Form HTML. |
| 300 | 410 | $forms = new ConvertKit_Resource_Forms( 'output_form' ); |
| 301 | - $form = $forms->get_html( $form_id ); | |
| 411 | + $form = $forms->get_html( $form_id, $post_id ); | |
| 302 | 412 | |
| 303 | - // If an error occured, it might be that we're requesting a Form ID that exists in ConvertKit | |
| 413 | + // If an error occurred, it might be that we're requesting a Form ID that exists in ConvertKit | |
| 304 | 414 | // but does not yet exist in the Plugin's Form Resources. |
| 305 | 415 | // If so, refresh the Form Resources and try again. |
| 306 | - if ( is_wp_error( $form ) ) { | |
| 416 | + if ( is_wp_error( $form ) && $form->get_error_data() === 404 ) { | |
| 307 | 417 | // Refresh Forms from the API. |
| 308 | - $forms->refresh(); | |
| 418 | + $result = $forms->refresh(); | |
| 309 | 419 | |
| 420 | + // Bail if an error occurred. | |
| 421 | + if ( is_wp_error( $result ) ) { | |
| 422 | + if ( $settings->debug_enabled() ) { | |
| 423 | + return '<!-- ' . $result->get_error_message() . ' --> <!-- ' . $form->get_error_message() . ' -->'; | |
| 424 | + } | |
| 425 | + | |
| 426 | + return ''; | |
| 427 | + } | |
| 428 | + | |
| 429 | + // Refresh succeeded. | |
| 310 | 430 | // Get Form HTML again. |
| 311 | - $form = $forms->get_html( $form_id ); | |
| 431 | + $form = $forms->get_html( $form_id, $post_id ); | |
| 312 | 432 | } |
| 313 | 433 | |
| 314 | - // If an error still occured, the shortcode might be from the ConvertKit App for a Legacy Form ID | |
| 434 | + // If an error still occurred, the shortcode might be from the ConvertKit App for a Legacy Form ID | |
| 315 | 435 | // These ConvertKit App shortcodes, for some reason, use a different Form ID than the one presented |
| 316 | 436 | // to us in the API. |
| 317 | 437 | // For example, a Legacy Form ID might be 470099, but the ConvertKit app says to use the shortcode [convertkit form=5281783]). |
| 318 | 438 | // In this instance, fetch the Form HTML without checking that the Form ID exists in the Form Resources. |
| @@ -317,12 +437,19 @@ | ||
| 317 | 437 | // For example, a Legacy Form ID might be 470099, but the ConvertKit app says to use the shortcode [convertkit form=5281783]). |
| 318 | 438 | // In this instance, fetch the Form HTML without checking that the Form ID exists in the Form Resources. |
| 319 | 439 | if ( is_wp_error( $form ) ) { |
| 320 | 440 | // Initialize the API. |
| 321 | - $api = new ConvertKit_API( $settings->get_api_key(), $settings->get_api_secret(), $settings->debug_enabled(), 'output_form' ); | |
| 441 | + $api = new ConvertKit_API_V4( | |
| 442 | + CONVERTKIT_OAUTH_CLIENT_ID, | |
| 443 | + CONVERTKIT_OAUTH_CLIENT_REDIRECT_URI, | |
| 444 | + $settings->get_access_token(), | |
| 445 | + $settings->get_refresh_token(), | |
| 446 | + $settings->debug_enabled(), | |
| 447 | + 'output_form' | |
| 448 | + ); | |
| 322 | 449 | |
| 323 | 450 | // Return Legacy Form HTML from the API, which bypasses any internal Plugin check to see if the Form ID exists. |
| 324 | - $form = $api->get_form_html( $form_id ); | |
| 451 | + $form = $api->get_form_html( $form_id, $settings->get_api_key() ); | |
| 325 | 452 | } |
| 326 | 453 | |
| 327 | 454 | // Finally, if we still get an error, there's nothing more we can do. The Form ID isn't valid. |
| 328 | 455 | if ( is_wp_error( $form ) ) { |
| @@ -330,8 +457,22 @@ | ||
| 330 | 457 | return '<!-- ' . $form->get_error_message() . ' -->'; |
| 331 | 458 | } |
| 332 | 459 | |
| 333 | 460 | return ''; |
| 461 | + } | |
| 462 | + | |
| 463 | + // Build HTML. | |
| 464 | + // For the block editor, don't include compiled CSS classes and styles, | |
| 465 | + // as the block editor will add these to the parent container. | |
| 466 | + // Otherwise the block will render incorrectly with double padding, double margins etc. | |
| 467 | + // If there's no Form HTML, it's a non-inline form, so don't render any output. | |
| 468 | + if ( ! $this->is_block_editor_request() && ! empty( $form ) ) { | |
| 469 | + $form = sprintf( | |
| 470 | + '<div class="%s" style="%s">%s</div>', | |
| 471 | + implode( ' ', map_deep( $this->get_css_classes(), 'sanitize_html_class' ) ), | |
| 472 | + implode( ';', map_deep( $this->get_css_styles( $atts ), 'esc_attr' ) ), | |
| 473 | + $form | |
| 474 | + ); | |
| 334 | 475 | } |
| 335 | 476 | |
| 336 | 477 | /** |
| 337 | 478 | * Filter the block's content immediately before it is output. |