$this->get_title(), 'description' => __( 'Displays a Kit Form.', 'convertkit' ), 'icon' => $this->get_icon(), 'category' => 'convertkit', 'keywords' => array( __( 'ConvertKit', 'convertkit' ), __( 'Kit', 'convertkit' ), __( 'Form', 'convertkit' ), ), // Function to call when rendering as a block or a shortcode on the frontend web site. 'render_callback' => array( $this, 'render' ), // Shortcode: TinyMCE / QuickTags Modal Width and Height. 'modal' => array( 'width' => 500, 'height' => 55, ), // Shortcode: Include a closing [/shortcode] tag when using TinyMCE or QuickTag Modals. 'shortcode_include_closing_tag' => false, // Gutenberg: Block Icon in Editor. 'gutenberg_icon' => convertkit_get_file_contents( CONVERTKIT_PLUGIN_PATH . '/resources/backend/images/block-icon-form.svg' ), // Gutenberg: Example image showing how this block looks when choosing it in Gutenberg. 'gutenberg_example_image' => CONVERTKIT_PLUGIN_URL . 'resources/backend/images/block-example-form.png', // Help descriptions, displayed when no API key / resources exist and this block/shortcode is added. 'no_access_token' => array( 'notice' => __( 'Not connected to Kit.', 'convertkit' ), 'link' => convertkit_get_setup_wizard_plugin_link(), 'link_text' => __( 'Click here to connect your Kit account.', 'convertkit' ), 'instruction_text' => __( 'Connect your Kit account at Settings > Kit, and then refresh this page to select a form.', 'convertkit' ), ), 'no_resources' => array( 'notice' => __( 'No forms exist in Kit.', 'convertkit' ), 'link' => convertkit_get_new_form_url(), 'link_text' => __( 'Click here to create your first form.', 'convertkit' ), 'instruction_text' => __( 'Add a form to your Kit account, and then refresh this page to select a form.', 'convertkit' ), ), // Gutenberg: Help descriptions, displayed when no settings defined for a newly added Block. 'gutenberg_help_description' => __( 'Select a Form using the Form option in the Gutenberg sidebar.', 'convertkit' ), // Gutenberg: JS function to call when rendering the block preview in the Gutenberg editor. // If not defined, render_callback above will be used. 'gutenberg_preview_render_callback' => 'convertKitGutenbergFormBlockRenderPreview', // General: Any other strings for use in JS that need to support translation / i18n. 'i18n' => array( /* translators: Form name in ConvertKit */ 'gutenberg_form_modal' => __( 'Modal form "%s" selected. View on the frontend site to see the modal form.', 'convertkit' ), /* translators: Form name in ConvertKit */ 'gutenberg_form_slide_in' => __( 'Slide in form "%s" selected. View on the frontend site to see the slide in form.', 'convertkit' ), /* translators: Form name in ConvertKit */ 'gutenberg_form_sticky_bar' => __( 'Sticky bar form "%s" selected. View on the frontend site to see the sticky bar form.', 'convertkit' ), ), // Whether an API Key exists in the Plugin, and are the required resources (forms) available. // If no API Key is specified in the Plugin's settings, render the "No API Key" output. 'has_access_token' => $settings->has_access_and_refresh_token(), 'has_resources' => $convertkit_forms->exist(), ); } /** * Returns this block's Attributes * * @since 1.9.6.5 * * @return array */ public function get_attributes() { return array( 'form' => array( 'type' => 'string', ), // get_supports() style, color and typography attributes. 'align' => array( 'type' => 'string', ), 'style' => array( 'type' => 'object', ), 'backgroundColor' => array( 'type' => 'string', ), // Always required for Gutenberg. 'is_gutenberg_example' => array( 'type' => 'boolean', 'default' => false, ), ); } /** * Returns this block's supported built-in Attributes. * * @since 1.9.7.4 * * @return array Supports */ public function get_supports() { return array( 'align' => true, 'className' => true, 'color' => array( 'link' => false, 'background' => true, 'text' => false, ), 'spacing' => array( 'margin' => true, 'padding' => true, ), ); } /** * Returns this block's Fields * * @since 1.9.6 * * @return bool|array */ public function get_fields() { // Get ConvertKit Forms. Non-legacy forms populate the sidebar dropdown; // legacy forms are exposed separately as a fallback so the sidebar can // keep displaying a previously-saved legacy form as the current // selection without offering other legacy forms as new choices. $forms = array(); $legacy_forms = array(); $convertkit_forms = new ConvertKit_Resource_Forms( 'block_edit' ); if ( $convertkit_forms->exist() ) { foreach ( $convertkit_forms->get() as $form ) { $label = sprintf( '%s [%s]', sanitize_text_field( $form['name'] ), // Legacy forms don't include a `format` key, so define them as inline. ( ! empty( $form['format'] ) ? sanitize_text_field( $form['format'] ) : 'inline' ) ); if ( ! empty( $form['format'] ) ) { $forms[ absint( $form['id'] ) ] = $label; } else { $legacy_forms[ absint( $form['id'] ) ] = $label; } } } return array( 'form' => array( 'label' => __( 'Form', 'convertkit' ), 'type' => 'resource', 'resource' => 'forms', 'values' => $forms, 'legacy_values' => $legacy_forms, 'data' => array( // Used by resources/backend/js/gutenberg-block-form.js to determine the selected form's format // (modal, slide in, sticky bar) and output a message in the block editor for the preview to explain // why some formats cannot be previewed. Includes legacy forms so the preview code can still find // them when a saved block references a legacy form. 'forms' => ( $convertkit_forms->exist() ? $convertkit_forms->get() : array() ), ), ), ); } /** * Returns this block's UI panels / sections. * * @since 1.9.6 * * @return bool|array */ public function get_panels() { return array( 'general' => array( 'label' => __( 'General', 'convertkit' ), 'fields' => array( 'form', ), ), ); } /** * Returns this block's Default Values * * @since 1.9.6 * * @return array */ public function get_default_values() { return array( 'form' => '', 'id' => '', // Backward compat. ); } /** * Returns the block's output, based on the supplied configuration attributes. * * @since 1.9.6 * * @param array $atts Block / Shortcode Attributes. * @return string Output */ public function render( $atts ) { global $post; $post_id = is_a( $post, 'WP_Post' ) ? $post->ID : 0; // Check if the Block Visibility Plugin permits displaying this block. if ( ! $this->is_block_visible( $atts ) ) { // Block should not be displayed due to Block Visibility Plugin conditions. // Return a blank string now. return ''; } // Parse shortcode attributes, defining fallback defaults if required. $atts = shortcode_atts( $this->get_default_values(), $this->sanitize_atts( $atts ), $this->get_name() ); // Setup Settings class. $settings = new ConvertKit_Settings(); // Determine Form ID. // 'id' attribute is for backward compat. $form_id = 0; if ( $atts['form'] > 0 ) { $form_id = $atts['form']; } elseif ( $atts['id'] > 0 ) { $form_id = $atts['id']; } // If no Form ID specified, bail. if ( ! $form_id ) { if ( $settings->debug_enabled() ) { return ''; } return ''; } // Get Form HTML. $forms = new ConvertKit_Resource_Forms( 'output_form' ); $form = $forms->get_html( $form_id, $post_id ); // If an error occurred, it might be that we're requesting a Form ID that exists in ConvertKit // but does not yet exist in the Plugin's Form Resources. // If so, refresh the Form Resources and try again. if ( is_wp_error( $form ) && $form->get_error_data() === 404 ) { // Refresh Forms from the API. $result = $forms->refresh(); // Bail if an error occurred. if ( is_wp_error( $result ) ) { if ( $settings->debug_enabled() ) { return ' '; } return ''; } // Refresh succeeded. // Get Form HTML again. $form = $forms->get_html( $form_id, $post_id ); } // If an error still occurred, the shortcode might be from the ConvertKit App for a Legacy Form ID // These ConvertKit App shortcodes, for some reason, use a different Form ID than the one presented // to us in the API. // For example, a Legacy Form ID might be 470099, but the ConvertKit app says to use the shortcode [convertkit form=5281783]). // In this instance, fetch the Form HTML without checking that the Form ID exists in the Form Resources. if ( is_wp_error( $form ) ) { // Initialize the API. $api = new ConvertKit_API_V4( CONVERTKIT_OAUTH_CLIENT_ID, CONVERTKIT_OAUTH_CLIENT_REDIRECT_URI, $settings->get_access_token(), $settings->get_refresh_token(), $settings->debug_enabled(), 'output_form' ); // Return Legacy Form HTML from the API, which bypasses any internal Plugin check to see if the Form ID exists. $form = $api->get_form_html( $form_id, $settings->get_api_key() ); } // Finally, if we still get an error, there's nothing more we can do. The Form ID isn't valid. if ( is_wp_error( $form ) ) { if ( $settings->debug_enabled() ) { return ''; } return ''; } // Build HTML. // For the block editor, don't include compiled CSS classes and styles, // as the block editor will add these to the parent container. // Otherwise the block will render incorrectly with double padding, double margins etc. // If there's no Form HTML, it's a non-inline form, so don't render any output. if ( ! $this->is_block_editor_request() && ! empty( $form ) ) { $form = sprintf( '