Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions inc/class-base-css.php
Original file line number Diff line number Diff line change
Expand Up @@ -683,10 +683,10 @@ public function get_animation_classes( $blocks ) {
);

foreach ( $blocks as $block ) {
if ( isset( $block['attrs']['className'] ) && ! empty( $block['attrs']['className'] ) ) {
if ( preg_match( '/\banimated\b/', $block['attrs']['className'] ) ) {
$classes = array_merge( $classes, explode( ' ', trim( $block['attrs']['className'] ) ) );
}
$block_classes = Registration::get_class_name( isset( $block['attrs'] ) ? $block['attrs'] : array() );

if ( ! empty( $block_classes ) && preg_match( '/\banimated\b/', $block_classes ) ) {
$classes = array_merge( $classes, explode( ' ', trim( $block_classes ) ) );
}

if ( isset( $block['innerBlocks'] ) && ! empty( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) ) {
Expand Down
36 changes: 34 additions & 2 deletions inc/class-registration.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,38 @@ public static function get_editor_global_defaults() {
return is_object( $defaults ) ? $defaults : new \stdClass();
}

/**
* Get the `className` attribute of a block as a string.
*
* @param mixed $attributes Block attributes.
* @return string
*/
public static function get_class_name( $attributes ) {
if ( ! is_array( $attributes ) || ! isset( $attributes['className'] ) ) {
return '';
}

$class_name = $attributes['className'];

if ( is_array( $class_name ) ) {
// Flatten nested arrays and drop anything that is not printable.
$flat = array();

array_walk_recursive(
$class_name,
function ( $value ) use ( &$flat ) {
if ( is_scalar( $value ) ) {
$flat[] = (string) $value;
}
}
);

return implode( ' ', $flat );
}

return is_scalar( $class_name ) ? (string) $class_name : '';
}

/**
* Initialize the class
*/
Expand Down Expand Up @@ -1076,7 +1108,7 @@ public function subscribe_fa( $block_content, $block ) {
$has_navigation_block = \WP_Block_Type_Registry::get_instance()->is_registered( 'core/navigation' );

if ( $has_navigation_block && ( 'core/navigation-link' === $block['blockName'] || 'core/navigation-submenu' === $block['blockName'] ) ) {
if ( isset( $block['attrs']['className'] ) && strpos( $block['attrs']['className'], 'fa-' ) !== false ) {
if ( strpos( self::get_class_name( isset( $block['attrs'] ) ? $block['attrs'] : array() ), 'fa-' ) !== false ) {
self::$is_fa_loaded = true;

// See the src/blocks/plugins/menu-icons/inline.css file for where this comes from.
Expand Down Expand Up @@ -1118,7 +1150,7 @@ public function load_sticky( $block_content, $block ) {
return $block_content;
}

if ( isset( $block['attrs']['className'] ) && false !== strpos( $block['attrs']['className'], 'o-sticky' ) ) {
if ( false !== strpos( self::get_class_name( isset( $block['attrs'] ) ? $block['attrs'] : array() ), 'o-sticky' ) ) {
$asset_file = include OTTER_BLOCKS_PATH . '/build/blocks/sticky.asset.php';
wp_enqueue_script(
'otter-sticky',
Expand Down
4 changes: 2 additions & 2 deletions inc/css/blocks/class-posts-css.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace ThemeIsle\GutenbergBlocks\CSS\Blocks;

use ThemeIsle\GutenbergBlocks\Base_CSS;
use ThemeIsle\GutenbergBlocks\Registration;

use ThemeIsle\GutenbergBlocks\CSS\CSS_Utility;

Expand Down Expand Up @@ -429,8 +430,7 @@ function ( $position, $css_variable ) {
return $value[ $position ];
},
'condition' => function ( $attrs ) {
// @phpstan-ignore-next-line
return isset( $attrs['className'] ) && strpos( $attrs['className'], 'is-style-tiled' ) !== false;
return strpos( Registration::get_class_name( $attrs ), 'is-style-tiled' ) !== false;
},
);
},
Expand Down
6 changes: 4 additions & 2 deletions inc/render/class-posts-grid-block.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

namespace ThemeIsle\GutenbergBlocks\Render;

use ThemeIsle\GutenbergBlocks\Registration;

/**
* Class Posts_Grid_Block
*/
Expand All @@ -26,7 +28,7 @@ public function render( $attributes ) {
add_filter( 'wp_img_tag_add_auto_sizes', '__return_false' );
$has_pagination = isset( $attributes['hasPagination'] ) && $attributes['hasPagination'];
$page_number = 1;
$is_tiled = isset( $attributes['className'] ) && false !== strpos( $attributes['className'], 'is-style-tiled' );
$is_tiled = false !== strpos( Registration::get_class_name( $attributes ), 'is-style-tiled' );

if ( $has_pagination ) {
if ( ! empty( get_query_var( 'page' ) ) || ! empty( get_query_var( 'paged' ) ) ) {
Expand Down Expand Up @@ -301,7 +303,7 @@ protected function render_featured_post( $post, $attributes ) {
$image_alt = get_post_meta( $thumb_id, '_wp_attachment_image_alt', true );
$style = '';
$image_url = wp_get_attachment_image_src( $thumb_id, $size );
$is_tiled = isset( $attributes['className'] ) && false !== strpos( $attributes['className'], 'is-style-tiled' );
$is_tiled = false !== strpos( Registration::get_class_name( $attributes ), 'is-style-tiled' );

if ( ! $image_alt ) {
$image_alt = get_the_title( $id );
Expand Down
7 changes: 5 additions & 2 deletions plugins/otter-pro/inc/render/class-modal-block.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace ThemeIsle\OtterPro\Render;

use ThemeIsle\OtterPro\Plugins\License;
use ThemeIsle\GutenbergBlocks\Registration;

/**
* Class Modal_CSS.
Expand Down Expand Up @@ -45,8 +46,10 @@ public function render( $attributes, $content, $block ) {

$classes = array( 'wp-block-themeisle-blocks-modal', 'is-active', 'is-front' );

if ( ! empty( $attributes['className'] ) ) {
$classes[] = esc_attr( $attributes['className'] );
$class_name = Registration::get_class_name( $attributes );

if ( ! empty( $class_name ) ) {
$classes[] = esc_attr( $class_name );
}

if ( ! empty( $attributes['closeButtonType'] ) && 'outside' === $attributes['closeButtonType'] ) {
Expand Down
2 changes: 2 additions & 0 deletions tests/php/foreign-sabberworm-sandbox.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ function ( $class ) {
}
);

// Base_CSS reads block class names through Registration::get_class_name().
require OTTER_BLOCKS_PATH . '/inc/class-registration.php';
require OTTER_BLOCKS_PATH . '/inc/class-base-css.php';

$base = new \ThemeIsle\GutenbergBlocks\Base_CSS();
Expand Down
156 changes: 156 additions & 0 deletions tests/test-block-class-name.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<?php
/**
* Class Test_Block_Class_Name
*
* @package gutenberg-blocks
*/

use ThemeIsle\GutenbergBlocks\Base_CSS;
use ThemeIsle\GutenbergBlocks\Registration;
use ThemeIsle\GutenbergBlocks\Render\Posts_Grid_Block;

/**
* An array `className` attribute must not fatal the render/asset paths that
* search it with string functions.
*/
class Test_Block_Class_Name extends WP_UnitTestCase {

/**
* Static asset flags mutated by the paths under test, restored in teardown.
*
* @var array<string, bool>
*/
private $saved_flags = array();

/**
* Set up test environment.
*/
public function set_up() {
parent::set_up();

$this->saved_flags = array(
'is_fa_loaded' => Registration::$is_fa_loaded,
'sticky' => Registration::$scripts_loaded['sticky'],
);
}

/**
* Tear down test environment.
*/
public function tear_down() {
Registration::$is_fa_loaded = $this->saved_flags['is_fa_loaded'];
Registration::$scripts_loaded['sticky'] = $this->saved_flags['sticky'];

wp_dequeue_script( 'otter-sticky' );
wp_deregister_script( 'otter-sticky' );

parent::tear_down();
}

/**
* A string `className` is returned untouched.
*/
public function test_get_class_name_returns_string_attribute() {
$this->assertSame( 'is-style-tiled o-sticky', Registration::get_class_name( array( 'className' => 'is-style-tiled o-sticky' ) ) );
}

/**
* An array `className` is flattened to a space separated list.
*/
public function test_get_class_name_flattens_array_attribute() {
$this->assertSame(
'fa-solid fa-star extra',
Registration::get_class_name( array( 'className' => array( 'fa-solid', array( 'fa-star' ), 'extra' ) ) )
);
}

/**
* Missing, empty and non-printable values fall back to an empty string.
*/
public function test_get_class_name_returns_empty_string_for_unusable_values() {
$this->assertSame( '', Registration::get_class_name( array() ) );
$this->assertSame( '', Registration::get_class_name( 'not-an-array' ) );
$this->assertSame( '', Registration::get_class_name( array( 'className' => array() ) ) );
$this->assertSame( '', Registration::get_class_name( array( 'className' => new stdClass() ) ) );
$this->assertSame( '', Registration::get_class_name( array( 'className' => array( new stdClass() ) ) ) );
}

/**
* The Font Awesome subscriber must read an array `className` without fataling.
*/
public function test_subscribe_fa_handles_array_class_name() {
Registration::$is_fa_loaded = false;

$block = array(
'blockName' => 'core/navigation-link',
'attrs' => array( 'className' => array( 'fa-solid', 'fa-star' ) ),
);

$this->assertSame( 'content', Registration::instance()->subscribe_fa( 'content', $block ) );

if ( \WP_Block_Type_Registry::get_instance()->is_registered( 'core/navigation' ) ) {
$this->assertTrue( Registration::$is_fa_loaded, 'The array class list contains fa-, so FA must be flagged as needed.' );
}
}

/**
* The sticky subscriber must read an array `className` without fataling.
*/
public function test_load_sticky_handles_array_class_name() {
Registration::$scripts_loaded['sticky'] = false;

$block = array(
'blockName' => 'core/group',
'attrs' => array( 'className' => array( 'o-sticky', 'o-sticky-pos-top' ) ),
);

$this->assertSame( 'content', Registration::instance()->load_sticky( 'content', $block ) );
$this->assertTrue( wp_script_is( 'otter-sticky', 'enqueued' ) );
}

/**
* Animation class collection must read an array `className` without fataling.
*/
public function test_get_animation_classes_handles_array_class_name() {
$base_css = new Base_CSS();

$blocks = array(
array(
'blockName' => 'core/paragraph',
'attrs' => array( 'className' => array( 'animated', 'fadeIn' ) ),
),
);

$this->assertSame( array( 'animated', 'fadeIn' ), array_values( $base_css->get_animation_classes( $blocks ) ) );
}

/**
* The posts block must render with an array `className` instead of fataling.
*/
public function test_posts_grid_block_renders_with_array_class_name() {
$this->factory()->post->create( array( 'post_title' => 'Otter array className' ) );

WP_Block_Supports::init();
WP_Block_Supports::$block_to_render = array( 'blockName' => 'themeisle-blocks/posts-grid' );

$render = new Posts_Grid_Block();
$output = $render->render(
array(
'id' => 'wp-block-themeisle-blocks-posts-grid-a94bab18',
'className' => array( 'is-style-tiled', 'custom' ),
'columns' => 2,
'style' => 'grid',
'postTypes' => array(),
'template' => array( 'title' ),
'postsToShow' => 1,
'order' => 'desc',
'orderBy' => 'date',
'offset' => 0,
'displayTitle' => true,
'titleTag' => 'h5',
)
);

$this->assertStringContainsString( 'Otter array className', $output );
}
}
Loading