From 278af8a4e93f8dd143f790885a6b856d30c1d919 Mon Sep 17 00:00:00 2001 From: Imants Date: Tue, 4 Nov 2025 16:03:13 +0200 Subject: [PATCH 01/17] fix: tooltip usage and styling --- .../controls/MultisiteSharingSettings.tsx | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/js/components/EditorSidebar/controls/MultisiteSharingSettings.tsx b/src/js/components/EditorSidebar/controls/MultisiteSharingSettings.tsx index 27d6c57d..bae5bd08 100644 --- a/src/js/components/EditorSidebar/controls/MultisiteSharingSettings.tsx +++ b/src/js/components/EditorSidebar/controls/MultisiteSharingSettings.tsx @@ -1,39 +1,41 @@ import React from 'react' import { __ } from '@wordpress/i18n' import { useSnippetForm } from '../../../hooks/useSnippetForm' +import { Tooltip } from '../../common/Tooltip' export const MultisiteSharingSettings: React.FC = () => { const { snippet, setSnippet, isReadOnly } = useSnippetForm() return ( -
+

- + {__('Share with Subsites', 'code-snippets')}

-
- - { - __('Instead of running on every site, allow this snippet to be activated on individual sites on the network.', 'code-snippets') - } -
+ + {__('Instead of running on every site, allow this snippet to be activated on individual sites on the network.', 'code-snippets')} + - - setSnippet(previous => ({ - ...previous, - active: false, - shared_network: event.target.checked - }))} - /> +
) } From 9fd853143ae8d8679059769f4f7693e8ef67c55a Mon Sep 17 00:00:00 2001 From: Imants Date: Tue, 4 Nov 2025 18:13:05 +0200 Subject: [PATCH 02/17] fix: update checkbox checked state logic in MultisiteSharingSettings --- .../EditorSidebar/controls/MultisiteSharingSettings.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/components/EditorSidebar/controls/MultisiteSharingSettings.tsx b/src/js/components/EditorSidebar/controls/MultisiteSharingSettings.tsx index bae5bd08..cefc8e81 100644 --- a/src/js/components/EditorSidebar/controls/MultisiteSharingSettings.tsx +++ b/src/js/components/EditorSidebar/controls/MultisiteSharingSettings.tsx @@ -26,7 +26,7 @@ export const MultisiteSharingSettings: React.FC = () => { name="snippet_sharing" type="checkbox" className="switch" - checked={true === snippet.shared_network} + checked={!!snippet.shared_network} disabled={isReadOnly} onChange={event => setSnippet(previous => ({ From 95d81b2fcb60d395f7946c2a609bdd0a9f5b10bf Mon Sep 17 00:00:00 2001 From: Imants Date: Tue, 4 Nov 2025 18:13:10 +0200 Subject: [PATCH 03/17] fix: include shared_network in mapToSchema for snippet API --- src/js/utils/snippets/api.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/js/utils/snippets/api.ts b/src/js/utils/snippets/api.ts index e9072fd9..64bfb155 100644 --- a/src/js/utils/snippets/api.ts +++ b/src/js/utils/snippets/api.ts @@ -35,6 +35,7 @@ const mapToSchema = ({ priority, active, network, + shared_network, conditionId }: Partial): WritableSnippetSchema => ({ name, @@ -45,6 +46,7 @@ const mapToSchema = ({ priority, active, network, + shared_network, condition_id: conditionId }) From 675bd45796a4518f29a659346b7d8d3aabe8d751 Mon Sep 17 00:00:00 2001 From: Imants Date: Tue, 4 Nov 2025 18:13:25 +0200 Subject: [PATCH 04/17] fix: merge shared network snippets in get_items method --- .../class-snippets-rest-controller.php | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/php/rest-api/class-snippets-rest-controller.php b/src/php/rest-api/class-snippets-rest-controller.php index 4027d46b..2cfec385 100644 --- a/src/php/rest-api/class-snippets-rest-controller.php +++ b/src/php/rest-api/class-snippets-rest-controller.php @@ -198,6 +198,7 @@ public function register_routes() { public function get_items( $request ): WP_REST_Response { $network = $request->get_param( 'network' ); $all_snippets = get_snippets( [], $network ); + $all_snippets = $this->get_network_items( $all_snippets, $network ); // Get collection params (page, per_page). $collection_params = $this->get_collection_params(); @@ -229,6 +230,36 @@ public function get_items( $request ): WP_REST_Response { return $response; } + /** + * Retrieve and merge shared network snippets. + * + * @param array $all_snippets List of snippets to merge with. + * @param bool|null $network Whether fetching network snippets. + * + * @return array Modified list of snippets. + */ + private function get_network_items( array $all_snippets, $network ): array { + if ( ! is_multisite() || $network ) { + return $all_snippets; + } + + $shared_ids = get_site_option( 'shared_network_snippets' ); + + if ( ! $shared_ids || ! is_array( $shared_ids ) ) { + return $all_snippets; + } + + $active_shared_snippets = get_option( 'active_shared_network_snippets', array() ); + $shared_snippets = get_snippets( $shared_ids, true ); + + foreach ( $shared_snippets as $snippet ) { + $snippet->shared_network = true; + $snippet->active = in_array( $snippet->id, $active_shared_snippets, true ); + } + + return array_merge( $all_snippets, $shared_snippets ); + } + /** * Retrieves one item from the collection. * From 807e3bdeab2ac066af79deb668037881efc15451 Mon Sep 17 00:00:00 2001 From: Imants Date: Tue, 4 Nov 2025 18:13:35 +0200 Subject: [PATCH 05/17] fix: update shared network snippet handling and styling in List_Table and badges --- src/css/common/_badges.scss | 9 +++++- src/php/class-list-table.php | 54 ++++++++++++++++++------------------ 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/css/common/_badges.scss b/src/css/common/_badges.scss index 6ebb3cde..ffd2ee3d 100644 --- a/src/css/common/_badges.scss +++ b/src/css/common/_badges.scss @@ -18,7 +18,7 @@ padding-inline: 3px; box-sizing: border-box; gap: 5px; - line-height: 1; + .dashicons { font-size: 18px; @@ -27,6 +27,13 @@ } } +.network-shared { + color: #2271b1; + font-size: 22px; + width: 100%; + cursor: help; +} + .small-badge { block-size: auto; inline-size: auto; diff --git a/src/php/class-list-table.php b/src/php/class-list-table.php index 703765cf..f4914675 100644 --- a/src/php/class-list-table.php +++ b/src/php/class-list-table.php @@ -307,7 +307,14 @@ protected function column_activate( Snippet $snippet ): string { return ''; } - if ( $this->is_network && ( $snippet->shared_network || ( ! $this->is_network && $snippet->network && ! $snippet->shared_network ) ) ) { + // Show icon for shared network snippets on network admin. + if ( $snippet->shared_network && $this->is_network ) { + return ''; + } + + if ( $this->is_network && ( ! $this->is_network && $snippet->network && ! $snippet->shared_network ) ) { return ''; } @@ -377,10 +384,6 @@ protected function column_name( Snippet $snippet ): string { ); } - if ( $snippet->shared_network ) { - $out .= ' ' . esc_html__( 'Shared on Network', 'code-snippets' ) . ''; - } - $out = apply_filters( 'code_snippets/list_table/column_name', $out, $snippet ); return $out . $row_actions; } @@ -986,46 +989,43 @@ public function no_items() { /** * Fetch all shared network snippets for the current site. * - * @return void + * @param array $all_snippets List of snippets to merge with. + * + * @return array Updated list of snippets. */ - private function fetch_shared_network_snippets() { - /** - * Table data. - * - * @var $snippets array - */ - global $snippets; + private function fetch_shared_network_snippets( array $all_snippets ): array { + if ( ! is_multisite() ) { + return $all_snippets; + } - $ids = get_site_option( 'shared_network_snippets' ); + $shared_ids = get_site_option( 'shared_network_snippets' ); - if ( ! is_multisite() || ! $ids ) { - return; + if ( ! $shared_ids || ! is_array( $shared_ids ) ) { + return $all_snippets; } if ( $this->is_network ) { - $limit = count( $snippets['all'] ); - - for ( $i = 0; $i < $limit; $i++ ) { - $snippet = &$snippets['all'][ $i ]; - - if ( in_array( $snippet->id, $ids, true ) ) { + // Mark shared network snippets on the network admin page. + foreach ( $all_snippets as $snippet ) { + if ( in_array( $snippet->id, $shared_ids, true ) ) { $snippet->shared_network = true; - $snippet->tags = array_merge( $snippet->tags, array( 'shared on network' ) ); $snippet->active = false; } } } else { + // Fetch shared network snippets for subsites. $active_shared_snippets = get_option( 'active_shared_network_snippets', array() ); - $shared_snippets = get_snippets( $ids, true ); + $shared_snippets = get_snippets( $shared_ids, true ); foreach ( $shared_snippets as $snippet ) { $snippet->shared_network = true; - $snippet->tags = array_merge( $snippet->tags, array( 'shared on network' ) ); $snippet->active = in_array( $snippet->id, $active_shared_snippets, true ); } - $snippets['all'] = array_merge( $snippets['all'], $shared_snippets ); + $all_snippets = array_merge( $all_snippets, $shared_snippets ); } + + return $all_snippets; } /** @@ -1062,7 +1062,7 @@ public function prepare_items() { $snippets = array_fill_keys( $this->statuses, array() ); $all_snippets = apply_filters( 'code_snippets/list_table/get_snippets', get_snippets() ); - $this->fetch_shared_network_snippets(); + $all_snippets = $this->fetch_shared_network_snippets( $all_snippets ); // Separate trashed snippets from the main collection $snippets['trashed'] = array_filter( $all_snippets, function( $snippet ) { From d0effba43e150016e4603244b8e5df54a53ea1d3 Mon Sep 17 00:00:00 2001 From: Imants Date: Wed, 5 Nov 2025 08:48:03 +0200 Subject: [PATCH 06/17] fix: Update _badges.scss Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/css/common/_badges.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/css/common/_badges.scss b/src/css/common/_badges.scss index ffd2ee3d..eb3ca9b2 100644 --- a/src/css/common/_badges.scss +++ b/src/css/common/_badges.scss @@ -28,7 +28,7 @@ } .network-shared { - color: #2271b1; + color: #2271b1; font-size: 22px; width: 100%; cursor: help; From f033f1dfefdc12da5673938347199f9c21abf281 Mon Sep 17 00:00:00 2001 From: Imants Date: Thu, 6 Nov 2025 10:29:10 +0200 Subject: [PATCH 07/17] fix: revert line-height in badge styles --- src/css/common/_badges.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/css/common/_badges.scss b/src/css/common/_badges.scss index eb3ca9b2..4c5dad8f 100644 --- a/src/css/common/_badges.scss +++ b/src/css/common/_badges.scss @@ -18,7 +18,7 @@ padding-inline: 3px; box-sizing: border-box; gap: 5px; - + line-height: 1; .dashicons { font-size: 18px; From 60a68db93899788ff2507d8247868dc40b449daf Mon Sep 17 00:00:00 2001 From: Imants Date: Thu, 6 Nov 2025 15:21:37 +0200 Subject: [PATCH 08/17] fix: correct network condition check and streamline snippet fetching --- src/php/class-list-table.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/php/class-list-table.php b/src/php/class-list-table.php index f4914675..829d196c 100644 --- a/src/php/class-list-table.php +++ b/src/php/class-list-table.php @@ -314,7 +314,7 @@ protected function column_activate( Snippet $snippet ): string { '">'; } - if ( $this->is_network && ( ! $this->is_network && $snippet->network && ! $snippet->shared_network ) ) { + if ( ! $this->is_network && $snippet->network && ! $snippet->shared_network ) { return ''; } @@ -1061,8 +1061,7 @@ public function prepare_items() { $this->process_requested_actions(); $snippets = array_fill_keys( $this->statuses, array() ); - $all_snippets = apply_filters( 'code_snippets/list_table/get_snippets', get_snippets() ); - $all_snippets = $this->fetch_shared_network_snippets( $all_snippets ); + $all_snippets = apply_filters( 'code_snippets/list_table/get_snippets', $this->fetch_shared_network_snippets( get_snippets() ) ); // Separate trashed snippets from the main collection $snippets['trashed'] = array_filter( $all_snippets, function( $snippet ) { From 75b89fe11d9305c6dce515499e12e3e05c8a0abe Mon Sep 17 00:00:00 2001 From: Imants Date: Thu, 6 Nov 2025 16:06:09 +0200 Subject: [PATCH 09/17] fix: indentation --- src/css/common/_badges.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/css/common/_badges.scss b/src/css/common/_badges.scss index 4c5dad8f..ddef26a1 100644 --- a/src/css/common/_badges.scss +++ b/src/css/common/_badges.scss @@ -28,10 +28,10 @@ } .network-shared { - color: #2271b1; - font-size: 22px; - width: 100%; - cursor: help; + color: #2271b1; + font-size: 22px; + width: 100%; + cursor: help; } .small-badge { From e405b7ad243126764ce6a46811e591a18e55684c Mon Sep 17 00:00:00 2001 From: Imants Date: Thu, 6 Nov 2025 16:20:33 +0200 Subject: [PATCH 10/17] chore: composer upgrade --- src/composer.lock | 65 +++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/src/composer.lock b/src/composer.lock index 2914eafd..cd9b5b92 100644 --- a/src/composer.lock +++ b/src/composer.lock @@ -488,16 +488,16 @@ }, { "name": "phpcompatibility/phpcompatibility-paragonie", - "version": "1.3.3", + "version": "1.3.4", "source": { "type": "git", "url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git", - "reference": "293975b465e0e709b571cbf0c957c6c0a7b9a2ac" + "reference": "244d7b04fc4bc2117c15f5abe23eb933b5f02bbf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/293975b465e0e709b571cbf0c957c6c0a7b9a2ac", - "reference": "293975b465e0e709b571cbf0c957c6c0a7b9a2ac", + "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/244d7b04fc4bc2117c15f5abe23eb933b5f02bbf", + "reference": "244d7b04fc4bc2117c15f5abe23eb933b5f02bbf", "shasum": "" }, "require": { @@ -554,22 +554,26 @@ { "url": "https://opencollective.com/php_codesniffer", "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcompatibility", + "type": "thanks_dev" } ], - "time": "2024-04-24T21:30:46+00:00" + "time": "2025-09-19T17:43:28+00:00" }, { "name": "phpcompatibility/phpcompatibility-wp", - "version": "2.1.7", + "version": "2.1.8", "source": { "type": "git", "url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git", - "reference": "5bfbbfbabb3df2b9a83e601de9153e4a7111962c" + "reference": "7c8d18b4d90dac9e86b0869a608fa09158e168fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/5bfbbfbabb3df2b9a83e601de9153e4a7111962c", - "reference": "5bfbbfbabb3df2b9a83e601de9153e4a7111962c", + "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/7c8d18b4d90dac9e86b0869a608fa09158e168fa", + "reference": "7c8d18b4d90dac9e86b0869a608fa09158e168fa", "shasum": "" }, "require": { @@ -631,26 +635,26 @@ "type": "thanks_dev" } ], - "time": "2025-05-12T16:38:37+00:00" + "time": "2025-10-18T00:05:59+00:00" }, { "name": "phpcsstandards/phpcsextra", - "version": "1.4.0", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHPCSExtra.git", - "reference": "fa4b8d051e278072928e32d817456a7fdb57b6ca" + "reference": "8e89a01c7b8fed84a12a2a7f5a23a44cdbe4f62e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/fa4b8d051e278072928e32d817456a7fdb57b6ca", - "reference": "fa4b8d051e278072928e32d817456a7fdb57b6ca", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/8e89a01c7b8fed84a12a2a7f5a23a44cdbe4f62e", + "reference": "8e89a01c7b8fed84a12a2a7f5a23a44cdbe4f62e", "shasum": "" }, "require": { "php": ">=5.4", - "phpcsstandards/phpcsutils": "^1.1.0", - "squizlabs/php_codesniffer": "^3.13.0 || ^4.0" + "phpcsstandards/phpcsutils": "^1.1.2", + "squizlabs/php_codesniffer": "^3.13.4 || ^4.0" }, "require-dev": { "php-parallel-lint/php-console-highlighter": "^1.0", @@ -713,26 +717,26 @@ "type": "thanks_dev" } ], - "time": "2025-06-14T07:40:39+00:00" + "time": "2025-10-28T17:00:02+00:00" }, { "name": "phpcsstandards/phpcsutils", - "version": "1.1.1", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHPCSUtils.git", - "reference": "f7eb16f2fa4237d5db9e8fed8050239bee17a9bd" + "reference": "8b8e17615d04f2fc2cd46fc1d2fd888fa21b3cf9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/f7eb16f2fa4237d5db9e8fed8050239bee17a9bd", - "reference": "f7eb16f2fa4237d5db9e8fed8050239bee17a9bd", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/8b8e17615d04f2fc2cd46fc1d2fd888fa21b3cf9", + "reference": "8b8e17615d04f2fc2cd46fc1d2fd888fa21b3cf9", "shasum": "" }, "require": { "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7 || ^1.0", "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.13.0 || ^4.0" + "squizlabs/php_codesniffer": "^3.13.3 || ^4.0" }, "require-dev": { "ext-filter": "*", @@ -806,20 +810,20 @@ "type": "thanks_dev" } ], - "time": "2025-08-10T01:04:45+00:00" + "time": "2025-10-16T16:39:32+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.13.2", + "version": "3.13.5", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "5b5e3821314f947dd040c70f7992a64eac89025c" + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5b5e3821314f947dd040c70f7992a64eac89025c", - "reference": "5b5e3821314f947dd040c70f7992a64eac89025c", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0ca86845ce43291e8f5692c7356fccf3bcf02bf4", + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4", "shasum": "" }, "require": { @@ -836,11 +840,6 @@ "bin/phpcs" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" @@ -890,7 +889,7 @@ "type": "thanks_dev" } ], - "time": "2025-06-17T22:17:01+00:00" + "time": "2025-11-04T16:30:35+00:00" }, { "name": "wp-coding-standards/wpcs", From 7bc08c5ac0263de99500fd66d34636d65453325f Mon Sep 17 00:00:00 2001 From: Imants Date: Fri, 7 Nov 2025 00:43:57 +0200 Subject: [PATCH 11/17] fix: add support for shared network snippets and improve status labels --- src/php/class-list-table.php | 148 ++++++++++++++++++++++++----------- 1 file changed, 103 insertions(+), 45 deletions(-) diff --git a/src/php/class-list-table.php b/src/php/class-list-table.php index 829d196c..a11553ba 100644 --- a/src/php/class-list-table.php +++ b/src/php/class-list-table.php @@ -37,7 +37,7 @@ class List_Table extends WP_List_Table { * * @var array */ - public array $statuses = [ 'all', 'active', 'inactive', 'recently_activated', 'trashed' ]; + public array $statuses = [ 'all', 'active', 'inactive', 'recently_activated', 'shared_network', 'trashed' ]; /** * Column name to use when ordering the snippets list. @@ -246,6 +246,23 @@ public function get_action_link( string $action, Snippet $snippet ): string { private function get_snippet_action_links( Snippet $snippet ): array { $actions = array(); + if ( $snippet->shared_network && ! $this->is_network ) { + $actions['network_shared'] = sprintf( + '%s', + esc_html__( 'Network Snippet', 'code-snippets' ) + ); + + if ( is_multisite() && is_super_admin() ) { + $actions['edit'] = sprintf( + '%s', + esc_url( $this->get_action_link( 'edit', $snippet ) ), + esc_html__( 'Edit', 'code-snippets' ) + ); + } + + return apply_filters( 'code_snippets/list_table/row_actions', $actions, $snippet ); + } + if ( $snippet->is_trashed() ) { $actions['restore'] = sprintf( '%s', @@ -548,60 +565,88 @@ public function get_views(): array { // Loop through the view counts. foreach ( $totals as $type => $count ) { - $labels = []; - if ( ! $count ) { continue; } - // translators: %s: total number of snippets. - $labels['all'] = _n( - 'All (%s)', - 'All (%s)', - $count, - 'code-snippets' - ); - - // translators: %s: total number of active snippets. - $labels['active'] = _n( - 'Active (%s)', - 'Active (%s)', - $count, - 'code-snippets' - ); + switch ( $type ) { + case 'all': + // translators: %s: total number of snippets. + $template = _n( + 'All (%s)', + 'All (%s)', + $count, + 'code-snippets' + ); + break; + + case 'active': + // translators: %s: total number of active snippets. + $template = _n( + 'Active (%s)', + 'Active (%s)', + $count, + 'code-snippets' + ); + break; + + case 'inactive': + // translators: %s: total number of inactive snippets. + $template = _n( + 'Inactive (%s)', + 'Inactive (%s)', + $count, + 'code-snippets' + ); + break; + + case 'recently_activated': + // translators: %s: total number of recently activated snippets. + $template = _n( + 'Recently Active (%s)', + 'Recently Active (%s)', + $count, + 'code-snippets' + ); + break; - // translators: %s: total number of inactive snippets. - $labels['inactive'] = _n( - 'Inactive (%s)', - 'Inactive (%s)', - $count, - 'code-snippets' - ); + case 'shared_network': + if ( ! is_multisite() ) { + continue 2; + } - // translators: %s: total number of recently activated snippets. - $labels['recently_activated'] = _n( - 'Recently Active (%s)', - 'Recently Active (%s)', - $count, - 'code-snippets' - ); + $shared_label_template = $this->is_network + ? _n_noop( + 'Shared with Subsites (%s)', + 'Shared with Subsites (%s)', + 'code-snippets' + ) + : _n_noop( + 'Network Snippets (%s)', + 'Network Snippets (%s)', + 'code-snippets' + ); + + $template = translate_nooped_plural( $shared_label_template, $count, 'code-snippets' ); + break; + + case 'trashed': + // translators: %s: total number of trashed snippets. + $template = _n( + 'Trashed (%s)', + 'Trashed (%s)', + $count, + 'code-snippets' + ); + break; - // translators: %s: total number of trashed snippets. - $labels['trashed'] = _n( - 'Trashed (%s)', - 'Trashed (%s)', - $count, - 'code-snippets' - ); + default: + continue 2; + } - // The page URL with the status parameter. $url = esc_url( add_query_arg( 'status', $type ) ); - - // Add a class if this view is currently being viewed. $class = $type === $status ? ' class="current"' : ''; - - // Add the view count to the label. - $text = sprintf( $labels[ $type ], number_format_i18n( $count ) ); + $text = sprintf( $template, number_format_i18n( $count ) ); $status_links[ $type ] = sprintf( '%s', $url, $class, $text ); } @@ -1124,6 +1169,19 @@ function ( Snippet $snippet ) use ( $type ) { $snippets['trashed'] = array_filter( $snippets['trashed'], array( $this, 'search_by_line_callback' ) ); } + if ( is_multisite() ) { + $snippets['shared_network'] = array_values( + array_filter( + $snippets['all'], + static function ( Snippet $snippet ) { + return $snippet->shared_network; + } + ) + ); + } else { + $snippets['shared_network'] = array(); + } + // Clear recently activated snippets older than a week. $recently_activated = $this->is_network ? get_site_option( 'recently_activated_snippets', array() ) : From 435c455e13fd9a7a4a55d534de45e1aa6291949d Mon Sep 17 00:00:00 2001 From: Imants Date: Fri, 7 Nov 2025 01:10:48 +0200 Subject: [PATCH 12/17] feat: update badge styles for network snippets and adjust color in row actions --- src/css/common/_badges.scss | 5 +++++ src/php/class-list-table.php | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/css/common/_badges.scss b/src/css/common/_badges.scss index ddef26a1..a8c0a748 100644 --- a/src/css/common/_badges.scss +++ b/src/css/common/_badges.scss @@ -20,6 +20,11 @@ gap: 5px; line-height: 1; + @at-root .row-actions & { + color: #8c8c8c; + padding-inline: 0px; + } + .dashicons { font-size: 18px; inline-size: 18px; diff --git a/src/php/class-list-table.php b/src/php/class-list-table.php index a11553ba..e3d9233f 100644 --- a/src/php/class-list-table.php +++ b/src/php/class-list-table.php @@ -248,7 +248,7 @@ private function get_snippet_action_links( Snippet $snippet ): array { if ( $snippet->shared_network && ! $this->is_network ) { $actions['network_shared'] = sprintf( - '%s', + '%s', esc_html__( 'Network Snippet', 'code-snippets' ) ); From 2e4a11a9858cbcf2155eb3bcdf288c6c1ffa106b Mon Sep 17 00:00:00 2001 From: Imants Date: Fri, 7 Nov 2025 01:11:02 +0200 Subject: [PATCH 13/17] feat: add network snippets management capabilities and subsite menu checks --- src/php/class-plugin.php | 45 ++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/src/php/class-plugin.php b/src/php/class-plugin.php index a38e216e..c05613e2 100644 --- a/src/php/class-plugin.php +++ b/src/php/class-plugin.php @@ -309,25 +309,52 @@ public function get_network_cap_name(): string { return apply_filters( 'code_snippets_network_cap', 'manage_network_options' ); } + /** + * Determine if a subsite user menu is enabled via *Network Settings > Enable administration menus*. + * + * @return bool + */ + public function is_subsite_menu_enabled(): bool { + if ( ! is_multisite() ) { + return true; + } + + $menu_perms = get_site_option( 'menu_items', array() ); + return ! empty( $menu_perms['snippets'] ); + } + + /** + * Determine if the current user should have the network snippets capability. + * + * @return bool + */ + public function user_can_manage_network_snippets(): bool { + return is_super_admin() || current_user_can( $this->get_network_cap_name() ); + } + + /** + * Determine whether the current request originates in the network admin. + * + * @return bool + */ + public function is_network_context(): bool { + return is_network_admin(); + } + /** * Get the required capability to perform a certain action on snippets. * Does not check if the user has this capability or not. * - * If multisite, checks if *Enable Administration Menus: Snippets* is active - * under the *Settings > Network Settings* network admin menu + * If multisite, adjusts the capability based on whether the user is viewing + * the network dashboard or a subsite and whether the menu is enabled for subsites. * * @return string The capability required to manage snippets. * * @since 2.0 */ public function get_cap(): string { - if ( is_multisite() ) { - $menu_perms = get_site_option( 'menu_items', array() ); - - // If multisite is enabled and the snippet menu is not activated, restrict snippet operations to super admins only. - if ( empty( $menu_perms['snippets'] ) ) { - return $this->get_network_cap_name(); - } + if ( is_multisite() && $this->is_network_context() ) { + return $this->get_network_cap_name(); } return $this->get_cap_name(); From ef94d5683612828d8f43ffea3ffa5c57c1054a7d Mon Sep 17 00:00:00 2001 From: Imants Date: Fri, 7 Nov 2025 19:25:43 +0200 Subject: [PATCH 14/17] feat: add "Snippets" row action to the Network Sites table --- src/php/class-admin.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/php/class-admin.php b/src/php/class-admin.php index 70c293a9..dfdf093d 100644 --- a/src/php/class-admin.php +++ b/src/php/class-admin.php @@ -63,6 +63,7 @@ public function run() { add_action( 'init', array( $this, 'load_classes' ), 11 ); add_filter( 'mu_menu_items', array( $this, 'mu_menu_items' ) ); + add_filter( 'manage_sites_action_links', array( $this, 'add_sites_row_action' ), 10, 2 ); add_filter( 'plugin_action_links_' . plugin_basename( PLUGIN_FILE ), array( $this, 'plugin_action_links' ), 10, 2 ); add_filter( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 2 ); add_filter( 'debug_information', array( $this, 'debug_information' ) ); @@ -89,6 +90,29 @@ public function mu_menu_items( array $menu_items ): array { return $menu_items; } + /** + * Add a "Snippets" row action to the Network Sites table. + * + * @param array $actions Existing row actions. + * @param int $site_id Current site ID. + * + * @return array + */ + public function add_sites_row_action( array $actions, int $site_id ): array { + if ( ! is_multisite() || ! current_user_can( code_snippets()->get_network_cap_name() ) ) { + return $actions; + } + + $menu_slug = code_snippets()->get_menu_slug(); + $actions['code_snippets'] = sprintf( + '%s', + esc_url( get_admin_url( $site_id, 'admin.php?page=' . $menu_slug ) ), + esc_html__( 'Snippets', 'code-snippets' ) + ); + + return $actions; + } + /** * Modify the action links for this plugin. * From 6da668753eb22702c44112e8a08135fbda6399a7 Mon Sep 17 00:00:00 2001 From: Imants Date: Fri, 7 Nov 2025 19:31:26 +0200 Subject: [PATCH 15/17] fix: improve snippet name visibility for network users --- src/php/class-list-table.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/php/class-list-table.php b/src/php/class-list-table.php index e3d9233f..41ed1379 100644 --- a/src/php/class-list-table.php +++ b/src/php/class-list-table.php @@ -391,14 +391,17 @@ protected function column_name( Snippet $snippet ): string { ); $out = esc_html( $snippet->display_name ); + $user_can_manage_network = current_user_can( code_snippets()->get_network_cap_name() ); // Add a link to the snippet if it isn't an unreadable network-only snippet and isn't trashed. - if ( ! $snippet->is_trashed() && ( $this->is_network || ! $snippet->network || current_user_can( code_snippets()->get_network_cap_name() ) ) ) { + if ( ! $snippet->is_trashed() && ( $this->is_network || ! $snippet->network || $user_can_manage_network ) ) { $out = sprintf( '%s', esc_attr( code_snippets()->get_snippet_edit_url( $snippet->id, $snippet->network ? 'network' : 'admin' ) ), $out ); + } else { + $out = sprintf( '%s', $out ); } $out = apply_filters( 'code_snippets/list_table/column_name', $out, $snippet ); From 3e0feebab9d3c8c9ada488d42ea6a9bdcf17e7bb Mon Sep 17 00:00:00 2001 From: Imants Date: Fri, 7 Nov 2025 19:31:35 +0200 Subject: [PATCH 16/17] fix: enhance badge styles for row actions and improve pro badge hover effects --- src/css/common/_badges.scss | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/css/common/_badges.scss b/src/css/common/_badges.scss index a8c0a748..4cfbe15f 100644 --- a/src/css/common/_badges.scss +++ b/src/css/common/_badges.scss @@ -23,6 +23,8 @@ @at-root .row-actions & { color: #8c8c8c; padding-inline: 0px; + text-transform: capitalize; + font-weight: 500; } .dashicons { @@ -85,6 +87,33 @@ .inverted-badges .badge { color: #fff; background-color: #a7aaad; + border-color: #fff !important; + + .dashicons { + color: #fff; + } +} + +.nav-tab-inactive { + $colors: map.get(theme.$badges, 'pro'); + $text-color: list.nth($colors, 2); + $background-color: list.nth($colors, 1); + + .badge.pro-badge { + color: $text-color; + background-color: $background-color; + } + + &:hover { + &.button, .dashicons-external { + color: #3c434a; + } + + .badge.pro-badge { + color: $background-color; + background-color: $text-color; + } + } } .nav-tab-inactive { From 305b8585b23c695f0b6c022dafc2688a21bd3eef Mon Sep 17 00:00:00 2001 From: Imants Date: Fri, 7 Nov 2025 19:31:52 +0200 Subject: [PATCH 17/17] fix: update selector for active snippet name styling --- src/css/manage.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/css/manage.scss b/src/css/manage.scss index 0332fc59..7c293d53 100644 --- a/src/css/manage.scss +++ b/src/css/manage.scss @@ -24,7 +24,7 @@ } } -.active-snippet .column-name > a { +.active-snippet .column-name > .snippet-name { font-weight: 600; }