Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
af447eb
fix: improve snippet filtering for multisite support
imantsk Dec 15, 2025
750af73
fix: enhance multisite snippet handling by ensuring local snippets us…
imantsk Dec 15, 2025
2966921
fix: refactor snippet execution logic for multisite support by centra…
imantsk Dec 15, 2025
0ce8c45
phpcs: enhance documentation for Snippet_Files class with detailed PH…
imantsk Dec 15, 2025
5c5c035
fix: reorganize class and move private method to the bottom
imantsk Dec 15, 2025
4223530
fix: multisite capability check in Plugin class
imantsk Dec 15, 2025
49f9e95
fix: add screenshot assertions maxDiffPixelRatio
imantsk Dec 18, 2025
2fb1b60
fix: enhance Playwright test workflow with multisite support and impr…
imantsk Dec 18, 2025
47a20a4
fix: clarify documentation is_network_snippet_enabled
imantsk Dec 18, 2025
d840f7d
fix: update create_all_flat_files method to remove unused parameter a…
imantsk Dec 18, 2025
6e1b965
Merge branch 'core/core' into fix/multisite-issues
imantsk Dec 18, 2025
c49e829
fix: enhance Playwright test workflow and add wpCli helper for WP-CLI…
imantsk Dec 18, 2025
faf2978
fix: update Playwright workflow to support `multisite` configuration …
imantsk Dec 18, 2025
81579b5
fix: remove unnecessary WordPress mode echo statement from Playwright…
imantsk Dec 18, 2025
cc2ec6b
fix: update Playwright workflow conditions to support multisite execu…
imantsk Dec 18, 2025
7ceb12a
fix: enhance pull request workflow to handle labeled and unlabeled ev…
imantsk Dec 18, 2025
ad354e0
fix: correct artifact name output in build workflow and update zip fi…
imantsk Dec 18, 2025
64c39f9
fix: concurrency conditions in Playwright workflow
imantsk Dec 18, 2025
bac0f66
fix: standardize GH_TOKEN usage in pull request workflow
imantsk Dec 18, 2025
c2a10bb
fix: update GH_TOKEN usage to use secrets in pull request workflow
imantsk Dec 18, 2025
d9e36f7
fix: concurrency settings in Playwright workflow
imantsk Dec 18, 2025
8145e5d
fix: add concurrency settings for pull request builds
imantsk Dec 18, 2025
9cb25e7
fix: concurrency settings in Playwright workflow
imantsk Dec 18, 2025
7aad242
fix: add emoji to build started message in pull request workflow
imantsk Dec 18, 2025
a4d74ab
fix: update flat files setup to support multisite mode
imantsk Dec 19, 2025
da2faf9
fix: add multisite mode support to Playwright test environment
imantsk Dec 19, 2025
e4af12e
fix: correct wpAdminbase path for multisite mode in flat files setup
imantsk Dec 19, 2025
da84739
fix: improve caching strategy for Playwright tests to avoid collision…
imantsk Dec 19, 2025
919ca63
chore: test workflow setup cache
imantsk Dec 19, 2025
b8e2474
chore(ci): make cache keys deterministic and add cache debug logging
imantsk Dec 19, 2025
2c598ed
Revert "chore(ci): make cache keys deterministic and add cache debug …
imantsk Dec 19, 2025
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
203 changes: 114 additions & 89 deletions src/php/class-db.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,53 +197,95 @@ public static function create_table( string $table_name ): bool {
return $success;
}

/**
* Generate the SQL for fetching active snippets from the database.
*
* @param string[] $scopes List of scopes to retrieve in.
*
* @return array{
* id: int,
* code: string,
* scope: string,
* table: string,
* network: bool,
* priority: int,
* } List of active snippets.
*/
public function fetch_active_snippets( array $scopes ): array {
$active_snippets = [];

// Fetch the active snippets for the current site, if there are any.
$snippets = $this->fetch_snippets_from_table( $this->table, $scopes, true );
if ( $snippets ) {
foreach ( $snippets as $snippet ) {
$active_snippets[] = [
'id' => intval( $snippet['id'] ),
'code' => $snippet['code'],
'scope' => $snippet['scope'],
'table' => $this->table,
'network' => false,
'priority' => intval( $snippet['priority'] ),
];
}
}

// If multisite is enabled, fetch all snippets from the network table, and filter down to only active snippets.
if ( is_multisite() ) {
$ms_snippets = $this->fetch_snippets_from_table( $this->ms_table, $scopes, false );

if ( $ms_snippets ) {
$active_shared_ids = get_option( 'active_shared_network_snippets', [] );
$active_shared_ids = is_array( $active_shared_ids )
? array_map( 'intval', $active_shared_ids )
: [];

foreach ( $ms_snippets as $snippet ) {
$id = intval( $snippet['id'] );
$active_value = intval( $snippet['active'] );

if ( ! self::is_network_snippet_enabled( $active_value, $id, $active_shared_ids ) ) {
continue;
}

$active_snippets[] = [
'id' => $id,
'code' => $snippet['code'],
'scope' => $snippet['scope'],
'table' => $this->ms_table,
'network' => true,
'priority' => intval( $snippet['priority'] ),
];
}

$this->sort_active_snippets( $active_snippets );
}
}

return $active_snippets;
}

/**
* Fetch a list of active snippets from a database table.
* Determine whether a network snippet should execute on the current site.
*
* @param string $table_name Name of table to fetch snippets from.
* @param array<string> $scopes List of scopes to include in query.
* @param boolean $active_only Whether to only fetch active snippets from the table.
* Network snippets execute when active=1, or when the snippet is listed as active-shared for the site.
* Trashed snippets (active=-1) never execute.
*
* @return array<string, array<string, mixed>>|false List of active snippets, if any could be retrieved.
* @param int $active_value Raw active value from the snippet record.
* @param int $snippet_id Snippet ID.
* @param int[] $active_shared_ids Active shared network snippet IDs for the current site.
*
* @phpcs:disable WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
* @return bool
*/
private static function fetch_snippets_from_table( string $table_name, array $scopes, bool $active_only = true ) {
global $wpdb;

$cache_key = sprintf( 'active_snippets_%s_%s', sanitize_key( join( '_', $scopes ) ), $table_name );
$cached_snippets = wp_cache_get( $cache_key, CACHE_GROUP );

if ( is_array( $cached_snippets ) ) {
return $cached_snippets;
}

if ( ! self::table_exists( $table_name ) ) {
public static function is_network_snippet_enabled( int $active_value, int $snippet_id, array $active_shared_ids ): bool {
if ( -1 === $active_value ) {
return false;
}

$scopes_format = implode( ',', array_fill( 0, count( $scopes ), '%s' ) );
$extra_where = $active_only ? 'AND active=1' : '';

$snippets = $wpdb->get_results(
$wpdb->prepare(
"
SELECT id, code, scope, active, priority
FROM $table_name
WHERE scope IN ($scopes_format) $extra_where
ORDER BY priority, id",
$scopes
),
'ARRAY_A'
);

// Cache the full list of snippets.
if ( is_array( $snippets ) ) {
wp_cache_set( $cache_key, $snippets, CACHE_GROUP );
return $snippets;
if ( 1 === $active_value ) {
return true;
}

return false;
return in_array( $snippet_id, $active_shared_ids, true );
}

/**
Expand Down Expand Up @@ -282,68 +324,51 @@ static function ( $a, $b ) use ( $comparisons ) {
}

/**
* Generate the SQL for fetching active snippets from the database.
* Fetch a list of active snippets from a database table.
*
* @param string[] $scopes List of scopes to retrieve in.
* @param string $table_name Name of table to fetch snippets from.
* @param array<string> $scopes List of scopes to include in query.
* @param boolean $active_only Whether to only fetch active snippets from the table.
*
* @return array{
* id: int,
* code: string,
* scope: string,
* table: string,
* network: bool,
* priority: int,
* } List of active snippets.
* @return array<string, array<string, mixed>>|false List of active snippets, if any could be retrieved.
*
* @phpcs:disable WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
*/
public function fetch_active_snippets( array $scopes ): array {
$active_snippets = [];

// Fetch the active snippets for the current site, if there are any.
$snippets = $this->fetch_snippets_from_table( $this->table, $scopes, true );
if ( $snippets ) {
foreach ( $snippets as $snippet ) {
$active_snippets[] = [
'id' => intval( $snippet['id'] ),
'code' => $snippet['code'],
'scope' => $snippet['scope'],
'table' => $this->table,
'network' => false,
'priority' => intval( $snippet['priority'] ),
];
}
}
private static function fetch_snippets_from_table( string $table_name, array $scopes, bool $active_only = true ) {
global $wpdb;

// If multisite is enabled, fetch all snippets from the network table, and filter down to only active snippets.
if ( is_multisite() ) {
$ms_snippets = $this->fetch_snippets_from_table( $this->ms_table, $scopes, false );
$cache_key = sprintf( 'active_snippets_%s_%s', sanitize_key( join( '_', $scopes ) ), $table_name );
$cached_snippets = wp_cache_get( $cache_key, CACHE_GROUP );

if ( $ms_snippets ) {
$active_shared_ids = get_option( 'active_shared_network_snippets', [] );
$active_shared_ids = is_array( $active_shared_ids )
? array_map( 'intval', $active_shared_ids )
: [];
if ( is_array( $cached_snippets ) ) {
return $cached_snippets;
}

foreach ( $ms_snippets as $snippet ) {
$id = intval( $snippet['id'] );
if ( ! self::table_exists( $table_name ) ) {
return false;
}

if ( ! $snippet['active'] && ! in_array( $id, $active_shared_ids, true ) ) {
continue;
}
$scopes_format = implode( ',', array_fill( 0, count( $scopes ), '%s' ) );
$extra_where = $active_only ? 'AND active=1' : '';

$active_snippets[] = [
'id' => $id,
'code' => $snippet['code'],
'scope' => $snippet['scope'],
'table' => $this->ms_table,
'network' => true,
'priority' => intval( $snippet['priority'] ),
];
}
$snippets = $wpdb->get_results(
$wpdb->prepare(
"
SELECT id, code, scope, active, priority
FROM $table_name
WHERE scope IN ($scopes_format) $extra_where
ORDER BY priority, id",
$scopes
),
'ARRAY_A'
);

$this->sort_active_snippets( $active_snippets );
}
// Cache the full list of snippets.
if ( is_array( $snippets ) ) {
wp_cache_set( $cache_key, $snippets, CACHE_GROUP );
return $snippets;
}

return $active_snippets;
return false;
}
}
6 changes: 5 additions & 1 deletion src/php/class-plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public function load_plugin() {
// Settings component.
require_once $includes_path . '/settings/settings-fields.php';
require_once $includes_path . '/settings/editor-preview.php';
require_once $includes_path . '/settings/class-version-switch.php';
require_once $includes_path . '/settings/class-version-switch.php';
require_once $includes_path . '/settings/settings.php';

// Cloud List Table shared functions.
Expand Down Expand Up @@ -357,6 +357,10 @@ public function get_cap(): string {
return $this->get_network_cap_name();
}

if ( is_multisite() && ! $this->is_subsite_menu_enabled() ) {
return $this->get_network_cap_name();
}

return $this->get_cap_name();
}

Expand Down
Loading
Loading