diff --git a/includes/blocks/broadcasts/block.json b/includes/blocks/broadcasts/block.json index b074a7eaf..df0b5217e 100644 --- a/includes/blocks/broadcasts/block.json +++ b/includes/blocks/broadcasts/block.json @@ -61,6 +61,14 @@ "link": true, "background": true, "text": true + }, + "typography": { + "fontSize": true, + "lineHeight": true + }, + "spacing": { + "margin": true, + "padding": true } }, "editorScript": "convertkit-gutenberg" diff --git a/includes/blocks/class-convertkit-block-broadcasts.php b/includes/blocks/class-convertkit-block-broadcasts.php index f441f0d12..5fe48a98d 100644 --- a/includes/blocks/class-convertkit-block-broadcasts.php +++ b/includes/blocks/class-convertkit-block-broadcasts.php @@ -226,7 +226,7 @@ public function get_attributes() { 'default' => $this->get_default_value( 'paginate_label_next' ), ), - // get_supports() color attribute. + // get_supports() style, color and typography attributes. 'style' => array( 'type' => 'object', ), @@ -236,6 +236,9 @@ public function get_attributes() { 'textColor' => array( 'type' => 'string', ), + 'fontSize' => array( + 'type' => 'string', + ), // Always required for Gutenberg. 'is_gutenberg_example' => array( @@ -256,12 +259,20 @@ public function get_attributes() { public function get_supports() { return array( - 'className' => true, - 'color' => array( + 'className' => true, + 'color' => array( 'link' => true, 'background' => true, 'text' => true, ), + 'typography' => array( + 'fontSize' => true, + 'lineHeight' => true, + ), + 'spacing' => array( + 'margin' => true, + 'padding' => true, + ), ); } @@ -441,8 +452,8 @@ public function get_default_values() { * * @since 1.9.7.4 * - * @param array $atts Block / Shortcode Attributes. - * @return string Output + * @param array $atts Block / Shortcode / Page Builder Module Attributes. + * @return string */ public function render( $atts ) { @@ -473,15 +484,21 @@ public function render( $atts ) { } // Build HTML. - $html = $this->build_html( $posts, $atts ); + $html = $this->build_html( + $posts, + $atts, + ! $this->is_block_editor_request(), + $this->get_css_classes(), + $this->get_css_styles( $atts ) + ); /** * Filter the block's content immediately before it is output. * * @since 1.9.7.4 * - * @param string $html ConvertKit Broadcasts HTML. - * @param array $atts Block Attributes. + * @param string $html ConvertKit Broadcasts HTML. + * @param array $atts Block Attributes. */ $html = apply_filters( 'convertkit_block_broadcasts_render', $html, $atts ); @@ -550,9 +567,11 @@ public function render_ajax() { * @param ConvertKit_Resource_Posts $posts ConvertKit Posts Resource class. * @param array $atts Block attributes. * @param bool $include_container Include container div in HTML. - * @return string HTML + * @param array $css_classes CSS classes to apply to block. + * @param array $css_styles CSS inline styles to apply to block. + * @return string */ - private function build_html( $posts, $atts, $include_container = true ) { + private function build_html( $posts, $atts, $include_container = true, $css_classes = array(), $css_styles = array() ) { // Get paginated subset of Posts. $broadcasts = $posts->get_paginated_subset( $atts['page'], $atts['limit'] ); @@ -565,7 +584,7 @@ private function build_html( $posts, $atts, $include_container = true ) { // Include container, if required. if ( $include_container ) { - $html .= '
get_atts_as_html_data_attributes( $atts ) . '>'; + $html .= '
get_atts_as_html_data_attributes( $atts ) . '>'; } // Start list. diff --git a/includes/blocks/class-convertkit-block-form-trigger.php b/includes/blocks/class-convertkit-block-form-trigger.php index 8851e3935..acd9061c1 100644 --- a/includes/blocks/class-convertkit-block-form-trigger.php +++ b/includes/blocks/class-convertkit-block-form-trigger.php @@ -159,42 +159,20 @@ public function get_attributes() { // The below are built in Gutenberg attributes registered in get_supports(). - // Color. + // get_supports() style, color and typography attributes. + 'style' => array( + 'type' => 'object', + ), 'backgroundColor' => array( 'type' => 'string', ), 'textColor' => array( 'type' => 'string', ), - - // Typography. 'fontSize' => array( 'type' => 'string', ), - // Spacing/Dimensions > Padding. - 'style' => array( - 'type' => 'object', - 'visualizers' => array( - 'type' => 'object', - 'padding' => array( - 'type' => 'object', - 'top' => array( - 'type' => 'boolean', - ), - 'bottom' => array( - 'type' => 'boolean', - ), - 'left' => array( - 'type' => 'boolean', - ), - 'right' => array( - 'type' => 'boolean', - ), - ), - ), - ), - // Always required for Gutenberg. 'is_gutenberg_example' => array( 'type' => 'boolean', @@ -225,13 +203,12 @@ public function get_supports() { '__experimentalSkipSerialization' => true, ), 'typography' => array( - 'fontSize' => true, + 'fontSize' => true, + 'lineHeight' => true, ), 'spacing' => array( - 'padding' => array( - 'horizontal', - 'vertical', - ), + 'margin' => true, + 'padding' => true, ), ); @@ -363,8 +340,8 @@ public function get_default_values() { * * @since 2.2.0 * - * @param array $atts Block / Shortcode Attributes. - * @return string Output + * @param array $atts Block / Shortcode / Page Builder Module Attributes. + * @return string */ public function render( $atts ) { @@ -376,7 +353,13 @@ public function render( $atts ) { $settings = new ConvertKit_Settings(); // Build HTML. - $html = $this->get_html( $atts['form'], $atts['text'], $atts['_css_classes'], $atts['_css_styles'], $this->is_block_editor_request() ); + $html = $this->get_html( + $atts['form'], + $atts['text'], + $this->get_css_classes( array( 'wp-block-button__link', 'wp-element-button' ) ), + $this->get_css_styles( $atts ), + $this->is_block_editor_request() + ); // Bail if an error occured. if ( is_wp_error( $html ) ) { @@ -409,7 +392,7 @@ public function render( $atts ) { * @param int $id Form ID. * @param string $button_text Button Text. * @param array $css_classes CSS classes to apply to link (typically included when using Gutenberg). - * @param array $css_styles CSS inline styles to apply to link (typically included when using Gutenberg). + * @param array $css_styles CSS inline styles to apply to link (typically included when using Shortcode or third party page builder module / widget). * @param bool $return_as_span If true, returns a instead of . Useful for the block editor so that the element is interactible. * @return WP_Error|string Button HTML */ @@ -467,7 +450,7 @@ private function get_html( $id, $button_text, $css_classes = array(), $css_style $html .= ''; + $html .= ' class="' . implode( ' ', map_deep( $css_classes, 'sanitize_html_class' ) ) . '" style="' . implode( ';', map_deep( $css_styles, 'esc_attr' ) ) . '">'; $html .= esc_html( $button_text ); if ( $return_as_span ) { diff --git a/includes/blocks/class-convertkit-block-product.php b/includes/blocks/class-convertkit-block-product.php index d64482d9a..fa6c617f8 100644 --- a/includes/blocks/class-convertkit-block-product.php +++ b/includes/blocks/class-convertkit-block-product.php @@ -195,42 +195,20 @@ public function get_attributes() { // The below are built in Gutenberg attributes registered in get_supports(). - // Color. + // get_supports() style, color and typography attributes. + 'style' => array( + 'type' => 'object', + ), 'backgroundColor' => array( 'type' => 'string', ), 'textColor' => array( 'type' => 'string', ), - - // Typography. 'fontSize' => array( 'type' => 'string', ), - // Spacing/Dimensions > Padding. - 'style' => array( - 'type' => 'object', - 'visualizers' => array( - 'type' => 'object', - 'padding' => array( - 'type' => 'object', - 'top' => array( - 'type' => 'boolean', - ), - 'bottom' => array( - 'type' => 'boolean', - ), - 'left' => array( - 'type' => 'boolean', - ), - 'right' => array( - 'type' => 'boolean', - ), - ), - ), - ), - // Always required for Gutenberg. 'is_gutenberg_example' => array( 'type' => 'boolean', @@ -261,13 +239,12 @@ public function get_supports() { '__experimentalSkipSerialization' => true, ), 'typography' => array( - 'fontSize' => true, + 'fontSize' => true, + 'lineHeight' => true, ), 'spacing' => array( - 'padding' => array( - 'horizontal', - 'vertical', - ), + 'margin' => true, + 'padding' => true, ), ); @@ -414,8 +391,8 @@ public function get_default_values() { * * @since 1.9.8.5 * - * @param array $atts Block / Shortcode Attributes. - * @return string Output + * @param array $atts Block / Shortcode / Page Builder Module Attributes. + * @return string */ public function render( $atts ) { @@ -437,8 +414,8 @@ public function render( $atts ) { 'discount_code' => $atts['discount_code'], 'checkout' => $atts['checkout'], 'disable_modal' => ( $atts['disable_modal_on_mobile'] && wp_is_mobile() ), - 'css_classes' => $atts['_css_classes'], - 'css_styles' => $atts['_css_styles'], + 'css_classes' => $this->get_css_classes( array( 'wp-block-button__link', 'wp-element-button' ) ), + 'css_styles' => $this->get_css_styles( $atts ), 'return_as_span' => $this->is_block_editor_request(), ) ); diff --git a/includes/blocks/class-convertkit-block.php b/includes/blocks/class-convertkit-block.php index 1762b09ab..edd87f40f 100644 --- a/includes/blocks/class-convertkit-block.php +++ b/includes/blocks/class-convertkit-block.php @@ -220,69 +220,8 @@ public function sanitize_and_declare_atts( $atts ) { } } - // Build CSS class(es) that might need to be added to the top level element for this block. - $atts['_css_classes'] = array( 'convertkit-' . $this->get_name() ); - $atts['_css_styles'] = array(); - - // If the block supports a text color, and a preset color was selected, add it to the - // array of CSS classes. - if ( $atts['textColor'] ) { - $atts['_css_classes'][] = 'has-text-color'; - $atts['_css_classes'][] = 'has-' . $atts['textColor'] . '-color'; - } - - // If the block supports a text color, and a custom hex color was selected, add it to the - // array of CSS inline styles. - if ( isset( $atts['style']['color'] ) && isset( $atts['style']['color']['text'] ) ) { - $atts['_css_classes'][] = 'has-text-color'; - $atts['_css_styles']['color'] = 'color:' . $atts['style']['color']['text']; - } - - // If the shortcode supports a text color, and a custom hex color was selected, add it to the - // array of CSS inline styles. - if ( isset( $atts['text_color'] ) && ! empty( $atts['text_color'] ) ) { - $atts['_css_classes'][] = 'has-text-color'; - $atts['_css_styles']['color'] = 'color:' . $atts['text_color']; - } - - // If the block supports a background color, and a preset color was selected, add it to the - // array of CSS classes. - if ( $atts['backgroundColor'] ) { - $atts['_css_classes'][] = 'has-background'; - $atts['_css_classes'][] = 'has-' . $atts['backgroundColor'] . '-background-color'; - } - - // If the block supports a background color, and a custom hex color was selected, add it to the - // array of CSS inline styles. - if ( isset( $atts['style']['color'] ) && isset( $atts['style']['color']['background'] ) ) { - $atts['_css_classes'][] = 'has-background'; - $atts['_css_styles']['background'] = 'background-color:' . $atts['style']['color']['background']; - } - - // If the block supports a font size, and a preset font size was selected, add it to the - // array of CSS classes. - if ( isset( $atts['fontSize'] ) && ! empty( $atts['fontSize'] ) ) { - $atts['_css_classes'][] = 'has-custom-font-size'; - $atts['_css_classes'][] = 'has-' . $atts['fontSize'] . '-font-size'; - } - - // If the block supports padding, and padding is set, add it to the - // array of CSS inline styles. - if ( isset( $atts['style']['spacing'] ) && isset( $atts['style']['spacing']['padding'] ) ) { - foreach ( $atts['style']['spacing']['padding'] as $position => $value ) { - $atts['_css_styles'][ 'padding-' . $position ] = 'padding-' . $position . ':' . $value; - } - } - - // If the shortcode supports a background color, and a custom hex color was selected, add it to the - // array of CSS inline styles. - if ( isset( $atts['background_color'] ) && ! empty( $atts['background_color'] ) ) { - $atts['_css_classes'][] = 'has-background'; - $atts['_css_styles']['background'] = 'background-color:' . $atts['background_color']; - } - // Remove some unused attributes, now they're declared above. - unset( $atts['style'] ); + unset( $atts['style'], $atts['backgroundColor'], $atts['textColor'], $atts['className'] ); return $atts; @@ -295,7 +234,7 @@ public function sanitize_and_declare_atts( $atts ) { * @since 1.9.6 * * @param array $atts Block or shortcode attributes. - * @return array Block or shortcode attributes + * @return array */ public function sanitize_atts( $atts ) { @@ -311,6 +250,84 @@ public function sanitize_atts( $atts ) { } + /** + * Builds CSS class(es) that might need to be added to the top level element's `class` attribute + * when using Gutenberg, to honor the block's styles and layout settings. + * + * @since 2.8.3 + * + * @param array $additional_classes Additional classes to add to the block. + * @return array + */ + public function get_css_classes( $additional_classes = array() ) { + + // Get the block wrapper attributes string. + $wrapper_attributes = get_block_wrapper_attributes( + array( + 'class' => implode( + ' ', + array_merge( + array( + 'convertkit-' . $this->get_name(), + ), + $additional_classes + ) + ), + ) + ); + + // Extract the class attribute from the wrapper attributes string, returning as an array. + // Extract just the class attribute value from the wrapper attributes string. + $classes = array(); + if ( preg_match( '/class="([^"]*)"/', $wrapper_attributes, $matches ) ) { + $classes = explode( ' ', $matches[1] ); + } else { + $classes = array( + 'convertkit-' . $this->get_name(), + ); + } + + // Remove some classes WordPress adds that we don't want, as they break the layout. + $classes = array_diff( $classes, array( 'alignfull', 'wp-block-post-content' ) ); + + return $classes; + + } + + /** + * Builds inline CSS style(s) that might need to be added to the top level element's `style` attribute + * when using Gutenberg, a shortcode or third party page builder module / widget. + * + * @since 2.8.3 + * + * @param array $atts Block or shortcode attributes. + * @return array + */ + public function get_css_styles( $atts ) { + + $styles = array(); + + // Get the block wrapper attributes string, extracting any styles that the block has set, + // such as margin, padding or block spacing. + $wrapper_attributes = get_block_wrapper_attributes(); + if ( preg_match( '/style="([^"]*)"/', $wrapper_attributes, $matches ) ) { + return array_filter( explode( ';', $matches[1] ) ); + } + + // If here, no block styles were found. + // This might be a shortcode or third party page builder module / widget that has + // specific attributes set. + if ( isset( $atts['text_color'] ) && ! empty( $atts['text_color'] ) ) { + $styles[] = 'color:' . $atts['text_color']; + } + if ( isset( $atts['background_color'] ) && ! empty( $atts['background_color'] ) ) { + $styles[] = 'background-color:' . $atts['background_color']; + } + + return $styles; + + } + /** * Returns the given block / shortcode attributes array as HTML data-* attributes, which can be output * in a block's container. @@ -327,7 +344,6 @@ public function get_atts_as_html_data_attributes( $atts ) { $skip_keys = array( 'backgroundColor', 'textColor', - '_css_classes', '_css_styles', ); @@ -340,6 +356,11 @@ public function get_atts_as_html_data_attributes( $atts ) { continue; } + // Skip empty values. + if ( empty( $value ) ) { + continue; + } + // Append to data string, replacing underscores with hyphens in the key name. $data .= ' data-' . strtolower( str_replace( '_', '-', $key ) ) . '="' . esc_attr( $value ) . '"'; } diff --git a/includes/blocks/formtrigger/block.json b/includes/blocks/formtrigger/block.json index 3c8348d14..3dba03250 100644 --- a/includes/blocks/formtrigger/block.json +++ b/includes/blocks/formtrigger/block.json @@ -36,6 +36,14 @@ "color": { "background": true, "text": true + }, + "typography": { + "fontSize": true, + "lineHeight": true + }, + "spacing": { + "margin": true, + "padding": true } }, "editorScript": "convertkit-gutenberg" diff --git a/includes/blocks/product/block.json b/includes/blocks/product/block.json index cdd77a812..534a3123d 100644 --- a/includes/blocks/product/block.json +++ b/includes/blocks/product/block.json @@ -36,6 +36,14 @@ "color": { "background": true, "text": true + }, + "typography": { + "fontSize": true, + "lineHeight": true + }, + "spacing": { + "margin": true, + "padding": true } }, "editorScript": "convertkit-gutenberg" diff --git a/includes/class-convertkit-output-restrict-content.php b/includes/class-convertkit-output-restrict-content.php index 80246ef72..33b3c6df4 100644 --- a/includes/class-convertkit-output-restrict-content.php +++ b/includes/class-convertkit-output-restrict-content.php @@ -1310,7 +1310,13 @@ function () { // Output. ob_start(); - $button = $products->get_html( $this->resource_id, $this->restrict_content_settings->get_by_key( 'subscribe_button_label' ) ); + $button = $products->get_html( + $this->resource_id, + $this->restrict_content_settings->get_by_key( 'subscribe_button_label' ), + array( + 'css_classes' => array( 'wp-block-button__link', 'wp-element-button' ), + ) + ); include CONVERTKIT_PLUGIN_PATH . '/views/frontend/restrict-content/product.php'; return trim( ob_get_clean() ); diff --git a/includes/class-convertkit-resource-products.php b/includes/class-convertkit-resource-products.php index ce618d246..37ea22d0c 100644 --- a/includes/class-convertkit-resource-products.php +++ b/includes/class-convertkit-resource-products.php @@ -177,7 +177,7 @@ public function get_html( $id, $button_text, $options = false ) { } $html .= sprintf( - ' class="wp-block-button__link %s" style="%s"%s>', + ' class="%s" style="%s"%s>', implode( ' ', map_deep( $options['css_classes'], 'sanitize_html_class' ) ), implode( ';', map_deep( $options['css_styles'], 'esc_attr' ) ), ( ! $options['disable_modal'] ? ' data-commerce' : '' ) diff --git a/includes/integrations/divi/class-convertkit-divi-module.php b/includes/integrations/divi/class-convertkit-divi-module.php index d3f85a450..aa1baccb1 100644 --- a/includes/integrations/divi/class-convertkit-divi-module.php +++ b/includes/integrations/divi/class-convertkit-divi-module.php @@ -185,6 +185,18 @@ public function get_fields() { */ public function render( $unprocessed_props, $content, $render_slug ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter + // To avoid errors in get_block_wrapper_attributes(), tell WordPress that a block is being rendered. + // The attributes don't matter, as we send them to the render() function. + if ( class_exists( 'WP_Block_Supports' ) && is_null( WP_Block_Supports::$block_to_render ) ) { // @phpstan-ignore-line + WP_Block_Supports::$block_to_render = array( + 'blockName' => 'convertkit/' . $this->block_name, + 'attrs' => array(), + 'innerBlocks' => array(), + 'innerHTML' => '', + 'innerContent' => array(), + ); + } + // Render using Block class' render() function. // Output is already escaped in render() function. return WP_ConvertKit()->get_class( 'blocks_convertkit_' . $this->block_name )->render( $unprocessed_props ); // phpcs:ignore WordPress.Security.EscapeOutput diff --git a/includes/integrations/elementor/class-convertkit-elementor-widget.php b/includes/integrations/elementor/class-convertkit-elementor-widget.php index 850bc9905..4abc4e885 100644 --- a/includes/integrations/elementor/class-convertkit-elementor-widget.php +++ b/includes/integrations/elementor/class-convertkit-elementor-widget.php @@ -260,6 +260,18 @@ protected function render() { return $this->block->get_error_message(); } + // To avoid errors in get_block_wrapper_attributes(), tell WordPress that a block is being rendered. + // The attributes don't matter, as we send them to the render() function. + if ( class_exists( 'WP_Block_Supports' ) && is_null( WP_Block_Supports::$block_to_render ) ) { // @phpstan-ignore-line + WP_Block_Supports::$block_to_render = array( + 'blockName' => 'convertkit/' . $this->get_block_name(), + 'attrs' => array(), + 'innerBlocks' => array(), + 'innerHTML' => '', + 'innerContent' => array(), + ); + } + // Render using Block class' render() function. // Output is already escaped in render() function. echo WP_ConvertKit()->get_class( 'blocks_convertkit_' . $this->get_block_name() )->render( $this->get_settings_for_display() ); // phpcs:ignore WordPress.Security.EscapeOutput diff --git a/readme.txt b/readme.txt index 852e9a0af..4c34e6eca 100755 --- a/readme.txt +++ b/readme.txt @@ -2,7 +2,7 @@ Contributors: nathanbarry, growdev, travisnorthcutt, ggwicz Donate link: https://kit.com Tags: email marketing, email newsletter, subscribers, landing page, membership -Requires at least: 5.0 +Requires at least: 5.6 Tested up to: 6.8 Requires PHP: 7.1 Stable tag: 2.8.2 diff --git a/resources/frontend/css/broadcasts.css b/resources/frontend/css/broadcasts.css index fd6a5c185..e9de60188 100644 --- a/resources/frontend/css/broadcasts.css +++ b/resources/frontend/css/broadcasts.css @@ -1,4 +1,5 @@ .convertkit-broadcasts.has-background, +.convertkit-broadcasts[data-background-color], .editor-styles-wrapper .convertkit-broadcasts.has-background { padding: 20px; } diff --git a/tests/EndToEnd/broadcasts/blocks-shortcodes/PageBlockBroadcastsCest.php b/tests/EndToEnd/broadcasts/blocks-shortcodes/PageBlockBroadcastsCest.php index 284188641..b78dbe239 100644 --- a/tests/EndToEnd/broadcasts/blocks-shortcodes/PageBlockBroadcastsCest.php +++ b/tests/EndToEnd/broadcasts/blocks-shortcodes/PageBlockBroadcastsCest.php @@ -685,7 +685,7 @@ public function testBroadcastsBlockWithThemeColorParameters(EndToEndTester $I) $I->seeInSource('seeInSource('
seeInSource('seeInSource('
setupKitPlugin($I); $I->setupKitPluginResources($I); - // Define a 'bad' block. This is difficult to do in Gutenberg, but let's assume it's possible. + // It's tricky to interact with Gutenberg's margin and padding pickers, so we programmatically create the Page + // instead to then confirm the settings apply on the output. + // We don't need to test the margin and padding pickers themselves, as they are Gutenberg supplied components, and our + // other End To End tests confirm that the block can be added in Gutenberg etc. $I->havePageInDatabase( [ - 'post_name' => 'kit-page-broadcasts-block-parameter-escaping', - 'post_content' => '', + 'post_name' => 'kit-page-broadcasts-block-margin-padding-params', + 'post_content' => '', ] ); // Load the Page on the frontend site. - $I->amOnPage('/kit-page-broadcasts-block-parameter-escaping'); + $I->amOnPage('/kit-page-broadcasts-block-margin-padding-params'); // Wait for frontend web site to load. $I->waitForElementVisible('body.page-template-default'); @@ -771,16 +773,67 @@ public function testBroadcastsBlockParameterEscaping(EndToEndTester $I) // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); - // Confirm that the output is escaped. - $I->seeInSource('style="color:red" onmouseover="alert(1)""'); - $I->dontSeeInSource('style="color:red" onmouseover="alert(1)""'); + // Confirm that the block displays correctly with the expected number of Broadcasts. + $I->seeBroadcastsOutput( + $I, + [ + 'number_posts' => $_ENV['CONVERTKIT_API_BROADCAST_COUNT'], + ] + ); - // Test pagination. - $I->testBroadcastsPagination($I, 'Previous', 'Next'); + // Confirm that our stylesheet loaded. + $I->seeInSource('setupKitPlugin($I); + $I->setupKitPluginResources($I); + + // It's tricky to interact with Gutenberg's typography pickers, so we programmatically create the Page + // instead to then confirm the settings apply on the output. + // We don't need to test the typography picker itself, as it's a Gutenberg supplied component, and our + // other End To End tests confirm that the block can be added in Gutenberg etc. + $I->havePageInDatabase( + [ + 'post_name' => 'kit-page-broadcasts-block-typography-params', + 'post_content' => '', + ] + ); + + // Load the Page on the frontend site. + $I->amOnPage('/kit-page-broadcasts-block-typography-params'); + + // Wait for frontend web site to load. + $I->waitForElementVisible('body.page-template-default'); + + // Check that no PHP warnings or notices were output. + $I->checkNoWarningsAndNoticesOnScreen($I); + + // Confirm that the block displays correctly with the expected number of Broadcasts. + $I->seeBroadcastsOutput( + $I, + [ + 'number_posts' => $_ENV['CONVERTKIT_API_BROADCAST_COUNT'], + ] + ); + + // Confirm that our stylesheet loaded. + $I->seeInSource('dontSeeInSource('style="color:red" onmouseover="alert(1)""'); + // Confirm that the chosen typography settings are applied as CSS styles. + $I->seeInSource('
seeInSource('seeInSource('
seeInSource('seeFormTriggerOutput($I, $_ENV['CONVERTKIT_API_FORM_FORMAT_MODAL_URL']); // Confirm that the chosen colors are applied as CSS styles. - $I->seeInSource('class="wp-block-button__link convertkit-formtrigger has-text-color has-' . $textColor . '-color has-background has-' . $backgroundColor . '-background-color'); + $I->seeInSource('class="convertkit-formtrigger wp-block-button__link wp-element-button wp-block-convertkit-formtrigger has-text-color has-' . $textColor . '-color has-background has-' . $backgroundColor . '-background-color'); } /** @@ -327,34 +327,46 @@ public function testFormTriggerBlockWithHexColorParameters(EndToEndTester $I) // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); + // Confirm that the chosen colors are applied as CSS styles. + $I->seeInSource('class="convertkit-formtrigger wp-block-button__link wp-element-button wp-block-convertkit-formtrigger has-text-color has-background"'); + // Confirm that the block displays. - $I->seeFormTriggerOutput($I, $_ENV['CONVERTKIT_API_FORM_FORMAT_MODAL_URL'], 'Subscribe', $textColor, $backgroundColor); + $I->seeFormTriggerOutput( + $I, + formURL: $_ENV['CONVERTKIT_API_FORM_FORMAT_MODAL_URL'], + text: 'Subscribe', + textColor: $textColor, + backgroundColor: $backgroundColor, + isBlock: true + ); } /** - * Test the Form Trigger block's parameters are correctly escaped on output, - * to prevent XSS. + * Test the Form Trigger block's margin and padding parameters works. * - * @since 2.0.5 + * @since 2.8.4 * * @param EndToEndTester $I Tester. */ - public function testFormTriggerBlockParameterEscaping(EndToEndTester $I) + public function testFormTriggerBlockWithMarginAndPaddingParameters(EndToEndTester $I) { - // Setup Kit Plugin with no default form specified. - $I->setupKitPluginNoDefaultForms($I); + // Setup Plugin and enable debug log. + $I->setupKitPlugin($I); $I->setupKitPluginResources($I); - // Define a 'bad' block. This is difficult to do in Gutenberg, but let's assume it's possible. + // It's tricky to interact with Gutenberg's margin and padding pickers, so we programmatically create the Page + // instead to then confirm the settings apply on the output. + // We don't need to test the margin and padding pickers themselves, as they are Gutenberg supplied components, and our + // other End To End tests confirm that the block can be added in Gutenberg etc. $I->havePageInDatabase( [ - 'post_name' => 'kit-page-form-trigger-block-parameter-escaping', - 'post_content' => '', + 'post_name' => 'kit-page-form-trigger-block-margin-padding-params', + 'post_content' => '', ] ); // Load the Page on the frontend site. - $I->amOnPage('/kit-page-form-trigger-block-parameter-escaping'); + $I->amOnPage('/kit-page-form-trigger-block-margin-padding-params'); // Wait for frontend web site to load. $I->waitForElementVisible('body.page-template-default'); @@ -362,12 +374,58 @@ public function testFormTriggerBlockParameterEscaping(EndToEndTester $I) // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); - // Confirm that the output is escaped. - $I->seeInSource('style="color:red" onmouseover="alert(1)""'); - $I->dontSeeInSource('style="color:red" onmouseover="alert(1)""'); + // Confirm that the block displays and has the inline styles applied. + $I->seeFormTriggerOutput( + $I, + formURL: $_ENV['CONVERTKIT_API_FORM_FORMAT_MODAL_URL'], + text: 'Subscribe', + styles: 'padding-top:var(--wp--preset--spacing--30);margin-top:var(--wp--preset--spacing--30)', + isBlock: true + ); + } - // Confirm that the Kit Form Trigger is displayed. - $I->seeFormTriggerOutput($I, $_ENV['CONVERTKIT_API_FORM_FORMAT_MODAL_URL'], 'Subscribe'); + /** + * Test the Form Trigger block's typography parameters works. + * + * @since 2.8.4 + * + * @param EndToEndTester $I Tester. + */ + public function testFormTriggerBlockWithTypographyParameters(EndToEndTester $I) + { + // Setup Plugin and enable debug log. + $I->setupKitPlugin($I); + $I->setupKitPluginResources($I); + + // It's tricky to interact with Gutenberg's typography pickers, so we programmatically create the Page + // instead to then confirm the settings apply on the output. + // We don't need to test the typography picker itself, as it's a Gutenberg supplied component, and our + // other End To End tests confirm that the block can be added in Gutenberg etc. + $I->havePageInDatabase( + [ + 'post_name' => 'kit-page-form-trigger-block-typography-params', + 'post_content' => '', + ] + ); + + // Load the Page on the frontend site. + $I->amOnPage('/kit-page-form-trigger-block-typography-params'); + + // Wait for frontend web site to load. + $I->waitForElementVisible('body.page-template-default'); + + // Check that no PHP warnings or notices were output. + $I->checkNoWarningsAndNoticesOnScreen($I); + + // Confirm that the block displays and has the inline styles applied. + $I->seeFormTriggerOutput( + $I, + formURL: $_ENV['CONVERTKIT_API_FORM_FORMAT_MODAL_URL'], + text: 'Subscribe', + cssClasses: 'has-large-font-size', + styles: 'line-height:2', + isBlock: true + ); } /** diff --git a/tests/EndToEnd/integrations/other/ElementorBroadcastsCest.php b/tests/EndToEnd/integrations/other/ElementorBroadcastsCest.php index 38b0363c1..b36771d5a 100644 --- a/tests/EndToEnd/integrations/other/ElementorBroadcastsCest.php +++ b/tests/EndToEnd/integrations/other/ElementorBroadcastsCest.php @@ -284,7 +284,7 @@ public function testBroadcastsWidgetWithHexColorParameters(EndToEndTester $I) $I->seeInSource('seeInSource('
seeInSource('seeInSource('class="wp-block-button__link convertkit-product has-text-color has-' . $textColor . '-color has-background has-' . $backgroundColor . '-background-color'); + $I->seeInSource('class="convertkit-product wp-block-button__link wp-element-button wp-block-convertkit-product has-text-color has-' . $textColor . '-color has-background has-' . $backgroundColor . '-background-color'); } /** @@ -516,7 +516,95 @@ public function testProductBlockWithHexColorParameters(EndToEndTester $I) productURL: $_ENV['CONVERTKIT_API_PRODUCT_URL'], text: 'Buy my product', textColor: $textColor, - backgroundColor: $backgroundColor + backgroundColor: $backgroundColor, + isBlock: true + ); + } + + /** + * Test the Form Trigger block's margin and padding parameters works. + * + * @since 2.8.4 + * + * @param EndToEndTester $I Tester. + */ + public function testProductBlockWithMarginAndPaddingParameters(EndToEndTester $I) + { + // Setup Plugin and enable debug log. + $I->setupKitPlugin($I); + $I->setupKitPluginResources($I); + + // It's tricky to interact with Gutenberg's margin and padding pickers, so we programmatically create the Page + // instead to then confirm the settings apply on the output. + // We don't need to test the margin and padding pickers themselves, as they are Gutenberg supplied components, and our + // other End To End tests confirm that the block can be added in Gutenberg etc. + $I->havePageInDatabase( + [ + 'post_name' => 'kit-page-product-block-margin-padding-params', + 'post_content' => '', + ] + ); + + // Load the Page on the frontend site. + $I->amOnPage('/kit-page-product-block-margin-padding-params'); + + // Wait for frontend web site to load. + $I->waitForElementVisible('body.page-template-default'); + + // Check that no PHP warnings or notices were output. + $I->checkNoWarningsAndNoticesOnScreen($I); + + // Confirm that the block displays and has the inline styles applied. + $I->seeProductOutput( + $I, + productURL: $_ENV['CONVERTKIT_API_PRODUCT_URL'], + text: 'Buy my product', + styles: 'padding-top:var(--wp--preset--spacing--30);margin-top:var(--wp--preset--spacing--30)', + isBlock: true + ); + } + + /** + * Test the Product block's typography parameters works. + * + * @since 2.8.4 + * + * @param EndToEndTester $I Tester. + */ + public function testProductBlockWithTypographyParameters(EndToEndTester $I) + { + // Setup Plugin and enable debug log. + $I->setupKitPlugin($I); + $I->setupKitPluginResources($I); + + // It's tricky to interact with Gutenberg's typography pickers, so we programmatically create the Page + // instead to then confirm the settings apply on the output. + // We don't need to test the typography picker itself, as it's a Gutenberg supplied component, and our + // other End To End tests confirm that the block can be added in Gutenberg etc. + $I->havePageInDatabase( + [ + 'post_name' => 'kit-page-product-block-typography-params', + 'post_content' => '', + ] + ); + + // Load the Page on the frontend site. + $I->amOnPage('/kit-page-product-block-typography-params'); + + // Wait for frontend web site to load. + $I->waitForElementVisible('body.page-template-default'); + + // Check that no PHP warnings or notices were output. + $I->checkNoWarningsAndNoticesOnScreen($I); + + // Confirm that the block displays and has the inline styles applied. + $I->seeProductOutput( + $I, + productURL: $_ENV['CONVERTKIT_API_PRODUCT_URL'], + text: 'Buy my product', + cssClasses: 'has-large-font-size', + styles: 'line-height:2', + isBlock: true ); } @@ -632,49 +720,6 @@ public function testProductBlockRefreshButton(EndToEndTester $I) $I->publishAndViewGutenbergPage($I); } - /** - * Test the Product block's parameters are correctly escaped on output, - * to prevent XSS. - * - * @since 2.0.5 - * - * @param EndToEndTester $I Tester. - */ - public function testProductBlockParameterEscaping(EndToEndTester $I) - { - // Setup Kit Plugin with no default form specified. - $I->setupKitPluginNoDefaultForms($I); - $I->setupKitPluginResources($I); - - // Define a 'bad' block. This is difficult to do in Gutenberg, but let's assume it's possible. - $I->havePageInDatabase( - [ - 'post_name' => 'kit-page-product-block-parameter-escaping', - 'post_content' => '', - ] - ); - - // Load the Page on the frontend site. - $I->amOnPage('/kit-page-product-block-parameter-escaping'); - - // Wait for frontend web site to load. - $I->waitForElementVisible('body.page-template-default'); - - // Check that no PHP warnings or notices were output. - $I->checkNoWarningsAndNoticesOnScreen($I); - - // Confirm that the output is escaped. - $I->seeInSource('style="color:red" onmouseover="alert(1)""'); - $I->dontSeeInSource('style="color:red" onmouseover="alert(1)""'); - - // Confirm that the Kit Product is displayed. - $I->seeProductOutput( - $I, - productURL: $_ENV['CONVERTKIT_API_PRODUCT_URL'], - text: 'Buy my product' - ); - } - /** * Deactivate and reset Plugin(s) after each test, if the test passes. * We don't use _after, as this would provide a screenshot of the Plugin diff --git a/tests/Integration/ResourceProductsTest.php b/tests/Integration/ResourceProductsTest.php index 7037f9b18..84bf2fb33 100644 --- a/tests/Integration/ResourceProductsTest.php +++ b/tests/Integration/ResourceProductsTest.php @@ -235,8 +235,28 @@ public function testExist() */ public function testGetHTML() { - $result = $this->resource->get_html($_ENV['CONVERTKIT_API_PRODUCT_ID'], 'Buy now'); - $this->assertSame($result, ''); + $result = $this->resource->get_html( + id: $_ENV['CONVERTKIT_API_PRODUCT_ID'], + button_text: 'Buy now', + ); + $this->assertSame($result, ''); + + // Test with CSS classes and styles. + $result = $this->resource->get_html( + id: $_ENV['CONVERTKIT_API_PRODUCT_ID'], + button_text: 'Buy now', + options: [ + 'css_classes' => array( 'wp-block-button__link', 'wp-element-button' ), + 'css_styles' => array( + 'color' => 'color:#000', + 'background' => 'background-color:#fff', + ), + ] + ); + $this->assertSame( + $result, + '' + ); } /** diff --git a/tests/Support/Helper/KitForms.php b/tests/Support/Helper/KitForms.php index 09619157f..a2f6b05c8 100644 --- a/tests/Support/Helper/KitForms.php +++ b/tests/Support/Helper/KitForms.php @@ -76,13 +76,16 @@ public function seeFormOutput($I, $formID, $position = false, $element = false, * * @since 2.2.0 * - * @param EndToEndTester $I Tester. - * @param string $formURL Form URL. - * @param bool|string $text Test if the button text matches the given value. - * @param bool|string $textColor Test if the given text color is applied. + * @param EndToEndTester $I Tester. + * @param string $formURL Form URL. + * @param bool|string $text Test if the button text matches the given value. + * @param bool|string $textColor Test if the given text color is applied. * @param bool|string $backgroundColor Test is the given background color is applied. + * @param bool|string $cssClasses Test if the given CSS classes are applied. + * @param bool|string $styles Test if the given styles are applied. + * @param bool $isBlock Test if this is a form trigger block or shortcode. */ - public function seeFormTriggerOutput($I, $formURL, $text = false, $textColor = false, $backgroundColor = false) + public function seeFormTriggerOutput($I, $formURL, $text = false, $textColor = false, $backgroundColor = false, $cssClasses = false, $styles = false, $isBlock = false) { // Confirm that the button stylesheet loaded. $I->seeInSource('