Skip to content
Open
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
4 changes: 2 additions & 2 deletions src/compatibility/ewww.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
}

if ( ! function_exists( 'stackable_load_image_optimizer_polyfill_frontend_script' ) ) {
function stackable_load_image_optimizer_polyfill_frontend_script( $block_content, $block ) {
function stackable_load_image_optimizer_polyfill_frontend_script( $block_content ) {
// If Easy IO setting is activated for EWWW Image Optimizer, dynamic images becomes blurry.
// Load the script to fix the issue.
if ( ! is_admin() ) {
Expand All @@ -26,7 +26,7 @@ function stackable_load_image_optimizer_polyfill_frontend_script( $block_content
function stackable_ewww_image_optimzer_plugin_checker() {
if ( ! is_admin() && defined( 'EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE' ) ) {
// Load the script in the frontend if EWWW Image Optimizer is active.
add_action( 'stackable/enqueue_scripts', 'stackable_load_image_optimizer_polyfill_frontend_script', 10, 2 );
add_action( 'stackable/enqueue_scripts', 'stackable_load_image_optimizer_polyfill_frontend_script' );
}
}

Expand Down
77 changes: 56 additions & 21 deletions src/init.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ class Stackable_Init {
* Holds the scripts which are already enqueued, to ensure we only do it once per script.
* @var Array
*/
public $scripts_loaded = array();
public static $scripts_loaded = array();

/**
* Enqueue the frontend scripts, ensures we only do it once.
*
* @var boolean
*/
public $is_main_script_loaded = false;
public static $is_main_script_loaded = false;

/**
* Add our hooks.
Expand Down Expand Up @@ -81,9 +81,9 @@ function __construct() {
* @return void
*/
public function maybe_force_css_load() {
if ( ! $this->is_main_script_loaded && apply_filters( 'stackable_force_css_load', false ) ) {
$this->block_enqueue_frontend_assets();
$this->is_main_script_loaded = true;
if ( ! self::$is_main_script_loaded && apply_filters( 'stackable_force_css_load', false ) ) {
self::block_enqueue_frontend_assets();
self::$is_main_script_loaded = true;
}
}

Expand All @@ -92,7 +92,7 @@ public function maybe_force_css_load() {
*
* @since 0.1
*/
public function register_frontend_assets() {
public static function register_frontend_assets() {
// Frontend block styles.
wp_register_style(
'ugb-style-css',
Expand Down Expand Up @@ -171,7 +171,7 @@ public function register_frontend_assets() {
*/
public function load_frontend_scripts_conditionally_head() {
// Only do this in the frontend.
if ( $this->is_main_script_loaded ) {
if ( self::$is_main_script_loaded ) {
return;
}

Expand All @@ -186,8 +186,8 @@ public function load_frontend_scripts_conditionally_head() {
stripos( $post->post_content, 'stk-highlight' ) !== false
) {
// Enqueue our main scripts and styles.
$this->block_enqueue_frontend_assets();
$this->is_main_script_loaded = true;
self::block_enqueue_frontend_assets();
self::$is_main_script_loaded = true;
}
}
}
Expand Down Expand Up @@ -216,12 +216,12 @@ public function load_frontend_scripts_conditionally( $block_content, $block ) {

// Load our main frontend scripts if there's a Stackable block
// loaded in the frontend.
if ( ! $this->is_main_script_loaded && ! is_admin() ) {
if ( ! self::$is_main_script_loaded && ! is_admin() ) {
if ( strpos( $block_content, '<!-- wp:stackable/' ) !== false ||
strpos( $block_content, 'stk-highlight' ) !== false
strpos( $block_content, 'stk-highlight' ) !== false
) {
$this->block_enqueue_frontend_assets();
$this->is_main_script_loaded = true;
self::block_enqueue_frontend_assets();
self::$is_main_script_loaded = true;
}
}

Expand All @@ -231,21 +231,21 @@ public function load_frontend_scripts_conditionally( $block_content, $block ) {
}

// Load our main frontend scripts if not yet loaded.
if ( ! $this->is_main_script_loaded && ! is_admin() ) {
$this->block_enqueue_frontend_assets();
$this->is_main_script_loaded = true;
if ( ! self::$is_main_script_loaded && ! is_admin() ) {
self::block_enqueue_frontend_assets();
self::$is_main_script_loaded = true;
}

// Enqueue the block script once.
if ( ! isset( $this->scripts_loaded[ $block['blockName'] ] ) ) {
if ( ! isset( self::$scripts_loaded[ $block['blockName'] ] ) ) {
$stackable_block = substr( $block['blockName'], 10 );
do_action( 'stackable/' . $stackable_block . '/enqueue_scripts' );
$this->scripts_loaded[ $block['blockName'] ] = true;
self::$scripts_loaded[ $block['blockName'] ] = true;
}

// Check whether the current block needs to enqueue some scripts.
// This gets called across all the blocks.
do_action( 'stackable/enqueue_scripts', $block_content, $block );
do_action( 'stackable/enqueue_scripts', $block_content );

return $block_content;
}
Expand All @@ -255,8 +255,8 @@ public function load_frontend_scripts_conditionally( $block_content, $block ) {
*
* @since 2.17.2
*/
public function block_enqueue_frontend_assets() {
$this->register_frontend_assets();
public static function block_enqueue_frontend_assets() {
self::register_frontend_assets();
wp_enqueue_style( 'ugb-style-css' );
if ( is_frontend() ) {
wp_enqueue_style( 'ugb-block-style-inheritance-nodep' );
Expand All @@ -266,6 +266,41 @@ public function block_enqueue_frontend_assets() {
do_action( 'stackable_block_enqueue_frontend_assets' );
}

/**
* Enqueue frontend scripts and styles for a given post content.
*
* @param string $post_content The post content.
* @return void
*/
public static function enqueue_frontend_assets_for_content( $post_content ) {
// If a Stackable block is present in the post content, enqueue the frontend assets.
if ( ! self::$is_main_script_loaded && ! is_admin() ) {
if ( stripos( $post_content, '<!-- wp:stackable/' ) !== false ) {
self::block_enqueue_frontend_assets();
self::$is_main_script_loaded = true;
}
}

// Gather all the unique Stackable blocks and load all the block scripts once.
// Gather all the "<!-- wp:stackable/BLOCK_NAME"
preg_match_all( '/<!-- wp:stackable\/([a-zA-Z_-]+)/', $post_content, $stackable_blocks );
// Go through each unique block name.
foreach ( $stackable_blocks[1] as $_block_name ) {
// Clean up the block name, trailing "-" from the end since it may have "--" in the end if the post content is compressed.
$block_name = trim( $_block_name, '-' );
Comment on lines +286 to +290
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify the regex pattern and trailing dash trimming logic.

The regex /<!-- wp:stackable\/([a-zA-Z_-]+)/ captures block names, and line 290 trims trailing dashes "since it may have '--' in the end if the post content is compressed." This seems like a workaround for a specific edge case.

Ensure that:

  1. The regex pattern correctly handles all valid Stackable block names
  2. The trimming logic doesn't inadvertently truncate valid block names with trailing hyphens
  3. Compressed content scenarios are properly tested

You can verify the block name extraction logic with this script:


🏁 Script executed:

#!/bin/bash
# Description: Find all Stackable block names in the codebase to verify the regex pattern covers them

# Search for block registrations to find all valid block names
rg -n --type=php -C2 'register_block_type.*stackable/' | head -50

Length of output: 0


Now I need to search the codebase directly to find the actual block names and verify the regex pattern:Let me run shell scripts to search the codebase directly for block definitions and usage:


🏁 Script executed:

#!/bin/bash
# Find block HTML comments in the codebase to see actual block names
rg -n --type=php '<!-- wp:stackable' | head -30

Length of output: 442


🏁 Script executed:

#!/bin/bash
# Look for where blocks might be defined or registered in PHP
rg -n --type=php "stackable/" | head -50

Length of output: 3397


🏁 Script executed:

#!/bin/bash
# Search for any file that might define block names
find . -name "*.json" -o -name "block*.php" | head -20

Length of output: 572


🏁 Script executed:

#!/bin/bash
# Look for the enqueue_frontend_assets_for_content method implementation context
rg -n -A20 "enqueue_frontend_assets_for_content" --type=php | head -60

Length of output: 1463


Let me verify if there are any block names with underscores or uppercase letters:


🏁 Script executed:

#!/bin/bash
# Search all block.json files to find actual block names
find . -name "block.json" -type f -exec grep -h '"name"' {} \; | sort -u | head -50

Length of output: 1576


🏁 Script executed:

#!/bin/bash
# Look for block names in stk-block-types.php to get a complete picture
rg -n "'name' => 'stackable/" src/stk-block-types.php | head -100

Length of output: 1926


🏁 Script executed:

#!/bin/bash
# Check if there's any test data or documentation about block names
rg -n "stackable/[a-zA-Z0-9_-]+" --type=php src/ | grep -E "(stackable/[A-Z]|stackable/.*_)" | head -20

Length of output: 2369


🏁 Script executed:

#!/bin/bash
# Look at the actual HTML comment context in tests or examples
rg -B2 -A2 "<!-- wp:stackable/" --type=php --type=json | head -80

Length of output: 1280


Improve regex pattern to match WordPress block naming conventions.

The regex /<!-- wp:stackable\/([a-zA-Z_-]+)/ at line 286 includes uppercase letters [A-Z] and underscores [_] which don't appear in any actual Stackable block names and violate WordPress block naming standards. All 50+ Stackable blocks use only lowercase letters and hyphens (e.g., button-group, call-to-action, icon-button).

The trimming at line 290 is a valid workaround but indicates the regex lacks proper boundary detection. Recommended fix:

preg_match_all( '/<!-- wp:stackable\/([a-z0-9-]+)(?:\s|-->)/', $post_content, $stackable_blocks );

This uses the correct character class [a-z0-9-] and adds an explicit boundary (?:\s|-->) to eliminate reliance on trim as a corrective measure. The trim call becomes redundant but can remain for safety.

🤖 Prompt for AI Agents
In src/init.php around lines 286 to 290, the current regex /<!--
wp:stackable\/([a-zA-Z_-]+)/ is too permissive (allows uppercase and
underscores) and relies on trimming; replace it with a pattern that matches
WordPress block names only (lowercase letters, numbers and hyphens) and enforces
a boundary (e.g., use a pattern equivalent to /<!--
wp:stackable\/([a-z0-9-]+)(?:\s|-->)/ ), and then remove the redundant trim call
(you may keep it as a harmless safety net).


// Enqueue the block script once.
if ( ! isset( self::$scripts_loaded[ $block_name ] ) ) {
do_action( 'stackable/' . $block_name . '/enqueue_scripts' );
self::$scripts_loaded[ $block_name ] = true;
}
}

// Check whether the current block needs to enqueue some scripts.
// This gets called across all the blocks.
do_action( 'stackable/enqueue_scripts', $post_content );
}

/**
* Enqueue CodeMirror separately. This originally was enqueued in
* `register_block_editor_assets`, but we want to enqueue this only when
Expand Down
4 changes: 2 additions & 2 deletions src/lightbox/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
}

if ( ! function_exists( 'stackable_load_lightbox_frontend_script' ) ) {
function stackable_load_lightbox_frontend_script( $block_content, $block ) {
function stackable_load_lightbox_frontend_script( $block_content ) {
if ( strpos( $block_content, 'stk--has-lightbox' ) !== false ) {
wp_enqueue_script(
'stk-frontend-image-lightbox',
Expand All @@ -32,6 +32,6 @@ function stackable_load_lightbox_frontend_script( $block_content, $block ) {
}

if ( ! is_admin() ) {
add_action( 'stackable/enqueue_scripts', 'stackable_load_lightbox_frontend_script', 10, 2 );
add_action( 'stackable/enqueue_scripts', 'stackable_load_lightbox_frontend_script' );
}
}
Loading