PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / trunk
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages vtrunk
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 2.3.2 2.3.3 All 194 releases
convertkit / includes / blocks / class-convertkit-block-form.php

class-convertkit-block-form.php in Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages trunk, at includes/blocks/class-convertkit-block-form.php

503 lines 14.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * ConvertKit Form Block class.
4 *
5 * @package ConvertKit
6 * @author ConvertKit
7 */
8
9 /**
10 * ConvertKit Form Block for Gutenberg and Shortcode.
11 *
12 * @package ConvertKit
13 * @author ConvertKit
14 */
15 class ConvertKit_Block_Form extends ConvertKit_Block {
16
17 /**
18 * Constructor
19 *
20 * @since 1.9.6
21 */
22 public function __construct() {
23
24 // Register this as a shortcode in the ConvertKit Plugin.
25 add_filter( 'convertkit_shortcodes', array( $this, 'register' ) );
26
27 // Register this as a Gutenberg block in the ConvertKit Plugin.
28 add_filter( 'convertkit_blocks', array( $this, 'register' ) );
29
30 // Register this block's MCP abilities.
31 add_filter( 'convertkit_abilities', array( $this, 'register_abilities' ) );
32
33 // Enqueue scripts for this Gutenberg Block in the editor view.
34 add_action( 'convertkit_gutenberg_enqueue_scripts', array( $this, 'enqueue_scripts_editor' ) );
35
36 // Enqueue styles for this Gutenberg Block in the editor view.
37 add_action( 'convertkit_gutenberg_enqueue_styles', array( $this, 'enqueue_styles_editor' ) );
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
42 }
43
44 /**
45 * Enqueues scripts for this Gutenberg Block in the editor view.
46 *
47 * @since 1.9.6.5
48 */
49 public function enqueue_scripts_editor() {
50
51 wp_enqueue_script( 'convertkit-gutenberg-block-form', CONVERTKIT_PLUGIN_URL . 'resources/backend/js/gutenberg-block-form.js', array( 'convertkit-gutenberg' ), CONVERTKIT_PLUGIN_VERSION, true );
52
53 }
54
55 /**
56 * Enqueues styles for this Gutenberg Block in the editor view.
57 *
58 * @since 1.9.6.9
59 */
60 public function enqueue_styles_editor() {
61
62 wp_enqueue_style( 'convertkit-gutenberg', CONVERTKIT_PLUGIN_URL . 'resources/backend/css/gutenberg.css', array( 'wp-edit-blocks' ), CONVERTKIT_PLUGIN_VERSION );
63
64 }
65
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 /**
78 * Returns this block's programmatic name, excluding the convertkit- prefix.
79 *
80 * @since 1.9.6
81 *
82 * @return string
83 */
84 public function get_name() {
85
86 /**
87 * This will register as:
88 * - a shortcode, with the name [convertkit_form].
89 * - a shortcode, with the name [convertkit], for backward compat.
90 * - a Gutenberg block, with the name convertkit/form.
91 */
92 return 'form';
93
94 }
95
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 /**
132 * Returns this block's Title, Icon, Categories, Keywords and properties.
133 *
134 * @since 1.9.6
135 *
136 * @return array
137 */
138 public function get_overview() {
139
140 $convertkit_forms = new ConvertKit_Resource_Forms( 'block_edit' );
141 $settings = new ConvertKit_Settings();
142
143 return array(
144 'title' => $this->get_title(),
145 'description' => __( 'Displays a Kit Form.', 'convertkit' ),
146 'icon' => $this->get_icon(),
147 'category' => 'convertkit',
148 'keywords' => array(
149 __( 'ConvertKit', 'convertkit' ),
150 __( 'Kit', 'convertkit' ),
151 __( 'Form', 'convertkit' ),
152 ),
153
154 // Function to call when rendering as a block or a shortcode on the frontend web site.
155 'render_callback' => array( $this, 'render' ),
156
157 // Shortcode: TinyMCE / QuickTags Modal Width and Height.
158 'modal' => array(
159 'width' => 500,
160 'height' => 55,
161 ),
162
163 // Shortcode: Include a closing [/shortcode] tag when using TinyMCE or QuickTag Modals.
164 'shortcode_include_closing_tag' => false,
165
166 // Gutenberg: Block Icon in Editor.
167 'gutenberg_icon' => convertkit_get_file_contents( CONVERTKIT_PLUGIN_PATH . '/resources/backend/images/block-icon-form.svg' ),
168
169 // Gutenberg: Example image showing how this block looks when choosing it in Gutenberg.
170 'gutenberg_example_image' => CONVERTKIT_PLUGIN_URL . 'resources/backend/images/block-example-form.png',
171
172 // Help descriptions, displayed when no API key / resources exist and this block/shortcode is added.
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' ),
178 ),
179 'no_resources' => array(
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' ),
184 ),
185
186 // Gutenberg: Help descriptions, displayed when no settings defined for a newly added Block.
187 'gutenberg_help_description' => __( 'Select a Form using the Form option in the Gutenberg sidebar.', 'convertkit' ),
188
189 // Gutenberg: JS function to call when rendering the block preview in the Gutenberg editor.
190 // If not defined, render_callback above will be used.
191 'gutenberg_preview_render_callback' => 'convertKitGutenbergFormBlockRenderPreview',
192
193 // General: Any other strings for use in JS that need to support translation / i18n.
194 'i18n' => array(
195 /* translators: Form name in ConvertKit */
196 'gutenberg_form_modal' => __( 'Modal form "%s" selected. View on the frontend site to see the modal form.', 'convertkit' ),
197
198 /* translators: Form name in ConvertKit */
199 'gutenberg_form_slide_in' => __( 'Slide in form "%s" selected. View on the frontend site to see the slide in form.', 'convertkit' ),
200
201 /* translators: Form name in ConvertKit */
202 'gutenberg_form_sticky_bar' => __( 'Sticky bar form "%s" selected. View on the frontend site to see the sticky bar form.', 'convertkit' ),
203 ),
204
205 // Whether an API Key exists in the Plugin, and are the required resources (forms) available.
206 // If no API Key is specified in the Plugin's settings, render the "No API Key" output.
207 'has_access_token' => $settings->has_access_and_refresh_token(),
208 'has_resources' => $convertkit_forms->exist(),
209 );
210
211 }
212
213 /**
214 * Returns this block's Attributes
215 *
216 * @since 1.9.6.5
217 *
218 * @return array
219 */
220 public function get_attributes() {
221
222 return array(
223 'form' => array(
224 'type' => 'string',
225 ),
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
238 // Always required for Gutenberg.
239 'is_gutenberg_example' => array(
240 'type' => 'boolean',
241 'default' => false,
242 ),
243 );
244
245 }
246
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 /**
273 * Returns this block's Fields
274 *
275 * @since 1.9.6
276 *
277 * @return bool|array
278 */
279 public function get_fields() {
280
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.
285 $forms = array();
286 $legacy_forms = array();
287 $convertkit_forms = new ConvertKit_Resource_Forms( 'block_edit' );
288 if ( $convertkit_forms->exist() ) {
289 foreach ( $convertkit_forms->get() as $form ) {
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 }
302 }
303 }
304
305 return array(
306 'form' => array(
307 'label' => __( 'Form', 'convertkit' ),
308 'type' => 'resource',
309 'resource' => 'forms',
310 'values' => $forms,
311 'legacy_values' => $legacy_forms,
312 'data' => array(
313 // Used by resources/backend/js/gutenberg-block-form.js to determine the selected form's format
314 // (modal, slide in, sticky bar) and output a message in the block editor for the preview to explain
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.
317 'forms' => ( $convertkit_forms->exist() ? $convertkit_forms->get() : array() ),
318 ),
319 ),
320 );
321
322 }
323
324 /**
325 * Returns this block's UI panels / sections.
326 *
327 * @since 1.9.6
328 *
329 * @return bool|array
330 */
331 public function get_panels() {
332
333 return array(
334 'general' => array(
335 'label' => __( 'General', 'convertkit' ),
336 'fields' => array(
337 'form',
338 ),
339 ),
340 );
341
342 }
343
344 /**
345 * Returns this block's Default Values
346 *
347 * @since 1.9.6
348 *
349 * @return array
350 */
351 public function get_default_values() {
352
353 return array(
354 'form' => '',
355 'id' => '', // Backward compat.
356 );
357
358 }
359
360 /**
361 * Returns the block's output, based on the supplied configuration attributes.
362 *
363 * @since 1.9.6
364 *
365 * @param array $atts Block / Shortcode Attributes.
366 * @return string Output
367 */
368 public function render( $atts ) {
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
381 // Parse shortcode attributes, defining fallback defaults if required.
382 $atts = shortcode_atts(
383 $this->get_default_values(),
384 $this->sanitize_atts( $atts ),
385 $this->get_name()
386 );
387
388 // Setup Settings class.
389 $settings = new ConvertKit_Settings();
390
391 // Determine Form ID.
392 // 'id' attribute is for backward compat.
393 $form_id = 0;
394 if ( $atts['form'] > 0 ) {
395 $form_id = $atts['form'];
396 } elseif ( $atts['id'] > 0 ) {
397 $form_id = $atts['id'];
398 }
399
400 // If no Form ID specified, bail.
401 if ( ! $form_id ) {
402 if ( $settings->debug_enabled() ) {
403 return '<!-- No Form ID Specified -->';
404 }
405
406 return '';
407 }
408
409 // Get Form HTML.
410 $forms = new ConvertKit_Resource_Forms( 'output_form' );
411 $form = $forms->get_html( $form_id, $post_id );
412
413 // If an error occurred, it might be that we're requesting a Form ID that exists in ConvertKit
414 // but does not yet exist in the Plugin's Form Resources.
415 // If so, refresh the Form Resources and try again.
416 if ( is_wp_error( $form ) && $form->get_error_data() === 404 ) {
417 // Refresh Forms from the API.
418 $result = $forms->refresh();
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.
430 // Get Form HTML again.
431 $form = $forms->get_html( $form_id, $post_id );
432 }
433
434 // If an error still occurred, the shortcode might be from the ConvertKit App for a Legacy Form ID
435 // These ConvertKit App shortcodes, for some reason, use a different Form ID than the one presented
436 // to us in the API.
437 // For example, a Legacy Form ID might be 470099, but the ConvertKit app says to use the shortcode [convertkit form=5281783]).
438 // In this instance, fetch the Form HTML without checking that the Form ID exists in the Form Resources.
439 if ( is_wp_error( $form ) ) {
440 // Initialize the API.
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 );
449
450 // Return Legacy Form HTML from the API, which bypasses any internal Plugin check to see if the Form ID exists.
451 $form = $api->get_form_html( $form_id, $settings->get_api_key() );
452 }
453
454 // Finally, if we still get an error, there's nothing more we can do. The Form ID isn't valid.
455 if ( is_wp_error( $form ) ) {
456 if ( $settings->debug_enabled() ) {
457 return '<!-- ' . $form->get_error_message() . ' -->';
458 }
459
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 );
475 }
476
477 /**
478 * Filter the block's content immediately before it is output.
479 *
480 * @since 1.9.6
481 *
482 * @param string $form ConvertKit Form HTML.
483 * @param array $atts Block Attributes.
484 * @param int $form_id Form ID.
485 */
486 $form = apply_filters( 'convertkit_block_form_render', $form, $atts, $form_id );
487
488 /**
489 * Backward compat. filter for < 1.9.6. Filter the block's content immediately before it is output.
490 *
491 * @since 1.0.0
492 *
493 * @param string $form ConvertKit Form HTML.
494 * @param array $atts Block Attributes.
495 */
496 $form = apply_filters( 'wp_convertkit_get_form_embed', $form, $atts );
497
498 return $form;
499
500 }
501
502 }
503