| @@ -12,10 +12,12 @@ | ||
| 12 | 12 | |
| 13 | 13 | $style_depends = []; |
| 14 | 14 | $scripts_depends = []; |
| 15 | 15 | $aBlocks = []; |
| 16 | + $seen_refs = []; | |
| 17 | + $global_classes = []; | |
| 16 | 18 | |
| 17 | - self::recursive_block_parser( $parse_blocks_content, $aBlocks, $style_depends, $scripts_depends ); | |
| 19 | + self::recursive_block_parser( $parse_blocks_content, $aBlocks, $style_depends, $scripts_depends, $seen_refs, $global_classes ); | |
| 18 | 20 | |
| 19 | 21 | // Dedupe once, after the whole block tree has been walked. |
| 20 | 22 | $style_depends = array_unique( $style_depends ); |
| 21 | 23 | $scripts_depends = array_unique( $scripts_depends ); |
| @@ -62,18 +64,25 @@ | ||
| 62 | 64 | if ( (bool) apply_filters( 'ablocks/perf/dedupe_css', true ) ) { |
| 63 | 65 | $dynamic_css = CssDedupe::process( $dynamic_css ); |
| 64 | 66 | } |
| 65 | 67 | |
| 68 | + // Global classes, narrowed to the ones this page uses. They sit between | |
| 69 | + // the blocks' static CSS and their per-instance rules so a block's own | |
| 70 | + // styles still win over a class it carries. | |
| 71 | + $global_css = GlobalClasses::compiled_css_for( | |
| 72 | + array_values( array_unique( $global_classes ) ) | |
| 73 | + ); | |
| 74 | + | |
| 66 | 75 | $FileUpload = new FileUpload(); |
| 67 | 76 | $destination_folder = $FileUpload->get_upload_dir(); |
| 68 | 77 | self::copy_build_image_folder_to_uploads( $destination_folder ); |
| 69 | - $FileUpload->create_file( $file_name . '.min.css', $library_css . $static_css . $dynamic_css ); | |
| 78 | + $FileUpload->create_file( $file_name . '.min.css', $library_css . $static_css . $global_css . $dynamic_css ); | |
| 70 | 79 | $FileUpload->create_file( $file_name . '.min.js', $library_js . $static_js ); |
| 71 | 80 | |
| 72 | 81 | return $aBlocks; |
| 73 | 82 | } |
| 74 | 83 | |
| 75 | - public static function recursive_block_parser( $parse_content, &$aBlocks, &$style_depends, &$scripts_depends, &$seen_refs = [] ) { | |
| 84 | + public static function recursive_block_parser( $parse_content, &$aBlocks, &$style_depends, &$scripts_depends, &$seen_refs = [], &$global_classes = [] ) { | |
| 76 | 85 | if ( count( $parse_content ) > 0 ) { |
| 77 | 86 | foreach ( $parse_content as $item ) { |
| 78 | 87 | if ( ! empty( $item['blockName'] ) ) { |
| 79 | 88 | // Handle reusable blocks or patterns using "ref" |
| @@ -86,11 +95,21 @@ | ||
| 86 | 95 | $seen_refs[] = $ref_post_id; |
| 87 | 96 | $ref_post = get_post( $ref_post_id ); // Get the reusable block or pattern |
| 88 | 97 | if ( $ref_post ) { |
| 89 | 98 | $ref_content = parse_blocks( $ref_post->post_content ); // Parse the reusable block's content |
| 90 | - self::recursive_block_parser( $ref_content, $aBlocks, $style_depends, $scripts_depends, $seen_refs ); // Recursively parse the referenced block/pattern | |
| 99 | + self::recursive_block_parser( $ref_content, $aBlocks, $style_depends, $scripts_depends, $seen_refs, $global_classes ); // Recursively parse the referenced block/pattern | |
| 91 | 100 | } |
| 92 | 101 | } elseif ( strpos( $item['blockName'], 'ablocks' ) !== false ) { |
| 102 | + // Which global classes this page actually needs. Collected | |
| 103 | + // from the walk rather than from a stored per-post index: | |
| 104 | + // the walk is happening anyway, and an index would be one | |
| 105 | + // more thing to keep in sync with the content. | |
| 106 | + if ( ! empty( $item['attrs']['globalClasses'] ) && is_array( $item['attrs']['globalClasses'] ) ) { | |
| 107 | + foreach ( $item['attrs']['globalClasses'] as $global_class_id ) { | |
| 108 | + $global_classes[] = (string) $global_class_id; | |
| 109 | + } | |
| 110 | + } | |
| 111 | + | |
| 93 | 112 | $block_name_class = str_replace( ' ', '', ucwords( str_replace( '-', ' ', explode( '/', $item['blockName'] )[1] ) ) ); |
| 94 | 113 | |
| 95 | 114 | $dynamic_class = '\\ABlocks\\Blocks\\' . $block_name_class . '\\Block'; |
| 96 | 115 | if ( ! class_exists( $dynamic_class ) ) { |
| @@ -120,15 +139,29 @@ | ||
| 120 | 139 | // array_unique on every block). |
| 121 | 140 | $style_depends = array_merge( $style_depends, $instance->get_style_depends() ); |
| 122 | 141 | $scripts_depends = array_merge( $scripts_depends, $instance->get_script_depends() ); |
| 123 | 142 | |
| 124 | - // Capture dynamic CSS | |
| 143 | + // Capture dynamic CSS. | |
| 144 | + // | |
| 145 | + // A block can be reached twice in one walk: on an FSE theme | |
| 146 | + // `pre_render_block` collects EVERY block — parents and their | |
| 147 | + // children alike — and this parser also recurses into | |
| 148 | + // `innerBlocks`, so a nested block is seen once as a child and | |
| 149 | + // once as a collected top-level entry. Compiling it a second | |
| 150 | + // time is not idempotent for blocks whose CSS is emitted | |
| 151 | + // through a per-request dedupe (the atomic blocks' hashed | |
| 152 | + // `ablocks-s-*` rules): the repeat build returns an empty | |
| 153 | + // string because the rule was already emitted, and writing | |
| 154 | + // that over the first result stripped every nested atomic | |
| 155 | + // block's styles from the page. Keep the first result. | |
| 125 | 156 | if ( isset( $item['attrs']['ref'] ) || isset( $item['attrs']['block_id'] ) ) { |
| 126 | 157 | $block_id_or_ref = ! empty( $item['attrs']['block_id'] ) ? $item['attrs']['block_id'] : 'core_pattern_ref_' . $item['attrs']['ref']; |
| 127 | - $aBlocks[ $block_id_or_ref ] = [ | |
| 128 | - 'block_name' => $item['blockName'], | |
| 129 | - 'dynamic_style' => $instance->build_css( $attributes ), | |
| 130 | - ]; | |
| 158 | + if ( ! isset( $aBlocks[ $block_id_or_ref ]['dynamic_style'] ) ) { | |
| 159 | + $aBlocks[ $block_id_or_ref ] = [ | |
| 160 | + 'block_name' => $item['blockName'], | |
| 161 | + 'dynamic_style' => $instance->build_css( $attributes ), | |
| 162 | + ]; | |
| 163 | + } | |
| 131 | 164 | } |
| 132 | 165 | }//end if |
| 133 | 166 | }//end if |
| 134 | 167 | |
| @@ -133,9 +166,9 @@ | ||
| 133 | 166 | }//end if |
| 134 | 167 | |
| 135 | 168 | // Check for inner blocks and recursively process them |
| 136 | 169 | if ( is_array( $item['innerBlocks'] ) && count( $item['innerBlocks'] ) ) { |
| 137 | - self::recursive_block_parser( $item['innerBlocks'], $aBlocks, $style_depends, $scripts_depends, $seen_refs ); | |
| 170 | + self::recursive_block_parser( $item['innerBlocks'], $aBlocks, $style_depends, $scripts_depends, $seen_refs, $global_classes ); | |
| 138 | 171 | } |
| 139 | 172 | }//end if |
| 140 | 173 | }//end foreach |
| 141 | 174 | }//end if |