Plugin Directory

Changeset 3764408


Ignore:
Timestamp:
10/25/2026 11:14:14 AM (11 hours ago)
Author:
mohammaadfarid
Message:

readme.txt

Location:
zoloblocks
Files:
932 added
4 edited

Legend:

Unmodified
Added
Removed
  • zoloblocks/trunk/includes/Classes/StyleGenerator.php

    r3513384 r3764408  
    1515
    1616    private $dynamic_styles = '';
     17
     18    /**
     19     * Block styles already printed in <head> (keyed by md5), so the footer
     20     * output does not repeat them.
     21     *
     22     * @var array
     23     */
     24    private $head_styles = [];
    1725
    1826    public function __construct() {
    … …  
    2836            add_action('wp_head', [$this, 'output_dynamic_styles']);
    2937        } else {
     38            // Classic themes render the content after wp_head, so styles collected
     39            // during render can only be printed in the footer, which causes layout
     40            // shift (CLS). Pre-collect the current post's block styles and print
     41            // them in <head>; the footer still prints anything rendered later
     42            // (widgets, other loops). Priority 99 keeps them after enqueued styles.
     43            add_action('wp_head', [$this, 'output_head_styles'], 99);
    3044            add_action('wp_footer', [$this, 'output_dynamic_styles']);
    3145        }
     46    }
     47
     48    /**
     49     * Print the block styles of the queried post in <head> on classic themes.
     50     *
     51     * @return void
     52     */
     53    public function output_head_styles() {
     54        /**
     55         * Filters whether ZoloBlocks prints the current post's block styles in
     56         * <head> on classic themes. Return false to keep the footer-only output.
     57         *
     58         * @param bool $print_in_head Default true on singular views.
     59         */
     60        if (! apply_filters('zolo_print_styles_in_head', is_singular())) {
     61            return;
     62        }
     63
     64        $post = get_queried_object();
     65        if (! $post instanceof \WP_Post || ! has_blocks($post->post_content)) {
     66            return;
     67        }
     68
     69        $seen_refs = [];
     70        $css       = apply_filters('zolo_dynamic_styles', $this->collect_block_styles(parse_blocks($post->post_content), $seen_refs));
     71        $safe_css  = ZoloHelpers::zolo_sanitize_inline_css($css);
     72        if ('' !== $safe_css) {
     73            echo '<style id="zolo-block-inline-styles">' . $safe_css . '</style>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
     74        }
     75    }
     76
     77    /**
     78     * Collect zoloStyles from parsed blocks, including inner and synced (reusable) blocks.
     79     *
     80     * @param array $blocks    Parsed blocks.
     81     * @param array $seen_refs Synced block IDs already visited (prevents loops).
     82     * @return string
     83     */
     84    private function collect_block_styles($blocks, &$seen_refs) {
     85        $css = '';
     86
     87        // Inner blocks are collected before their parent to match render order
     88        // (render_block runs for children first), so the CSS cascade is unchanged.
     89        foreach ($blocks as $block) {
     90            $name = $block['blockName'] ?? '';
     91
     92            if (! empty($block['innerBlocks'])) {
     93                $css .= $this->collect_block_styles($block['innerBlocks'], $seen_refs);
     94            }
     95
     96            if ('core/block' === $name && ! empty($block['attrs']['ref'])) {
     97                $ref = (int) $block['attrs']['ref'];
     98                if (! isset($seen_refs[$ref])) {
     99                    $seen_refs[$ref] = true;
     100                    $synced          = get_post($ref);
     101                    if ($synced instanceof \WP_Post && 'wp_block' === $synced->post_type && 'publish' === $synced->post_status) {
     102                        $css .= $this->collect_block_styles(parse_blocks($synced->post_content), $seen_refs);
     103                    }
     104                }
     105            }
     106
     107            if (str_starts_with((string) $name, 'zolo/') && isset($block['attrs']['zoloStyles'])) {
     108                $style = ZoloHelpers::zolo_generate_style($block['attrs']['zoloStyles']);
     109                $key   = md5($style);
     110                if ('' !== $style && ! isset($this->head_styles[$key])) {
     111                    $this->head_styles[$key] = true;
     112                    $css .= $style;
     113                }
     114            }
     115        }
     116
     117        return $css;
    32118    }
    33119
    … …  
    37123            if (isset($block['attrs']['zoloStyles'])) {
    38124                $style = ZoloHelpers::zolo_generate_style($block['attrs']['zoloStyles']);
    39                 $this->dynamic_styles .= $style;
     125                // Skip styles already printed in <head> (classic themes).
     126                if (! isset($this->head_styles[md5($style)])) {
     127                    $this->dynamic_styles .= $style;
     128                }
    40129            }
    41130
    … …  
    59148            $safe_css = ZoloHelpers::zolo_sanitize_inline_css($dynamic_styles);
    60149            if ('' !== $safe_css) {
    61                 echo '<style id="zolo-block-inline-styles">' . $safe_css . '</style>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
     150                // Use a distinct id when the head already printed the main block styles.
     151                $style_id = empty($this->head_styles) ? 'zolo-block-inline-styles' : 'zolo-block-inline-styles-footer';
     152                echo '<style id="' . esc_attr($style_id) . '">' . $safe_css . '</style>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    62153            }
    63154        }
  • zoloblocks/trunk/languages/zoloblocks.pot

    r3757694 r3764408  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: ZoloBlocks 2.8.1\n"
     5"Project-Id-Version: ZoloBlocks 2.8.2\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/zoloblocks\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
    … …  
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2026-10-20T11:09:43+00:00\n"
     12"POT-Creation-Date: 2026-10-25T10:54:18+00:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.12.0\n"
  • zoloblocks/trunk/readme.txt

    r3757694 r3764408  
    66Tested up to: 7.1
    77Requires PHP: 7.4
    8 Stable tag: 2.8.1
     8Stable tag: 2.8.2
    99License: GPLv2 or later
    1010License URI: http://www.gnu.org/licenses/gpl-2.0.html
    … …  
    193193
    194194== Changelog ==
     195
     196### 2.8.2 [October 25, 2026]
     197
     198#### Performance
     199- Block styles now load in the page head on classic themes, removing the layout shift (CLS) caused by styles printed in the footer.
     200
     201#### Added
     202- `zolo_print_styles_in_head` filter to keep the old footer-only style output on classic themes.
    195203
    196204### 2.8.1 [October 20, 2026]
  • zoloblocks/trunk/zoloblocks.php

    r3757694 r3764408  
    44 * Plugin Name: ZoloBlocks
    55 * Plugin URI: https://zoloblocks.com/
    6  * Version: 2.8.1
     6 * Version: 2.8.2
    77 * Author: BdThemes
    88 * Author URI: https://bdthemes.com/
    … …  
    7777        define( 'ZOLO_NAMESPACE', 'zoloblocks' );
    7878        define( 'ZOLO_SLUG', 'zoloblocks' );
    79         define( 'ZOLO_VERSION', '2.8.1' );
     79        define( 'ZOLO_VERSION', '2.8.2' );
    8080        define( 'ZOLO_DIR_PATH', plugin_dir_path( __FILE__ ) );
    8181        define( 'ZOLO_ADMIN_URL', plugin_dir_url( __FILE__ ) );
Note: See TracChangeset for help on using the changeset viewer.