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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### Fixed

- Fixed Bricks sites hanging when removed Core Framework classes were cleaned up. The initial lookup joined post metadata five times, multiplying rows on sites with many metadata entries. It now checks all five Bricks metadata keys through one join while retaining the existing batched cleanup.
- Fixed transparent variants and shade/tint counts for RAW colors that reference another variable, such as `var(--bg-body)`. Generated variants now follow the current source color, while manually edited swatches are preserved. Older saved swatches without edit history are left unchanged on load; use Reset on a stale swatch to return it to automatic generation, then save to update the site's CSS.
- Fixed the block editor going blank with the Core Framework Gutenberg integration enabled. The editor script was loaded with an outdated, hard-coded dependency list that left out WordPress's `react-jsx-runtime`, so rendering the Core Framework class panel threw on an undefined `ReactJSXRuntime` and took the whole editor down. The script now loads the dependencies its build declares.
- Fixed saving from the Figma plugin to a connected WordPress site, which waited 15 seconds and then reported "Failed to sync css with Figma" and "Failed to update project" even though the changes had reached the site. The plugin handed WordPress's reply back under the wrong message type, so the editor never recognised it. Builder synchronization now also waits for the stylesheet and project to finish saving, so Bricks global variables, color swatches and the Style Manager show the values you just saved, including on projects that define variables but no classes. An empty class list no longer creates a blank Oxygen selector.
Expand Down
43 changes: 41 additions & 2 deletions packages/wp/Tests/BricksSynchronizationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,11 @@ function get_post_types( $args = array(), $output = 'names' ) {

if ( ! function_exists( 'get_posts' ) ) {
function get_posts( $args = array() ) {
$meta_keys = array_column( array_filter( $args['meta_query'] ?? array(), 'is_array' ), 'key' );
$post_ids = array();
$meta_keys = array();
foreach ( array_filter( $args['meta_query'] ?? array(), 'is_array' ) as $clause ) {
$meta_keys = array_merge( $meta_keys, (array) $clause['key'] );
}
$post_ids = array();

foreach ( $GLOBALS['cf_test_post_meta'] as $post_id => $post_meta ) {
if ( array_intersect( $meta_keys, array_keys( $post_meta ) ) ) {
Expand Down Expand Up @@ -447,6 +450,42 @@ public function testSelectorsThatSanitizeToTheSameIdProduceOneClass(): void {
);
}

public function testReferenceSweepFindsEveryBricksMetaKeyAndSkipsUnrelatedPosts(): void {
$meta_keys = array(
'_bricks_page_header_2',
'_bricks_page_content_2',
'_bricks_page_footer_2',
'_bricks_page_settings',
'_bricks_template_settings',
);

foreach ( $meta_keys as $index => $meta_key ) {
$GLOBALS['cf_test_post_meta'][ $index + 1 ] = array(
$meta_key => array( '_cssGlobalClasses' => array( 'removed_c', 'keep-me' ) ),
);
}
$GLOBALS['cf_test_post_meta'][6] = array( '_bricks_page_content_2' => '' );
$GLOBALS['cf_test_post_meta'][7] = array( '_bricks_page_settings' => array() );
$GLOBALS['cf_test_post_meta'][8] = array(
'unrelated_meta' => array( '_cssGlobalClasses' => array( 'removed_c' ) ),
);

$method = new ReflectionMethod( BricksFunctions::class, 'remove_class_references' );
$method->setAccessible( true );
$method->invoke( $this->createBricksFunctions(), array( 'removed_c' ) );

$this->assertSame( array( range( 1, 7 ) ), $GLOBALS['cf_test_meta_primes'] );
foreach ( $meta_keys as $index => $meta_key ) {
$this->assertSame(
array( 'keep-me' ),
$GLOBALS['cf_test_post_meta'][ $index + 1 ][ $meta_key ]['_cssGlobalClasses']
);
}
$this->assertSame( '', $GLOBALS['cf_test_post_meta'][6]['_bricks_page_content_2'] );
$this->assertSame( array(), $GLOBALS['cf_test_post_meta'][7]['_bricks_page_settings'] );
$this->assertSame( array( 'removed_c' ), $GLOBALS['cf_test_post_meta'][8]['unrelated_meta']['_cssGlobalClasses'] );
}

public function testReferenceSweepIsBatchedAndRunsAfterClassesArePersisted(): void {
$GLOBALS['cf_test_options'][ BricksFunctions::BRICKS_CLASSES_OPTION ] = array(
array(
Expand Down
16 changes: 9 additions & 7 deletions packages/wp/wp/App/Bricks/Functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -254,13 +254,15 @@ private function remove_class_references( array $class_ids ): void {
defined( 'BRICKS_DB_TEMPLATE_SETTINGS' ) ? constant( 'BRICKS_DB_TEMPLATE_SETTINGS' ) : '_bricks_template_settings',
);

$meta_query = array( 'relation' => 'OR' );
foreach ( $meta_keys as $meta_key ) {
$meta_query[] = array(
'key' => $meta_key,
'compare' => 'EXISTS',
);
}
// Separate OR/EXISTS clauses create one postmeta join per key, multiplying
// rows on posts with lots of metadata. Match all keys through a single join.
$meta_query = array(
array(
'key' => $meta_keys,
'compare_key' => 'IN',
'compare' => 'EXISTS',
),
);

$post_ids = get_posts(
array(
Expand Down
27 changes: 27 additions & 0 deletions scripts/test-wp-e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,33 @@ if (!is_file($path)) {
WP_CLI::success("Generated stylesheet exists in the uploads directory.");
'

# Exercise the real WP_Query SQL builder: unit tests use a get_posts() stub.
# Short-circuit execution so this regression check never runs a Cartesian join.
wp_cli eval '
$queries = array();
$capture = static function ($posts, $query) use (&$queries) {
$queries[] = $query->request;
return array();
};
add_filter("posts_pre_query", $capture, 10, 2);
try {
$class = new ReflectionClass(\CoreFramework\App\Bricks\Functions::class);
$method = $class->getMethod("remove_class_references");
$method->setAccessible(true);
$method->invoke($class->newInstanceWithoutConstructor(), array("cf-e2e-removed_c"));
} finally {
remove_filter("posts_pre_query", $capture, 10);
}
global $wpdb;
if (count($queries) !== 1 || substr_count($queries[0], "JOIN $wpdb->postmeta") !== 1) {
WP_CLI::error("Bricks reference discovery must use exactly one postmeta join.");
}
if (strpos($queries[0], "$wpdb->postmeta.meta_key IN (") === false) {
WP_CLI::error("Bricks reference discovery must filter metadata keys together.");
}
WP_CLI::success("Bricks reference discovery uses one postmeta join.");
'

curl --fail --silent --show-error --cookie-jar "$COOKIE_FILE" "$SITE_URL/wp-login.php" >/dev/null
curl --fail --silent --show-error --location \
--cookie "$COOKIE_FILE" \
Expand Down
Loading