From 10351061200bf2cd28a382b914ce33b9c3fe1317 Mon Sep 17 00:00:00 2001
From: lightbulbman
Date: Fri, 14 Mar 2025 00:33:19 +0000
Subject: [PATCH 001/106] #228 html validation bug fix
---
src/php/snippet-ops.php | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/php/snippet-ops.php b/src/php/snippet-ops.php
index 2e3a9023..6e189d32 100644
--- a/src/php/snippet-ops.php
+++ b/src/php/snippet-ops.php
@@ -295,10 +295,12 @@ function activate_snippet( int $id, ?bool $network = null ) {
// translators: %d: snippet identifier.
return sprintf( __( 'Could not locate snippet with ID %d.', 'code-snippets' ), $id );
}
-
- $validator = new Validator( $snippet->code );
- if ( $validator->validate() ) {
- return __( 'Could not activate snippet: code did not pass validation.', 'code-snippets' );
+
+ if('php' == $snippet->type ){
+ $validator = new Validator( $snippet->code );
+ if ( $validator->validate() ) {
+ return __( 'Could not activate snippet: code did not pass validation.', 'code-snippets' );
+ }
}
$result = $wpdb->update(
From b2be2b83233e1c8a4689842871ef72a007909b7d Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Tue, 1 Jul 2025 22:43:51 +0200
Subject: [PATCH 002/106] wip
---
src/php/class-db.php | 10 +++
src/php/class-plugin.php | 4 +
src/php/class-snippet-files.php | 125 ++++++++++++++++++++++++++++++++
src/php/class-snippet.php | 2 +-
src/php/load.php | 3 +-
src/php/snippet-ops.php | 58 ++++++++++++++-
6 files changed, 197 insertions(+), 5 deletions(-)
create mode 100644 src/php/class-snippet-files.php
diff --git a/src/php/class-db.php b/src/php/class-db.php
index 64ea5f47..a0b50782 100644
--- a/src/php/class-db.php
+++ b/src/php/class-db.php
@@ -283,4 +283,14 @@ function ( $snippet ) use ( $active_shared_ids ) {
return $active_snippets;
}
+
+ public function get_active_tables(): array {
+ $active_tables = array( $this->table );
+
+ if ( is_multisite() ) {
+ $active_tables[] = $this->ms_table;
+ }
+
+ return $active_tables;
+ }
}
diff --git a/src/php/class-plugin.php b/src/php/class-plugin.php
index 92bebfa3..32a679db 100644
--- a/src/php/class-plugin.php
+++ b/src/php/class-plugin.php
@@ -119,6 +119,10 @@ public function load_plugin() {
// Cloud List Table shared functions.
require_once $includes_path . '/cloud/list-table-shared-ops.php';
+ // Snippet files.
+ require_once $includes_path . '/class-snippet-files.php';
+ ( new Snippet_Files() )->register_hooks();
+
$this->active_snippets = new Active_Snippets();
$this->front_end = new Front_End();
$this->cloud_api = new Cloud_API();
diff --git a/src/php/class-snippet-files.php b/src/php/class-snippet-files.php
new file mode 100644
index 00000000..f319b5ee
--- /dev/null
+++ b/src/php/class-snippet-files.php
@@ -0,0 +1,125 @@
+get_type() ) {
+ return;
+ }
+ $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table;
+
+ if ( ! is_dir( $base_dir ) ) {
+ wp_mkdir_p( $base_dir );
+ }
+
+ $file_path = trailingslashit( $base_dir ) . $snippet->id . '.php';
+
+ if ( $snippet->active ) {
+ $content = "code;
+
+ file_put_contents( $file_path, $content );
+ } else {
+ @unlink( $file_path );
+ }
+
+ $index_file_path = trailingslashit( $base_dir ) . 'index.php';
+
+ $active_snippets = is_file( $index_file_path ) ? require $index_file_path : [];
+
+ if ( $snippet->active ) {
+ $active_snippets[ $snippet->id ] = $snippet->get_fields();
+ } else {
+ unset( $active_snippets[ $snippet->id ] );
+ }
+
+ $index_content = "get_type() ) {
+ return;
+ }
+
+ $table = code_snippets()->db->get_table_name( $network );
+
+ $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table;
+
+ $file_path = trailingslashit( $base_dir ) . $snippet->id . '.php';
+
+ @unlink( $file_path );
+
+ $index_file_path = trailingslashit( $base_dir ) . 'index.php';
+
+ $active_snippets = is_file( $index_file_path ) ? require $index_file_path : [];
+
+ unset( $active_snippets[ $snippet_id ] );
+
+ $index_content = "get_type() ) {
+ return;
+ }
+
+ $table = code_snippets()->db->get_table_name( $network );
+
+ $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table;
+
+ $file_path = trailingslashit( $base_dir ) . $snippet->id . '.php';
+
+ $content = "code;
+
+ file_put_contents( $file_path, $content );
+
+ $index_file_path = trailingslashit( $base_dir ) . 'index.php';
+
+ $active_snippets = is_file( $index_file_path ) ? require $index_file_path : [];
+
+ $active_snippets[ $snippet->id ] = $snippet->get_fields();
+
+ $index_content = "get_type() ) {
+ return;
+ }
+
+ $table = code_snippets()->db->get_table_name( $network );
+
+ $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table;
+
+ $file_path = trailingslashit( $base_dir ) . $snippet->id . '.php';
+
+ @unlink( $file_path );
+
+ $index_file_path = trailingslashit( $base_dir ) . 'index.php';
+
+ $active_snippets = is_file( $index_file_path ) ? require $index_file_path : [];
+
+ unset( $active_snippets[ $snippet_id ] );
+
+ $index_content = "scope, -4 ) ) {
return 'css';
} elseif ( '-js' === substr( $this->scope, -3 ) ) {
diff --git a/src/php/load.php b/src/php/load.php
index 2de59ce2..8700186a 100644
--- a/src/php/load.php
+++ b/src/php/load.php
@@ -65,4 +65,5 @@ function code_snippets(): Plugin {
code_snippets()->load_plugin();
// Execute the snippets once the plugins are loaded.
-add_action( 'plugins_loaded', __NAMESPACE__ . '\execute_active_snippets', 1 );
+// add_action( 'plugins_loaded', __NAMESPACE__ . '\execute_active_snippets', 1 );
+add_action( 'plugins_loaded', __NAMESPACE__ . '\execute_active_snippets_from_flat_files', 1 );
diff --git a/src/php/snippet-ops.php b/src/php/snippet-ops.php
index 2e3a9023..fd8c391e 100644
--- a/src/php/snippet-ops.php
+++ b/src/php/snippet-ops.php
@@ -314,7 +314,7 @@ function activate_snippet( int $id, ?bool $network = null ) {
}
update_shared_network_snippets( [ $snippet ] );
- do_action( 'code_snippets/activate_snippet', $snippet );
+ do_action( 'code_snippets/activate_snippet', $snippet, $network );
clean_snippets_cache( $table_name );
return $snippet;
}
@@ -392,7 +392,7 @@ function deactivate_snippet( int $id, ?bool $network = null ): ?Snippet {
$network = DB::validate_network_param( $network );
$table = code_snippets()->db->get_table_name( $network );
- // Set the snippet to active.
+ // Set the snippet to inactive.
$result = $wpdb->update(
$table,
array( 'active' => '0' ),
@@ -433,6 +433,8 @@ function delete_snippet( int $id, ?bool $network = null ): bool {
$network = DB::validate_network_param( $network );
$table = code_snippets()->db->get_table_name( $network );
+ $snippet = get_snippet( $id, $network );
+
$result = $wpdb->delete(
$table,
array( 'id' => $id ),
@@ -440,7 +442,7 @@ function delete_snippet( int $id, ?bool $network = null ): bool {
);
if ( $result ) {
- do_action( 'code_snippets/delete_snippet', $id, $network );
+ do_action( 'code_snippets/delete_snippet', $snippet, $network );
clean_snippets_cache( $table );
code_snippets()->cloud_api->delete_snippet_from_transient_data( $id );
}
@@ -670,6 +672,56 @@ function execute_active_snippets(): bool {
return true;
}
+function execute_active_snippets_from_flat_files(): bool {
+ $tables = code_snippets()->db->get_active_tables();
+ $scopes = array( 'global', 'single-use', is_admin() ? 'admin' : 'front-end' );
+
+ foreach ( $tables as $table ) {
+ $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table;
+
+ if ( ! is_dir( $base_dir ) ) {
+ continue;
+ }
+
+ $active_snippets_file_path = $base_dir . '/index.php';
+ if ( ! is_file( $active_snippets_file_path ) ) {
+ continue;
+ }
+
+ $active_snippets = require $active_snippets_file_path;
+ $sorted_snippets = sort_by_priority( $active_snippets );
+
+ foreach ( $sorted_snippets as $snippet_id => $snippet_data ) {
+ if ( ! in_array( $snippet_data['scope'], $scopes, true ) ) {
+ continue;
+ }
+
+ $file = $base_dir . '/' . $snippet_id . '.php';
+ execute_snippet_from_flat_file( $file, $snippet_id );
+ }
+ }
+
+ return true;
+}
+
+function sort_by_priority( array $snippets ): array {
+ uasort( $snippets, function ( $a, $b ) {
+ return $a['priority'] <=> $b['priority'];
+ } );
+
+ return $snippets;
+}
+
+function execute_snippet_from_flat_file( $file, int $id = 0, bool $force = false ) {
+ if ( ! is_file( $file ) || ( ! $force && defined( 'CODE_SNIPPETS_SAFE_MODE' ) && CODE_SNIPPETS_SAFE_MODE ) ) {
+ return false;
+ }
+
+ require_once $file;
+
+ do_action( 'code_snippets/after_execute_snippet_from_flat_file', $file, $id );
+}
+
/**
* Retrieve a single snippets from the database using its cloud ID.
*
From 510e49e69da1ff6eb0c384469d97e09d46dcba84 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 09:15:12 +0200
Subject: [PATCH 003/106] wip
---
src/php/class-snippet-files.php | 154 ++++++++++++++++----------------
1 file changed, 76 insertions(+), 78 deletions(-)
diff --git a/src/php/class-snippet-files.php b/src/php/class-snippet-files.php
index f319b5ee..00e2f375 100644
--- a/src/php/class-snippet-files.php
+++ b/src/php/class-snippet-files.php
@@ -4,122 +4,120 @@
class Snippet_Files {
- public function register_hooks() {
- add_action( 'code_snippets/create_snippet', [ $this, 'handle_snippet' ], 10, 2 );
- add_action( 'code_snippets/update_snippet', [ $this, 'handle_snippet' ], 10, 2 );
- add_action( 'code_snippets/delete_snippet', [ $this, 'delete_snippet' ], 10, 2 );
- add_action( 'code_snippets/activate_snippet', [ $this, 'activate_snippet' ], 10, 2 );
- add_action( 'code_snippets/deactivate_snippet', [ $this, 'deactivate_snippet' ], 10, 2 );
- }
+ public function register_hooks() {
+ add_action( 'code_snippets/create_snippet', [ $this, 'handle_snippet' ], 10, 2 );
+ add_action( 'code_snippets/update_snippet', [ $this, 'handle_snippet' ], 10, 2 );
+ add_action( 'code_snippets/delete_snippet', [ $this, 'delete_snippet' ], 10, 2 );
+ add_action( 'code_snippets/activate_snippet', [ $this, 'activate_snippet' ], 10, 2 );
+ add_action( 'code_snippets/deactivate_snippet', [ $this, 'deactivate_snippet' ], 10, 2 );
+ }
- public function handle_snippet( $snippet, $table ) {
- if ( 'php' !== $snippet->get_type() ) {
- return;
- }
- $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table;
+ public function handle_snippet( $snippet, $table ) {
+ if ( 'php' !== $snippet->get_type() ) {
+ return;
+ }
+ $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table;
- if ( ! is_dir( $base_dir ) ) {
- wp_mkdir_p( $base_dir );
- }
+ if ( ! is_dir( $base_dir ) ) {
+ wp_mkdir_p( $base_dir );
+ }
- $file_path = trailingslashit( $base_dir ) . $snippet->id . '.php';
+ $file_path = trailingslashit( $base_dir ) . $snippet->id . '.php';
- if ( $snippet->active ) {
- $content = "code;
+ if ( $snippet->active ) {
+ $content = "code;
- file_put_contents( $file_path, $content );
- } else {
- @unlink( $file_path );
- }
+ file_put_contents( $file_path, $content );
+ } else {
+ @unlink( $file_path );
+ }
- $index_file_path = trailingslashit( $base_dir ) . 'index.php';
+ $index_file_path = trailingslashit( $base_dir ) . 'index.php';
- $active_snippets = is_file( $index_file_path ) ? require $index_file_path : [];
+ $active_snippets = is_file( $index_file_path ) ? require $index_file_path : [];
- if ( $snippet->active ) {
- $active_snippets[ $snippet->id ] = $snippet->get_fields();
- } else {
- unset( $active_snippets[ $snippet->id ] );
- }
-
- $index_content = "active ) {
+ $active_snippets[ $snippet->id ] = $snippet->get_fields();
+ } else {
+ unset( $active_snippets[ $snippet->id ] );
+ }
- public function delete_snippet( $snippet, $network ) {
- if ( 'php' !== $snippet->get_type() ) {
- return;
- }
+ $index_content = "db->get_table_name( $network );
+ file_put_contents( $index_file_path, $index_content );
+ }
- $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table;
+ public function delete_snippet( $snippet, $network ) {
+ if ( 'php' !== $snippet->get_type() ) {
+ return;
+ }
- $file_path = trailingslashit( $base_dir ) . $snippet->id . '.php';
+ $table = code_snippets()->db->get_table_name( $network );
- @unlink( $file_path );
+ $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table;
- $index_file_path = trailingslashit( $base_dir ) . 'index.php';
+ $file_path = trailingslashit( $base_dir ) . $snippet->id . '.php';
- $active_snippets = is_file( $index_file_path ) ? require $index_file_path : [];
+ @unlink( $file_path );
- unset( $active_snippets[ $snippet_id ] );
+ $index_file_path = trailingslashit( $base_dir ) . 'index.php';
- $index_content = "get_type() ) {
- return;
- }
+ $index_content = "db->get_table_name( $network );
+ file_put_contents( $index_file_path, $index_content );
+ }
- $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table;
+ public function activate_snippet( $snippet, $network ) {
+ if ( 'php' !== $snippet->get_type() ) {
+ return;
+ }
- $file_path = trailingslashit( $base_dir ) . $snippet->id . '.php';
+ $table = code_snippets()->db->get_table_name( $network );
- $content = "code;
+ $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table;
- file_put_contents( $file_path, $content );
+ $file_path = trailingslashit( $base_dir ) . $snippet->id . '.php';
- $index_file_path = trailingslashit( $base_dir ) . 'index.php';
+ $content = "code;
- $active_snippets = is_file( $index_file_path ) ? require $index_file_path : [];
+ file_put_contents( $file_path, $content );
- $active_snippets[ $snippet->id ] = $snippet->get_fields();
+ $index_file_path = trailingslashit( $base_dir ) . 'index.php';
- $index_content = "id ] = $snippet->get_fields();
- public function deactivate_snippet( $snippet_id, $network ) {
- $snippet = get_snippet( $snippet_id, $network );
+ $index_content = "get_type() ) {
- return;
- }
+ file_put_contents( $index_file_path, $index_content );
+ }
- $table = code_snippets()->db->get_table_name( $network );
+ public function deactivate_snippet( $snippet_id, $network ) {
+ $snippet = get_snippet( $snippet_id, $network );
- $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table;
+ if ( 'php' !== $snippet->get_type() ) {
+ return;
+ }
- $file_path = trailingslashit( $base_dir ) . $snippet->id . '.php';
+ $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $network;
- @unlink( $file_path );
+ $file_path = trailingslashit( $base_dir ) . $snippet_id . '.php';
- $index_file_path = trailingslashit( $base_dir ) . 'index.php';
+ @unlink( $file_path );
- $active_snippets = is_file( $index_file_path ) ? require $index_file_path : [];
+ $index_file_path = trailingslashit( $base_dir ) . 'index.php';
- unset( $active_snippets[ $snippet_id ] );
+ $active_snippets = is_file( $index_file_path ) ? require $index_file_path : [];
- $index_content = "
Date: Wed, 2 Jul 2025 09:29:04 +0200
Subject: [PATCH 004/106] wip
---
src/php/class-snippet-files.php | 166 +++++++++++++++++++++-----------
1 file changed, 108 insertions(+), 58 deletions(-)
diff --git a/src/php/class-snippet-files.php b/src/php/class-snippet-files.php
index 00e2f375..d81572a9 100644
--- a/src/php/class-snippet-files.php
+++ b/src/php/class-snippet-files.php
@@ -4,6 +4,29 @@
class Snippet_Files {
+ /**
+ * Holds the WP_Filesystem instance.
+ *
+ * @var \WP_Filesystem_Base
+ */
+ private $fs;
+
+ public function __construct() {
+ $this->init_filesystem();
+ }
+
+ /**
+ * Initialize WP_Filesystem.
+ */
+ private function init_filesystem() {
+ if ( ! function_exists( 'WP_Filesystem' ) ) {
+ require_once ABSPATH . 'wp-admin/includes/file.php';
+ }
+ WP_Filesystem();
+ global $wp_filesystem;
+ $this->fs = $wp_filesystem;
+ }
+
public function register_hooks() {
add_action( 'code_snippets/create_snippet', [ $this, 'handle_snippet' ], 10, 2 );
add_action( 'code_snippets/update_snippet', [ $this, 'handle_snippet' ], 10, 2 );
@@ -16,35 +39,19 @@ public function handle_snippet( $snippet, $table ) {
if ( 'php' !== $snippet->get_type() ) {
return;
}
- $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table;
- if ( ! is_dir( $base_dir ) ) {
- wp_mkdir_p( $base_dir );
- }
+ $base_dir = $this->get_base_dir( $table );
+ $this->maybe_create_directory( $base_dir );
- $file_path = trailingslashit( $base_dir ) . $snippet->id . '.php';
+ $file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
if ( $snippet->active ) {
- $content = "code;
-
- file_put_contents( $file_path, $content );
+ $this->write_snippet_file( $file_path, $snippet->code );
} else {
- @unlink( $file_path );
+ $this->delete_file( $file_path );
}
- $index_file_path = trailingslashit( $base_dir ) . 'index.php';
-
- $active_snippets = is_file( $index_file_path ) ? require $index_file_path : [];
-
- if ( $snippet->active ) {
- $active_snippets[ $snippet->id ] = $snippet->get_fields();
- } else {
- unset( $active_snippets[ $snippet->id ] );
- }
-
- $index_content = "update_index_file( $base_dir, $snippet, $snippet->active );
}
public function delete_snippet( $snippet, $network ) {
@@ -53,22 +60,12 @@ public function delete_snippet( $snippet, $network ) {
}
$table = code_snippets()->db->get_table_name( $network );
+ $base_dir = $this->get_base_dir( $table );
- $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table;
-
- $file_path = trailingslashit( $base_dir ) . $snippet->id . '.php';
-
- @unlink( $file_path );
+ $file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
+ $this->delete_file( $file_path );
- $index_file_path = trailingslashit( $base_dir ) . 'index.php';
-
- $active_snippets = is_file( $index_file_path ) ? require $index_file_path : [];
-
- unset( $active_snippets[ $snippet_id ] );
-
- $index_content = "update_index_file( $base_dir, $snippet, false );
}
public function activate_snippet( $snippet, $network ) {
@@ -77,47 +74,100 @@ public function activate_snippet( $snippet, $network ) {
}
$table = code_snippets()->db->get_table_name( $network );
+ $base_dir = $this->get_base_dir( $table );
- $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table;
-
- $file_path = trailingslashit( $base_dir ) . $snippet->id . '.php';
+ $this->maybe_create_directory( $base_dir );
- $content = "code;
+ $file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
+ $this->write_snippet_file( $file_path, $snippet->code );
- file_put_contents( $file_path, $content );
+ $this->update_index_file( $base_dir, $snippet, true );
+ }
- $index_file_path = trailingslashit( $base_dir ) . 'index.php';
+ public function deactivate_snippet( $snippet_id, $network ) {
+ $snippet = get_snippet( $snippet_id, $network );
- $active_snippets = is_file( $index_file_path ) ? require $index_file_path : [];
+ if ( ! $snippet || 'php' !== $snippet->get_type() ) {
+ return;
+ }
- $active_snippets[ $snippet->id ] = $snippet->get_fields();
+ $table = code_snippets()->db->get_table_name( $network );
+ $base_dir = $this->get_base_dir( $table );
- $index_content = "get_snippet_file_path( $base_dir, $snippet_id );
+ $this->delete_file( $file_path );
- file_put_contents( $index_file_path, $index_content );
+ $this->update_index_file( $base_dir, $snippet, false );
}
- public function deactivate_snippet( $snippet_id, $network ) {
- $snippet = get_snippet( $snippet_id, $network );
+ /**
+ * Returns the base directory path for a given table.
+ */
+ private function get_base_dir( $table ) {
+ return WP_CONTENT_DIR . '/code-snippets/' . $table;
+ }
- if ( 'php' !== $snippet->get_type() ) {
- return;
+ /**
+ * Creates the directory if it does not exist.
+ */
+ private function maybe_create_directory( $dir ) {
+ if ( ! $this->fs->is_dir( $dir ) ) {
+ $this->fs->mkdir( $dir, FS_CHMOD_DIR );
}
+ }
- $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $network;
+ /**
+ * Returns the path to the snippet PHP file.
+ */
+ private function get_snippet_file_path( $base_dir, $snippet_id ) {
+ return trailingslashit( $base_dir ) . $snippet_id . '.php';
+ }
- $file_path = trailingslashit( $base_dir ) . $snippet_id . '.php';
+ /**
+ * Writes the snippet code to a file, with the required header.
+ */
+ private function write_snippet_file( $file_path, $code ) {
+ $content = "fs->put_contents( $file_path, $content, FS_CHMOD_FILE );
+ }
- @unlink( $file_path );
+ /**
+ * Deletes a file if it exists.
+ */
+ private function delete_file( $file_path ) {
+ if ( $this->fs->exists( $file_path ) ) {
+ $this->fs->delete( $file_path );
+ }
+ }
- $index_file_path = trailingslashit( $base_dir ) . 'index.php';
+ /**
+ * Loads the index.php array by requiring it directly.
+ */
+ private function load_index_file( $index_file_path ) {
+ return is_file( $index_file_path ) ? require $index_file_path : [];
+ }
- $active_snippets = is_file( $index_file_path ) ? require $index_file_path : [];
+ /**
+ * Saves the index.php file via WP_Filesystem.
+ */
+ private function save_index_file( $index_file_path, $active_snippets ) {
+ $index_content = "fs->put_contents( $index_file_path, $index_content, FS_CHMOD_FILE );
+ }
- unset( $active_snippets[ $snippet_id ] );
+ /**
+ * Updates the index.php file by adding or removing a snippet.
+ */
+ private function update_index_file( $base_dir, $snippet, $active ) {
+ $index_file_path = trailingslashit( $base_dir ) . 'index.php';
+ $active_snippets = $this->load_index_file( $index_file_path );
- $index_content = "id ] = $snippet->get_fields();
+ } else {
+ unset( $active_snippets[ $snippet->id ] );
+ }
- file_put_contents( $index_file_path, $index_content );
+ $this->save_index_file( $index_file_path, $active_snippets );
}
}
From f65f5bc6f325392b0de9b75054d5afdb88a5ad57 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 09:43:56 +0200
Subject: [PATCH 005/106] wip
---
src/php/class-plugin.php | 2 +-
src/php/class-snippet-files.php | 28 ++++++++++++++--------------
2 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/src/php/class-plugin.php b/src/php/class-plugin.php
index 32a679db..fda65d6f 100644
--- a/src/php/class-plugin.php
+++ b/src/php/class-plugin.php
@@ -121,7 +121,7 @@ public function load_plugin() {
// Snippet files.
require_once $includes_path . '/class-snippet-files.php';
- ( new Snippet_Files() )->register_hooks();
+ ( new Snippet_Files() )->init();
$this->active_snippets = new Active_Snippets();
$this->front_end = new Front_End();
diff --git a/src/php/class-snippet-files.php b/src/php/class-snippet-files.php
index d81572a9..4cb1b9b5 100644
--- a/src/php/class-snippet-files.php
+++ b/src/php/class-snippet-files.php
@@ -11,20 +11,9 @@ class Snippet_Files {
*/
private $fs;
- public function __construct() {
- $this->init_filesystem();
- }
-
- /**
- * Initialize WP_Filesystem.
- */
- private function init_filesystem() {
- if ( ! function_exists( 'WP_Filesystem' ) ) {
- require_once ABSPATH . 'wp-admin/includes/file.php';
- }
- WP_Filesystem();
- global $wp_filesystem;
- $this->fs = $wp_filesystem;
+ public function init() {
+ $this->ensure_filesystem();
+ $this->register_hooks();
}
public function register_hooks() {
@@ -35,6 +24,17 @@ public function register_hooks() {
add_action( 'code_snippets/deactivate_snippet', [ $this, 'deactivate_snippet' ], 10, 2 );
}
+ private function ensure_filesystem() {
+ if ( ! $this->fs ) {
+ if ( ! function_exists( 'WP_Filesystem' ) ) {
+ require_once ABSPATH . 'wp-admin/includes/file.php';
+ }
+ WP_Filesystem();
+ global $wp_filesystem;
+ $this->fs = $wp_filesystem;
+ }
+ }
+
public function handle_snippet( $snippet, $table ) {
if ( 'php' !== $snippet->get_type() ) {
return;
From c7f3d3cb49245f2fc1fd56e3b6b3204f8219f5d2 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 09:46:42 +0200
Subject: [PATCH 006/106] wip
---
src/php/snippet-ops.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/php/snippet-ops.php b/src/php/snippet-ops.php
index fd8c391e..5927ff7b 100644
--- a/src/php/snippet-ops.php
+++ b/src/php/snippet-ops.php
@@ -689,7 +689,7 @@ function execute_active_snippets_from_flat_files(): bool {
}
$active_snippets = require $active_snippets_file_path;
- $sorted_snippets = sort_by_priority( $active_snippets );
+ $sorted_snippets = cs_sort_snippets_by_priority( $active_snippets );
foreach ( $sorted_snippets as $snippet_id => $snippet_data ) {
if ( ! in_array( $snippet_data['scope'], $scopes, true ) ) {
@@ -704,7 +704,7 @@ function execute_active_snippets_from_flat_files(): bool {
return true;
}
-function sort_by_priority( array $snippets ): array {
+function cs_sort_snippets_by_priority( array $snippets ): array {
uasort( $snippets, function ( $a, $b ) {
return $a['priority'] <=> $b['priority'];
} );
From 29a540c1b29a1d4c1017de3923445d511a1b5cb0 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 09:58:00 +0200
Subject: [PATCH 007/106] wip
---
src/php/class-snippet-files.php | 24 ++++++++++++++----------
src/php/snippet-ops.php | 2 +-
2 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/src/php/class-snippet-files.php b/src/php/class-snippet-files.php
index 4cb1b9b5..bee41b59 100644
--- a/src/php/class-snippet-files.php
+++ b/src/php/class-snippet-files.php
@@ -36,11 +36,12 @@ private function ensure_filesystem() {
}
public function handle_snippet( $snippet, $table ) {
- if ( 'php' !== $snippet->get_type() ) {
+ $snippet_type = $snippet->get_type();
+ if ( 'php' !== $snippet_type ) {
return;
}
- $base_dir = $this->get_base_dir( $table );
+ $base_dir = $this->get_base_dir( $table, $snippet_type );
$this->maybe_create_directory( $base_dir );
$file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
@@ -55,12 +56,13 @@ public function handle_snippet( $snippet, $table ) {
}
public function delete_snippet( $snippet, $network ) {
- if ( 'php' !== $snippet->get_type() ) {
+ $snippet_type = $snippet->get_type();
+ if ( 'php' !== $snippet_type ) {
return;
}
$table = code_snippets()->db->get_table_name( $network );
- $base_dir = $this->get_base_dir( $table );
+ $base_dir = $this->get_base_dir( $table, $snippet_type );
$file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
$this->delete_file( $file_path );
@@ -69,12 +71,13 @@ public function delete_snippet( $snippet, $network ) {
}
public function activate_snippet( $snippet, $network ) {
- if ( 'php' !== $snippet->get_type() ) {
+ $snippet_type = $snippet->get_type();
+ if ( 'php' !== $snippet_type ) {
return;
}
$table = code_snippets()->db->get_table_name( $network );
- $base_dir = $this->get_base_dir( $table );
+ $base_dir = $this->get_base_dir( $table, $snippet_type );
$this->maybe_create_directory( $base_dir );
@@ -86,13 +89,14 @@ public function activate_snippet( $snippet, $network ) {
public function deactivate_snippet( $snippet_id, $network ) {
$snippet = get_snippet( $snippet_id, $network );
+ $snippet_type = $snippet->get_type();
- if ( ! $snippet || 'php' !== $snippet->get_type() ) {
+ if ( ! $snippet || 'php' !== $snippet_type ) {
return;
}
$table = code_snippets()->db->get_table_name( $network );
- $base_dir = $this->get_base_dir( $table );
+ $base_dir = $this->get_base_dir( $table, $snippet_type );
$file_path = $this->get_snippet_file_path( $base_dir, $snippet_id );
$this->delete_file( $file_path );
@@ -103,8 +107,8 @@ public function deactivate_snippet( $snippet_id, $network ) {
/**
* Returns the base directory path for a given table.
*/
- private function get_base_dir( $table ) {
- return WP_CONTENT_DIR . '/code-snippets/' . $table;
+ private function get_base_dir( $table, $snippet_type ) {
+ return WP_CONTENT_DIR . '/code-snippets/' . $table . '/' . $snippet_type;
}
/**
diff --git a/src/php/snippet-ops.php b/src/php/snippet-ops.php
index 5927ff7b..7cf791bd 100644
--- a/src/php/snippet-ops.php
+++ b/src/php/snippet-ops.php
@@ -677,7 +677,7 @@ function execute_active_snippets_from_flat_files(): bool {
$scopes = array( 'global', 'single-use', is_admin() ? 'admin' : 'front-end' );
foreach ( $tables as $table ) {
- $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table;
+ $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table . '/php';
if ( ! is_dir( $base_dir ) ) {
continue;
From c47c344cc004ddac7d961b7d59833040b7c81563 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 10:01:54 +0200
Subject: [PATCH 008/106] wip
---
src/php/class-snippet-files.php | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/php/class-snippet-files.php b/src/php/class-snippet-files.php
index bee41b59..bd313cde 100644
--- a/src/php/class-snippet-files.php
+++ b/src/php/class-snippet-files.php
@@ -36,7 +36,7 @@ private function ensure_filesystem() {
}
public function handle_snippet( $snippet, $table ) {
- $snippet_type = $snippet->get_type();
+ $snippet_type = $snippet->get_type();
if ( 'php' !== $snippet_type ) {
return;
}
@@ -56,7 +56,7 @@ public function handle_snippet( $snippet, $table ) {
}
public function delete_snippet( $snippet, $network ) {
- $snippet_type = $snippet->get_type();
+ $snippet_type = $snippet->get_type();
if ( 'php' !== $snippet_type ) {
return;
}
@@ -71,7 +71,7 @@ public function delete_snippet( $snippet, $network ) {
}
public function activate_snippet( $snippet, $network ) {
- $snippet_type = $snippet->get_type();
+ $snippet_type = $snippet->get_type();
if ( 'php' !== $snippet_type ) {
return;
}
@@ -89,7 +89,7 @@ public function activate_snippet( $snippet, $network ) {
public function deactivate_snippet( $snippet_id, $network ) {
$snippet = get_snippet( $snippet_id, $network );
- $snippet_type = $snippet->get_type();
+ $snippet_type = $snippet->get_type();
if ( ! $snippet || 'php' !== $snippet_type ) {
return;
From b66db45dde19a4092bac879ebfc90460acc8fcd9 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 10:46:05 +0200
Subject: [PATCH 009/106] wip
---
src/php/class-snippet-files.php | 23 +++++++++++++++--------
src/php/front-end/class-front-end.php | 27 +++++++++++++++++++++++++++
2 files changed, 42 insertions(+), 8 deletions(-)
diff --git a/src/php/class-snippet-files.php b/src/php/class-snippet-files.php
index bd313cde..6fdadfcb 100644
--- a/src/php/class-snippet-files.php
+++ b/src/php/class-snippet-files.php
@@ -37,7 +37,7 @@ private function ensure_filesystem() {
public function handle_snippet( $snippet, $table ) {
$snippet_type = $snippet->get_type();
- if ( 'php' !== $snippet_type ) {
+ if ( 'php' !== $snippet_type && 'html' !== $snippet_type ) {
return;
}
@@ -47,7 +47,7 @@ public function handle_snippet( $snippet, $table ) {
$file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
if ( $snippet->active ) {
- $this->write_snippet_file( $file_path, $snippet->code );
+ $this->write_snippet_file( $file_path, $snippet->code, $snippet_type );
} else {
$this->delete_file( $file_path );
}
@@ -57,7 +57,7 @@ public function handle_snippet( $snippet, $table ) {
public function delete_snippet( $snippet, $network ) {
$snippet_type = $snippet->get_type();
- if ( 'php' !== $snippet_type ) {
+ if ( 'php' !== $snippet_type && 'html' !== $snippet_type ) {
return;
}
@@ -72,7 +72,7 @@ public function delete_snippet( $snippet, $network ) {
public function activate_snippet( $snippet, $network ) {
$snippet_type = $snippet->get_type();
- if ( 'php' !== $snippet_type ) {
+ if ( 'php' !== $snippet_type && 'html' !== $snippet_type ) {
return;
}
@@ -82,7 +82,7 @@ public function activate_snippet( $snippet, $network ) {
$this->maybe_create_directory( $base_dir );
$file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
- $this->write_snippet_file( $file_path, $snippet->code );
+ $this->write_snippet_file( $file_path, $snippet->code, $snippet_type );
$this->update_index_file( $base_dir, $snippet, true );
}
@@ -91,7 +91,7 @@ public function deactivate_snippet( $snippet_id, $network ) {
$snippet = get_snippet( $snippet_id, $network );
$snippet_type = $snippet->get_type();
- if ( ! $snippet || 'php' !== $snippet_type ) {
+ if ( 'php' !== $snippet_type && 'html' !== $snippet_type ) {
return;
}
@@ -130,8 +130,15 @@ private function get_snippet_file_path( $base_dir, $snippet_id ) {
/**
* Writes the snippet code to a file, with the required header.
*/
- private function write_snippet_file( $file_path, $code ) {
- $content = "\n\n";
+ }
+
+ $content .= $code;
+
$this->fs->put_contents( $file_path, $content, FS_CHMOD_FILE );
}
diff --git a/src/php/front-end/class-front-end.php b/src/php/front-end/class-front-end.php
index 8d76ae8a..60429b35 100644
--- a/src/php/front-end/class-front-end.php
+++ b/src/php/front-end/class-front-end.php
@@ -245,6 +245,16 @@ protected function evaluate_shortcode_content( Snippet $snippet, array $atts ):
return $snippet->code;
}
+ $network = DB::validate_network_param( $snippet->network );
+ $table_name = code_snippets()->db->get_table_name( $network );
+ $filepath = WP_CONTENT_DIR . '/code-snippets/' . $table_name . '/html/' . $snippet->id . '.php';
+
+ return file_exists( $filepath )
+ ? $this->evaluate_shortcode_from_flat_file( $filepath, $atts )
+ : $this->evaluate_shortcode_from_db( $snippet, $atts );
+ }
+
+ private function evaluate_shortcode_from_db( Snippet $snippet, array $atts ): string {
/**
* Avoiding extract is typically recommended, however in this situation we want to make it easy for snippet
* authors to use custom attributes.
@@ -259,6 +269,23 @@ protected function evaluate_shortcode_content( Snippet $snippet, array $atts ):
return ob_get_clean();
}
+ private function evaluate_shortcode_from_flat_file( $filepath, array $atts ): string {
+ ob_start();
+
+ ( function( $atts ) use ( $filepath ) {
+ /**
+ * Avoiding extract is typically recommended, however in this situation we want to make it easy for snippet
+ * authors to use custom attributes.
+ *
+ * @phpcs:disable WordPress.PHP.DontExtract.extract_extract
+ */
+ extract( $atts );
+ require_once $filepath;
+ } )( $atts );
+
+ return ob_get_clean();
+ }
+
/**
* Render the value of a content shortcode
*
From 55561ca4d233bcfe94dd66f10de11adc057c984e Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 10:50:19 +0200
Subject: [PATCH 010/106] wip
---
src/php/class-snippet-files.php | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/src/php/class-snippet-files.php b/src/php/class-snippet-files.php
index 6fdadfcb..92d18ab4 100644
--- a/src/php/class-snippet-files.php
+++ b/src/php/class-snippet-files.php
@@ -52,7 +52,7 @@ public function handle_snippet( $snippet, $table ) {
$this->delete_file( $file_path );
}
- $this->update_index_file( $base_dir, $snippet, $snippet->active );
+ $this->update_config_file( $base_dir, $snippet, $snippet->active );
}
public function delete_snippet( $snippet, $network ) {
@@ -67,7 +67,7 @@ public function delete_snippet( $snippet, $network ) {
$file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
$this->delete_file( $file_path );
- $this->update_index_file( $base_dir, $snippet, false );
+ $this->update_config_file( $base_dir, $snippet, false );
}
public function activate_snippet( $snippet, $network ) {
@@ -84,7 +84,7 @@ public function activate_snippet( $snippet, $network ) {
$file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
$this->write_snippet_file( $file_path, $snippet->code, $snippet_type );
- $this->update_index_file( $base_dir, $snippet, true );
+ $this->update_config_file( $base_dir, $snippet, true );
}
public function deactivate_snippet( $snippet_id, $network ) {
@@ -101,7 +101,7 @@ public function deactivate_snippet( $snippet_id, $network ) {
$file_path = $this->get_snippet_file_path( $base_dir, $snippet_id );
$this->delete_file( $file_path );
- $this->update_index_file( $base_dir, $snippet, false );
+ $this->update_config_file( $base_dir, $snippet, false );
}
/**
@@ -133,9 +133,9 @@ private function get_snippet_file_path( $base_dir, $snippet_id ) {
private function write_snippet_file( $file_path, $code, $snippet_type ) {
$content = "\n\n";
- }
+ if ( 'html' === $snippet_type ) {
+ $content .= "?>\n\n";
+ }
$content .= $code;
@@ -154,24 +154,24 @@ private function delete_file( $file_path ) {
/**
* Loads the index.php array by requiring it directly.
*/
- private function load_index_file( $index_file_path ) {
- return is_file( $index_file_path ) ? require $index_file_path : [];
+ private function load_config_file( $config_file_path ) {
+ return is_file( $config_file_path ) ? require $config_file_path : [];
}
/**
* Saves the index.php file via WP_Filesystem.
*/
- private function save_index_file( $index_file_path, $active_snippets ) {
+ private function save_config_file( $config_file_path, $active_snippets ) {
$index_content = "fs->put_contents( $index_file_path, $index_content, FS_CHMOD_FILE );
+ $this->fs->put_contents( $config_file_path, $index_content, FS_CHMOD_FILE );
}
/**
* Updates the index.php file by adding or removing a snippet.
*/
- private function update_index_file( $base_dir, $snippet, $active ) {
- $index_file_path = trailingslashit( $base_dir ) . 'index.php';
- $active_snippets = $this->load_index_file( $index_file_path );
+ private function update_config_file( $base_dir, $snippet, $active ) {
+ $config_file_path = trailingslashit( $base_dir ) . 'index.php';
+ $active_snippets = $this->load_config_file( $config_file_path );
if ( $active ) {
$active_snippets[ $snippet->id ] = $snippet->get_fields();
@@ -179,6 +179,6 @@ private function update_index_file( $base_dir, $snippet, $active ) {
unset( $active_snippets[ $snippet->id ] );
}
- $this->save_index_file( $index_file_path, $active_snippets );
+ $this->save_config_file( $config_file_path, $active_snippets );
}
}
From f2720ace011c9edd529f4e63cea633d699039910 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 12:39:17 +0200
Subject: [PATCH 011/106] wip
---
src/php/class-snippet-files.php | 51 +++++++++++++++++++--------------
1 file changed, 30 insertions(+), 21 deletions(-)
diff --git a/src/php/class-snippet-files.php b/src/php/class-snippet-files.php
index 92d18ab4..1040df23 100644
--- a/src/php/class-snippet-files.php
+++ b/src/php/class-snippet-files.php
@@ -11,17 +11,19 @@ class Snippet_Files {
*/
private $fs;
+ const TYPES_TO_HANDLE = [ 'php', 'html' ];
+
public function init() {
$this->ensure_filesystem();
$this->register_hooks();
}
public function register_hooks() {
- add_action( 'code_snippets/create_snippet', [ $this, 'handle_snippet' ], 10, 2 );
- add_action( 'code_snippets/update_snippet', [ $this, 'handle_snippet' ], 10, 2 );
- add_action( 'code_snippets/delete_snippet', [ $this, 'delete_snippet' ], 10, 2 );
- add_action( 'code_snippets/activate_snippet', [ $this, 'activate_snippet' ], 10, 2 );
- add_action( 'code_snippets/deactivate_snippet', [ $this, 'deactivate_snippet' ], 10, 2 );
+ add_action( 'code_snippets/create_snippet', array( $this, 'handle_snippet' ), 10, 2 );
+ add_action( 'code_snippets/update_snippet', array( $this, 'handle_snippet' ), 10, 2 );
+ add_action( 'code_snippets/delete_snippet', array( $this, 'delete_snippet' ), 10, 2 );
+ add_action( 'code_snippets/activate_snippet', array( $this, 'activate_snippet' ), 10, 2 );
+ add_action( 'code_snippets/deactivate_snippet', array( $this, 'deactivate_snippet' ), 10, 2 );
}
private function ensure_filesystem() {
@@ -29,15 +31,22 @@ private function ensure_filesystem() {
if ( ! function_exists( 'WP_Filesystem' ) ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
}
+
WP_Filesystem();
+
global $wp_filesystem;
+
$this->fs = $wp_filesystem;
}
}
- public function handle_snippet( $snippet, $table ) {
+ private function should_handle_snippet( string $snippet_type ) {
+ return in_array( $snippet_type, self::TYPES_TO_HANDLE, true );
+ }
+
+ public function handle_snippet( Snippet $snippet, string $table ) {
$snippet_type = $snippet->get_type();
- if ( 'php' !== $snippet_type && 'html' !== $snippet_type ) {
+ if ( ! $this->should_handle_snippet( $snippet_type ) ) {
return;
}
@@ -55,9 +64,9 @@ public function handle_snippet( $snippet, $table ) {
$this->update_config_file( $base_dir, $snippet, $snippet->active );
}
- public function delete_snippet( $snippet, $network ) {
+ public function delete_snippet( Snippet $snippet, bool $network ) {
$snippet_type = $snippet->get_type();
- if ( 'php' !== $snippet_type && 'html' !== $snippet_type ) {
+ if ( ! $this->should_handle_snippet( $snippet_type ) ) {
return;
}
@@ -70,9 +79,9 @@ public function delete_snippet( $snippet, $network ) {
$this->update_config_file( $base_dir, $snippet, false );
}
- public function activate_snippet( $snippet, $network ) {
+ public function activate_snippet( Snippet $snippet, bool $network ) {
$snippet_type = $snippet->get_type();
- if ( 'php' !== $snippet_type && 'html' !== $snippet_type ) {
+ if ( ! $this->should_handle_snippet( $snippet_type ) ) {
return;
}
@@ -87,11 +96,11 @@ public function activate_snippet( $snippet, $network ) {
$this->update_config_file( $base_dir, $snippet, true );
}
- public function deactivate_snippet( $snippet_id, $network ) {
+ public function deactivate_snippet( int $snippet_id, bool $network ) {
$snippet = get_snippet( $snippet_id, $network );
$snippet_type = $snippet->get_type();
- if ( 'php' !== $snippet_type && 'html' !== $snippet_type ) {
+ if ( ! $this->should_handle_snippet( $snippet_type ) ) {
return;
}
@@ -107,14 +116,14 @@ public function deactivate_snippet( $snippet_id, $network ) {
/**
* Returns the base directory path for a given table.
*/
- private function get_base_dir( $table, $snippet_type ) {
+ private function get_base_dir( string $table, string $snippet_type ) {
return WP_CONTENT_DIR . '/code-snippets/' . $table . '/' . $snippet_type;
}
/**
* Creates the directory if it does not exist.
*/
- private function maybe_create_directory( $dir ) {
+ private function maybe_create_directory( string $dir ) {
if ( ! $this->fs->is_dir( $dir ) ) {
$this->fs->mkdir( $dir, FS_CHMOD_DIR );
}
@@ -123,14 +132,14 @@ private function maybe_create_directory( $dir ) {
/**
* Returns the path to the snippet PHP file.
*/
- private function get_snippet_file_path( $base_dir, $snippet_id ) {
+ private function get_snippet_file_path( string $base_dir, int $snippet_id ) {
return trailingslashit( $base_dir ) . $snippet_id . '.php';
}
/**
* Writes the snippet code to a file, with the required header.
*/
- private function write_snippet_file( $file_path, $code, $snippet_type ) {
+ private function write_snippet_file( string $file_path, string $code, string $snippet_type ) {
$content = "fs->exists( $file_path ) ) {
$this->fs->delete( $file_path );
}
@@ -154,14 +163,14 @@ private function delete_file( $file_path ) {
/**
* Loads the index.php array by requiring it directly.
*/
- private function load_config_file( $config_file_path ) {
+ private function load_config_file( string $config_file_path ) {
return is_file( $config_file_path ) ? require $config_file_path : [];
}
/**
* Saves the index.php file via WP_Filesystem.
*/
- private function save_config_file( $config_file_path, $active_snippets ) {
+ private function save_config_file( string $config_file_path, array $active_snippets ) {
$index_content = "fs->put_contents( $config_file_path, $index_content, FS_CHMOD_FILE );
}
@@ -169,7 +178,7 @@ private function save_config_file( $config_file_path, $active_snippets ) {
/**
* Updates the index.php file by adding or removing a snippet.
*/
- private function update_config_file( $base_dir, $snippet, $active ) {
+ private function update_config_file( string $base_dir, Snippet $snippet, bool $active ) {
$config_file_path = trailingslashit( $base_dir ) . 'index.php';
$active_snippets = $this->load_config_file( $config_file_path );
From 6477f86889b33c2b2756b5570c6aa11ac283ce9e Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 13:01:40 +0200
Subject: [PATCH 012/106] wip
---
src/php/snippet-ops.php | 68 +++++++++++++++++++++++++++++++++++++----
1 file changed, 62 insertions(+), 6 deletions(-)
diff --git a/src/php/snippet-ops.php b/src/php/snippet-ops.php
index 7cf791bd..d6200091 100644
--- a/src/php/snippet-ops.php
+++ b/src/php/snippet-ops.php
@@ -659,6 +659,9 @@ function execute_active_snippets(): bool {
array( '%d' )
);
clean_snippets_cache( $table_name );
+
+ $network = $table_name === $db->ms_table;
+ do_action( 'code_snippets/deactivate_snippet', $snippet_id, $network );
}
}
@@ -672,12 +675,38 @@ function execute_active_snippets(): bool {
return true;
}
+/**
+ * Execute the active snippets from the flat files.
+ * Read-write-execute operation.
+ *
+ * @return bool true on success, false on failure.
+ */
function execute_active_snippets_from_flat_files(): bool {
- $tables = code_snippets()->db->get_active_tables();
+ $db = code_snippets()->db;
+ $tables = $db->get_active_tables();
$scopes = array( 'global', 'single-use', is_admin() ? 'admin' : 'front-end' );
- foreach ( $tables as $table ) {
- $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table . '/php';
+ // Detect if a snippet is currently being edited, and if so, spare it from execution.
+ $edit_id = 0;
+ $edit_table = $db->table;
+
+ if ( wp_is_json_request() && ! empty( $_SERVER['REQUEST_URI'] ) ) {
+ $url = wp_parse_url( esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
+
+ if ( isset( $url['path'] ) && false !== strpos( $url['path'], Snippets_REST_Controller::get_prefixed_base_route() ) ) {
+ $path_parts = explode( '/', $url['path'] );
+ $edit_id = intval( end( $path_parts ) );
+
+ if ( ! empty( $url['query'] ) ) {
+ wp_parse_str( $url['query'], $path_params );
+ $edit_table = isset( $path_params['network'] ) && rest_sanitize_boolean( $path_params['network'] ) ?
+ $db->ms_table : $db->table;
+ }
+ }
+ }
+
+ foreach ( $tables as $table_name ) {
+ $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table_name . '/php';
if ( ! is_dir( $base_dir ) ) {
continue;
@@ -691,13 +720,40 @@ function execute_active_snippets_from_flat_files(): bool {
$active_snippets = require $active_snippets_file_path;
$sorted_snippets = cs_sort_snippets_by_priority( $active_snippets );
- foreach ( $sorted_snippets as $snippet_id => $snippet_data ) {
- if ( ! in_array( $snippet_data['scope'], $scopes, true ) ) {
+ foreach ( $sorted_snippets as $snippet_id => $snippet ) {
+ if ( ! in_array( $snippet['scope'], $scopes, true ) ) {
continue;
}
+ // If the snippet is a single-use snippet, deactivate it before execution to ensure that the process always happens.
+ if ( 'single-use' === $snippet['scope'] ) {
+ $active_shared_ids = get_option( 'active_shared_network_snippets', array() );
+
+ if ( $table_name === $db->ms_table && is_array( $active_shared_ids ) && in_array( $snippet_id, $active_shared_ids, true ) ) {
+ unset( $active_shared_ids[ array_search( $snippet_id, $active_shared_ids, true ) ] );
+ $active_shared_ids = array_values( $active_shared_ids );
+ update_option( 'active_shared_network_snippets', $active_shared_ids );
+ clean_active_snippets_cache( $table_name );
+ } else {
+ $wpdb->update(
+ $table_name,
+ array( 'active' => '0' ),
+ array( 'id' => $snippet_id ),
+ array( '%d' ),
+ array( '%d' )
+ );
+ clean_snippets_cache( $table_name );
+
+ $network = $table_name === $db->ms_table;
+ do_action( 'code_snippets/deactivate_snippet', $snippet_id, $network );
+ }
+ }
+
$file = $base_dir . '/' . $snippet_id . '.php';
- execute_snippet_from_flat_file( $file, $snippet_id );
+ if ( apply_filters( 'code_snippets/allow_execute_snippet', true, $snippet_id, $table_name ) &&
+ ! ( $edit_id === $snippet_id && $table_name === $edit_table ) ) {
+ execute_snippet_from_flat_file( $file, $snippet_id );
+ }
}
}
From 0eda7c915b2a0e4747954afd34df5ebc77fef6e0 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 13:09:46 +0200
Subject: [PATCH 013/106] wip
---
src/php/class-snippet-files.php | 10 +++++-----
src/php/snippet-ops.php | 2 +-
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/php/class-snippet-files.php b/src/php/class-snippet-files.php
index 1040df23..cf3b7302 100644
--- a/src/php/class-snippet-files.php
+++ b/src/php/class-snippet-files.php
@@ -50,7 +50,7 @@ public function handle_snippet( Snippet $snippet, string $table ) {
return;
}
- $base_dir = $this->get_base_dir( $table, $snippet_type );
+ $base_dir = self::get_base_dir( $table, $snippet_type );
$this->maybe_create_directory( $base_dir );
$file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
@@ -71,7 +71,7 @@ public function delete_snippet( Snippet $snippet, bool $network ) {
}
$table = code_snippets()->db->get_table_name( $network );
- $base_dir = $this->get_base_dir( $table, $snippet_type );
+ $base_dir = self::get_base_dir( $table, $snippet_type );
$file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
$this->delete_file( $file_path );
@@ -86,7 +86,7 @@ public function activate_snippet( Snippet $snippet, bool $network ) {
}
$table = code_snippets()->db->get_table_name( $network );
- $base_dir = $this->get_base_dir( $table, $snippet_type );
+ $base_dir = self::get_base_dir( $table, $snippet_type );
$this->maybe_create_directory( $base_dir );
@@ -105,7 +105,7 @@ public function deactivate_snippet( int $snippet_id, bool $network ) {
}
$table = code_snippets()->db->get_table_name( $network );
- $base_dir = $this->get_base_dir( $table, $snippet_type );
+ $base_dir = self::get_base_dir( $table, $snippet_type );
$file_path = $this->get_snippet_file_path( $base_dir, $snippet_id );
$this->delete_file( $file_path );
@@ -116,7 +116,7 @@ public function deactivate_snippet( int $snippet_id, bool $network ) {
/**
* Returns the base directory path for a given table.
*/
- private function get_base_dir( string $table, string $snippet_type ) {
+ public static function get_base_dir( string $table, string $snippet_type ) {
return WP_CONTENT_DIR . '/code-snippets/' . $table . '/' . $snippet_type;
}
diff --git a/src/php/snippet-ops.php b/src/php/snippet-ops.php
index d6200091..dc96a6df 100644
--- a/src/php/snippet-ops.php
+++ b/src/php/snippet-ops.php
@@ -706,7 +706,7 @@ function execute_active_snippets_from_flat_files(): bool {
}
foreach ( $tables as $table_name ) {
- $base_dir = WP_CONTENT_DIR . '/code-snippets/' . $table_name . '/php';
+ $base_dir = Snippet_Files::get_base_dir( $table_name, 'php' );
if ( ! is_dir( $base_dir ) ) {
continue;
From 759aabdedf2460adad77b95053e3a9cf334c4a1a Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 13:35:15 +0200
Subject: [PATCH 014/106] wip
---
src/php/snippet-ops.php | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/php/snippet-ops.php b/src/php/snippet-ops.php
index dc96a6df..91326aec 100644
--- a/src/php/snippet-ops.php
+++ b/src/php/snippet-ops.php
@@ -682,6 +682,12 @@ function execute_active_snippets(): bool {
* @return bool true on success, false on failure.
*/
function execute_active_snippets_from_flat_files(): bool {
+ // Bail early if safe mode is active.
+ if ( ( defined( 'CODE_SNIPPETS_SAFE_MODE' ) && CODE_SNIPPETS_SAFE_MODE ) ||
+ ! apply_filters( 'code_snippets/execute_snippets', true ) ) {
+ return false;
+ }
+
$db = code_snippets()->db;
$tables = $db->get_active_tables();
$scopes = array( 'global', 'single-use', is_admin() ? 'admin' : 'front-end' );
From 18bcfa399954a92cbe8cda4df9999183944c0707 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 14:40:19 +0200
Subject: [PATCH 015/106] wip
---
src/php/snippet-ops.php | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/php/snippet-ops.php b/src/php/snippet-ops.php
index 91326aec..34d2c787 100644
--- a/src/php/snippet-ops.php
+++ b/src/php/snippet-ops.php
@@ -682,6 +682,8 @@ function execute_active_snippets(): bool {
* @return bool true on success, false on failure.
*/
function execute_active_snippets_from_flat_files(): bool {
+ global $wpdb;
+
// Bail early if safe mode is active.
if ( ( defined( 'CODE_SNIPPETS_SAFE_MODE' ) && CODE_SNIPPETS_SAFE_MODE ) ||
! apply_filters( 'code_snippets/execute_snippets', true ) ) {
From dc91357dc608e501df27926fe35e385a1c37bc76 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 21:46:20 +0200
Subject: [PATCH 016/106] wip
---
src/php/class-snippet-files.php | 37 +++++++++++++--------------------
src/php/snippet-ops.php | 4 ++++
2 files changed, 19 insertions(+), 22 deletions(-)
diff --git a/src/php/class-snippet-files.php b/src/php/class-snippet-files.php
index cf3b7302..3aa97f7a 100644
--- a/src/php/class-snippet-files.php
+++ b/src/php/class-snippet-files.php
@@ -19,11 +19,11 @@ public function init() {
}
public function register_hooks() {
- add_action( 'code_snippets/create_snippet', array( $this, 'handle_snippet' ), 10, 2 );
- add_action( 'code_snippets/update_snippet', array( $this, 'handle_snippet' ), 10, 2 );
- add_action( 'code_snippets/delete_snippet', array( $this, 'delete_snippet' ), 10, 2 );
- add_action( 'code_snippets/activate_snippet', array( $this, 'activate_snippet' ), 10, 2 );
- add_action( 'code_snippets/deactivate_snippet', array( $this, 'deactivate_snippet' ), 10, 2 );
+ add_action( 'code_snippets/create_snippet', [ $this, 'handle_snippet' ], 10, 2 );
+ add_action( 'code_snippets/update_snippet', [ $this, 'handle_snippet' ], 10, 2 );
+ add_action( 'code_snippets/delete_snippet', [ $this, 'delete_snippet' ], 10, 2 );
+ add_action( 'code_snippets/activate_snippet', [ $this, 'activate_snippet' ], 10, 2 );
+ add_action( 'code_snippets/deactivate_snippet', [ $this, 'deactivate_snippet' ], 10, 2 );
}
private function ensure_filesystem() {
@@ -55,13 +55,9 @@ public function handle_snippet( Snippet $snippet, string $table ) {
$file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
- if ( $snippet->active ) {
- $this->write_snippet_file( $file_path, $snippet->code, $snippet_type );
- } else {
- $this->delete_file( $file_path );
- }
+ $this->write_snippet_file( $file_path, $snippet->code, $snippet_type );
- $this->update_config_file( $base_dir, $snippet, $snippet->active );
+ $this->update_config_file( $base_dir, $snippet );
}
public function delete_snippet( Snippet $snippet, bool $network ) {
@@ -76,7 +72,7 @@ public function delete_snippet( Snippet $snippet, bool $network ) {
$file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
$this->delete_file( $file_path );
- $this->update_config_file( $base_dir, $snippet, false );
+ $this->update_config_file( $base_dir, $snippet, true );
}
public function activate_snippet( Snippet $snippet, bool $network ) {
@@ -93,7 +89,7 @@ public function activate_snippet( Snippet $snippet, bool $network ) {
$file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
$this->write_snippet_file( $file_path, $snippet->code, $snippet_type );
- $this->update_config_file( $base_dir, $snippet, true );
+ $this->update_config_file( $base_dir, $snippet );
}
public function deactivate_snippet( int $snippet_id, bool $network ) {
@@ -107,10 +103,7 @@ public function deactivate_snippet( int $snippet_id, bool $network ) {
$table = code_snippets()->db->get_table_name( $network );
$base_dir = self::get_base_dir( $table, $snippet_type );
- $file_path = $this->get_snippet_file_path( $base_dir, $snippet_id );
- $this->delete_file( $file_path );
-
- $this->update_config_file( $base_dir, $snippet, false );
+ $this->update_config_file( $base_dir, $snippet );
}
/**
@@ -176,16 +169,16 @@ private function save_config_file( string $config_file_path, array $active_snipp
}
/**
- * Updates the index.php file by adding or removing a snippet.
+ * Updates the index.php file with snippet config.
*/
- private function update_config_file( string $base_dir, Snippet $snippet, bool $active ) {
+ private function update_config_file( string $base_dir, Snippet $snippet, bool $remove = false ) {
$config_file_path = trailingslashit( $base_dir ) . 'index.php';
$active_snippets = $this->load_config_file( $config_file_path );
- if ( $active ) {
- $active_snippets[ $snippet->id ] = $snippet->get_fields();
- } else {
+ if ( $remove ) {
unset( $active_snippets[ $snippet->id ] );
+ } else {
+ $active_snippets[ $snippet->id ] = $snippet->get_fields();
}
$this->save_config_file( $config_file_path, $active_snippets );
diff --git a/src/php/snippet-ops.php b/src/php/snippet-ops.php
index 34d2c787..39565c59 100644
--- a/src/php/snippet-ops.php
+++ b/src/php/snippet-ops.php
@@ -733,6 +733,10 @@ function execute_active_snippets_from_flat_files(): bool {
continue;
}
+ if ( ! $snippet['active'] ) {
+ continue;
+ }
+
// If the snippet is a single-use snippet, deactivate it before execution to ensure that the process always happens.
if ( 'single-use' === $snippet['scope'] ) {
$active_shared_ids = get_option( 'active_shared_network_snippets', array() );
From 1d99420c70a43658f380f89c832540086f997161 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 22:28:45 +0200
Subject: [PATCH 017/106] wip
---
src/php/class-snippet-files.php | 37 ++++++++++++++++++++++++++++-----
1 file changed, 32 insertions(+), 5 deletions(-)
diff --git a/src/php/class-snippet-files.php b/src/php/class-snippet-files.php
index 3aa97f7a..3219540e 100644
--- a/src/php/class-snippet-files.php
+++ b/src/php/class-snippet-files.php
@@ -24,6 +24,7 @@ public function register_hooks() {
add_action( 'code_snippets/delete_snippet', [ $this, 'delete_snippet' ], 10, 2 );
add_action( 'code_snippets/activate_snippet', [ $this, 'activate_snippet' ], 10, 2 );
add_action( 'code_snippets/deactivate_snippet', [ $this, 'deactivate_snippet' ], 10, 2 );
+ add_action( 'updated_option', [ $this, 'sync_active_shared_network_snippets' ], 10, 3 );
}
private function ensure_filesystem() {
@@ -107,10 +108,20 @@ public function deactivate_snippet( int $snippet_id, bool $network ) {
}
/**
- * Returns the base directory path for a given table.
+ * Returns the base directory path for a given context.
*/
- public static function get_base_dir( string $table, string $snippet_type ) {
- return WP_CONTENT_DIR . '/code-snippets/' . $table . '/' . $snippet_type;
+ public static function get_base_dir( string $table = '', string $snippet_type = '' ) {
+ $base_dir = WP_CONTENT_DIR . '/code-snippets';
+
+ if ( ! empty( $table ) ) {
+ $base_dir .= '/' . $table;
+ }
+
+ if ( ! empty( $snippet_type ) ) {
+ $base_dir .= '/' . $snippet_type;
+ }
+
+ return $base_dir;
}
/**
@@ -164,8 +175,8 @@ private function load_config_file( string $config_file_path ) {
* Saves the index.php file via WP_Filesystem.
*/
private function save_config_file( string $config_file_path, array $active_snippets ) {
- $index_content = "fs->put_contents( $config_file_path, $index_content, FS_CHMOD_FILE );
+ $file_content = "fs->put_contents( $config_file_path, $file_content, FS_CHMOD_FILE );
}
/**
@@ -183,4 +194,20 @@ private function update_config_file( string $base_dir, Snippet $snippet, bool $r
$this->save_config_file( $config_file_path, $active_snippets );
}
+
+ public function sync_active_shared_network_snippets( $option, $old_value, $value ) {
+ if ( 'active_shared_network_snippets' !== $option ) {
+ return;
+ }
+
+ $table = code_snippets()->db->get_table_name();
+ $base_dir = self::get_base_dir( $table );
+
+ $this->maybe_create_directory( $base_dir );
+
+ $file_path = trailingslashit( $base_dir ) . 'active-shared-network-snippets.php';
+ $file_content = "fs->put_contents( $file_path, $file_content, FS_CHMOD_FILE );
+ }
}
From 918e7697737b95c49be29342762cbc517917c455 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 23:25:38 +0200
Subject: [PATCH 018/106] wip
---
src/php/class-snippet-files.php | 52 ++++++++++++++++++++++++++++++---
src/php/snippet-ops.php | 37 +++++------------------
2 files changed, 56 insertions(+), 33 deletions(-)
diff --git a/src/php/class-snippet-files.php b/src/php/class-snippet-files.php
index 3219540e..4fc0bab0 100644
--- a/src/php/class-snippet-files.php
+++ b/src/php/class-snippet-files.php
@@ -77,6 +77,8 @@ public function delete_snippet( Snippet $snippet, bool $network ) {
}
public function activate_snippet( Snippet $snippet, bool $network ) {
+ $snippet = get_snippet( $snippet->id, $network );
+
$snippet_type = $snippet->get_type();
if ( ! $this->should_handle_snippet( $snippet_type ) ) {
return;
@@ -182,14 +184,14 @@ private function save_config_file( string $config_file_path, array $active_snipp
/**
* Updates the index.php file with snippet config.
*/
- private function update_config_file( string $base_dir, Snippet $snippet, bool $remove = false ) {
+ private function update_config_file( string $base_dir, Snippet $snippet, ?bool $remove = false ) {
$config_file_path = trailingslashit( $base_dir ) . 'index.php';
$active_snippets = $this->load_config_file( $config_file_path );
- if ( $remove ) {
- unset( $active_snippets[ $snippet->id ] );
- } else {
+ if ( ! $remove ) {
$active_snippets[ $snippet->id ] = $snippet->get_fields();
+ } else {
+ unset( $active_snippets[ $snippet->id ] );
}
$this->save_config_file( $config_file_path, $active_snippets );
@@ -210,4 +212,46 @@ public function sync_active_shared_network_snippets( $option, $old_value, $value
$this->fs->put_contents( $file_path, $file_content, FS_CHMOD_FILE );
}
+
+ public static function get_active_snippets_from_flat_files() {
+ $snippets = [];
+
+ $table = code_snippets()->db->get_table_name();
+ $base_dir = self::get_base_dir( $table, 'php' );
+ $snippets_file_path = $base_dir . '/index.php';
+
+ if ( is_file( $snippets_file_path ) ) {
+ $site_snippets = is_file( $snippets_file_path ) ? require $snippets_file_path : [];
+
+ $snippets[ $table ] = array_filter(
+ $site_snippets,
+ function ( $snippet ) {
+ return $snippet['active'];
+ }
+ );
+ }
+
+ if ( is_multisite() ) {
+ $root_base_dir = self::get_base_dir( $table );
+ $active_shared_ids_file_path = $root_base_dir . '/active-shared-network-snippets.php';
+
+ $active_shared_ids = is_file( $active_shared_ids_file_path ) ? require $active_shared_ids_file_path : [];
+ $ms_table = code_snippets()->db->get_table_name( true );
+ $ms_base_dir = self::get_base_dir( $ms_table, 'php' );
+ $ms_snippets_file_path = $ms_base_dir . '/index.php';
+
+ if ( is_file( $ms_snippets_file_path ) ) {
+ $ms_snippets = is_file( $ms_snippets_file_path ) ? require $ms_snippets_file_path : [];
+
+ $snippets[ $ms_table ] = array_filter(
+ $ms_snippets,
+ function ( $snippet ) use ( $active_shared_ids ) {
+ return $snippet['active'] || in_array( intval( $snippet['id'] ), $active_shared_ids, true );
+ }
+ );
+ }
+ }
+
+ return $snippets;
+ }
}
diff --git a/src/php/snippet-ops.php b/src/php/snippet-ops.php
index 39565c59..2eab3c94 100644
--- a/src/php/snippet-ops.php
+++ b/src/php/snippet-ops.php
@@ -675,12 +675,6 @@ function execute_active_snippets(): bool {
return true;
}
-/**
- * Execute the active snippets from the flat files.
- * Read-write-execute operation.
- *
- * @return bool true on success, false on failure.
- */
function execute_active_snippets_from_flat_files(): bool {
global $wpdb;
@@ -691,8 +685,8 @@ function execute_active_snippets_from_flat_files(): bool {
}
$db = code_snippets()->db;
- $tables = $db->get_active_tables();
$scopes = array( 'global', 'single-use', is_admin() ? 'admin' : 'front-end' );
+ $data = Snippet_Files::get_active_snippets_from_flat_files();
// Detect if a snippet is currently being edited, and if so, spare it from execution.
$edit_id = 0;
@@ -713,29 +707,14 @@ function execute_active_snippets_from_flat_files(): bool {
}
}
- foreach ( $tables as $table_name ) {
+ foreach ( $data as $table_name => $active_snippets ) {
$base_dir = Snippet_Files::get_base_dir( $table_name, 'php' );
+ $active_snippets = cs_sort_snippets_by_priority( $active_snippets );
- if ( ! is_dir( $base_dir ) ) {
- continue;
- }
-
- $active_snippets_file_path = $base_dir . '/index.php';
- if ( ! is_file( $active_snippets_file_path ) ) {
- continue;
- }
-
- $active_snippets = require $active_snippets_file_path;
- $sorted_snippets = cs_sort_snippets_by_priority( $active_snippets );
-
- foreach ( $sorted_snippets as $snippet_id => $snippet ) {
- if ( ! in_array( $snippet['scope'], $scopes, true ) ) {
- continue;
- }
-
- if ( ! $snippet['active'] ) {
- continue;
- }
+ // Loop through the returned snippets and execute the PHP code.
+ foreach ( $active_snippets as $snippet ) {
+ $snippet_id = intval( $snippet['id'] );
+ $code = $snippet['code'];
// If the snippet is a single-use snippet, deactivate it before execution to ensure that the process always happens.
if ( 'single-use' === $snippet['scope'] ) {
@@ -761,9 +740,9 @@ function execute_active_snippets_from_flat_files(): bool {
}
}
- $file = $base_dir . '/' . $snippet_id . '.php';
if ( apply_filters( 'code_snippets/allow_execute_snippet', true, $snippet_id, $table_name ) &&
! ( $edit_id === $snippet_id && $table_name === $edit_table ) ) {
+ $file = $base_dir . '/' . $snippet_id . '.php';
execute_snippet_from_flat_file( $file, $snippet_id );
}
}
From 737b3cfe7d6230b2c25417bb006057094ad6166c Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 23:37:42 +0200
Subject: [PATCH 019/106] wip
---
src/php/class-snippet-files.php | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/php/class-snippet-files.php b/src/php/class-snippet-files.php
index 4fc0bab0..9bb7bdd6 100644
--- a/src/php/class-snippet-files.php
+++ b/src/php/class-snippet-files.php
@@ -232,10 +232,6 @@ function ( $snippet ) {
}
if ( is_multisite() ) {
- $root_base_dir = self::get_base_dir( $table );
- $active_shared_ids_file_path = $root_base_dir . '/active-shared-network-snippets.php';
-
- $active_shared_ids = is_file( $active_shared_ids_file_path ) ? require $active_shared_ids_file_path : [];
$ms_table = code_snippets()->db->get_table_name( true );
$ms_base_dir = self::get_base_dir( $ms_table, 'php' );
$ms_snippets_file_path = $ms_base_dir . '/index.php';
@@ -243,6 +239,10 @@ function ( $snippet ) {
if ( is_file( $ms_snippets_file_path ) ) {
$ms_snippets = is_file( $ms_snippets_file_path ) ? require $ms_snippets_file_path : [];
+ $root_base_dir = self::get_base_dir( $table );
+ $active_shared_ids_file_path = $root_base_dir . '/active-shared-network-snippets.php';
+ $active_shared_ids = is_file( $active_shared_ids_file_path ) ? require $active_shared_ids_file_path : [];
+
$snippets[ $ms_table ] = array_filter(
$ms_snippets,
function ( $snippet ) use ( $active_shared_ids ) {
From 20ec1896523dd192ab305bba28ec62896685e442 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 23:41:08 +0200
Subject: [PATCH 020/106] wip
---
src/php/class-db.php | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/src/php/class-db.php b/src/php/class-db.php
index a0b50782..64ea5f47 100644
--- a/src/php/class-db.php
+++ b/src/php/class-db.php
@@ -283,14 +283,4 @@ function ( $snippet ) use ( $active_shared_ids ) {
return $active_snippets;
}
-
- public function get_active_tables(): array {
- $active_tables = array( $this->table );
-
- if ( is_multisite() ) {
- $active_tables[] = $this->ms_table;
- }
-
- return $active_tables;
- }
}
From 04e706d756eeb215921d38c830a56663efe22003 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Wed, 2 Jul 2025 23:46:21 +0200
Subject: [PATCH 021/106] wip
---
src/php/snippet-ops.php | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/php/snippet-ops.php b/src/php/snippet-ops.php
index 2eab3c94..8fc90ff2 100644
--- a/src/php/snippet-ops.php
+++ b/src/php/snippet-ops.php
@@ -685,7 +685,7 @@ function execute_active_snippets_from_flat_files(): bool {
}
$db = code_snippets()->db;
- $scopes = array( 'global', 'single-use', is_admin() ? 'admin' : 'front-end' );
+ $scopes = [ 'global', 'single-use', is_admin() ? 'admin' : 'front-end' ];
$data = Snippet_Files::get_active_snippets_from_flat_files();
// Detect if a snippet is currently being edited, and if so, spare it from execution.
@@ -713,8 +713,11 @@ function execute_active_snippets_from_flat_files(): bool {
// Loop through the returned snippets and execute the PHP code.
foreach ( $active_snippets as $snippet ) {
+ if ( ! in_array( $snippet['scope'], $scopes, true ) ) {
+ continue;
+ }
+
$snippet_id = intval( $snippet['id'] );
- $code = $snippet['code'];
// If the snippet is a single-use snippet, deactivate it before execution to ensure that the process always happens.
if ( 'single-use' === $snippet['scope'] ) {
From 890481ae74afc246e4b6debe10c3a784d02f089d Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Sat, 5 Jul 2025 23:40:40 +0200
Subject: [PATCH 022/106] wip
---
src/php/class-plugin.php | 9 +-
.../classes/class-file-system-adapter.php | 35 ++++++++
.../classes}/class-snippet-files.php | 86 +++++++------------
.../files/handlers/html-snippet-handler.php | 17 ++++
.../files/handlers/php-snippet-handler.php | 17 ++++
.../interfaces/interface-file-system.php | 11 +++
.../interfaces/interface-snippet-handler.php | 9 ++
src/php/files/load.php | 9 ++
src/php/files/registry.php | 47 ++++++++++
9 files changed, 183 insertions(+), 57 deletions(-)
create mode 100644 src/php/files/classes/class-file-system-adapter.php
rename src/php/{ => files/classes}/class-snippet-files.php (78%)
create mode 100644 src/php/files/handlers/html-snippet-handler.php
create mode 100644 src/php/files/handlers/php-snippet-handler.php
create mode 100644 src/php/files/interfaces/interface-file-system.php
create mode 100644 src/php/files/interfaces/interface-snippet-handler.php
create mode 100644 src/php/files/load.php
create mode 100644 src/php/files/registry.php
diff --git a/src/php/class-plugin.php b/src/php/class-plugin.php
index fda65d6f..c09edbb4 100644
--- a/src/php/class-plugin.php
+++ b/src/php/class-plugin.php
@@ -120,8 +120,13 @@ public function load_plugin() {
require_once $includes_path . '/cloud/list-table-shared-ops.php';
// Snippet files.
- require_once $includes_path . '/class-snippet-files.php';
- ( new Snippet_Files() )->init();
+ require_once $includes_path . '/files/load.php';
+ $registry = new Snippet_Handler_Registry( [
+ 'php' => new Php_Snippet_Handler(),
+ 'html' => new Html_Snippet_Handler(),
+ ] );
+ $fs = new WordPress_Filesystem_Adapter();
+ ( new Snippet_Files( $registry, $fs ) )->register_hooks();
$this->active_snippets = new Active_Snippets();
$this->front_end = new Front_End();
diff --git a/src/php/files/classes/class-file-system-adapter.php b/src/php/files/classes/class-file-system-adapter.php
new file mode 100644
index 00000000..b22308e3
--- /dev/null
+++ b/src/php/files/classes/class-file-system-adapter.php
@@ -0,0 +1,35 @@
+fs = $wp_filesystem;
+ }
+
+ public function put_contents( string $path, string $contents, $chmod ) {
+ return $this->fs->put_contents( $path, $contents, $chmod );
+ }
+
+ public function exists( string $path ): bool {
+ return $this->fs->exists( $path );
+ }
+
+ public function delete( string $path ): bool {
+ return $this->fs->delete( $path );
+ }
+
+ public function is_dir( string $path ): bool {
+ return $this->fs->is_dir( $path );
+ }
+
+ public function mkdir( string $path, $chmod ) {
+ return $this->fs->mkdir( $path, $chmod );
+ }
+}
diff --git a/src/php/class-snippet-files.php b/src/php/files/classes/class-snippet-files.php
similarity index 78%
rename from src/php/class-snippet-files.php
rename to src/php/files/classes/class-snippet-files.php
index 9bb7bdd6..a7a0df61 100644
--- a/src/php/class-snippet-files.php
+++ b/src/php/files/classes/class-snippet-files.php
@@ -4,19 +4,17 @@
class Snippet_Files {
- /**
- * Holds the WP_Filesystem instance.
- *
- * @var \WP_Filesystem_Base
- */
- private $fs;
+ private Snippet_Handler_Registry $handler_registry;
- const TYPES_TO_HANDLE = [ 'php', 'html' ];
+ private File_System_Interface $fs;
- public function init() {
- $this->ensure_filesystem();
- $this->register_hooks();
- }
+ public function __construct(
+ Snippet_Handler_Registry $handler_registry,
+ File_System_Interface $fs
+ ) {
+ $this->handler_registry = $handler_registry;
+ $this->fs = $fs;
+ }
public function register_hooks() {
add_action( 'code_snippets/create_snippet', [ $this, 'handle_snippet' ], 10, 2 );
@@ -27,48 +25,36 @@ public function register_hooks() {
add_action( 'updated_option', [ $this, 'sync_active_shared_network_snippets' ], 10, 3 );
}
- private function ensure_filesystem() {
- if ( ! $this->fs ) {
- if ( ! function_exists( 'WP_Filesystem' ) ) {
- require_once ABSPATH . 'wp-admin/includes/file.php';
- }
-
- WP_Filesystem();
-
- global $wp_filesystem;
-
- $this->fs = $wp_filesystem;
- }
- }
-
- private function should_handle_snippet( string $snippet_type ) {
- return in_array( $snippet_type, self::TYPES_TO_HANDLE, true );
- }
-
public function handle_snippet( Snippet $snippet, string $table ) {
$snippet_type = $snippet->get_type();
- if ( ! $this->should_handle_snippet( $snippet_type ) ) {
+ $handler = $this->handler_registry->get_handler( $snippet_type );
+
+ if ( ! $handler ) {
return;
}
- $base_dir = self::get_base_dir( $table, $snippet_type );
+ $base_dir = self::get_base_dir( $table, $handler->get_dir_name() );
$this->maybe_create_directory( $base_dir );
$file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
- $this->write_snippet_file( $file_path, $snippet->code, $snippet_type );
+ $contents = $handler->wrap_code( $snippet->code );
+
+ $this->fs->put_contents( $file_path, $contents, FS_CHMOD_FILE );
$this->update_config_file( $base_dir, $snippet );
}
public function delete_snippet( Snippet $snippet, bool $network ) {
$snippet_type = $snippet->get_type();
- if ( ! $this->should_handle_snippet( $snippet_type ) ) {
+ $handler = $this->handler_registry->get_handler( $snippet_type );
+
+ if ( ! $handler ) {
return;
}
$table = code_snippets()->db->get_table_name( $network );
- $base_dir = self::get_base_dir( $table, $snippet_type );
+ $base_dir = self::get_base_dir( $table, $handler->get_dir_name() );
$file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
$this->delete_file( $file_path );
@@ -78,19 +64,23 @@ public function delete_snippet( Snippet $snippet, bool $network ) {
public function activate_snippet( Snippet $snippet, bool $network ) {
$snippet = get_snippet( $snippet->id, $network );
-
$snippet_type = $snippet->get_type();
- if ( ! $this->should_handle_snippet( $snippet_type ) ) {
+ $handler = $this->handler_registry->get_handler( $snippet_type );
+
+ if ( ! $handler ) {
return;
}
$table = code_snippets()->db->get_table_name( $network );
- $base_dir = self::get_base_dir( $table, $snippet_type );
+ $base_dir = self::get_base_dir( $table, $handler->get_dir_name() );
$this->maybe_create_directory( $base_dir );
$file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
- $this->write_snippet_file( $file_path, $snippet->code, $snippet_type );
+
+ $contents = $handler->wrap_code( $snippet->code );
+
+ $this->fs->put_contents( $file_path, $contents, FS_CHMOD_FILE );
$this->update_config_file( $base_dir, $snippet );
}
@@ -98,13 +88,14 @@ public function activate_snippet( Snippet $snippet, bool $network ) {
public function deactivate_snippet( int $snippet_id, bool $network ) {
$snippet = get_snippet( $snippet_id, $network );
$snippet_type = $snippet->get_type();
+ $handler = $this->handler_registry->get_handler( $snippet_type );
- if ( ! $this->should_handle_snippet( $snippet_type ) ) {
+ if ( ! $handler ) {
return;
}
$table = code_snippets()->db->get_table_name( $network );
- $base_dir = self::get_base_dir( $table, $snippet_type );
+ $base_dir = self::get_base_dir( $table, $handler->get_dir_name() );
$this->update_config_file( $base_dir, $snippet );
}
@@ -142,21 +133,6 @@ private function get_snippet_file_path( string $base_dir, int $snippet_id ) {
return trailingslashit( $base_dir ) . $snippet_id . '.php';
}
- /**
- * Writes the snippet code to a file, with the required header.
- */
- private function write_snippet_file( string $file_path, string $code, string $snippet_type ) {
- $content = "\n\n";
- }
-
- $content .= $code;
-
- $this->fs->put_contents( $file_path, $content, FS_CHMOD_FILE );
- }
-
/**
* Deletes a file if it exists.
*/
diff --git a/src/php/files/handlers/html-snippet-handler.php b/src/php/files/handlers/html-snippet-handler.php
new file mode 100644
index 00000000..7916297d
--- /dev/null
+++ b/src/php/files/handlers/html-snippet-handler.php
@@ -0,0 +1,17 @@
+\n\n" . $code;
+ }
+}
diff --git a/src/php/files/handlers/php-snippet-handler.php b/src/php/files/handlers/php-snippet-handler.php
new file mode 100644
index 00000000..666617b0
--- /dev/null
+++ b/src/php/files/handlers/php-snippet-handler.php
@@ -0,0 +1,17 @@
+ $handler ) {
+ $this->register_handler( $type, $handler );
+ }
+ }
+
+ /**
+ * Registers a handler for a snippet type.
+ *
+ * @param string $type
+ * @param Snippet_Type_Handler_Interface $handler
+ * @return void
+ */
+ public function register_handler( string $type, Snippet_Type_Handler_Interface $handler ): void {
+ $this->handlers[ $type ] = $handler;
+ }
+
+ /**
+ * Gets the handler for a snippet type.
+ *
+ * @param string $type
+ *
+ * @return Snippet_Type_Handler_Interface|null
+ */
+ public function get_handler( string $type ): ?Snippet_Type_Handler_Interface {
+ if ( ! isset( $this->handlers[ $type ] ) ) {
+ return null;
+ }
+
+ return $this->handlers[ $type ];
+ }
+}
From 3f5eea3fb3ddeebceb6a9a4d51939ccdd02930af Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Sat, 5 Jul 2025 23:44:39 +0200
Subject: [PATCH 023/106] wip
---
src/php/class-plugin.php | 2 +-
.../{files => flat-files}/classes/class-file-system-adapter.php | 0
src/php/{files => flat-files}/classes/class-snippet-files.php | 0
src/php/{files => flat-files}/handlers/html-snippet-handler.php | 0
src/php/{files => flat-files}/handlers/php-snippet-handler.php | 0
.../{files => flat-files}/interfaces/interface-file-system.php | 0
.../interfaces/interface-snippet-handler.php | 0
src/php/{files => flat-files}/load.php | 0
src/php/{files => flat-files}/registry.php | 0
9 files changed, 1 insertion(+), 1 deletion(-)
rename src/php/{files => flat-files}/classes/class-file-system-adapter.php (100%)
rename src/php/{files => flat-files}/classes/class-snippet-files.php (100%)
rename src/php/{files => flat-files}/handlers/html-snippet-handler.php (100%)
rename src/php/{files => flat-files}/handlers/php-snippet-handler.php (100%)
rename src/php/{files => flat-files}/interfaces/interface-file-system.php (100%)
rename src/php/{files => flat-files}/interfaces/interface-snippet-handler.php (100%)
rename src/php/{files => flat-files}/load.php (100%)
rename src/php/{files => flat-files}/registry.php (100%)
diff --git a/src/php/class-plugin.php b/src/php/class-plugin.php
index c09edbb4..ed07aaec 100644
--- a/src/php/class-plugin.php
+++ b/src/php/class-plugin.php
@@ -120,7 +120,7 @@ public function load_plugin() {
require_once $includes_path . '/cloud/list-table-shared-ops.php';
// Snippet files.
- require_once $includes_path . '/files/load.php';
+ require_once $includes_path . '/flat-files/load.php';
$registry = new Snippet_Handler_Registry( [
'php' => new Php_Snippet_Handler(),
'html' => new Html_Snippet_Handler(),
diff --git a/src/php/files/classes/class-file-system-adapter.php b/src/php/flat-files/classes/class-file-system-adapter.php
similarity index 100%
rename from src/php/files/classes/class-file-system-adapter.php
rename to src/php/flat-files/classes/class-file-system-adapter.php
diff --git a/src/php/files/classes/class-snippet-files.php b/src/php/flat-files/classes/class-snippet-files.php
similarity index 100%
rename from src/php/files/classes/class-snippet-files.php
rename to src/php/flat-files/classes/class-snippet-files.php
diff --git a/src/php/files/handlers/html-snippet-handler.php b/src/php/flat-files/handlers/html-snippet-handler.php
similarity index 100%
rename from src/php/files/handlers/html-snippet-handler.php
rename to src/php/flat-files/handlers/html-snippet-handler.php
diff --git a/src/php/files/handlers/php-snippet-handler.php b/src/php/flat-files/handlers/php-snippet-handler.php
similarity index 100%
rename from src/php/files/handlers/php-snippet-handler.php
rename to src/php/flat-files/handlers/php-snippet-handler.php
diff --git a/src/php/files/interfaces/interface-file-system.php b/src/php/flat-files/interfaces/interface-file-system.php
similarity index 100%
rename from src/php/files/interfaces/interface-file-system.php
rename to src/php/flat-files/interfaces/interface-file-system.php
diff --git a/src/php/files/interfaces/interface-snippet-handler.php b/src/php/flat-files/interfaces/interface-snippet-handler.php
similarity index 100%
rename from src/php/files/interfaces/interface-snippet-handler.php
rename to src/php/flat-files/interfaces/interface-snippet-handler.php
diff --git a/src/php/files/load.php b/src/php/flat-files/load.php
similarity index 100%
rename from src/php/files/load.php
rename to src/php/flat-files/load.php
diff --git a/src/php/files/registry.php b/src/php/flat-files/registry.php
similarity index 100%
rename from src/php/files/registry.php
rename to src/php/flat-files/registry.php
From 69449a01470195e85102078a1dcfe55a3b1e9ebb Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Sat, 5 Jul 2025 23:48:38 +0200
Subject: [PATCH 024/106] wip
---
.../classes/class-file-system-adapter.php | 48 ++++++------
.../handlers/html-snippet-handler.php | 18 ++---
.../interfaces/interface-file-system.php | 10 +--
.../interfaces/interface-snippet-handler.php | 6 +-
src/php/flat-files/registry.php | 74 +++++++++----------
5 files changed, 78 insertions(+), 78 deletions(-)
diff --git a/src/php/flat-files/classes/class-file-system-adapter.php b/src/php/flat-files/classes/class-file-system-adapter.php
index b22308e3..c8085e5c 100644
--- a/src/php/flat-files/classes/class-file-system-adapter.php
+++ b/src/php/flat-files/classes/class-file-system-adapter.php
@@ -2,34 +2,34 @@
namespace Code_Snippets;
class WordPress_Filesystem_Adapter implements File_System_Interface {
- private $fs;
+ private $fs;
- public function __construct() {
- if ( ! function_exists( 'WP_Filesystem' ) ) {
- require_once ABSPATH . 'wp-admin/includes/file.php';
- }
- WP_Filesystem();
- global $wp_filesystem;
- $this->fs = $wp_filesystem;
- }
+ public function __construct() {
+ if ( ! function_exists( 'WP_Filesystem' ) ) {
+ require_once ABSPATH . 'wp-admin/includes/file.php';
+ }
+ WP_Filesystem();
+ global $wp_filesystem;
+ $this->fs = $wp_filesystem;
+ }
- public function put_contents( string $path, string $contents, $chmod ) {
- return $this->fs->put_contents( $path, $contents, $chmod );
- }
+ public function put_contents( string $path, string $contents, $chmod ) {
+ return $this->fs->put_contents( $path, $contents, $chmod );
+ }
- public function exists( string $path ): bool {
- return $this->fs->exists( $path );
- }
+ public function exists( string $path ): bool {
+ return $this->fs->exists( $path );
+ }
- public function delete( string $path ): bool {
- return $this->fs->delete( $path );
- }
+ public function delete( string $path ): bool {
+ return $this->fs->delete( $path );
+ }
- public function is_dir( string $path ): bool {
- return $this->fs->is_dir( $path );
- }
+ public function is_dir( string $path ): bool {
+ return $this->fs->is_dir( $path );
+ }
- public function mkdir( string $path, $chmod ) {
- return $this->fs->mkdir( $path, $chmod );
- }
+ public function mkdir( string $path, $chmod ) {
+ return $this->fs->mkdir( $path, $chmod );
+ }
}
diff --git a/src/php/flat-files/handlers/html-snippet-handler.php b/src/php/flat-files/handlers/html-snippet-handler.php
index 7916297d..d7a4446a 100644
--- a/src/php/flat-files/handlers/html-snippet-handler.php
+++ b/src/php/flat-files/handlers/html-snippet-handler.php
@@ -3,15 +3,15 @@
namespace Code_Snippets;
class Html_Snippet_Handler implements Snippet_Type_Handler_Interface {
- public function get_file_extension(): string {
- return 'php';
- }
+ public function get_file_extension(): string {
+ return 'php';
+ }
- public function get_dir_name(): string {
- return 'html';
- }
+ public function get_dir_name(): string {
+ return 'html';
+ }
- public function wrap_code( string $code ): string {
- return "\n\n" . $code;
- }
+ public function wrap_code( string $code ): string {
+ return "\n\n" . $code;
+ }
}
diff --git a/src/php/flat-files/interfaces/interface-file-system.php b/src/php/flat-files/interfaces/interface-file-system.php
index 3a8cc7a3..38ab5bd0 100644
--- a/src/php/flat-files/interfaces/interface-file-system.php
+++ b/src/php/flat-files/interfaces/interface-file-system.php
@@ -3,9 +3,9 @@
namespace Code_Snippets;
interface File_System_Interface {
- public function put_contents( string $path, string $contents, $chmod );
- public function exists( string $path ): bool;
- public function delete( string $path ): bool;
- public function is_dir( string $path ): bool;
- public function mkdir( string $path, $chmod );
+ public function put_contents( string $path, string $contents, $chmod );
+ public function exists( string $path ): bool;
+ public function delete( string $path ): bool;
+ public function is_dir( string $path ): bool;
+ public function mkdir( string $path, $chmod );
}
diff --git a/src/php/flat-files/interfaces/interface-snippet-handler.php b/src/php/flat-files/interfaces/interface-snippet-handler.php
index fdcbb6b8..4ff024cb 100644
--- a/src/php/flat-files/interfaces/interface-snippet-handler.php
+++ b/src/php/flat-files/interfaces/interface-snippet-handler.php
@@ -3,7 +3,7 @@
namespace Code_Snippets;
interface Snippet_Type_Handler_Interface {
- public function get_file_extension(): string;
- public function get_dir_name(): string;
- public function wrap_code( string $code ): string;
+ public function get_file_extension(): string;
+ public function get_dir_name(): string;
+ public function wrap_code( string $code ): string;
}
diff --git a/src/php/flat-files/registry.php b/src/php/flat-files/registry.php
index a02b589b..4fce503d 100644
--- a/src/php/flat-files/registry.php
+++ b/src/php/flat-files/registry.php
@@ -3,45 +3,45 @@
namespace Code_Snippets;
class Snippet_Handler_Registry {
- /**
- * @var Snippet_Type_Handler_Interface[]
- */
- private array $handlers = [];
+ /**
+ * @var Snippet_Type_Handler_Interface[]
+ */
+ private array $handlers = [];
- /**
- * Constructor
- *
- * @param Snippet_Type_Handler_Interface[] $handlers
- */
- public function __construct( array $handlers ) {
- foreach ( $handlers as $type => $handler ) {
- $this->register_handler( $type, $handler );
- }
- }
+ /**
+ * Constructor
+ *
+ * @param Snippet_Type_Handler_Interface[] $handlers
+ */
+ public function __construct( array $handlers ) {
+ foreach ( $handlers as $type => $handler ) {
+ $this->register_handler( $type, $handler );
+ }
+ }
- /**
- * Registers a handler for a snippet type.
- *
- * @param string $type
- * @param Snippet_Type_Handler_Interface $handler
- * @return void
- */
- public function register_handler( string $type, Snippet_Type_Handler_Interface $handler ): void {
- $this->handlers[ $type ] = $handler;
- }
+ /**
+ * Registers a handler for a snippet type.
+ *
+ * @param string $type
+ * @param Snippet_Type_Handler_Interface $handler
+ * @return void
+ */
+ public function register_handler( string $type, Snippet_Type_Handler_Interface $handler ): void {
+ $this->handlers[ $type ] = $handler;
+ }
- /**
- * Gets the handler for a snippet type.
- *
- * @param string $type
- *
- * @return Snippet_Type_Handler_Interface|null
- */
- public function get_handler( string $type ): ?Snippet_Type_Handler_Interface {
- if ( ! isset( $this->handlers[ $type ] ) ) {
- return null;
- }
+ /**
+ * Gets the handler for a snippet type.
+ *
+ * @param string $type
+ *
+ * @return Snippet_Type_Handler_Interface|null
+ */
+ public function get_handler( string $type ): ?Snippet_Type_Handler_Interface {
+ if ( ! isset( $this->handlers[ $type ] ) ) {
+ return null;
+ }
- return $this->handlers[ $type ];
- }
+ return $this->handlers[ $type ];
+ }
}
From 91b754696d144c0c119b89482aa8dfcecb6bd342 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Sat, 5 Jul 2025 23:49:37 +0200
Subject: [PATCH 025/106] wip
---
src/php/flat-files/classes/class-snippet-files.php | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/php/flat-files/classes/class-snippet-files.php b/src/php/flat-files/classes/class-snippet-files.php
index a7a0df61..9750d2a2 100644
--- a/src/php/flat-files/classes/class-snippet-files.php
+++ b/src/php/flat-files/classes/class-snippet-files.php
@@ -8,13 +8,13 @@ class Snippet_Files {
private File_System_Interface $fs;
- public function __construct(
- Snippet_Handler_Registry $handler_registry,
+ public function __construct(
+ Snippet_Handler_Registry $handler_registry,
File_System_Interface $fs
- ) {
- $this->handler_registry = $handler_registry;
- $this->fs = $fs;
- }
+ ) {
+ $this->handler_registry = $handler_registry;
+ $this->fs = $fs;
+ }
public function register_hooks() {
add_action( 'code_snippets/create_snippet', [ $this, 'handle_snippet' ], 10, 2 );
From 0029e0f0dde5f386acaf1b1695f4dc0a8baa0f89 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Sat, 5 Jul 2025 23:55:22 +0200
Subject: [PATCH 026/106] wip
---
src/php/flat-files/classes/class-snippet-files.php | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/php/flat-files/classes/class-snippet-files.php b/src/php/flat-files/classes/class-snippet-files.php
index 9750d2a2..add308ad 100644
--- a/src/php/flat-files/classes/class-snippet-files.php
+++ b/src/php/flat-files/classes/class-snippet-files.php
@@ -36,7 +36,7 @@ public function handle_snippet( Snippet $snippet, string $table ) {
$base_dir = self::get_base_dir( $table, $handler->get_dir_name() );
$this->maybe_create_directory( $base_dir );
- $file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
+ $file_path = $this->get_snippet_file_path( $base_dir, $snippet->id, $handler->get_file_extension() );
$contents = $handler->wrap_code( $snippet->code );
@@ -56,7 +56,7 @@ public function delete_snippet( Snippet $snippet, bool $network ) {
$table = code_snippets()->db->get_table_name( $network );
$base_dir = self::get_base_dir( $table, $handler->get_dir_name() );
- $file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
+ $file_path = $this->get_snippet_file_path( $base_dir, $snippet->id, $handler->get_file_extension() );
$this->delete_file( $file_path );
$this->update_config_file( $base_dir, $snippet, true );
@@ -76,7 +76,7 @@ public function activate_snippet( Snippet $snippet, bool $network ) {
$this->maybe_create_directory( $base_dir );
- $file_path = $this->get_snippet_file_path( $base_dir, $snippet->id );
+ $file_path = $this->get_snippet_file_path( $base_dir, $snippet->id, $handler->get_file_extension() );
$contents = $handler->wrap_code( $snippet->code );
@@ -129,8 +129,8 @@ private function maybe_create_directory( string $dir ) {
/**
* Returns the path to the snippet PHP file.
*/
- private function get_snippet_file_path( string $base_dir, int $snippet_id ) {
- return trailingslashit( $base_dir ) . $snippet_id . '.php';
+ private function get_snippet_file_path( string $base_dir, int $snippet_id, string $ext ) {
+ return trailingslashit( $base_dir ) . $snippet_id . '.' . $ext;
}
/**
From 1a7789e9792923dba658880188f7b00d961c10a6 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Sun, 6 Jul 2025 00:07:32 +0200
Subject: [PATCH 027/106] wip
---
src/php/class-plugin.php | 7 ++-
.../classes/class-config-repository.php | 41 +++++++++++++
.../classes/class-snippet-files.php | 57 +++----------------
.../interface-config-repository.php | 9 +++
src/php/flat-files/load.php | 1 +
5 files changed, 66 insertions(+), 49 deletions(-)
create mode 100644 src/php/flat-files/classes/class-config-repository.php
create mode 100644 src/php/flat-files/interfaces/interface-config-repository.php
diff --git a/src/php/class-plugin.php b/src/php/class-plugin.php
index ed07aaec..9366a5f8 100644
--- a/src/php/class-plugin.php
+++ b/src/php/class-plugin.php
@@ -121,12 +121,17 @@ public function load_plugin() {
// Snippet files.
require_once $includes_path . '/flat-files/load.php';
+
$registry = new Snippet_Handler_Registry( [
'php' => new Php_Snippet_Handler(),
'html' => new Html_Snippet_Handler(),
] );
+
$fs = new WordPress_Filesystem_Adapter();
- ( new Snippet_Files( $registry, $fs ) )->register_hooks();
+
+ $config_repo = new Snippet_Config_Repository( $fs );
+
+ ( new Snippet_Files( $registry, $fs, $config_repo ) )->register_hooks();
$this->active_snippets = new Active_Snippets();
$this->front_end = new Front_End();
diff --git a/src/php/flat-files/classes/class-config-repository.php b/src/php/flat-files/classes/class-config-repository.php
new file mode 100644
index 00000000..bcf48535
--- /dev/null
+++ b/src/php/flat-files/classes/class-config-repository.php
@@ -0,0 +1,41 @@
+fs = $fs;
+ }
+
+ public function load( string $base_dir ): array {
+ $config_file_path = trailingslashit( $base_dir ) . 'index.php';
+
+ return is_file( $config_file_path )
+ ? require $config_file_path
+ : [];
+ }
+
+ public function save( string $base_dir, array $active_snippets ): void {
+ $config_file_path = trailingslashit( $base_dir ) . 'index.php';
+
+ $file_content = "fs->put_contents( $config_file_path, $file_content, FS_CHMOD_FILE );
+ }
+
+ public function update( string $base_dir, Snippet $snippet, ?bool $remove = false ): void {
+ $active_snippets = $this->load( $base_dir );
+
+ if ( ! $remove ) {
+ $active_snippets[ $snippet->id ] = $snippet->get_fields();
+ } else {
+ unset( $active_snippets[ $snippet->id ] );
+ }
+
+ $this->save( $base_dir, $active_snippets );
+ }
+}
diff --git a/src/php/flat-files/classes/class-snippet-files.php b/src/php/flat-files/classes/class-snippet-files.php
index add308ad..35ccaa03 100644
--- a/src/php/flat-files/classes/class-snippet-files.php
+++ b/src/php/flat-files/classes/class-snippet-files.php
@@ -8,12 +8,16 @@ class Snippet_Files {
private File_System_Interface $fs;
+ private Snippet_Config_Repository_Interface $config_repo;
+
public function __construct(
Snippet_Handler_Registry $handler_registry,
- File_System_Interface $fs
+ File_System_Interface $fs,
+ Snippet_Config_Repository_Interface $config_repo
) {
$this->handler_registry = $handler_registry;
$this->fs = $fs;
+ $this->config_repo = $config_repo;
}
public function register_hooks() {
@@ -42,7 +46,7 @@ public function handle_snippet( Snippet $snippet, string $table ) {
$this->fs->put_contents( $file_path, $contents, FS_CHMOD_FILE );
- $this->update_config_file( $base_dir, $snippet );
+ $this->config_repo->update( $base_dir, $snippet );
}
public function delete_snippet( Snippet $snippet, bool $network ) {
@@ -59,7 +63,7 @@ public function delete_snippet( Snippet $snippet, bool $network ) {
$file_path = $this->get_snippet_file_path( $base_dir, $snippet->id, $handler->get_file_extension() );
$this->delete_file( $file_path );
- $this->update_config_file( $base_dir, $snippet, true );
+ $this->config_repo->update( $base_dir, $snippet, true );
}
public function activate_snippet( Snippet $snippet, bool $network ) {
@@ -82,7 +86,7 @@ public function activate_snippet( Snippet $snippet, bool $network ) {
$this->fs->put_contents( $file_path, $contents, FS_CHMOD_FILE );
- $this->update_config_file( $base_dir, $snippet );
+ $this->config_repo->update( $base_dir, $snippet );
}
public function deactivate_snippet( int $snippet_id, bool $network ) {
@@ -97,12 +101,9 @@ public function deactivate_snippet( int $snippet_id, bool $network ) {
$table = code_snippets()->db->get_table_name( $network );
$base_dir = self::get_base_dir( $table, $handler->get_dir_name() );
- $this->update_config_file( $base_dir, $snippet );
+ $this->config_repo->update( $base_dir, $snippet );
}
- /**
- * Returns the base directory path for a given context.
- */
public static function get_base_dir( string $table = '', string $snippet_type = '' ) {
$base_dir = WP_CONTENT_DIR . '/code-snippets';
@@ -117,62 +118,22 @@ public static function get_base_dir( string $table = '', string $snippet_type =
return $base_dir;
}
- /**
- * Creates the directory if it does not exist.
- */
private function maybe_create_directory( string $dir ) {
if ( ! $this->fs->is_dir( $dir ) ) {
$this->fs->mkdir( $dir, FS_CHMOD_DIR );
}
}
- /**
- * Returns the path to the snippet PHP file.
- */
private function get_snippet_file_path( string $base_dir, int $snippet_id, string $ext ) {
return trailingslashit( $base_dir ) . $snippet_id . '.' . $ext;
}
- /**
- * Deletes a file if it exists.
- */
private function delete_file( string $file_path ) {
if ( $this->fs->exists( $file_path ) ) {
$this->fs->delete( $file_path );
}
}
- /**
- * Loads the index.php array by requiring it directly.
- */
- private function load_config_file( string $config_file_path ) {
- return is_file( $config_file_path ) ? require $config_file_path : [];
- }
-
- /**
- * Saves the index.php file via WP_Filesystem.
- */
- private function save_config_file( string $config_file_path, array $active_snippets ) {
- $file_content = "fs->put_contents( $config_file_path, $file_content, FS_CHMOD_FILE );
- }
-
- /**
- * Updates the index.php file with snippet config.
- */
- private function update_config_file( string $base_dir, Snippet $snippet, ?bool $remove = false ) {
- $config_file_path = trailingslashit( $base_dir ) . 'index.php';
- $active_snippets = $this->load_config_file( $config_file_path );
-
- if ( ! $remove ) {
- $active_snippets[ $snippet->id ] = $snippet->get_fields();
- } else {
- unset( $active_snippets[ $snippet->id ] );
- }
-
- $this->save_config_file( $config_file_path, $active_snippets );
- }
-
public function sync_active_shared_network_snippets( $option, $old_value, $value ) {
if ( 'active_shared_network_snippets' !== $option ) {
return;
diff --git a/src/php/flat-files/interfaces/interface-config-repository.php b/src/php/flat-files/interfaces/interface-config-repository.php
new file mode 100644
index 00000000..e8c3a819
--- /dev/null
+++ b/src/php/flat-files/interfaces/interface-config-repository.php
@@ -0,0 +1,9 @@
+
Date: Sun, 6 Jul 2025 00:08:36 +0200
Subject: [PATCH 028/106] wip
---
src/php/flat-files/load.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/php/flat-files/load.php b/src/php/flat-files/load.php
index ea42c050..476a5113 100644
--- a/src/php/flat-files/load.php
+++ b/src/php/flat-files/load.php
@@ -8,3 +8,4 @@
require_once 'handlers/html-snippet-handler.php';
require_once 'classes/class-file-system-adapter.php';
require_once 'classes/class-snippet-files.php';
+require_once 'classes/class-config-repository.php';
From 87b9b2dca9ae96755e4c0951489b8579ce4958ee Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Sun, 6 Jul 2025 00:27:08 +0200
Subject: [PATCH 029/106] wip
---
src/php/flat-files/load.php | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/src/php/flat-files/load.php b/src/php/flat-files/load.php
index 476a5113..dd87d808 100644
--- a/src/php/flat-files/load.php
+++ b/src/php/flat-files/load.php
@@ -1,11 +1,17 @@
Date: Sun, 6 Jul 2025 21:51:13 +0200
Subject: [PATCH 030/106] wip
---
src/php/flat-files/classes/class-snippet-files.php | 13 +++++++++++++
src/php/load.php | 7 +++++--
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/src/php/flat-files/classes/class-snippet-files.php b/src/php/flat-files/classes/class-snippet-files.php
index 35ccaa03..093e33fd 100644
--- a/src/php/flat-files/classes/class-snippet-files.php
+++ b/src/php/flat-files/classes/class-snippet-files.php
@@ -26,7 +26,10 @@ public function register_hooks() {
add_action( 'code_snippets/delete_snippet', [ $this, 'delete_snippet' ], 10, 2 );
add_action( 'code_snippets/activate_snippet', [ $this, 'activate_snippet' ], 10, 2 );
add_action( 'code_snippets/deactivate_snippet', [ $this, 'deactivate_snippet' ], 10, 2 );
+
add_action( 'updated_option', [ $this, 'sync_active_shared_network_snippets' ], 10, 3 );
+
+ add_filter( 'code_snippets_settings_fields', [ $this, 'add_settings_fields' ], 10, 1 );
}
public function handle_snippet( Snippet $snippet, string $table ) {
@@ -191,4 +194,14 @@ function ( $snippet ) use ( $active_shared_ids ) {
return $snippets;
}
+
+ public function add_settings_fields( array $fields ) {
+ $fields['general']['enable_flat_files'] = [
+ 'name' => __( 'Enable Flat Files', 'code-snippets' ),
+ 'type' => 'checkbox',
+ 'label' => __( 'Snippets will be executed from flat files instead of the database.', 'code-snippets' ),
+ ];
+
+ return $fields;
+ }
}
diff --git a/src/php/load.php b/src/php/load.php
index 8700186a..220d95a5 100644
--- a/src/php/load.php
+++ b/src/php/load.php
@@ -65,5 +65,8 @@ function code_snippets(): Plugin {
code_snippets()->load_plugin();
// Execute the snippets once the plugins are loaded.
-// add_action( 'plugins_loaded', __NAMESPACE__ . '\execute_active_snippets', 1 );
-add_action( 'plugins_loaded', __NAMESPACE__ . '\execute_active_snippets_from_flat_files', 1 );
+$snippet_execution_fn = Settings\get_setting( 'general', 'enable_flat_files' )
+ ? '\execute_active_snippets_from_flat_files'
+ : '\execute_active_snippets';
+
+add_action( 'plugins_loaded', __NAMESPACE__ . $snippet_execution_fn, 1 );
From 531ee3515a14ff6f0e5723337194e9524fa6b59b Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Sun, 6 Jul 2025 21:57:51 +0200
Subject: [PATCH 031/106] wip
---
src/php/front-end/class-front-end.php | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/php/front-end/class-front-end.php b/src/php/front-end/class-front-end.php
index 60429b35..258b27ec 100644
--- a/src/php/front-end/class-front-end.php
+++ b/src/php/front-end/class-front-end.php
@@ -245,6 +245,12 @@ protected function evaluate_shortcode_content( Snippet $snippet, array $atts ):
return $snippet->code;
}
+ $should_execute_from_flat_files = Settings\get_setting( 'general', 'enable_flat_files' );
+
+ if ( ! $should_execute_from_flat_files ) {
+ return $this->evaluate_shortcode_from_db( $snippet, $atts );
+ }
+
$network = DB::validate_network_param( $snippet->network );
$table_name = code_snippets()->db->get_table_name( $network );
$filepath = WP_CONTENT_DIR . '/code-snippets/' . $table_name . '/html/' . $snippet->id . '.php';
From 0b19d6ef3ef82408ff3b47cd1eec24bcae4cc850 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Sun, 6 Jul 2025 22:07:48 +0200
Subject: [PATCH 032/106] wip
---
src/php/class-plugin.php | 2 +-
src/php/front-end/class-front-end.php | 22 ++++++++++++++++++++--
2 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/src/php/class-plugin.php b/src/php/class-plugin.php
index 9366a5f8..bb21473a 100644
--- a/src/php/class-plugin.php
+++ b/src/php/class-plugin.php
@@ -134,7 +134,7 @@ public function load_plugin() {
( new Snippet_Files( $registry, $fs, $config_repo ) )->register_hooks();
$this->active_snippets = new Active_Snippets();
- $this->front_end = new Front_End();
+ $this->front_end = new Front_End( $registry );
$this->cloud_api = new Cloud_API();
$upgrade = new Upgrade( $this->version, $this->db );
diff --git a/src/php/front-end/class-front-end.php b/src/php/front-end/class-front-end.php
index 258b27ec..f0ddf8e1 100644
--- a/src/php/front-end/class-front-end.php
+++ b/src/php/front-end/class-front-end.php
@@ -33,10 +33,14 @@ class Front_End {
*/
const MAX_SHORTCODE_DEPTH = 5;
+ private Snippet_Handler_Registry $handler_registry;
+
/**
* Class constructor
*/
- public function __construct() {
+ public function __construct( Snippet_Handler_Registry $handler_registry ) {
+ $this->handler_registry = $handler_registry;
+
add_action( 'the_posts', [ $this, 'enqueue_highlighting' ] );
add_action( 'init', [ $this, 'setup_mce_plugin' ] );
@@ -232,6 +236,20 @@ protected function convert_boolean_attribute_flags( array $atts, array $boolean_
return $atts;
}
+ /**
+ * Build the file path for a snippet's flat file.
+ *
+ * @param string $table_name Table name for the snippet.
+ * @param Snippet $snippet Snippet object.
+ *
+ * @return string Full file path for the snippet.
+ */
+ private function build_snippet_filepath( string $table_name, Snippet $snippet ): string {
+ $handler = $this->handler_registry->get_handler( $snippet->get_type() );
+
+ return WP_CONTENT_DIR . '/code-snippets/' . $table_name . '/' . $handler->get_dir_name() . '/' . $snippet->id . '.' . $handler->get_file_extension();
+ }
+
/**
* Evaluate the code from a content shortcode.
*
@@ -253,7 +271,7 @@ protected function evaluate_shortcode_content( Snippet $snippet, array $atts ):
$network = DB::validate_network_param( $snippet->network );
$table_name = code_snippets()->db->get_table_name( $network );
- $filepath = WP_CONTENT_DIR . '/code-snippets/' . $table_name . '/html/' . $snippet->id . '.php';
+ $filepath = $this->build_snippet_filepath( $table_name, $snippet );
return file_exists( $filepath )
? $this->evaluate_shortcode_from_flat_file( $filepath, $atts )
From ff80d08a00934d88ab6ea02b2c6561dc355a278e Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Sun, 6 Jul 2025 22:10:29 +0200
Subject: [PATCH 033/106] wip
---
src/php/front-end/class-front-end.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/php/front-end/class-front-end.php b/src/php/front-end/class-front-end.php
index f0ddf8e1..66d00e05 100644
--- a/src/php/front-end/class-front-end.php
+++ b/src/php/front-end/class-front-end.php
@@ -244,7 +244,7 @@ protected function convert_boolean_attribute_flags( array $atts, array $boolean_
*
* @return string Full file path for the snippet.
*/
- private function build_snippet_filepath( string $table_name, Snippet $snippet ): string {
+ private function build_snippet_flat_file_path( string $table_name, Snippet $snippet ): string {
$handler = $this->handler_registry->get_handler( $snippet->get_type() );
return WP_CONTENT_DIR . '/code-snippets/' . $table_name . '/' . $handler->get_dir_name() . '/' . $snippet->id . '.' . $handler->get_file_extension();
@@ -271,7 +271,7 @@ protected function evaluate_shortcode_content( Snippet $snippet, array $atts ):
$network = DB::validate_network_param( $snippet->network );
$table_name = code_snippets()->db->get_table_name( $network );
- $filepath = $this->build_snippet_filepath( $table_name, $snippet );
+ $filepath = $this->build_snippet_flat_file_path( $table_name, $snippet );
return file_exists( $filepath )
? $this->evaluate_shortcode_from_flat_file( $filepath, $atts )
From b533854ab4f5ae9501298e858fcff31117b100f2 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Sun, 6 Jul 2025 22:13:32 +0200
Subject: [PATCH 034/106] wip
---
.../flat-files/classes/class-snippet-files.php | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/src/php/flat-files/classes/class-snippet-files.php b/src/php/flat-files/classes/class-snippet-files.php
index 093e33fd..8765780f 100644
--- a/src/php/flat-files/classes/class-snippet-files.php
+++ b/src/php/flat-files/classes/class-snippet-files.php
@@ -21,13 +21,15 @@ public function __construct(
}
public function register_hooks() {
- add_action( 'code_snippets/create_snippet', [ $this, 'handle_snippet' ], 10, 2 );
- add_action( 'code_snippets/update_snippet', [ $this, 'handle_snippet' ], 10, 2 );
- add_action( 'code_snippets/delete_snippet', [ $this, 'delete_snippet' ], 10, 2 );
- add_action( 'code_snippets/activate_snippet', [ $this, 'activate_snippet' ], 10, 2 );
- add_action( 'code_snippets/deactivate_snippet', [ $this, 'deactivate_snippet' ], 10, 2 );
-
- add_action( 'updated_option', [ $this, 'sync_active_shared_network_snippets' ], 10, 3 );
+ if ( Settings\get_setting( 'general', 'enable_flat_files' ) ) {
+ add_action( 'code_snippets/create_snippet', [ $this, 'handle_snippet' ], 10, 2 );
+ add_action( 'code_snippets/update_snippet', [ $this, 'handle_snippet' ], 10, 2 );
+ add_action( 'code_snippets/delete_snippet', [ $this, 'delete_snippet' ], 10, 2 );
+ add_action( 'code_snippets/activate_snippet', [ $this, 'activate_snippet' ], 10, 2 );
+ add_action( 'code_snippets/deactivate_snippet', [ $this, 'deactivate_snippet' ], 10, 2 );
+
+ add_action( 'updated_option', [ $this, 'sync_active_shared_network_snippets' ], 10, 3 );
+ }
add_filter( 'code_snippets_settings_fields', [ $this, 'add_settings_fields' ], 10, 1 );
}
From b983aa79f74cba15ecc33221815ea3155bee22c7 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Sun, 6 Jul 2025 22:29:23 +0200
Subject: [PATCH 035/106] wip
---
.../classes/class-file-system-adapter.php | 4 ++++
.../interfaces/interface-file-system.php | 1 +
src/php/uninstall.php | 15 ++++++++++++++-
3 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/src/php/flat-files/classes/class-file-system-adapter.php b/src/php/flat-files/classes/class-file-system-adapter.php
index c8085e5c..6c230f13 100644
--- a/src/php/flat-files/classes/class-file-system-adapter.php
+++ b/src/php/flat-files/classes/class-file-system-adapter.php
@@ -32,4 +32,8 @@ public function is_dir( string $path ): bool {
public function mkdir( string $path, $chmod ) {
return $this->fs->mkdir( $path, $chmod );
}
+
+ public function rmdir( string $path, bool $recursive = false ): bool {
+ return $this->fs->rmdir( $path, $recursive );
+ }
}
diff --git a/src/php/flat-files/interfaces/interface-file-system.php b/src/php/flat-files/interfaces/interface-file-system.php
index 38ab5bd0..7560d7bb 100644
--- a/src/php/flat-files/interfaces/interface-file-system.php
+++ b/src/php/flat-files/interfaces/interface-file-system.php
@@ -8,4 +8,5 @@ public function exists( string $path ): bool;
public function delete( string $path ): bool;
public function is_dir( string $path ): bool;
public function mkdir( string $path, $chmod );
+ public function rmdir( string $path, bool $recursive = false ): bool;
}
diff --git a/src/php/uninstall.php b/src/php/uninstall.php
index 4da58cfe..028aca5c 100644
--- a/src/php/uninstall.php
+++ b/src/php/uninstall.php
@@ -18,7 +18,7 @@ function complete_uninstall_enabled(): bool {
$unified = false;
if ( is_multisite() ) {
- $menu_perms = get_site_option( 'menu_items', array() );
+ $menu_perms = get_site_option( 'menu_items', [] );
$unified = empty( $menu_perms['snippets_settings'] );
}
@@ -72,6 +72,17 @@ function uninstall_multisite() {
delete_site_option( 'recently_activated_snippets' );
}
+function delete_flat_files_directory() {
+ $flat_files_dir = WP_CONTENT_DIR . '/code-snippets';
+
+ if ( ! is_dir( $flat_files_dir ) ) {
+ return;
+ }
+
+ $fs = new \Code_Snippets\WordPress_Filesystem_Adapter();
+ $fs->rmdir( $flat_files_dir, true );
+}
+
/**
* Uninstall the Code Snippets plugin.
*
@@ -85,5 +96,7 @@ function uninstall_plugin() {
} else {
uninstall_current_site();
}
+
+ delete_flat_files_directory();
}
}
From e3a96ab1a469657e6fc392e264a7db351dbb4851 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Sun, 6 Jul 2025 22:31:19 +0200
Subject: [PATCH 036/106] wip
---
src/php/flat-files/classes/class-config-repository.php | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/php/flat-files/classes/class-config-repository.php b/src/php/flat-files/classes/class-config-repository.php
index bcf48535..2087f572 100644
--- a/src/php/flat-files/classes/class-config-repository.php
+++ b/src/php/flat-files/classes/class-config-repository.php
@@ -3,6 +3,8 @@
class Snippet_Config_Repository implements Snippet_Config_Repository_Interface {
+ const CONFIG_FILE_NAME = 'index.php';
+
private File_System_Interface $fs;
public function __construct( File_System_Interface $fs ) {
@@ -10,7 +12,7 @@ public function __construct( File_System_Interface $fs ) {
}
public function load( string $base_dir ): array {
- $config_file_path = trailingslashit( $base_dir ) . 'index.php';
+ $config_file_path = trailingslashit( $base_dir ) . static::CONFIG_FILE_NAME;
return is_file( $config_file_path )
? require $config_file_path
@@ -18,7 +20,7 @@ public function load( string $base_dir ): array {
}
public function save( string $base_dir, array $active_snippets ): void {
- $config_file_path = trailingslashit( $base_dir ) . 'index.php';
+ $config_file_path = trailingslashit( $base_dir ) . static::CONFIG_FILE_NAME;
$file_content = "
Date: Sun, 6 Jul 2025 23:16:43 +0200
Subject: [PATCH 037/106] wip
---
.../classes/class-snippet-files.php | 25 +++++++++++++++++++
src/php/settings/settings.php | 2 ++
2 files changed, 27 insertions(+)
diff --git a/src/php/flat-files/classes/class-snippet-files.php b/src/php/flat-files/classes/class-snippet-files.php
index 8765780f..18a68176 100644
--- a/src/php/flat-files/classes/class-snippet-files.php
+++ b/src/php/flat-files/classes/class-snippet-files.php
@@ -32,6 +32,7 @@ public function register_hooks() {
}
add_filter( 'code_snippets_settings_fields', [ $this, 'add_settings_fields' ], 10, 1 );
+ add_action( 'code_snippets/settings_updated', [ $this, 'create_all_flat_files' ], 10, 2 );
}
public function handle_snippet( Snippet $snippet, string $table ) {
@@ -206,4 +207,28 @@ public function add_settings_fields( array $fields ) {
return $fields;
}
+
+ public function create_all_flat_files( array $settings, array $input ) {
+ if ( ! isset( $settings['general']['enable_flat_files'] ) ) {
+ return;
+ }
+
+ if ( ! $settings['general']['enable_flat_files'] ) {
+ return;
+ }
+
+ $db = code_snippets()->db;
+ $data = $db->fetch_active_snippets( Snippet::get_all_scopes() );
+
+ if ( empty( $data ) ) {
+ return;
+ }
+
+ foreach ( $data as $table_name => $active_snippets ) {
+ foreach ( $active_snippets as $snippet ) {
+ $snippet_obj = get_snippet( $snippet['id'], $table_name === $db->ms_table );
+ $this->handle_snippet( $snippet_obj, $table_name );
+ }
+ }
+ }
}
diff --git a/src/php/settings/settings.php b/src/php/settings/settings.php
index cf94f8b9..e3565b46 100644
--- a/src/php/settings/settings.php
+++ b/src/php/settings/settings.php
@@ -330,6 +330,8 @@ function sanitize_settings( array $input ): array {
__( 'Settings saved.', 'code-snippets' ),
'updated'
);
+
+ do_action( 'code_snippets/settings_updated', $settings, $input );
}
return $settings;
From 07f542bee02eda5b59fe8c4d2a71b1c3aa57bc1c Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Mon, 7 Jul 2025 22:04:13 +0200
Subject: [PATCH 038/106] wip
---
.../classes/class-file-system-adapter.php | 8 ++++
.../classes/class-snippet-files.php | 44 +++++++++++--------
.../interfaces/interface-file-system.php | 2 +
src/php/snippet-ops.php | 5 +--
4 files changed, 37 insertions(+), 22 deletions(-)
diff --git a/src/php/flat-files/classes/class-file-system-adapter.php b/src/php/flat-files/classes/class-file-system-adapter.php
index 6c230f13..c17cef28 100644
--- a/src/php/flat-files/classes/class-file-system-adapter.php
+++ b/src/php/flat-files/classes/class-file-system-adapter.php
@@ -36,4 +36,12 @@ public function mkdir( string $path, $chmod ) {
public function rmdir( string $path, bool $recursive = false ): bool {
return $this->fs->rmdir( $path, $recursive );
}
+
+ public function chmod( string $path, $chmod ): bool {
+ return $this->fs->chmod( $path, $chmod );
+ }
+
+ public function is_writable( string $path ): bool {
+ return $this->fs->is_writable( $path );
+ }
}
diff --git a/src/php/flat-files/classes/class-snippet-files.php b/src/php/flat-files/classes/class-snippet-files.php
index 18a68176..41f7b280 100644
--- a/src/php/flat-files/classes/class-snippet-files.php
+++ b/src/php/flat-files/classes/class-snippet-files.php
@@ -20,7 +20,11 @@ public function __construct(
$this->config_repo = $config_repo;
}
- public function register_hooks() {
+ public function register_hooks(): void {
+ if ( ! $this->fs->is_writable( WP_CONTENT_DIR ) ) {
+ return;
+ }
+
if ( Settings\get_setting( 'general', 'enable_flat_files' ) ) {
add_action( 'code_snippets/create_snippet', [ $this, 'handle_snippet' ], 10, 2 );
add_action( 'code_snippets/update_snippet', [ $this, 'handle_snippet' ], 10, 2 );
@@ -35,7 +39,7 @@ public function register_hooks() {
add_action( 'code_snippets/settings_updated', [ $this, 'create_all_flat_files' ], 10, 2 );
}
- public function handle_snippet( Snippet $snippet, string $table ) {
+ public function handle_snippet( Snippet $snippet, string $table ): void {
$snippet_type = $snippet->get_type();
$handler = $this->handler_registry->get_handler( $snippet_type );
@@ -55,7 +59,7 @@ public function handle_snippet( Snippet $snippet, string $table ) {
$this->config_repo->update( $base_dir, $snippet );
}
- public function delete_snippet( Snippet $snippet, bool $network ) {
+ public function delete_snippet( Snippet $snippet, bool $network ): void {
$snippet_type = $snippet->get_type();
$handler = $this->handler_registry->get_handler( $snippet_type );
@@ -72,7 +76,7 @@ public function delete_snippet( Snippet $snippet, bool $network ) {
$this->config_repo->update( $base_dir, $snippet, true );
}
- public function activate_snippet( Snippet $snippet, bool $network ) {
+ public function activate_snippet( Snippet $snippet, bool $network ): void {
$snippet = get_snippet( $snippet->id, $network );
$snippet_type = $snippet->get_type();
$handler = $this->handler_registry->get_handler( $snippet_type );
@@ -95,7 +99,7 @@ public function activate_snippet( Snippet $snippet, bool $network ) {
$this->config_repo->update( $base_dir, $snippet );
}
- public function deactivate_snippet( int $snippet_id, bool $network ) {
+ public function deactivate_snippet( int $snippet_id, bool $network ): void {
$snippet = get_snippet( $snippet_id, $network );
$snippet_type = $snippet->get_type();
$handler = $this->handler_registry->get_handler( $snippet_type );
@@ -110,7 +114,7 @@ public function deactivate_snippet( int $snippet_id, bool $network ) {
$this->config_repo->update( $base_dir, $snippet );
}
- public static function get_base_dir( string $table = '', string $snippet_type = '' ) {
+ public static function get_base_dir( string $table = '', string $snippet_type = '' ): string {
$base_dir = WP_CONTENT_DIR . '/code-snippets';
if ( ! empty( $table ) ) {
@@ -124,23 +128,27 @@ public static function get_base_dir( string $table = '', string $snippet_type =
return $base_dir;
}
- private function maybe_create_directory( string $dir ) {
+ private function maybe_create_directory( string $dir ): void {
if ( ! $this->fs->is_dir( $dir ) ) {
- $this->fs->mkdir( $dir, FS_CHMOD_DIR );
+ $result = wp_mkdir_p( $dir );
+
+ if ( $result ) {
+ $this->fs->chmod( $dir, FS_CHMOD_DIR );
+ }
}
}
- private function get_snippet_file_path( string $base_dir, int $snippet_id, string $ext ) {
+ private function get_snippet_file_path( string $base_dir, int $snippet_id, string $ext ): string {
return trailingslashit( $base_dir ) . $snippet_id . '.' . $ext;
}
- private function delete_file( string $file_path ) {
+ private function delete_file( string $file_path ): void {
if ( $this->fs->exists( $file_path ) ) {
$this->fs->delete( $file_path );
}
}
- public function sync_active_shared_network_snippets( $option, $old_value, $value ) {
+ public function sync_active_shared_network_snippets( $option, $old_value, $value ): void {
if ( 'active_shared_network_snippets' !== $option ) {
return;
}
@@ -156,7 +164,7 @@ public function sync_active_shared_network_snippets( $option, $old_value, $value
$this->fs->put_contents( $file_path, $file_content, FS_CHMOD_FILE );
}
- public static function get_active_snippets_from_flat_files() {
+ public static function get_active_snippets_from_flat_files( array $scopes = [] ): array {
$snippets = [];
$table = code_snippets()->db->get_table_name();
@@ -168,8 +176,8 @@ public static function get_active_snippets_from_flat_files() {
$snippets[ $table ] = array_filter(
$site_snippets,
- function ( $snippet ) {
- return $snippet['active'];
+ function ( $snippet ) use ( $scopes ) {
+ return $snippet['active'] && in_array( $snippet['scope'], $scopes, true );
}
);
}
@@ -188,8 +196,8 @@ function ( $snippet ) {
$snippets[ $ms_table ] = array_filter(
$ms_snippets,
- function ( $snippet ) use ( $active_shared_ids ) {
- return $snippet['active'] || in_array( intval( $snippet['id'] ), $active_shared_ids, true );
+ function ( $snippet ) use ( $active_shared_ids, $scopes ) {
+ return ( $snippet['active'] || in_array( intval( $snippet['id'] ), $active_shared_ids, true ) ) && in_array( $snippet['scope'], $scopes, true );
}
);
}
@@ -198,7 +206,7 @@ function ( $snippet ) use ( $active_shared_ids ) {
return $snippets;
}
- public function add_settings_fields( array $fields ) {
+ public function add_settings_fields( array $fields ): array {
$fields['general']['enable_flat_files'] = [
'name' => __( 'Enable Flat Files', 'code-snippets' ),
'type' => 'checkbox',
@@ -208,7 +216,7 @@ public function add_settings_fields( array $fields ) {
return $fields;
}
- public function create_all_flat_files( array $settings, array $input ) {
+ public function create_all_flat_files( array $settings, array $input ): void {
if ( ! isset( $settings['general']['enable_flat_files'] ) ) {
return;
}
diff --git a/src/php/flat-files/interfaces/interface-file-system.php b/src/php/flat-files/interfaces/interface-file-system.php
index 7560d7bb..71b0efe2 100644
--- a/src/php/flat-files/interfaces/interface-file-system.php
+++ b/src/php/flat-files/interfaces/interface-file-system.php
@@ -9,4 +9,6 @@ public function delete( string $path ): bool;
public function is_dir( string $path ): bool;
public function mkdir( string $path, $chmod );
public function rmdir( string $path, bool $recursive = false ): bool;
+ public function chmod( string $path, $chmod ): bool;
+ public function is_writable( string $path ): bool;
}
diff --git a/src/php/snippet-ops.php b/src/php/snippet-ops.php
index 8fc90ff2..9cf86b91 100644
--- a/src/php/snippet-ops.php
+++ b/src/php/snippet-ops.php
@@ -686,7 +686,7 @@ function execute_active_snippets_from_flat_files(): bool {
$db = code_snippets()->db;
$scopes = [ 'global', 'single-use', is_admin() ? 'admin' : 'front-end' ];
- $data = Snippet_Files::get_active_snippets_from_flat_files();
+ $data = Snippet_Files::get_active_snippets_from_flat_files( $scopes );
// Detect if a snippet is currently being edited, and if so, spare it from execution.
$edit_id = 0;
@@ -713,9 +713,6 @@ function execute_active_snippets_from_flat_files(): bool {
// Loop through the returned snippets and execute the PHP code.
foreach ( $active_snippets as $snippet ) {
- if ( ! in_array( $snippet['scope'], $scopes, true ) ) {
- continue;
- }
$snippet_id = intval( $snippet['id'] );
From 19708267fe80d473b9bed8a51e860bc55c1dc534 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Mon, 7 Jul 2025 22:15:22 +0200
Subject: [PATCH 039/106] wip
---
.../flat-files/classes/class-snippet-files.php | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/src/php/flat-files/classes/class-snippet-files.php b/src/php/flat-files/classes/class-snippet-files.php
index 41f7b280..0f98fa57 100644
--- a/src/php/flat-files/classes/class-snippet-files.php
+++ b/src/php/flat-files/classes/class-snippet-files.php
@@ -153,6 +153,10 @@ public function sync_active_shared_network_snippets( $option, $old_value, $value
return;
}
+ $this->create_active_shared_network_snippets_file( $value );
+ }
+
+ private function create_active_shared_network_snippets_file( $value ): void {
$table = code_snippets()->db->get_table_name();
$base_dir = self::get_base_dir( $table );
@@ -225,6 +229,11 @@ public function create_all_flat_files( array $settings, array $input ): void {
return;
}
+ $this->create_snippet_flat_files();
+ $this->create_active_shared_network_snippets_config_file();
+ }
+
+ private function create_snippet_flat_files(): void {
$db = code_snippets()->db;
$data = $db->fetch_active_snippets( Snippet::get_all_scopes() );
@@ -239,4 +248,11 @@ public function create_all_flat_files( array $settings, array $input ): void {
}
}
}
+
+ private function create_active_shared_network_snippets_config_file(): void {
+ $active_shared_network_snippets = get_option( 'active_shared_network_snippets' );
+ if ( false !== $active_shared_network_snippets ) {
+ $this->create_active_shared_network_snippets_file( $active_shared_network_snippets );
+ }
+ }
}
From 4cd5ee80783841433c9dc2c1b2a942b546c821ef Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Mon, 7 Jul 2025 22:24:41 +0200
Subject: [PATCH 040/106] wip
---
src/php/snippet-ops.php | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/php/snippet-ops.php b/src/php/snippet-ops.php
index 9cf86b91..9bdb7741 100644
--- a/src/php/snippet-ops.php
+++ b/src/php/snippet-ops.php
@@ -713,8 +713,8 @@ function execute_active_snippets_from_flat_files(): bool {
// Loop through the returned snippets and execute the PHP code.
foreach ( $active_snippets as $snippet ) {
-
$snippet_id = intval( $snippet['id'] );
+ $code = $snippet['code'];
// If the snippet is a single-use snippet, deactivate it before execution to ensure that the process always happens.
if ( 'single-use' === $snippet['scope'] ) {
@@ -743,7 +743,7 @@ function execute_active_snippets_from_flat_files(): bool {
if ( apply_filters( 'code_snippets/allow_execute_snippet', true, $snippet_id, $table_name ) &&
! ( $edit_id === $snippet_id && $table_name === $edit_table ) ) {
$file = $base_dir . '/' . $snippet_id . '.php';
- execute_snippet_from_flat_file( $file, $snippet_id );
+ execute_snippet_from_flat_file( $code, $file, $snippet_id );
}
}
}
@@ -759,8 +759,12 @@ function cs_sort_snippets_by_priority( array $snippets ): array {
return $snippets;
}
-function execute_snippet_from_flat_file( $file, int $id = 0, bool $force = false ) {
- if ( ! is_file( $file ) || ( ! $force && defined( 'CODE_SNIPPETS_SAFE_MODE' ) && CODE_SNIPPETS_SAFE_MODE ) ) {
+function execute_snippet_from_flat_file( $code, $file, int $id = 0, bool $force = false ) {
+ if ( ! is_file( $file ) ) {
+ execute_snippet( $code, $id, $force );
+ }
+
+ if ( ! $force && defined( 'CODE_SNIPPETS_SAFE_MODE' ) && CODE_SNIPPETS_SAFE_MODE ) {
return false;
}
From 4d84a24d1dad3ab9d40b62f71b3073ebf9a6be00 Mon Sep 17 00:00:00 2001
From: Louis Wolmarans
Date: Thu, 24 Jul 2025 22:11:39 +0200
Subject: [PATCH 041/106] sync all changes from pro
---
src/php/class-active-snippets.php | 35 ++-
src/php/class-plugin.php | 13 +-
.../classes/class-config-repository.php | 12 +-
.../classes/class-file-system-adapter.php | 4 +-
.../classes/class-snippet-files.php | 212 ++++++++++++++----
.../handlers/php-snippet-handler.php | 18 +-
src/php/flat-files/load.php | 2 +-
src/php/front-end/class-front-end.php | 10 +-
src/php/snippet-ops.php | 15 +-
src/php/uninstall.php | 12 +-
10 files changed, 255 insertions(+), 78 deletions(-)
diff --git a/src/php/class-active-snippets.php b/src/php/class-active-snippets.php
index 7c1de751..b04f04b3 100644
--- a/src/php/class-active-snippets.php
+++ b/src/php/class-active-snippets.php
@@ -26,8 +26,15 @@ public function __construct() {
* Initialise class functions.
*/
public function init() {
- add_action( 'wp_head', [ $this, 'load_head_content' ] );
- add_action( 'wp_footer', [ $this, 'load_footer_content' ] );
+ $should_use_flat_files = Settings\get_setting( 'general', 'enable_flat_files' );
+
+ if ( ! $should_use_flat_files ) {
+ add_action( 'wp_head', [ $this, 'load_head_content' ] );
+ add_action( 'wp_footer', [ $this, 'load_footer_content' ] );
+ } else {
+ add_action( 'wp_head', [ $this, 'load_head_content_from_flat_files' ] );
+ add_action( 'wp_footer', [ $this, 'load_footer_content_from_flat_files' ] );
+ }
}
/**
@@ -78,4 +85,28 @@ public function load_head_content() {
public function load_footer_content() {
$this->print_content_snippets( 'footer-content' );
}
+
+ public function load_head_content_from_flat_files() {
+ $this->load_content_snippets_from_flat_files( 'head-content' );
+ }
+
+ public function load_footer_content_from_flat_files() {
+ $this->load_content_snippets_from_flat_files( 'footer-content' );
+ }
+
+ private function load_content_snippets_from_flat_files( string $scope ) {
+ $handler = code_snippets()->snippet_handler_registry->get_handler( 'html' );
+ $dir_name = $handler->get_dir_name();
+ $ext = $handler->get_file_extension();
+ $snippets = Snippet_Files::get_active_snippets_from_flat_files( [ $scope ], $dir_name );
+
+ foreach ( $snippets as $table_name => $active_snippets ) {
+ $active_snippets = cs_sort_snippets_by_priority( $active_snippets );
+ $base_path = Snippet_Files::get_base_dir( $table_name, $dir_name );
+
+ foreach ( $active_snippets as $snippet ) {
+ require_once $base_path . '/' . $snippet['id'] . '.' . $ext;
+ }
+ }
+ }
}
diff --git a/src/php/class-plugin.php b/src/php/class-plugin.php
index bb21473a..f6f2d8f8 100644
--- a/src/php/class-plugin.php
+++ b/src/php/class-plugin.php
@@ -68,6 +68,13 @@ class Plugin {
*/
public Licensing $licensing;
+ /**
+ * Handles snippet handler registration.
+ *
+ * @var Snippet_Handler_Registry
+ */
+ public Snippet_Handler_Registry $snippet_handler_registry;
+
/**
* Class constructor
*
@@ -122,7 +129,7 @@ public function load_plugin() {
// Snippet files.
require_once $includes_path . '/flat-files/load.php';
- $registry = new Snippet_Handler_Registry( [
+ $this->snippet_handler_registry = new Snippet_Handler_Registry( [
'php' => new Php_Snippet_Handler(),
'html' => new Html_Snippet_Handler(),
] );
@@ -131,10 +138,10 @@ public function load_plugin() {
$config_repo = new Snippet_Config_Repository( $fs );
- ( new Snippet_Files( $registry, $fs, $config_repo ) )->register_hooks();
+ ( new Snippet_Files( $this->snippet_handler_registry, $fs, $config_repo ) )->register_hooks();
$this->active_snippets = new Active_Snippets();
- $this->front_end = new Front_End( $registry );
+ $this->front_end = new Front_End();
$this->cloud_api = new Cloud_API();
$upgrade = new Upgrade( $this->version, $this->db );
diff --git a/src/php/flat-files/classes/class-config-repository.php b/src/php/flat-files/classes/class-config-repository.php
index 2087f572..74c0388f 100644
--- a/src/php/flat-files/classes/class-config-repository.php
+++ b/src/php/flat-files/classes/class-config-repository.php
@@ -14,14 +14,20 @@ public function __construct( File_System_Interface $fs ) {
public function load( string $base_dir ): array {
$config_file_path = trailingslashit( $base_dir ) . static::CONFIG_FILE_NAME;
- return is_file( $config_file_path )
- ? require $config_file_path
- : [];
+ if ( is_file( $config_file_path ) ) {
+ if ( function_exists( 'opcache_invalidate' ) ) {
+ opcache_invalidate( $config_file_path, true );
+ }
+ return require $config_file_path;
+ }
+ return [];
}
public function save( string $base_dir, array $active_snippets ): void {
$config_file_path = trailingslashit( $base_dir ) . static::CONFIG_FILE_NAME;
+ ksort( $active_snippets );
+
$file_content = "fs->exists( $path );
}
- public function delete( string $path ): bool {
- return $this->fs->delete( $path );
+ public function delete( $file, $recursive = false, $type = false ): bool {
+ return $this->fs->delete( $file, $recursive, $type );
}
public function is_dir( string $path ): bool {
diff --git a/src/php/flat-files/classes/class-snippet-files.php b/src/php/flat-files/classes/class-snippet-files.php
index 0f98fa57..284c1677 100644
--- a/src/php/flat-files/classes/class-snippet-files.php
+++ b/src/php/flat-files/classes/class-snippet-files.php
@@ -31,15 +31,28 @@ public function register_hooks(): void {
add_action( 'code_snippets/delete_snippet', [ $this, 'delete_snippet' ], 10, 2 );
add_action( 'code_snippets/activate_snippet', [ $this, 'activate_snippet' ], 10, 2 );
add_action( 'code_snippets/deactivate_snippet', [ $this, 'deactivate_snippet' ], 10, 2 );
+ add_action( 'code_snippets/activate_snippets', [ $this, 'activate_snippets' ], 10, 2 );
add_action( 'updated_option', [ $this, 'sync_active_shared_network_snippets' ], 10, 3 );
+ add_action( 'add_option', [ $this, 'sync_active_shared_network_snippets_add' ], 10, 2 );
}
add_filter( 'code_snippets_settings_fields', [ $this, 'add_settings_fields' ], 10, 1 );
add_action( 'code_snippets/settings_updated', [ $this, 'create_all_flat_files' ], 10, 2 );
}
+ public function activate_snippets( $valid_snippets, $table ): void {
+ foreach ( $valid_snippets as $snippet ) {
+ $snippet->active = true;
+ $this->handle_snippet( $snippet, $table );
+ }
+ }
+
public function handle_snippet( Snippet $snippet, string $table ): void {
+ if ( 0 === $snippet->id ) {
+ return;
+ }
+
$snippet_type = $snippet->get_type();
$handler = $this->handler_registry->get_handler( $snippet_type );
@@ -47,6 +60,7 @@ public function handle_snippet( Snippet $snippet, string $table ): void {
return;
}
+ $table = self::get_hashed_table_name( $table );
$base_dir = self::get_base_dir( $table, $handler->get_dir_name() );
$this->maybe_create_directory( $base_dir );
@@ -67,7 +81,7 @@ public function delete_snippet( Snippet $snippet, bool $network ): void {
return;
}
- $table = code_snippets()->db->get_table_name( $network );
+ $table = self::get_hashed_table_name( code_snippets()->db->get_table_name( $network ) );
$base_dir = self::get_base_dir( $table, $handler->get_dir_name() );
$file_path = $this->get_snippet_file_path( $base_dir, $snippet->id, $handler->get_file_extension() );
@@ -85,7 +99,7 @@ public function activate_snippet( Snippet $snippet, bool $network ): void {
return;
}
- $table = code_snippets()->db->get_table_name( $network );
+ $table = self::get_hashed_table_name( code_snippets()->db->get_table_name( $network ) );
$base_dir = self::get_base_dir( $table, $handler->get_dir_name() );
$this->maybe_create_directory( $base_dir );
@@ -108,7 +122,7 @@ public function deactivate_snippet( int $snippet_id, bool $network ): void {
return;
}
- $table = code_snippets()->db->get_table_name( $network );
+ $table = self::get_hashed_table_name( code_snippets()->db->get_table_name( $network ) );
$base_dir = self::get_base_dir( $table, $handler->get_dir_name() );
$this->config_repo->update( $base_dir, $snippet );
@@ -128,6 +142,20 @@ public static function get_base_dir( string $table = '', string $snippet_type =
return $base_dir;
}
+ public static function get_base_url( string $table = '', string $snippet_type = '' ): string {
+ $base_url = WP_CONTENT_URL . '/code-snippets';
+
+ if ( ! empty( $table ) ) {
+ $base_url .= '/' . $table;
+ }
+
+ if ( ! empty( $snippet_type ) ) {
+ $base_url .= '/' . $snippet_type;
+ }
+
+ return $base_url;
+ }
+
private function maybe_create_directory( string $dir ): void {
if ( ! $this->fs->is_dir( $dir ) ) {
$result = wp_mkdir_p( $dir );
@@ -156,8 +184,16 @@ public function sync_active_shared_network_snippets( $option, $old_value, $value
$this->create_active_shared_network_snippets_file( $value );
}
+ public function sync_active_shared_network_snippets_add( $option, $value ): void {
+ if ( 'active_shared_network_snippets' !== $option ) {
+ return;
+ }
+
+ $this->create_active_shared_network_snippets_file( $value );
+ }
+
private function create_active_shared_network_snippets_file( $value ): void {
- $table = code_snippets()->db->get_table_name();
+ $table = self::get_hashed_table_name( code_snippets()->db->get_table_name( false ) );
$base_dir = self::get_base_dir( $table );
$this->maybe_create_directory( $base_dir );
@@ -168,53 +204,104 @@ private function create_active_shared_network_snippets_file( $value ): void {
$this->fs->put_contents( $file_path, $file_content, FS_CHMOD_FILE );
}
- public static function get_active_snippets_from_flat_files( array $scopes = [] ): array {
+ public static function get_hashed_table_name( string $table ): string {
+ return wp_hash( $table );
+ }
+
+ public static function get_active_snippets_from_flat_files(
+ array $scopes = [],
+ $snippet_type = 'php'
+ ): array {
$snippets = [];
- $table = code_snippets()->db->get_table_name();
- $base_dir = self::get_base_dir( $table, 'php' );
+ $table = self::get_hashed_table_name( code_snippets()->db->get_table_name() );
+ $snippets[ $table ] = self::load_active_snippets_from_file(
+ $table,
+ $snippet_type,
+ $scopes
+ );
+
+ if ( is_multisite() ) {
+ $ms_table = self::get_hashed_table_name( code_snippets()->db->get_table_name( true ) );
+
+ $root_base_dir = self::get_base_dir( $table );
+ $active_shared_ids_file_path = $root_base_dir . '/active-shared-network-snippets.php';
+ $active_shared_ids = is_file( $active_shared_ids_file_path )
+ ? require $active_shared_ids_file_path
+ : [];
+
+ $snippets[ $ms_table ] = self::load_active_snippets_from_file(
+ $ms_table,
+ $snippet_type,
+ $scopes,
+ $active_shared_ids
+ );
+ }
+
+ return $snippets;
+ }
+
+ private static function load_active_snippets_from_file(
+ string $table,
+ string $snippet_type,
+ array $scopes,
+ ?array $active_shared_ids = null
+ ): array {
+ $snippets = [];
+ $db = code_snippets()->db;
+
+ $base_dir = self::get_base_dir( $table, $snippet_type );
$snippets_file_path = $base_dir . '/index.php';
- if ( is_file( $snippets_file_path ) ) {
- $site_snippets = is_file( $snippets_file_path ) ? require $snippets_file_path : [];
+ if ( ! is_file( $snippets_file_path ) ) {
+ return $snippets;
+ }
- $snippets[ $table ] = array_filter(
- $site_snippets,
- function ( $snippet ) use ( $scopes ) {
- return $snippet['active'] && in_array( $snippet['scope'], $scopes, true );
- }
- );
+ $cache_key = sprintf(
+ 'active_snippets_%s_%s',
+ sanitize_key( join( '_', $scopes ) ),
+ self::get_hashed_table_name( $db->table ) === $table ? $db->table : $db->ms_table
+ );
+
+ $cached_snippets = wp_cache_get( $cache_key, CACHE_GROUP );
+
+ if ( is_array( $cached_snippets ) ) {
+ return $cached_snippets;
}
- if ( is_multisite() ) {
- $ms_table = code_snippets()->db->get_table_name( true );
- $ms_base_dir = self::get_base_dir( $ms_table, 'php' );
- $ms_snippets_file_path = $ms_base_dir . '/index.php';
+ $file_snippets = require $snippets_file_path;
- if ( is_file( $ms_snippets_file_path ) ) {
- $ms_snippets = is_file( $ms_snippets_file_path ) ? require $ms_snippets_file_path : [];
+ $filtered_snippets = array_filter(
+ $file_snippets,
+ function ( $snippet ) use ( $scopes, $active_shared_ids ) {
+ $is_active = $snippet['active'];
- $root_base_dir = self::get_base_dir( $table );
- $active_shared_ids_file_path = $root_base_dir . '/active-shared-network-snippets.php';
- $active_shared_ids = is_file( $active_shared_ids_file_path ) ? require $active_shared_ids_file_path : [];
+ if ( null !== $active_shared_ids ) {
+ $is_active = $is_active || in_array(
+ intval( $snippet['id'] ),
+ $active_shared_ids,
+ true
+ );
+ }
- $snippets[ $ms_table ] = array_filter(
- $ms_snippets,
- function ( $snippet ) use ( $active_shared_ids, $scopes ) {
- return ( $snippet['active'] || in_array( intval( $snippet['id'] ), $active_shared_ids, true ) ) && in_array( $snippet['scope'], $scopes, true );
- }
- );
+ return $is_active && in_array( $snippet['scope'], $scopes, true );
}
- }
+ );
- return $snippets;
+ wp_cache_set( $cache_key, $filtered_snippets, CACHE_GROUP );
+
+ return $filtered_snippets;
}
public function add_settings_fields( array $fields ): array {
$fields['general']['enable_flat_files'] = [
- 'name' => __( 'Enable Flat Files', 'code-snippets' ),
+ 'name' => __( 'Enable file-based execution', 'code-snippets' ),
'type' => 'checkbox',
- 'label' => __( 'Snippets will be executed from flat files instead of the database.', 'code-snippets' ),
+ 'label' => __( 'Snippets will be executed directly from files instead of the database.', 'code-snippets' ) . ' ' . sprintf(
+ '%s',
+ esc_url( 'https://codesnippets.pro/doc/file-based-execution/' ),
+ __( 'Learn more.', 'code-snippets' )
+ ),
];
return $fields;
@@ -235,24 +322,65 @@ public function create_all_flat_files( array $settings, array $input ): void {
private function create_snippet_flat_files(): void {
$db = code_snippets()->db;
- $data = $db->fetch_active_snippets( Snippet::get_all_scopes() );
- if ( empty( $data ) ) {
- return;
- }
+ $scopes = Snippet::get_all_scopes();
+
+ $data = $db->fetch_active_snippets( $scopes );
foreach ( $data as $table_name => $active_snippets ) {
foreach ( $active_snippets as $snippet ) {
- $snippet_obj = get_snippet( $snippet['id'], $table_name === $db->ms_table );
+ $snippet_obj = get_snippet( $snippet['id'], $db->ms_table === $table_name );
$this->handle_snippet( $snippet_obj, $table_name );
}
}
+
+ if ( is_multisite() ) {
+ $current_blog_id = get_current_blog_id();
+
+ $sites = get_sites( [ 'fields' => 'ids' ] );
+ foreach ( $sites as $site_id ) {
+ switch_to_blog( $site_id );
+ $db->set_table_vars();
+
+ $site_data = $db->fetch_active_snippets( $scopes );
+ foreach ( $site_data as $table_name => $active_snippets ) {
+ foreach ( $active_snippets as $snippet ) {
+ $snippet_obj = get_snippet( $snippet['id'], false );
+ $this->handle_snippet( $snippet_obj, $table_name );
+ }
+ }
+
+ restore_current_blog();
+ }
+
+ $db->set_table_vars();
+ }
}
private function create_active_shared_network_snippets_config_file(): void {
- $active_shared_network_snippets = get_option( 'active_shared_network_snippets' );
- if ( false !== $active_shared_network_snippets ) {
- $this->create_active_shared_network_snippets_file( $active_shared_network_snippets );
+ if ( is_multisite() ) {
+ $current_blog_id = get_current_blog_id();
+ $sites = get_sites( [ 'fields' => 'ids' ] );
+ $db = code_snippets()->db;
+
+ foreach ( $sites as $site_id ) {
+ switch_to_blog( $site_id );
+ $db->set_table_vars();
+
+ $active_shared_network_snippets = get_option( 'active_shared_network_snippets' );
+ if ( false !== $active_shared_network_snippets ) {
+ $this->create_active_shared_network_snippets_file( $active_shared_network_snippets );
+ }
+
+ restore_current_blog();
+ }
+
+ $db->set_table_vars();
+ } else {
+ $active_shared_network_snippets = get_option( 'active_shared_network_snippets' );
+ if ( false !== $active_shared_network_snippets ) {
+ $this->create_active_shared_network_snippets_file( $active_shared_network_snippets );
+ }
}
}
}
diff --git a/src/php/flat-files/handlers/php-snippet-handler.php b/src/php/flat-files/handlers/php-snippet-handler.php
index 666617b0..5d306392 100644
--- a/src/php/flat-files/handlers/php-snippet-handler.php
+++ b/src/php/flat-files/handlers/php-snippet-handler.php
@@ -3,15 +3,15 @@
namespace Code_Snippets;
class Php_Snippet_Handler implements Snippet_Type_Handler_Interface {
- public function get_file_extension(): string {
- return 'php';
- }
+ public function get_file_extension(): string {
+ return 'php';
+ }
- public function get_dir_name(): string {
- return 'php';
- }
+ public function get_dir_name(): string {
+ return 'php';
+ }
- public function wrap_code( string $code ): string {
- return "handler_registry = $handler_registry;
-
+ public function __construct() {
add_action( 'the_posts', [ $this, 'enqueue_highlighting' ] );
add_action( 'init', [ $this, 'setup_mce_plugin' ] );
@@ -245,9 +241,9 @@ protected function convert_boolean_attribute_flags( array $atts, array $boolean_
* @return string Full file path for the snippet.
*/
private function build_snippet_flat_file_path( string $table_name, Snippet $snippet ): string {
- $handler = $this->handler_registry->get_handler( $snippet->get_type() );
+ $handler = code_snippets()->snippet_handler_registry->get_handler( $snippet->get_type() );
- return WP_CONTENT_DIR . '/code-snippets/' . $table_name . '/' . $handler->get_dir_name() . '/' . $snippet->id . '.' . $handler->get_file_extension();
+ return Snippet_Files::get_base_dir( $table_name, $handler->get_dir_name() ) . '/' . $snippet->id . '.' . $handler->get_file_extension();
}
/**
diff --git a/src/php/snippet-ops.php b/src/php/snippet-ops.php
index 9bdb7741..f3789915 100644
--- a/src/php/snippet-ops.php
+++ b/src/php/snippet-ops.php
@@ -690,7 +690,7 @@ function execute_active_snippets_from_flat_files(): bool {
// Detect if a snippet is currently being edited, and if so, spare it from execution.
$edit_id = 0;
- $edit_table = $db->table;
+ $edit_table = Snippet_Files::get_hashed_table_name( $db->table );
if ( wp_is_json_request() && ! empty( $_SERVER['REQUEST_URI'] ) ) {
$url = wp_parse_url( esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
@@ -702,7 +702,7 @@ function execute_active_snippets_from_flat_files(): bool {
if ( ! empty( $url['query'] ) ) {
wp_parse_str( $url['query'], $path_params );
$edit_table = isset( $path_params['network'] ) && rest_sanitize_boolean( $path_params['network'] ) ?
- $db->ms_table : $db->table;
+ Snippet_Files::get_hashed_table_name( $db->ms_table ) : Snippet_Files::get_hashed_table_name( $db->table );
}
}
}
@@ -718,24 +718,25 @@ function execute_active_snippets_from_flat_files(): bool {
// If the snippet is a single-use snippet, deactivate it before execution to ensure that the process always happens.
if ( 'single-use' === $snippet['scope'] ) {
+ $table_to_update = Snippet_Files::get_hashed_table_name( $db->table ) === $table_name ? $db->table : $db->ms_table;
$active_shared_ids = get_option( 'active_shared_network_snippets', array() );
- if ( $table_name === $db->ms_table && is_array( $active_shared_ids ) && in_array( $snippet_id, $active_shared_ids, true ) ) {
+ if ( Snippet_Files::get_hashed_table_name( $db->ms_table ) === $table_name && is_array( $active_shared_ids ) && in_array( $snippet_id, $active_shared_ids, true ) ) {
unset( $active_shared_ids[ array_search( $snippet_id, $active_shared_ids, true ) ] );
$active_shared_ids = array_values( $active_shared_ids );
update_option( 'active_shared_network_snippets', $active_shared_ids );
- clean_active_snippets_cache( $table_name );
+ clean_active_snippets_cache( $table_to_update );
} else {
$wpdb->update(
- $table_name,
+ $table_to_update,
array( 'active' => '0' ),
array( 'id' => $snippet_id ),
array( '%d' ),
array( '%d' )
);
- clean_snippets_cache( $table_name );
+ clean_snippets_cache( $table_to_update );
- $network = $table_name === $db->ms_table;
+ $network = Snippet_Files::get_hashed_table_name( $db->ms_table ) === $table_name;
do_action( 'code_snippets/deactivate_snippet', $snippet_id, $network );
}
}
diff --git a/src/php/uninstall.php b/src/php/uninstall.php
index 028aca5c..5afaefb6 100644
--- a/src/php/uninstall.php
+++ b/src/php/uninstall.php
@@ -79,8 +79,16 @@ function delete_flat_files_directory() {
return;
}
- $fs = new \Code_Snippets\WordPress_Filesystem_Adapter();
- $fs->rmdir( $flat_files_dir, true );
+ if ( ! function_exists( 'request_filesystem_credentials' ) ) {
+ require_once ABSPATH . 'wp-admin/includes/file.php';
+ }
+
+ global $wp_filesystem;
+ WP_Filesystem();
+
+ if ( $wp_filesystem && $wp_filesystem->is_dir( $flat_files_dir ) ) {
+ $wp_filesystem->delete( $flat_files_dir, true );
+ }
}
/**
From d263c52dbe05c89bf3974bf409e7303a48156ce6 Mon Sep 17 00:00:00 2001
From: Imants
Date: Fri, 22 Aug 2025 11:54:22 +0300
Subject: [PATCH 042/106] feat: Add version switch settings file to plugin
initialization
---
src/php/class-plugin.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/php/class-plugin.php b/src/php/class-plugin.php
index 92bebfa3..d1d63e5f 100644
--- a/src/php/class-plugin.php
+++ b/src/php/class-plugin.php
@@ -114,6 +114,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/version-switch.php';
require_once $includes_path . '/settings/settings.php';
// Cloud List Table shared functions.
From 2dce9399fbd8635246d7b9aa157bf1b49638ef9b Mon Sep 17 00:00:00 2001
From: Imants
Date: Fri, 22 Aug 2025 11:54:54 +0300
Subject: [PATCH 043/106] feat: add render callback
---
src/php/settings/class-setting-field.php | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/php/settings/class-setting-field.php b/src/php/settings/class-setting-field.php
index e8d64dcd..e9887456 100644
--- a/src/php/settings/class-setting-field.php
+++ b/src/php/settings/class-setting-field.php
@@ -117,7 +117,11 @@ public function render() {
* Render a callback field.
*/
public function render_callback_field() {
- call_user_func( $this->render_callback );
+ if ( ! is_callable( $this->render_callback ) ) {
+ return;
+ }
+
+ call_user_func( $this->render_callback, $this->args );
}
/**
From cb278531471f9834a4924b556954f3b7585fb658 Mon Sep 17 00:00:00 2001
From: Imants
Date: Fri, 22 Aug 2025 11:55:07 +0300
Subject: [PATCH 044/106] feat: add version switch settings
---
src/php/settings/settings-fields.php | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/src/php/settings/settings-fields.php b/src/php/settings/settings-fields.php
index 593635b3..864e661f 100644
--- a/src/php/settings/settings-fields.php
+++ b/src/php/settings/settings-fields.php
@@ -46,6 +46,9 @@ function get_default_settings(): array {
'keymap' => 'default',
'theme' => 'default',
],
+ 'version-switch' => [
+ 'selected_version' => '',
+ ],
];
$defaults = apply_filters( 'code_snippets_settings_defaults', $defaults );
@@ -81,6 +84,19 @@ function get_settings_fields(): array {
],
];
+ $fields['version-switch'] = [
+ 'version_switcher' => [
+ 'name' => __( 'Switch Version', 'code-snippets' ),
+ 'type' => 'callback',
+ 'render_callback' => 'Code_Snippets\Settings\VersionSwitch\render_version_switch_field',
+ ],
+ 'refresh_versions' => [
+ 'name' => __( 'Refresh Versions', 'code-snippets' ),
+ 'type' => 'callback',
+ 'render_callback' => 'Code_Snippets\Settings\VersionSwitch\render_refresh_versions_field',
+ ],
+ ];
+
$fields['general'] = [
'activate_by_default' => [
'name' => __( 'Activate by Default', 'code-snippets' ),
From cc8faf977af7983b30e22903a6c7fb24cae09f2e Mon Sep 17 00:00:00 2001
From: Imants
Date: Fri, 22 Aug 2025 11:55:14 +0300
Subject: [PATCH 045/106] feat: add version switch section to settings
---
src/php/settings/settings.php | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/php/settings/settings.php b/src/php/settings/settings.php
index cf94f8b9..3d54b960 100644
--- a/src/php/settings/settings.php
+++ b/src/php/settings/settings.php
@@ -136,9 +136,10 @@ function update_setting( string $section, string $field, $new_value ): bool {
*/
function get_settings_sections(): array {
$sections = array(
- 'general' => __( 'General', 'code-snippets' ),
- 'editor' => __( 'Code Editor', 'code-snippets' ),
- 'debug' => __( 'Debug', 'code-snippets' ),
+ 'general' => __( 'General', 'code-snippets' ),
+ 'editor' => __( 'Code Editor', 'code-snippets' ),
+ 'debug' => __( 'Debug', 'code-snippets' ),
+ 'version-switch' => __( 'Version', 'code-snippets' ),
);
return apply_filters( 'code_snippets_settings_sections', $sections );
From 690d75648689ee8f76d5844ccbffc025138cc4f1 Mon Sep 17 00:00:00 2001
From: Imants
Date: Fri, 22 Aug 2025 11:55:26 +0300
Subject: [PATCH 046/106] feat: implement version switching functionality for
the plugin
---
src/php/settings/version-switch.php | 386 ++++++++++++++++++++++++++++
1 file changed, 386 insertions(+)
create mode 100644 src/php/settings/version-switch.php
diff --git a/src/php/settings/version-switch.php b/src/php/settings/version-switch.php
new file mode 100644
index 00000000..0a4325ea
--- /dev/null
+++ b/src/php/settings/version-switch.php
@@ -0,0 +1,386 @@
+ $download_url ) {
+ if ( 'trunk' !== $version ) {
+ $versions[] = [
+ 'version' => $version,
+ 'url' => $download_url,
+ ];
+ }
+ }
+
+ // Sort versions in descending order
+ usort( $versions, function( $a, $b ) {
+ return version_compare( $b['version'], $a['version'] );
+ });
+
+ // Cache for 1 hour
+ set_transient( $transient_key, $versions, HOUR_IN_SECONDS );
+ }
+
+ return $versions;
+}
+
+/**
+ * Get current plugin version
+ *
+ * @return string Current version
+ */
+function get_current_version(): string {
+ return defined( 'CODE_SNIPPETS_VERSION' ) ? CODE_SNIPPETS_VERSION : '0.0.0';
+}
+
+/**
+ * Check if a version switch is in progress
+ *
+ * @return bool True if switch is in progress
+ */
+function is_version_switch_in_progress(): bool {
+ return get_transient( 'code_snippets_version_switch_progress' ) !== false;
+}
+
+/**
+ * Handle version switch request
+ *
+ * @param string $target_version Target version to switch to
+ * @return array Result array with success status and message
+ */
+function handle_version_switch( string $target_version ): array {
+ // Check user capabilities
+ if ( ! current_user_can( 'update_plugins' ) ) {
+ return [
+ 'success' => false,
+ 'message' => __( 'You do not have permission to update plugins.', 'code-snippets' ),
+ ];
+ }
+
+ // Validate target version
+ $available_versions = get_available_versions();
+ $version_exists = false;
+ $download_url = '';
+
+ foreach ( $available_versions as $version_info ) {
+ if ( $version_info['version'] === $target_version ) {
+ $version_exists = true;
+ $download_url = $version_info['url'];
+ break;
+ }
+ }
+
+ if ( ! $version_exists ) {
+ return [
+ 'success' => false,
+ 'message' => __( 'Invalid version specified.', 'code-snippets' ),
+ ];
+ }
+
+ // Check if already on target version
+ if ( get_current_version() === $target_version ) {
+ return [
+ 'success' => false,
+ 'message' => __( 'Already on the specified version.', 'code-snippets' ),
+ ];
+ }
+
+ // Set switch in progress
+ set_transient( 'code_snippets_version_switch_progress', $target_version, 5 * MINUTE_IN_SECONDS );
+
+ // Include WordPress upgrade functions
+ if ( ! function_exists( 'wp_update_plugins' ) ) {
+ require_once ABSPATH . 'wp-admin/includes/update.php';
+ }
+ if ( ! function_exists( 'show_message' ) ) {
+ require_once ABSPATH . 'wp-admin/includes/misc.php';
+ }
+ if ( ! class_exists( 'Plugin_Upgrader' ) ) {
+ require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
+ }
+
+ // Create upgrader instance
+ $upgrader = new \Plugin_Upgrader( new \Automatic_Upgrader_Skin() );
+
+ // Perform the upgrade/downgrade
+ $result = $upgrader->upgrade( plugin_basename( CODE_SNIPPETS_FILE ), [
+ 'clear_destination' => true,
+ 'overwrite_package' => true,
+ ] );
+
+ // Clear progress transient
+ delete_transient( 'code_snippets_version_switch_progress' );
+
+ if ( is_wp_error( $result ) ) {
+ return [
+ 'success' => false,
+ 'message' => $result->get_error_message(),
+ ];
+ }
+
+ if ( $result ) {
+ // Clear version cache
+ delete_transient( 'code_snippets_available_versions' );
+
+ return [
+ 'success' => true,
+ 'message' => sprintf(
+ __( 'Successfully switched to version %s. Please refresh the page to see changes.', 'code-snippets' ),
+ $target_version
+ ),
+ ];
+ }
+
+ return [
+ 'success' => false,
+ 'message' => __( 'Failed to switch versions. Please try again.', 'code-snippets' ),
+ ];
+}
+
+/**
+ * Render the version switch field
+ *
+ * @param array $args Field arguments
+ */
+function render_version_switch_field( array $args ): void {
+ $current_version = get_current_version();
+ $available_versions = get_available_versions();
+ $is_switching = is_version_switch_in_progress();
+
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ __( 'You do not have permission to update plugins.', 'code-snippets' ),
+ ] );
+ }
+
+ $target_version = sanitize_text_field( $_POST['target_version'] ?? '' );
+
+ if ( empty( $target_version ) ) {
+ wp_send_json_error( [
+ 'message' => __( 'No target version specified.', 'code-snippets' ),
+ ] );
+ }
+
+ $result = handle_version_switch( $target_version );
+
+ if ( $result['success'] ) {
+ wp_send_json_success( $result );
+ } else {
+ wp_send_json_error( $result );
+ }
+}
+
+// Register AJAX handler
+add_action( 'wp_ajax_code_snippets_switch_version', __NAMESPACE__ . '\\ajax_switch_version' );
+
+/**
+ * Render refresh versions cache button
+ *
+ * @param array $args Field arguments
+ */
+function render_refresh_versions_field( array $args ): void {
+ ?>
+
+
+
+
+
+
+ __( 'You do not have permission to manage options.', 'code-snippets' ),
+ ] );
+ }
+
+ // Clear the cache
+ delete_transient( 'code_snippets_available_versions' );
+
+ // Fetch fresh data
+ get_available_versions();
+
+ wp_send_json_success( [
+ 'message' => __( 'Versions cache refreshed successfully.', 'code-snippets' ),
+ ] );
+}
+
+// Register AJAX handler
+add_action( 'wp_ajax_code_snippets_refresh_versions', __NAMESPACE__ . '\\ajax_refresh_versions' );
From fcd6831edac4267d3f9eeebad2021cbf28f23c64 Mon Sep 17 00:00:00 2001
From: Imants
Date: Fri, 22 Aug 2025 11:55:32 +0300
Subject: [PATCH 047/106] feat: add version switch styles and update sections
in settings
---
src/css/settings.scss | 75 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 74 insertions(+), 1 deletion(-)
diff --git a/src/css/settings.scss b/src/css/settings.scss
index 35817074..1a5ef20b 100644
--- a/src/css/settings.scss
+++ b/src/css/settings.scss
@@ -1,6 +1,6 @@
@use 'common/editor';
-$sections: general, editor, debug;
+$sections: general, editor, debug, version-switch;
p.submit {
display: flex;
@@ -128,3 +128,76 @@ body.js {
.cloud-settings tbody tr:nth-child(n+5) {
display: none;
}
+
+// Version Switch Styles
+.code-snippets-version-switch {
+ .current-version {
+ font-family: monospace;
+ font-size: 1.1em;
+ font-weight: bold;
+ color: #0073aa;
+ background: #f0f6fc;
+ padding: 2px 8px;
+ border-radius: 3px;
+ border: 1px solid #c3c4c7;
+ }
+
+ #target_version {
+ min-width: 200px;
+ margin-inline-start: 8px;
+ }
+
+ #switch-version-btn {
+ margin-inline-start: 8px;
+
+ &[disabled] {
+ opacity: 0.6;
+ cursor: not-allowed;
+ }
+ }
+
+ #version-switch-result {
+ margin-block-start: 12px;
+
+ &.notice {
+ padding: 8px 12px;
+ border-radius: 4px;
+ }
+ }
+
+ p.description {
+ font-style: italic;
+ color: #d63638;
+ background: #fcf0f1;
+ padding: 8px 12px;
+ border-radius: 4px;
+ border-left: 4px solid #d63638;
+ margin-block-start: 16px;
+ }
+
+ .notice {
+ &.notice-success {
+ border-left-color: #00a32a;
+ }
+
+ &.notice-error {
+ border-left-color: #d63638;
+ }
+
+ &.notice-warning {
+ border-left-color: #dba617;
+ }
+
+ &.notice-info {
+ border-left-color: #72aee6;
+ }
+ }
+}
+
+.version-switch-settings {
+ .form-table {
+ th {
+ width: 180px;
+ }
+ }
+}
From 2e54814b6b37fe5fc3078a5ec7ba72545a80979a Mon Sep 17 00:00:00 2001
From: Imants
Date: Fri, 22 Aug 2025 20:19:14 +0300
Subject: [PATCH 048/106] feat: refactor version switch functions and improve
error handling
---
src/php/settings/version-switch.php | 280 ++++++++++++++++++++++------
1 file changed, 224 insertions(+), 56 deletions(-)
diff --git a/src/php/settings/version-switch.php b/src/php/settings/version-switch.php
index 0a4325ea..be99d1ce 100644
--- a/src/php/settings/version-switch.php
+++ b/src/php/settings/version-switch.php
@@ -2,6 +2,12 @@
/**
* Handles version switching functionality for the Code Snippets plugin.
*
+ * This file provides a complete version switching system that allows users to:
+ * - View available plugin versions from WordPress.org
+ * - Switch between different versions safely
+ * - Track progress during version switching
+ * - Handle errors gracefully with detailed logging
+ *
* @package Code_Snippets
* @subpackage Settings
*/
@@ -10,17 +16,23 @@
use function Code_Snippets\code_snippets;
+// Configuration constants for version switching
+const VERSION_CACHE_KEY = 'code_snippets_available_versions';
+const PROGRESS_KEY = 'code_snippets_version_switch_progress';
+const VERSION_CACHE_DURATION = HOUR_IN_SECONDS;
+const PROGRESS_TIMEOUT = 5 * MINUTE_IN_SECONDS;
+const WORDPRESS_API_ENDPOINT = 'https://api.wordpress.org/plugins/info/1.2/?action=plugin_information&slug=code-snippets';
+
/**
* Get available plugin versions from WordPress.org repository
*
* @return array Array of version information
*/
function get_available_versions(): array {
- $transient_key = 'code_snippets_available_versions';
- $versions = get_transient( $transient_key );
+ $versions = get_transient( VERSION_CACHE_KEY );
if ( false === $versions ) {
- $response = wp_remote_get( 'https://api.wordpress.org/plugins/info/1.2/?action=plugin_information&slug=code-snippets' );
+ $response = wp_remote_get( WORDPRESS_API_ENDPOINT );
if ( is_wp_error( $response ) ) {
return [];
@@ -49,8 +61,8 @@ function get_available_versions(): array {
return version_compare( $b['version'], $a['version'] );
});
- // Cache for 1 hour
- set_transient( $transient_key, $versions, HOUR_IN_SECONDS );
+ // Cache for configured duration
+ set_transient( VERSION_CACHE_KEY, $versions, VERSION_CACHE_DURATION );
}
return $versions;
@@ -71,55 +83,80 @@ function get_current_version(): string {
* @return bool True if switch is in progress
*/
function is_version_switch_in_progress(): bool {
- return get_transient( 'code_snippets_version_switch_progress' ) !== false;
+ return get_transient( PROGRESS_KEY ) !== false;
}
/**
- * Handle version switch request
+ * Clear version-related caches
*
- * @param string $target_version Target version to switch to
- * @return array Result array with success status and message
+ * @return void
*/
-function handle_version_switch( string $target_version ): array {
- // Check user capabilities
- if ( ! current_user_can( 'update_plugins' ) ) {
+function clear_version_caches(): void {
+ delete_transient( VERSION_CACHE_KEY );
+ delete_transient( PROGRESS_KEY );
+}
+
+/**
+ * Validate target version against available versions
+ *
+ * @param string $target_version Target version to validate
+ * @param array $available_versions Array of available versions
+ * @return array Validation result with success status, message, and download URL
+ */
+function validate_target_version( string $target_version, array $available_versions ): array {
+ if ( empty( $target_version ) ) {
return [
'success' => false,
- 'message' => __( 'You do not have permission to update plugins.', 'code-snippets' ),
+ 'message' => __( 'No target version specified.', 'code-snippets' ),
+ 'download_url' => '',
];
}
- // Validate target version
- $available_versions = get_available_versions();
- $version_exists = false;
- $download_url = '';
-
foreach ( $available_versions as $version_info ) {
if ( $version_info['version'] === $target_version ) {
- $version_exists = true;
- $download_url = $version_info['url'];
- break;
+ return [
+ 'success' => true,
+ 'message' => '',
+ 'download_url' => $version_info['url'],
+ ];
}
}
- if ( ! $version_exists ) {
- return [
- 'success' => false,
- 'message' => __( 'Invalid version specified.', 'code-snippets' ),
- ];
- }
+ return [
+ 'success' => false,
+ 'message' => __( 'Invalid version specified.', 'code-snippets' ),
+ 'download_url' => '',
+ ];
+}
- // Check if already on target version
- if ( get_current_version() === $target_version ) {
- return [
- 'success' => false,
- 'message' => __( 'Already on the specified version.', 'code-snippets' ),
- ];
+/**
+ * Create a standardized error response
+ *
+ * @param string $message User-friendly error message
+ * @param string $technical_details Technical details for debugging (optional)
+ * @return array Error response array
+ */
+function create_error_response( string $message, string $technical_details = '' ): array {
+ if ( ! empty( $technical_details ) ) {
+ // Log technical details for debugging
+ if ( function_exists( 'error_log' ) ) {
+ error_log( sprintf( 'Code Snippets version switch error: %s. Details: %s', $message, $technical_details ) );
+ }
}
- // Set switch in progress
- set_transient( 'code_snippets_version_switch_progress', $target_version, 5 * MINUTE_IN_SECONDS );
+ return [
+ 'success' => false,
+ 'message' => $message,
+ ];
+}
+/**
+ * Perform the actual version installation using WordPress upgrader
+ *
+ * @param string $download_url URL to download the plugin version
+ * @return bool|\WP_Error Installation result
+ */
+function perform_version_install( string $download_url ) {
// Include WordPress upgrade functions
if ( ! function_exists( 'wp_update_plugins' ) ) {
require_once ABSPATH . 'wp-admin/includes/update.php';
@@ -131,28 +168,161 @@ function handle_version_switch( string $target_version ): array {
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
}
- // Create upgrader instance
- $upgrader = new \Plugin_Upgrader( new \Automatic_Upgrader_Skin() );
+ // Create update handler (captures Ajax responses and errors) and upgrader instance
+ $update_handler = new \WP_Ajax_Upgrader_Skin();
+ $upgrader = new \Plugin_Upgrader( $update_handler );
- // Perform the upgrade/downgrade
- $result = $upgrader->upgrade( plugin_basename( CODE_SNIPPETS_FILE ), [
- 'clear_destination' => true,
- 'overwrite_package' => true,
+ // Store the handler globally so we can access it later for error extraction
+ global $code_snippets_last_update_handler, $code_snippets_last_upgrader;
+ $code_snippets_last_update_handler = $update_handler;
+ $code_snippets_last_upgrader = $upgrader;
+
+ // Perform the install/overwrite using the package download URL from WordPress.org
+ return $upgrader->install( $download_url, [
+ 'overwrite_package' => true,
+ 'clear_update_cache' => true,
] );
+}
+
+/**
+ * Handle installation failure and extract useful error information
+ *
+ * @param string $target_version The target version that failed to install
+ * @param string $download_url The download URL used
+ * @param mixed $install_result The result from the upgrader
+ * @return array Error response with extracted information
+ */
+function handle_installation_failure( string $target_version, string $download_url, $install_result ): array {
+ global $code_snippets_last_update_handler, $code_snippets_last_upgrader;
+
+ $handler_messages = extract_handler_messages( $code_snippets_last_update_handler, $code_snippets_last_upgrader );
+
+ // Log details for server-side debugging
+ log_version_switch_attempt( $target_version, $install_result, "URL: $download_url, Messages: $handler_messages" );
+
+ // Return a more informative message when possible (still user-friendly)
+ $fallback_message = __( 'Failed to switch versions. Please try again.', 'code-snippets' );
+ if ( ! empty( $handler_messages ) ) {
+ // Trim and sanitize a bit for output
+ $short = wp_trim_words( wp_strip_all_tags( $handler_messages ), 40, '...' );
+ $fallback_message = sprintf( '%s %s', $fallback_message, $short );
+ }
+
+ return [
+ 'success' => false,
+ 'message' => $fallback_message,
+ ];
+}
+
+/**
+ * Extract helpful messages from the update handler
+ *
+ * @param mixed $update_handler The WP_Ajax_Upgrader_Skin instance
+ * @param mixed $upgrader The Plugin_Upgrader instance
+ * @return string Extracted messages
+ */
+function extract_handler_messages( $update_handler, $upgrader ): string {
+ $handler_messages = '';
+
+ if ( isset( $update_handler ) ) {
+ // Errors (WP_Ajax_Upgrader_Skin stores them)
+ if ( method_exists( $update_handler, 'get_errors' ) ) {
+ $errs = $update_handler->get_errors();
+ if ( $errs instanceof \WP_Error && $errs->has_errors() ) {
+ $handler_messages .= implode( "\n", $errs->get_error_messages() );
+ }
+ }
+ // Error messages string
+ if ( method_exists( $update_handler, 'get_error_messages' ) ) {
+ $em = $update_handler->get_error_messages();
+ if ( $em ) {
+ $handler_messages .= "\n" . $em;
+ }
+ }
+ // Upgrade messages (feedback/info)
+ if ( method_exists( $update_handler, 'get_upgrade_messages' ) ) {
+ $upgrade_msgs = $update_handler->get_upgrade_messages();
+ if ( is_array( $upgrade_msgs ) ) {
+ $handler_messages .= "\n" . implode( "\n", $upgrade_msgs );
+ } elseif ( $upgrade_msgs ) {
+ $handler_messages .= "\n" . (string) $upgrade_msgs;
+ }
+ }
+ }
+
+ // Fallback: if upgrader populated result with info, include it
+ if ( empty( $handler_messages ) && isset( $upgrader->result ) ) {
+ if ( is_wp_error( $upgrader->result ) ) {
+ $handler_messages = implode( "\n", $upgrader->result->get_error_messages() );
+ } else {
+ $handler_messages = is_scalar( $upgrader->result ) ? (string) $upgrader->result : print_r( $upgrader->result, true );
+ }
+ }
+
+ return trim( $handler_messages );
+}
+
+/**
+ * Log version switch attempt for debugging
+ *
+ * @param string $target_version Target version
+ * @param mixed $result Installation result
+ * @param string $details Additional details
+ * @return void
+ */
+function log_version_switch_attempt( string $target_version, $result, string $details = '' ): void {
+ if ( function_exists( 'error_log' ) ) {
+ error_log( sprintf(
+ 'Code Snippets version switch failed. target=%s, result=%s, details=%s',
+ $target_version,
+ var_export( $result, true ),
+ $details
+ ) );
+ }
+}
+
+/**
+ * Handle version switch request
+ *
+ * @param string $target_version Target version to switch to
+ * @return array Result array with success status and message
+ */
+function handle_version_switch( string $target_version ): array {
+ // Check user capabilities
+ if ( ! current_user_can( 'update_plugins' ) ) {
+ return create_error_response( __( 'You do not have permission to update plugins.', 'code-snippets' ) );
+ }
+
+ // Validate target version
+ $available_versions = get_available_versions();
+ $validation = validate_target_version( $target_version, $available_versions );
+
+ if ( ! $validation['success'] ) {
+ return create_error_response( $validation['message'] );
+ }
+
+ // Check if already on target version
+ if ( get_current_version() === $target_version ) {
+ return create_error_response( __( 'Already on the specified version.', 'code-snippets' ) );
+ }
+
+ // Set switch in progress
+ set_transient( PROGRESS_KEY, $target_version, PROGRESS_TIMEOUT );
+
+ // Perform the version installation
+ $install_result = perform_version_install( $validation['download_url'] );
// Clear progress transient
- delete_transient( 'code_snippets_version_switch_progress' );
+ delete_transient( PROGRESS_KEY );
- if ( is_wp_error( $result ) ) {
- return [
- 'success' => false,
- 'message' => $result->get_error_message(),
- ];
+ // Handle the result
+ if ( is_wp_error( $install_result ) ) {
+ return create_error_response( $install_result->get_error_message() );
}
- if ( $result ) {
- // Clear version cache
- delete_transient( 'code_snippets_available_versions' );
+ if ( $install_result ) {
+ // Clear version cache on success
+ delete_transient( VERSION_CACHE_KEY );
return [
'success' => true,
@@ -163,10 +333,8 @@ function handle_version_switch( string $target_version ): array {
];
}
- return [
- 'success' => false,
- 'message' => __( 'Failed to switch versions. Please try again.', 'code-snippets' ),
- ];
+ // If we get here, the installation failed but didn't return a WP_Error
+ return handle_installation_failure( $target_version, $validation['download_url'], $install_result );
}
/**
@@ -371,8 +539,8 @@ function ajax_refresh_versions(): void {
] );
}
- // Clear the cache
- delete_transient( 'code_snippets_available_versions' );
+ // Clear the cache using our helper function
+ delete_transient( VERSION_CACHE_KEY );
// Fetch fresh data
get_available_versions();
From 5af841c0caa47825b980768a0b7d314d1f50f8b0 Mon Sep 17 00:00:00 2001
From: Imants
Date: Fri, 22 Aug 2025 21:21:53 +0300
Subject: [PATCH 049/106] feat: move version warning to separate field
---
src/php/settings/settings-fields.php | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/php/settings/settings-fields.php b/src/php/settings/settings-fields.php
index 864e661f..6ec79b3e 100644
--- a/src/php/settings/settings-fields.php
+++ b/src/php/settings/settings-fields.php
@@ -95,6 +95,11 @@ function get_settings_fields(): array {
'type' => 'callback',
'render_callback' => 'Code_Snippets\Settings\VersionSwitch\render_refresh_versions_field',
],
+ 'version_warning' => [
+ 'name' => '',
+ 'type' => 'callback',
+ 'render_callback' => 'Code_Snippets\Settings\VersionSwitch\render_version_switch_warning',
+ ],
];
$fields['general'] = [
From f6225abf5b609d31eaab940cb7fb8b47424adc34 Mon Sep 17 00:00:00 2001
From: Imants
Date: Fri, 22 Aug 2025 21:22:05 +0300
Subject: [PATCH 050/106] feat: enhance version switch UI with warning and
button state management
---
src/php/settings/version-switch.php | 57 +++++++++++++++++++++--------
1 file changed, 42 insertions(+), 15 deletions(-)
diff --git a/src/php/settings/version-switch.php b/src/php/settings/version-switch.php
index be99d1ce..30fbaca7 100644
--- a/src/php/settings/version-switch.php
+++ b/src/php/settings/version-switch.php
@@ -378,32 +378,44 @@ function render_version_switch_field( array $args ): void {
-
-
-
-
-
-
-
-
-
-
Date: Thu, 16 Oct 2025 16:01:09 +0300
Subject: [PATCH 068/106] feat: add debug option to enable version change
section
---
src/php/settings/settings-fields.php | 8 ++++++++
src/php/settings/settings.php | 14 ++++++++++++--
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/src/php/settings/settings-fields.php b/src/php/settings/settings-fields.php
index 385791c4..a80f8801 100644
--- a/src/php/settings/settings-fields.php
+++ b/src/php/settings/settings-fields.php
@@ -50,6 +50,9 @@ function get_default_settings(): array {
'version-switch' => [
'selected_version' => '',
],
+ 'debug' => [
+ 'enable_version_change' => false,
+ ],
];
$defaults = apply_filters( 'code_snippets_settings_defaults', $defaults );
@@ -83,6 +86,11 @@ function get_settings_fields(): array {
'type' => 'action',
'desc' => __( 'Use this button to manually clear snippets caches.', 'code-snippets' ),
],
+ 'enable_version_change' => [
+ 'name' => __( 'Version Change', 'code-snippets' ),
+ 'type' => 'checkbox',
+ 'label' => __( 'Enable the ability to switch or rollback versions of the Code Snippets core plugin.', 'code-snippets' ),
+ ],
];
$fields['version-switch'] = [
diff --git a/src/php/settings/settings.php b/src/php/settings/settings.php
index 3d54b960..e359cca0 100644
--- a/src/php/settings/settings.php
+++ b/src/php/settings/settings.php
@@ -139,9 +139,14 @@ function get_settings_sections(): array {
'general' => __( 'General', 'code-snippets' ),
'editor' => __( 'Code Editor', 'code-snippets' ),
'debug' => __( 'Debug', 'code-snippets' ),
- 'version-switch' => __( 'Version', 'code-snippets' ),
);
+ // Only show the Version section when the debug setting to enable version changes is enabled.
+ $enable_version = get_setting( 'debug', 'enable_version_change' );
+ if ( $enable_version ) {
+ $sections['version-switch'] = __( 'Version', 'code-snippets' );
+ }
+
return apply_filters( 'code_snippets_settings_sections', $sections );
}
@@ -169,8 +174,13 @@ function register_plugin_settings() {
add_settings_section( $section_id, $section_name, '__return_empty_string', 'code-snippets' );
}
- // Register settings fields.
+ // Register settings fields. Only register fields for sections that exist (some sections may be gated by settings).
+ $registered_sections = get_settings_sections();
foreach ( get_settings_fields() as $section_id => $fields ) {
+ if ( ! isset( $registered_sections[ $section_id ] ) ) {
+ continue;
+ }
+
foreach ( $fields as $field_id => $field ) {
$field_object = new Setting_Field( $section_id, $field_id, $field );
add_settings_field( $field_id, $field['name'], [ $field_object, 'render' ], 'code-snippets', $section_id );
From 616f251d27285cf987f010375f4744080799bc21 Mon Sep 17 00:00:00 2001
From: Imants
Date: Thu, 16 Oct 2025 16:16:29 +0300
Subject: [PATCH 069/106] fix: update version switch integration to use
class-based implementation ref:
https://github.com/codesnippetspro/code-snippets/pull/251#discussion_r2320156008
---
src/php/class-plugin.php | 2 +-
src/php/settings/class-version-switch.php | 362 ++++++++++++++++++++++
src/php/settings/settings-fields.php | 8 +-
3 files changed, 367 insertions(+), 5 deletions(-)
create mode 100644 src/php/settings/class-version-switch.php
diff --git a/src/php/class-plugin.php b/src/php/class-plugin.php
index 8fb5ac7b..79cd8a5b 100644
--- a/src/php/class-plugin.php
+++ b/src/php/class-plugin.php
@@ -125,7 +125,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/version-switch.php';
+ require_once $includes_path . '/settings/class-version-switch.php';
require_once $includes_path . '/settings/settings.php';
// Cloud List Table shared functions.
diff --git a/src/php/settings/class-version-switch.php b/src/php/settings/class-version-switch.php
new file mode 100644
index 00000000..7738147d
--- /dev/null
+++ b/src/php/settings/class-version-switch.php
@@ -0,0 +1,362 @@
+ $download_url ) {
+ if ( 'trunk' !== $version ) {
+ $versions[] = [
+ 'version' => $version,
+ 'url' => $download_url,
+ ];
+ }
+ }
+
+ // Sort versions in descending order
+ usort( $versions, function( $a, $b ) {
+ return version_compare( $b['version'], $a['version'] );
+ });
+
+ // Cache for configured duration
+ set_transient( VERSION_CACHE_KEY, $versions, VERSION_CACHE_DURATION );
+ }
+
+ return $versions;
+ }
+
+ public static function get_current_version(): string {
+ return defined( 'CODE_SNIPPETS_VERSION' ) ? CODE_SNIPPETS_VERSION : '0.0.0';
+ }
+
+ public static function is_version_switch_in_progress(): bool {
+ return get_transient( PROGRESS_KEY ) !== false;
+ }
+
+ public static function clear_version_caches(): void {
+ delete_transient( VERSION_CACHE_KEY );
+ delete_transient( PROGRESS_KEY );
+ }
+
+ public static function validate_target_version( string $target_version, array $available_versions ): array {
+ if ( empty( $target_version ) ) {
+ return [
+ 'success' => false,
+ 'message' => __( 'No target version specified.', 'code-snippets' ),
+ 'download_url' => '',
+ ];
+ }
+
+ foreach ( $available_versions as $version_info ) {
+ if ( $version_info['version'] === $target_version ) {
+ return [
+ 'success' => true,
+ 'message' => '',
+ 'download_url' => $version_info['url'],
+ ];
+ }
+ }
+
+ return [
+ 'success' => false,
+ 'message' => __( 'Invalid version specified.', 'code-snippets' ),
+ 'download_url' => '',
+ ];
+ }
+
+ public static function create_error_response( string $message, string $technical_details = '' ): array {
+ if ( ! empty( $technical_details ) ) {
+ if ( function_exists( 'error_log' ) ) {
+ error_log( sprintf( 'Code Snippets version switch error: %s. Details: %s', $message, $technical_details ) );
+ }
+ }
+
+ return [
+ 'success' => false,
+ 'message' => $message,
+ ];
+ }
+
+ public static function perform_version_install( string $download_url ) {
+ if ( ! function_exists( 'wp_update_plugins' ) ) {
+ require_once ABSPATH . 'wp-admin/includes/update.php';
+ }
+ if ( ! function_exists( 'show_message' ) ) {
+ require_once ABSPATH . 'wp-admin/includes/misc.php';
+ }
+ if ( ! class_exists( 'Plugin_Upgrader' ) ) {
+ require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
+ }
+
+ $update_handler = new \WP_Ajax_Upgrader_Skin();
+ $upgrader = new \Plugin_Upgrader( $update_handler );
+
+ global $code_snippets_last_update_handler, $code_snippets_last_upgrader;
+ $code_snippets_last_update_handler = $update_handler;
+ $code_snippets_last_upgrader = $upgrader;
+
+ return $upgrader->install( $download_url, [
+ 'overwrite_package' => true,
+ 'clear_update_cache' => true,
+ ] );
+ }
+
+ public static function extract_handler_messages( $update_handler, $upgrader ): string {
+ $handler_messages = '';
+
+ if ( isset( $update_handler ) ) {
+ if ( method_exists( $update_handler, 'get_errors' ) ) {
+ $errs = $update_handler->get_errors();
+ if ( $errs instanceof \WP_Error && $errs->has_errors() ) {
+ $handler_messages .= implode( "\n", $errs->get_error_messages() );
+ }
+ }
+ if ( method_exists( $update_handler, 'get_error_messages' ) ) {
+ $em = $update_handler->get_error_messages();
+ if ( $em ) {
+ $handler_messages .= "\n" . $em;
+ }
+ }
+ if ( method_exists( $update_handler, 'get_upgrade_messages' ) ) {
+ $upgrade_msgs = $update_handler->get_upgrade_messages();
+ if ( is_array( $upgrade_msgs ) ) {
+ $handler_messages .= "\n" . implode( "\n", $upgrade_msgs );
+ } elseif ( $upgrade_msgs ) {
+ $handler_messages .= "\n" . (string) $upgrade_msgs;
+ }
+ }
+ }
+
+ if ( empty( $handler_messages ) && isset( $upgrader->result ) ) {
+ if ( is_wp_error( $upgrader->result ) ) {
+ $handler_messages = implode( "\n", $upgrader->result->get_error_messages() );
+ } else {
+ $handler_messages = is_scalar( $upgrader->result ) ? (string) $upgrader->result : print_r( $upgrader->result, true );
+ }
+ }
+
+ return trim( $handler_messages );
+ }
+
+ public static function log_version_switch_attempt( string $target_version, $result, string $details = '' ): void {
+ if ( function_exists( 'error_log' ) ) {
+ error_log( sprintf( 'Code Snippets version switch failed. target=%s, result=%s, details=%s', $target_version, var_export( $result, true ), $details ) );
+ }
+ }
+
+ public static function handle_installation_failure( string $target_version, string $download_url, $install_result ): array {
+ global $code_snippets_last_update_handler, $code_snippets_last_upgrader;
+
+ $handler_messages = self::extract_handler_messages( $code_snippets_last_update_handler, $code_snippets_last_upgrader );
+ self::log_version_switch_attempt( $target_version, $install_result, "URL: $download_url, Messages: $handler_messages" );
+
+ $fallback_message = __( 'Failed to switch versions. Please try again.', 'code-snippets' );
+ if ( ! empty( $handler_messages ) ) {
+ $short = wp_trim_words( wp_strip_all_tags( $handler_messages ), 40, '...' );
+ $fallback_message = sprintf( '%s %s', $fallback_message, $short );
+ }
+
+ return [
+ 'success' => false,
+ 'message' => $fallback_message,
+ ];
+ }
+
+ public static function handle_version_switch( string $target_version ): array {
+ if ( ! current_user_can( 'update_plugins' ) ) {
+ return self::create_error_response( __( 'You do not have permission to update plugins.', 'code-snippets' ) );
+ }
+
+ $available_versions = self::get_available_versions();
+ $validation = self::validate_target_version( $target_version, $available_versions );
+
+ if ( ! $validation['success'] ) {
+ return self::create_error_response( $validation['message'] );
+ }
+
+ if ( self::get_current_version() === $target_version ) {
+ return self::create_error_response( __( 'Already on the specified version.', 'code-snippets' ) );
+ }
+
+ set_transient( PROGRESS_KEY, $target_version, PROGRESS_TIMEOUT );
+
+ $install_result = self::perform_version_install( $validation['download_url'] );
+
+ delete_transient( PROGRESS_KEY );
+
+ if ( is_wp_error( $install_result ) ) {
+ return self::create_error_response( $install_result->get_error_message() );
+ }
+
+ if ( $install_result ) {
+ delete_transient( VERSION_CACHE_KEY );
+
+ return [
+ 'success' => true,
+ 'message' => sprintf( __( 'Successfully switched to version %s. Please refresh the page to see changes.', 'code-snippets' ), $target_version ),
+ ];
+ }
+
+ return self::handle_installation_failure( $target_version, $validation['download_url'], $install_result );
+ }
+
+ public static function render_version_switch_field( array $args ): void {
+ $current_version = self::get_current_version();
+ $available_versions = self::get_available_versions();
+ $is_switching = self::is_version_switch_in_progress();
+
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
__( 'You do not have permission to update plugins.', 'code-snippets' ),
+ ] );
+ }
+
+ $target_version = sanitize_text_field( $_POST['target_version'] ?? '' );
+
+ if ( empty( $target_version ) ) {
+ wp_send_json_error( [
+ 'message' => __( 'No target version specified.', 'code-snippets' ),
+ ] );
+ }
+
+ $result = self::handle_version_switch( $target_version );
+
+ if ( $result['success'] ) {
+ wp_send_json_success( $result );
+ } else {
+ wp_send_json_error( $result );
+ }
+ }
+
+ public static function render_refresh_versions_field( array $args ): void {
+ ?>
+
+
+
+
__( 'You do not have permission to manage options.', 'code-snippets' ),
+ ] );
+ }
+
+ delete_transient( VERSION_CACHE_KEY );
+ self::get_available_versions();
+
+ wp_send_json_success( [
+ 'message' => __( 'Available versions updated successfully.', 'code-snippets' ),
+ ] );
+ }
+
+ public static function render_version_switch_warning(): void {
+ ?>
+
+ 'action',
'desc' => __( 'Use this button to manually clear snippets caches.', 'code-snippets' ),
],
- 'enable_version_change' => [
+ 'enable_version_change' => [
'name' => __( 'Version Change', 'code-snippets' ),
'type' => 'checkbox',
'label' => __( 'Enable the ability to switch or rollback versions of the Code Snippets core plugin.', 'code-snippets' ),
@@ -97,17 +97,17 @@ function get_settings_fields(): array {
'version_switcher' => [
'name' => __( 'Switch Version', 'code-snippets' ),
'type' => 'callback',
- 'render_callback' => 'Code_Snippets\Settings\VersionSwitch\render_version_switch_field',
+ 'render_callback' => [ '\\Code_Snippets\\Settings\\Version_Switch', 'render_version_switch_field' ],
],
'refresh_versions' => [
'name' => __( 'Refresh Versions', 'code-snippets' ),
'type' => 'callback',
- 'render_callback' => 'Code_Snippets\Settings\VersionSwitch\render_refresh_versions_field',
+ 'render_callback' => [ '\\Code_Snippets\\Settings\\Version_Switch', 'render_refresh_versions_field' ],
],
'version_warning' => [
'name' => '',
'type' => 'callback',
- 'render_callback' => 'Code_Snippets\Settings\VersionSwitch\render_version_switch_warning',
+ 'render_callback' => [ '\\Code_Snippets\\Settings\\Version_Switch', 'render_version_switch_warning' ],
],
];
From 964da4303fd5fe0c38f6733935118cf188ec6458 Mon Sep 17 00:00:00 2001
From: Imants
Date: Thu, 16 Oct 2025 16:17:51 +0300
Subject: [PATCH 070/106] chore: remove unnecessary code
---
src/php/settings/version-switch.php | 476 ----------------------------
1 file changed, 476 deletions(-)
delete mode 100644 src/php/settings/version-switch.php
diff --git a/src/php/settings/version-switch.php b/src/php/settings/version-switch.php
deleted file mode 100644
index d41381c0..00000000
--- a/src/php/settings/version-switch.php
+++ /dev/null
@@ -1,476 +0,0 @@
- $download_url ) {
- if ( 'trunk' !== $version ) {
- $versions[] = [
- 'version' => $version,
- 'url' => $download_url,
- ];
- }
- }
-
- // Sort versions in descending order
- usort( $versions, function( $a, $b ) {
- return version_compare( $b['version'], $a['version'] );
- });
-
- // Cache for configured duration
- set_transient( VERSION_CACHE_KEY, $versions, VERSION_CACHE_DURATION );
- }
-
- return $versions;
-}
-
-/**
- * Get current plugin version
- *
- * @return string Current version
- */
-function get_current_version(): string {
- return defined( 'CODE_SNIPPETS_VERSION' ) ? CODE_SNIPPETS_VERSION : '0.0.0';
-}
-
-/**
- * Check if a version switch is in progress
- *
- * @return bool True if switch is in progress
- */
-function is_version_switch_in_progress(): bool {
- return get_transient( PROGRESS_KEY ) !== false;
-}
-
-/**
- * Clear version-related caches
- *
- * @return void
- */
-function clear_version_caches(): void {
- delete_transient( VERSION_CACHE_KEY );
- delete_transient( PROGRESS_KEY );
-}
-
-/**
- * Validate target version against available versions
- *
- * @param string $target_version Target version to validate
- * @param array $available_versions Array of available versions
- * @return array Validation result with success status, message, and download URL
- */
-function validate_target_version( string $target_version, array $available_versions ): array {
- if ( empty( $target_version ) ) {
- return [
- 'success' => false,
- 'message' => __( 'No target version specified.', 'code-snippets' ),
- 'download_url' => '',
- ];
- }
-
- foreach ( $available_versions as $version_info ) {
- if ( $version_info['version'] === $target_version ) {
- return [
- 'success' => true,
- 'message' => '',
- 'download_url' => $version_info['url'],
- ];
- }
- }
-
- return [
- 'success' => false,
- 'message' => __( 'Invalid version specified.', 'code-snippets' ),
- 'download_url' => '',
- ];
-}
-
-/**
- * Create a standardized error response
- *
- * @param string $message User-friendly error message
- * @param string $technical_details Technical details for debugging (optional)
- * @return array Error response array
- */
-function create_error_response( string $message, string $technical_details = '' ): array {
- if ( ! empty( $technical_details ) ) {
- // Log technical details for debugging
- if ( function_exists( 'error_log' ) ) {
- error_log( sprintf( 'Code Snippets version switch error: %s. Details: %s', $message, $technical_details ) );
- }
- }
-
- return [
- 'success' => false,
- 'message' => $message,
- ];
-}
-
-/**
- * Perform the actual version installation using WordPress upgrader
- *
- * @param string $download_url URL to download the plugin version
- * @return bool|\WP_Error Installation result
- */
-function perform_version_install( string $download_url ) {
- // Include WordPress upgrade functions
- if ( ! function_exists( 'wp_update_plugins' ) ) {
- require_once ABSPATH . 'wp-admin/includes/update.php';
- }
- if ( ! function_exists( 'show_message' ) ) {
- require_once ABSPATH . 'wp-admin/includes/misc.php';
- }
- if ( ! class_exists( 'Plugin_Upgrader' ) ) {
- require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
- }
-
- // Create update handler (captures Ajax responses and errors) and upgrader instance
- $update_handler = new \WP_Ajax_Upgrader_Skin();
- $upgrader = new \Plugin_Upgrader( $update_handler );
-
- // Store the handler globally so we can access it later for error extraction
- global $code_snippets_last_update_handler, $code_snippets_last_upgrader;
- $code_snippets_last_update_handler = $update_handler;
- $code_snippets_last_upgrader = $upgrader;
-
- // Perform the install/overwrite using the package download URL from WordPress.org
- return $upgrader->install( $download_url, [
- 'overwrite_package' => true,
- 'clear_update_cache' => true,
- ] );
-}
-
-/**
- * Handle installation failure and extract useful error information
- *
- * @param string $target_version The target version that failed to install
- * @param string $download_url The download URL used
- * @param mixed $install_result The result from the upgrader
- * @return array Error response with extracted information
- */
-function handle_installation_failure( string $target_version, string $download_url, $install_result ): array {
- global $code_snippets_last_update_handler, $code_snippets_last_upgrader;
-
- $handler_messages = extract_handler_messages( $code_snippets_last_update_handler, $code_snippets_last_upgrader );
-
- // Log details for server-side debugging
- log_version_switch_attempt( $target_version, $install_result, "URL: $download_url, Messages: $handler_messages" );
-
- // Return a more informative message when possible (still user-friendly)
- $fallback_message = __( 'Failed to switch versions. Please try again.', 'code-snippets' );
- if ( ! empty( $handler_messages ) ) {
- // Trim and sanitize a bit for output
- $short = wp_trim_words( wp_strip_all_tags( $handler_messages ), 40, '...' );
- $fallback_message = sprintf( '%s %s', $fallback_message, $short );
- }
-
- return [
- 'success' => false,
- 'message' => $fallback_message,
- ];
-}
-
-/**
- * Extract helpful messages from the update handler
- *
- * @param mixed $update_handler The WP_Ajax_Upgrader_Skin instance
- * @param mixed $upgrader The Plugin_Upgrader instance
- * @return string Extracted messages
- */
-function extract_handler_messages( $update_handler, $upgrader ): string {
- $handler_messages = '';
-
- if ( isset( $update_handler ) ) {
- // Errors (WP_Ajax_Upgrader_Skin stores them)
- if ( method_exists( $update_handler, 'get_errors' ) ) {
- $errs = $update_handler->get_errors();
- if ( $errs instanceof \WP_Error && $errs->has_errors() ) {
- $handler_messages .= implode( "\n", $errs->get_error_messages() );
- }
- }
- // Error messages string
- if ( method_exists( $update_handler, 'get_error_messages' ) ) {
- $em = $update_handler->get_error_messages();
- if ( $em ) {
- $handler_messages .= "\n" . $em;
- }
- }
- // Upgrade messages (feedback/info)
- if ( method_exists( $update_handler, 'get_upgrade_messages' ) ) {
- $upgrade_msgs = $update_handler->get_upgrade_messages();
- if ( is_array( $upgrade_msgs ) ) {
- $handler_messages .= "\n" . implode( "\n", $upgrade_msgs );
- } elseif ( $upgrade_msgs ) {
- $handler_messages .= "\n" . (string) $upgrade_msgs;
- }
- }
- }
-
- // Fallback: if upgrader populated result with info, include it
- if ( empty( $handler_messages ) && isset( $upgrader->result ) ) {
- if ( is_wp_error( $upgrader->result ) ) {
- $handler_messages = implode( "\n", $upgrader->result->get_error_messages() );
- } else {
- $handler_messages = is_scalar( $upgrader->result ) ? (string) $upgrader->result : print_r( $upgrader->result, true );
- }
- }
-
- return trim( $handler_messages );
-}
-
-/**
- * Log version switch attempt for debugging
- *
- * @param string $target_version Target version
- * @param mixed $result Installation result
- * @param string $details Additional details
- * @return void
- */
-function log_version_switch_attempt( string $target_version, $result, string $details = '' ): void {
- if ( function_exists( 'error_log' ) ) {
- error_log( sprintf(
- 'Code Snippets version switch failed. target=%s, result=%s, details=%s',
- $target_version,
- var_export( $result, true ),
- $details
- ) );
- }
-}
-
-/**
- * Handle version switch request
- *
- * @param string $target_version Target version to switch to
- * @return array Result array with success status and message
- */
-function handle_version_switch( string $target_version ): array {
-
- if ( ! current_user_can( 'update_plugins' ) ) {
- return create_error_response( __( 'You do not have permission to update plugins.', 'code-snippets' ) );
- }
-
- $available_versions = get_available_versions();
- $validation = validate_target_version( $target_version, $available_versions );
-
- if ( ! $validation['success'] ) {
- return create_error_response( $validation['message'] );
- }
-
- if ( get_current_version() === $target_version ) {
- return create_error_response( __( 'Already on the specified version.', 'code-snippets' ) );
- }
-
- set_transient( PROGRESS_KEY, $target_version, PROGRESS_TIMEOUT );
-
- $install_result = perform_version_install( $validation['download_url'] );
-
- delete_transient( PROGRESS_KEY );
-
- if ( is_wp_error( $install_result ) ) {
- return create_error_response( $install_result->get_error_message() );
- }
-
- if ( $install_result ) {
- delete_transient( VERSION_CACHE_KEY );
-
- return [
- 'success' => true,
- 'message' => sprintf(
- __( 'Successfully switched to version %s. Please refresh the page to see changes.', 'code-snippets' ),
- $target_version
- ),
- ];
- }
-
- return handle_installation_failure( $target_version, $validation['download_url'], $install_result );
-}
-
-/**
- * Render the version switch field
- *
- * @param array $args Field arguments
- */
-function render_version_switch_field( array $args ): void {
- $current_version = get_current_version();
- $available_versions = get_available_versions();
- $is_switching = is_version_switch_in_progress();
-
- ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
__( 'You do not have permission to update plugins.', 'code-snippets' ),
- ] );
- }
-
- $target_version = sanitize_text_field( $_POST['target_version'] ?? '' );
-
- if ( empty( $target_version ) ) {
- wp_send_json_error( [
- 'message' => __( 'No target version specified.', 'code-snippets' ),
- ] );
- }
-
- $result = handle_version_switch( $target_version );
-
- if ( $result['success'] ) {
- wp_send_json_success( $result );
- } else {
- wp_send_json_error( $result );
- }
-}
-
-// Register AJAX handler
-add_action( 'wp_ajax_code_snippets_switch_version', __NAMESPACE__ . '\\ajax_switch_version' );
-
-/**
- * Render refresh versions cache button
- *
- * @param array $args Field arguments
- */
-function render_refresh_versions_field( array $args ): void {
- ?>
-
-
-
-
__( 'You do not have permission to manage options.', 'code-snippets' ),
- ] );
- }
-
- // Clear the cache using our helper function
- delete_transient( VERSION_CACHE_KEY );
-
- // Fetch fresh data
- get_available_versions();
-
- wp_send_json_success( [
- 'message' => __( 'Available versions updated successfully.', 'code-snippets' ),
- ] );
-}
-
-// Register AJAX handler
-add_action( 'wp_ajax_code_snippets_refresh_versions', __NAMESPACE__ . '\\ajax_refresh_versions' );
-
-/**
- * Render the version switch warning that appears at the bottom
- * This should be called after all other version-related fields
- */
-function render_version_switch_warning(): void {
- ?>
-
-
Date: Thu, 16 Oct 2025 16:21:04 +0300
Subject: [PATCH 071/106] fix: notice styles
---
src/css/settings.scss | 36 +++++++++++++++++++-----------------
1 file changed, 19 insertions(+), 17 deletions(-)
diff --git a/src/css/settings.scss b/src/css/settings.scss
index fee9f64f..2ff6dc76 100644
--- a/src/css/settings.scss
+++ b/src/css/settings.scss
@@ -183,23 +183,25 @@ body.js {
}
}
- .notice {
- &.notice-success {
- border-left-color: #00a32a;
- }
-
- &.notice-error {
- border-left-color: #d63638;
- }
-
- &.notice-warning {
- border-left-color: #dba617;
- }
-
- &.notice-info {
- border-left-color: #72aee6;
- }
- }
+ .notice {
+ &.notice {
+ &-success {
+ border-left-color: #00a32a;
+ }
+
+ &-error {
+ border-left-color: #d63638;
+ }
+
+ &-warning {
+ border-left-color: #dba617;
+ }
+
+ &-info {
+ border-left-color: #72aee6;
+ }
+ }
+ }
}
.version-switch-settings {
From fe9754f1a327b41d84c48a53c9b8de7c96cfa806 Mon Sep 17 00:00:00 2001
From: code-snippets-bot <139164393+code-snippets-bot@users.noreply.github.com>
Date: Thu, 16 Oct 2025 17:08:54 +0000
Subject: [PATCH 072/106] chore(release): update changelog for v3.7.1-beta.1
---
CHANGELOG.md | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b058eab1..4da338bc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+
+## [3.7.1-beta.1] - 2025-10-16
+
+### Changed
+* 54 files modified across 140 commits
+* 19 PHP files updated
+* 13 JavaScript files updated
+
## 3.7.1 ([unreleased])
### Fixed
From 4c174da20cbf2a8a5df5c6dce4d75b89924d04e7 Mon Sep 17 00:00:00 2001
From: code-snippets-bot <139164393+code-snippets-bot@users.noreply.github.com>
Date: Thu, 16 Oct 2025 17:08:54 +0000
Subject: [PATCH 073/106] chore(release): update readme for v3.7.1-beta.1
---
src/readme.txt | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/readme.txt b/src/readme.txt
index ac8d5a2a..50b0444f 100644
--- a/src/readme.txt
+++ b/src/readme.txt
@@ -104,6 +104,12 @@ You can report security bugs found in the source code of this plugin through the
== Changelog ==
+
+= 3.7.1-beta.1 2025-10-16 =
+
+__Changed__
+* 54 files modified across 140 commits
+
= 3.7.0 (beta release) =
__Added__
From 984912866efa926ba8498f006ec23785ae9926ff Mon Sep 17 00:00:00 2001
From: code-snippets-bot <139164393+code-snippets-bot@users.noreply.github.com>
Date: Thu, 16 Oct 2025 17:09:32 +0000
Subject: [PATCH 074/106] chore(release): bump version to v3.7.1-beta.1
---
package-lock.json | 4 ++--
package.json | 2 +-
src/code-snippets.php | 6 +++---
src/readme.txt | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 000857bc..c159d714 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "code-snippets",
- "version": "3.7.0",
+ "version": "3.7.1-beta.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "code-snippets",
- "version": "3.7.0",
+ "version": "3.7.1-beta.1",
"license": "GPL-2.0-or-later",
"dependencies": {
"@codemirror/fold": "^0.19.4",
diff --git a/package.json b/package.json
index 5269b101..94b9eadd 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "code-snippets",
"description": "Manage code snippets running on a WordPress-powered site through a graphical interface.",
"homepage": "https://codesnippets.pro",
- "version": "3.7.0",
+ "version": "3.7.1-beta.1",
"main": "src/dist/edit.js",
"directories": {
"test": "tests"
diff --git a/src/code-snippets.php b/src/code-snippets.php
index d5a7ce77..0ed00973 100644
--- a/src/code-snippets.php
+++ b/src/code-snippets.php
@@ -8,11 +8,11 @@
* License: GPL-2.0-or-later
* License URI: license.txt
* Text Domain: code-snippets
- * Version: 3.7.0
+ * Version: 3.7.1-beta.1-beta.1
* Requires PHP: 7.4
* Requires at least: 5.0
*
- * @version 3.7.0
+ * @version 3.7.1-beta.1
* @package Code_Snippets
* @author Shea Bunge
* @copyright 2012-2024 Code Snippets Pro
@@ -37,7 +37,7 @@
*
* @const string
*/
- define( 'CODE_SNIPPETS_VERSION', '3.7.0' );
+ define( 'CODE_SNIPPETS_VERSION', '3.7.1-beta.1' );
/**
* The full path to the main file of this plugin.
diff --git a/src/readme.txt b/src/readme.txt
index 50b0444f..cb5aedf3 100644
--- a/src/readme.txt
+++ b/src/readme.txt
@@ -4,7 +4,7 @@ Donate link: https://codesnippets.pro
Tags: code, snippets, multisite, php, css
License: GPL-2.0-or-later
License URI: license.txt
-Stable tag: 3.7.0
+Stable tag: 3.7.1-beta.1
Tested up to: 6.8.2
An easy, clean and simple way to enhance your site with code snippets.
From ccfedd1a316150a3ea193ebd182cb3d53b8d707b Mon Sep 17 00:00:00 2001
From: Code Snippets <139164393+code-snippets-bot@users.noreply.github.com>
Date: Thu, 16 Oct 2025 20:37:37 +0300
Subject: [PATCH 075/106] fix: changelog
---
CHANGELOG.md | 8 --------
src/readme.txt | 6 ------
2 files changed, 14 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4da338bc..b058eab1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,13 +1,5 @@
# Changelog
-
-## [3.7.1-beta.1] - 2025-10-16
-
-### Changed
-* 54 files modified across 140 commits
-* 19 PHP files updated
-* 13 JavaScript files updated
-
## 3.7.1 ([unreleased])
### Fixed
diff --git a/src/readme.txt b/src/readme.txt
index cb5aedf3..1f7e464b 100644
--- a/src/readme.txt
+++ b/src/readme.txt
@@ -104,12 +104,6 @@ You can report security bugs found in the source code of this plugin through the
== Changelog ==
-
-= 3.7.1-beta.1 2025-10-16 =
-
-__Changed__
-* 54 files modified across 140 commits
-
= 3.7.0 (beta release) =
__Added__
From 7a5b4c8c31362483b02b7788d5d0d28b6d8fe689 Mon Sep 17 00:00:00 2001
From: code-snippets-bot <139164393+code-snippets-bot@users.noreply.github.com>
Date: Thu, 16 Oct 2025 17:57:12 +0000
Subject: [PATCH 076/106] chore(release): update changelog for v3.7.1-beta.1
---
CHANGELOG.md | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b058eab1..fbe808d1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,19 @@
# Changelog
+
+## [3.7.1-beta.1] - 2025-10-16
+
+### Added
+* Optional flat-file storage mode for snippets with HTML/PHP handlers and a file-based repository, configurable in settings with uninstall cleanup.
+* Added Carolina and Louis as plugin contributors (visible in plugin metadata/readme).
+
+### Changed
+* Minor UI/UX tweaks to the editor form and sidebar; improved editor preview behavior.
+
+### Fixed
+* Improved reliability of snippet evaluation and front-end integration.
+* Stabilized release/version automation (prepare-tag, changelog job, version regex/outputs).
+
## 3.7.1 ([unreleased])
### Fixed
From 50c8cbc63b9bc03ca36434b7b36eb884534da54f Mon Sep 17 00:00:00 2001
From: code-snippets-bot <139164393+code-snippets-bot@users.noreply.github.com>
Date: Thu, 16 Oct 2025 17:57:12 +0000
Subject: [PATCH 077/106] chore(release): update readme for v3.7.1-beta.1
---
src/readme.txt | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/src/readme.txt b/src/readme.txt
index 1f7e464b..5062f67c 100644
--- a/src/readme.txt
+++ b/src/readme.txt
@@ -104,6 +104,20 @@ You can report security bugs found in the source code of this plugin through the
== Changelog ==
+
+= 3.7.1-beta.1 2025-10-16 =
+
+__Added__
+* Optional flat-file storage mode for snippets with HTML/PHP handlers and a file-based repository, configurable in settings with uninstall cleanup.
+* Added Carolina and Louis as plugin contributors (visible in plugin metadata/readme).
+
+__Changed__
+* Minor UI/UX tweaks to the editor form and sidebar; improved editor preview behavior.
+
+__Fixed__
+* Improved reliability of snippet evaluation and front-end integration.
+* Stabilized release/version automation (prepare-tag, changelog job, version regex/outputs).
+
= 3.7.0 (beta release) =
__Added__
From 19b53ef79954591c7c42609f2b79496c8da819a1 Mon Sep 17 00:00:00 2001
From: Code Snippets <139164393+code-snippets-bot@users.noreply.github.com>
Date: Thu, 16 Oct 2025 21:13:24 +0300
Subject: [PATCH 078/106] fix: changelog
---
CHANGELOG.md | 16 +++++++---------
src/readme.txt | 24 ++++++++++++++++++------
2 files changed, 25 insertions(+), 15 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fbe808d1..d1114e26 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,22 +1,20 @@
# Changelog
-## [3.7.1-beta.1] - 2025-10-16
+## [3.7.1-beta.1] (2025-10-16)
### Added
-* Optional flat-file storage mode for snippets with HTML/PHP handlers and a file-based repository, configurable in settings with uninstall cleanup.
-* Added Carolina and Louis as plugin contributors (visible in plugin metadata/readme).
+* Added @CarolinaOP and @louiswol94 as plugin contributors
+* File-based execution mode for snippets (Optional)
+* Playwright integration for automated testing
+* Support for Composer package prefixing to prevent conflicts
### Changed
-* Minor UI/UX tweaks to the editor form and sidebar; improved editor preview behavior.
+* Minor UI/UX tweaks to the editor form and sidebar
+* Improved editor preview behavior.
### Fixed
* Improved reliability of snippet evaluation and front-end integration.
-* Stabilized release/version automation (prepare-tag, changelog job, version regex/outputs).
-
-## 3.7.1 ([unreleased])
-
-### Fixed
* Prefixed Composer packages to reduce collisions with other plugins, especially those using Guzzle.
* Functions conditions were loading before loop setup, resulting in some conditions not working. (PRO)
* JavaScript and CSS snippets loading twice due to a conditions bug. (PRO)
diff --git a/src/readme.txt b/src/readme.txt
index 5062f67c..33cd55d4 100644
--- a/src/readme.txt
+++ b/src/readme.txt
@@ -104,21 +104,33 @@ You can report security bugs found in the source code of this plugin through the
== Changelog ==
+= 3.7.1-beta.1 (2025-10-16) =
-= 3.7.1-beta.1 2025-10-16 =
__Added__
-* Optional flat-file storage mode for snippets with HTML/PHP handlers and a file-based repository, configurable in settings with uninstall cleanup.
-* Added Carolina and Louis as plugin contributors (visible in plugin metadata/readme).
+
+* Added @CarolinaOP and @louiswol94 as plugin contributors
+* File-based execution mode for snippets (Optional)
+* Playwright integration for automated testing
+* Support for Composer package prefixing to prevent conflicts
__Changed__
-* Minor UI/UX tweaks to the editor form and sidebar; improved editor preview behavior.
+
+* Minor UI/UX tweaks to the editor form and sidebar
+* Improved editor preview behavior.
__Fixed__
+
* Improved reliability of snippet evaluation and front-end integration.
-* Stabilized release/version automation (prepare-tag, changelog job, version regex/outputs).
+* Prefixed Composer packages to reduce collisions with other plugins, especially those using Guzzle.
+* Functions conditions were loading before loop setup, resulting in some conditions not working. (PRO)
+* JavaScript and CSS snippets loading twice due to a conditions bug. (PRO)
+
+__Removed__
+
+* Removed CSS linting within the editor until a modern replacement can be implemented.
-= 3.7.0 (beta release) =
+= 3.7.0 (2025-08-29) =
__Added__
From 66543b85df3acb7acdd0f50ec76801d24d263863 Mon Sep 17 00:00:00 2001
From: Imants
Date: Thu, 16 Oct 2025 21:40:33 +0300
Subject: [PATCH 079/106] fix: changelog
---
CHANGELOG.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d1114e26..dd5570ab 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,7 @@
### Added
* Added @CarolinaOP and @louiswol94 as plugin contributors
-* File-based execution mode for snippets (Optional)
+* File-based execution mode for snippets (Activate in Plugin Settings)
* Playwright integration for automated testing
* Support for Composer package prefixing to prevent conflicts
From e78d6643fba5177a2f76e26210320e52debbebfa Mon Sep 17 00:00:00 2001
From: Imants
Date: Thu, 16 Oct 2025 22:01:28 +0300
Subject: [PATCH 080/106] fix: changelog
---
src/readme.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/readme.txt b/src/readme.txt
index 33cd55d4..05389b2a 100644
--- a/src/readme.txt
+++ b/src/readme.txt
@@ -110,7 +110,7 @@ You can report security bugs found in the source code of this plugin through the
__Added__
* Added @CarolinaOP and @louiswol94 as plugin contributors
-* File-based execution mode for snippets (Optional)
+* File-based execution mode for snippets (Activate in Plugin Settings)
* Playwright integration for automated testing
* Support for Composer package prefixing to prevent conflicts
From e39cb344ae2cad58960812d3b2d1463d5fe2c0e5 Mon Sep 17 00:00:00 2001
From: Imants
Date: Tue, 21 Oct 2025 17:06:11 +0300
Subject: [PATCH 081/106] fix: correct version number in plugin header
---
src/code-snippets.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/code-snippets.php b/src/code-snippets.php
index 0ed00973..5c4ef911 100644
--- a/src/code-snippets.php
+++ b/src/code-snippets.php
@@ -8,7 +8,7 @@
* License: GPL-2.0-or-later
* License URI: license.txt
* Text Domain: code-snippets
- * Version: 3.7.1-beta.1-beta.1
+ * Version: 3.7.1-beta.1
* Requires PHP: 7.4
* Requires at least: 5.0
*
From a698ecc8266729ee7d4f8447bfcea47b3d3f5279 Mon Sep 17 00:00:00 2001
From: code-snippets-bot <139164393+code-snippets-bot@users.noreply.github.com>
Date: Tue, 21 Oct 2025 14:33:24 +0000
Subject: [PATCH 082/106] chore(release): bump version to v3.7.1-beta.1
---
src/code-snippets.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/code-snippets.php b/src/code-snippets.php
index 5c4ef911..0ed00973 100644
--- a/src/code-snippets.php
+++ b/src/code-snippets.php
@@ -8,7 +8,7 @@
* License: GPL-2.0-or-later
* License URI: license.txt
* Text Domain: code-snippets
- * Version: 3.7.1-beta.1
+ * Version: 3.7.1-beta.1-beta.1
* Requires PHP: 7.4
* Requires at least: 5.0
*
From e86b599ea57d536737c88755abdf817c92a3ff5a Mon Sep 17 00:00:00 2001
From: Imants
Date: Tue, 21 Oct 2025 17:34:30 +0300
Subject: [PATCH 083/106] fix: version nr
---
src/code-snippets.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/code-snippets.php b/src/code-snippets.php
index 0ed00973..5c4ef911 100644
--- a/src/code-snippets.php
+++ b/src/code-snippets.php
@@ -8,7 +8,7 @@
* License: GPL-2.0-or-later
* License URI: license.txt
* Text Domain: code-snippets
- * Version: 3.7.1-beta.1-beta.1
+ * Version: 3.7.1-beta.1
* Requires PHP: 7.4
* Requires at least: 5.0
*
From 7bd15a02e717e7a01a682fb44dd7dd7c31c395da Mon Sep 17 00:00:00 2001
From: Imants
Date: Tue, 21 Oct 2025 17:35:39 +0300
Subject: [PATCH 084/106] fix: double empty line
---
src/readme.txt | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/readme.txt b/src/readme.txt
index 05389b2a..bb6fd98d 100644
--- a/src/readme.txt
+++ b/src/readme.txt
@@ -106,7 +106,6 @@ You can report security bugs found in the source code of this plugin through the
= 3.7.1-beta.1 (2025-10-16) =
-
__Added__
* Added @CarolinaOP and @louiswol94 as plugin contributors
From 80e3118f936edac5404254afd6b3443f5b731933 Mon Sep 17 00:00:00 2001
From: Imants
Date: Tue, 21 Oct 2025 17:37:47 +0300
Subject: [PATCH 085/106] fix: changelog
---
CHANGELOG.md | 4 +---
src/readme.txt | 4 +---
2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dd5570ab..33780035 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,9 +5,7 @@
### Added
* Added @CarolinaOP and @louiswol94 as plugin contributors
-* File-based execution mode for snippets (Activate in Plugin Settings)
-* Playwright integration for automated testing
-* Support for Composer package prefixing to prevent conflicts
+* File-based execution mode for snippets (Optional in Plugin Settings)
### Changed
* Minor UI/UX tweaks to the editor form and sidebar
diff --git a/src/readme.txt b/src/readme.txt
index bb6fd98d..09f08d38 100644
--- a/src/readme.txt
+++ b/src/readme.txt
@@ -109,9 +109,7 @@ You can report security bugs found in the source code of this plugin through the
__Added__
* Added @CarolinaOP and @louiswol94 as plugin contributors
-* File-based execution mode for snippets (Activate in Plugin Settings)
-* Playwright integration for automated testing
-* Support for Composer package prefixing to prevent conflicts
+* File-based execution mode for snippets (Optional in Plugin Settings)
__Changed__
From 8ca4a1b98f620660f528bb4891e627d6ee170fee Mon Sep 17 00:00:00 2001
From: Imants
Date: Wed, 22 Oct 2025 10:17:57 +0300
Subject: [PATCH 086/106] fix: revert stable tag to 3.7.0
---
src/readme.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/readme.txt b/src/readme.txt
index 09f08d38..bdc8a70f 100644
--- a/src/readme.txt
+++ b/src/readme.txt
@@ -4,7 +4,7 @@ Donate link: https://codesnippets.pro
Tags: code, snippets, multisite, php, css
License: GPL-2.0-or-later
License URI: license.txt
-Stable tag: 3.7.1-beta.1
+Stable tag: 3.7.0
Tested up to: 6.8.2
An easy, clean and simple way to enhance your site with code snippets.
From 173085403e6335500c71b1c980634172e4619a14 Mon Sep 17 00:00:00 2001
From: Imants
Date: Wed, 22 Oct 2025 10:18:26 +0300
Subject: [PATCH 087/106] fix: conditionally update stable tag based on version
type
---
scripts/version.ts | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/scripts/version.ts b/scripts/version.ts
index a1716184..c5b70e01 100644
--- a/scripts/version.ts
+++ b/scripts/version.ts
@@ -15,8 +15,10 @@ replaceInFile(
.replace(/(?'CODE_SNIPPETS_VERSION',\s+)'[\w-.]+'/, `$1'${plugin.version}'`)
)
-replaceInFile(
- 'src/readme.txt',
- contents => contents
- .replace(/(?Stable tag:\s+|@version\s+)\d+\.\d+[\w-.]+$/mg, `$1${plugin.version}`)
-)
+if (!/beta/i.test(plugin.version)) {
+ replaceInFile(
+ 'src/readme.txt',
+ contents => contents
+ .replace(/(?Stable tag:\s+|@version\s+)\d+\.\d+[\w-.]+$/mg, `$1${plugin.version}`)
+ )
+}
From cad388876168497741297a0d83c7677fb76d80d7 Mon Sep 17 00:00:00 2001
From: code-snippets-bot <139164393+code-snippets-bot@users.noreply.github.com>
Date: Wed, 22 Oct 2025 07:30:18 +0000
Subject: [PATCH 088/106] chore(release): bump version to v3.7.1-beta.1
---
src/code-snippets.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/code-snippets.php b/src/code-snippets.php
index 5c4ef911..0ed00973 100644
--- a/src/code-snippets.php
+++ b/src/code-snippets.php
@@ -8,7 +8,7 @@
* License: GPL-2.0-or-later
* License URI: license.txt
* Text Domain: code-snippets
- * Version: 3.7.1-beta.1
+ * Version: 3.7.1-beta.1-beta.1
* Requires PHP: 7.4
* Requires at least: 5.0
*
From 55335e032d6a3b9d093f93eacb47e51763db14c3 Mon Sep 17 00:00:00 2001
From: Imants
Date: Wed, 22 Oct 2025 10:33:42 +0300
Subject: [PATCH 089/106] fix: version nr
---
src/code-snippets.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/code-snippets.php b/src/code-snippets.php
index 0ed00973..5c4ef911 100644
--- a/src/code-snippets.php
+++ b/src/code-snippets.php
@@ -8,7 +8,7 @@
* License: GPL-2.0-or-later
* License URI: license.txt
* Text Domain: code-snippets
- * Version: 3.7.1-beta.1-beta.1
+ * Version: 3.7.1-beta.1
* Requires PHP: 7.4
* Requires at least: 5.0
*
From 54fd5bdfdc6d875a14cfba404d991a7586389c4d Mon Sep 17 00:00:00 2001
From: code-snippets-bot <139164393+code-snippets-bot@users.noreply.github.com>
Date: Wed, 22 Oct 2025 07:46:15 +0000
Subject: [PATCH 090/106] chore(release): update changelog for v3.7.1-beta.2
---
CHANGELOG.md | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 33780035..2d8516e8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,21 @@
# Changelog
+
+## [3.7.1-beta.2] (2025-10-22)
+
+### Added
+* Implemented version switching with a new 'Version Switch' section in Settings
+* Added warning and confirmation UI with styled notices and button state management
+
+### Changed
+* Improved error handling and user feedback during version switching
+* Refined button and notice styling for clearer status visibility
+
+### Fixed
+* Fixed admin notice styles to align with WordPress notice behavior
+* Stabilized version switching by moving to a class-based integration and resolving related JS issues
+
## [3.7.1-beta.1] (2025-10-16)
### Added
From 5186122509642e81ac4433c775fa0a598dac81e5 Mon Sep 17 00:00:00 2001
From: code-snippets-bot <139164393+code-snippets-bot@users.noreply.github.com>
Date: Wed, 22 Oct 2025 07:46:15 +0000
Subject: [PATCH 091/106] chore(release): update readme for v3.7.1-beta.2
---
src/readme.txt | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/src/readme.txt b/src/readme.txt
index bdc8a70f..0d1f0178 100644
--- a/src/readme.txt
+++ b/src/readme.txt
@@ -104,6 +104,24 @@ You can report security bugs found in the source code of this plugin through the
== Changelog ==
+
+= 3.7.1-beta.2 (2025-10-22) =
+
+__Added__
+
+* Implemented version switching with a new 'Version Switch' section in Settings
+* Added warning and confirmation UI with styled notices and button state management
+
+__Changed__
+
+* Improved error handling and user feedback during version switching
+* Refined button and notice styling for clearer status visibility
+
+__Fixed__
+
+* Fixed admin notice styles to align with WordPress notice behavior
+* Stabilized version switching by moving to a class-based integration and resolving related JS issues
+
= 3.7.1-beta.1 (2025-10-16) =
__Added__
From 5a0c342fe020697fffaecb9b1cf7ea0ba0fa19e5 Mon Sep 17 00:00:00 2001
From: code-snippets-bot <139164393+code-snippets-bot@users.noreply.github.com>
Date: Wed, 22 Oct 2025 07:46:55 +0000
Subject: [PATCH 092/106] chore(release): bump version to v3.7.1-beta.2
---
package-lock.json | 4 ++--
package.json | 2 +-
src/code-snippets.php | 6 +++---
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index c159d714..a6ff81b7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "code-snippets",
- "version": "3.7.1-beta.1",
+ "version": "3.7.1-beta.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "code-snippets",
- "version": "3.7.1-beta.1",
+ "version": "3.7.1-beta.2",
"license": "GPL-2.0-or-later",
"dependencies": {
"@codemirror/fold": "^0.19.4",
diff --git a/package.json b/package.json
index 94b9eadd..63237fe4 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "code-snippets",
"description": "Manage code snippets running on a WordPress-powered site through a graphical interface.",
"homepage": "https://codesnippets.pro",
- "version": "3.7.1-beta.1",
+ "version": "3.7.1-beta.2",
"main": "src/dist/edit.js",
"directories": {
"test": "tests"
diff --git a/src/code-snippets.php b/src/code-snippets.php
index 5c4ef911..6ea2edc4 100644
--- a/src/code-snippets.php
+++ b/src/code-snippets.php
@@ -8,11 +8,11 @@
* License: GPL-2.0-or-later
* License URI: license.txt
* Text Domain: code-snippets
- * Version: 3.7.1-beta.1
+ * Version: 3.7.1-beta.2-beta.2
* Requires PHP: 7.4
* Requires at least: 5.0
*
- * @version 3.7.1-beta.1
+ * @version 3.7.1-beta.2
* @package Code_Snippets
* @author Shea Bunge
* @copyright 2012-2024 Code Snippets Pro
@@ -37,7 +37,7 @@
*
* @const string
*/
- define( 'CODE_SNIPPETS_VERSION', '3.7.1-beta.1' );
+ define( 'CODE_SNIPPETS_VERSION', '3.7.1-beta.2' );
/**
* The full path to the main file of this plugin.
From 9c468a34bf22ba93d6e9ab16d245a49362460a99 Mon Sep 17 00:00:00 2001
From: Imants
Date: Wed, 22 Oct 2025 10:57:24 +0300
Subject: [PATCH 093/106] fix: changelog
---
CHANGELOG.md | 9 ---------
src/readme.txt | 11 -----------
2 files changed, 20 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2d8516e8..7b12e762 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,15 +6,6 @@
### Added
* Implemented version switching with a new 'Version Switch' section in Settings
-* Added warning and confirmation UI with styled notices and button state management
-
-### Changed
-* Improved error handling and user feedback during version switching
-* Refined button and notice styling for clearer status visibility
-
-### Fixed
-* Fixed admin notice styles to align with WordPress notice behavior
-* Stabilized version switching by moving to a class-based integration and resolving related JS issues
## [3.7.1-beta.1] (2025-10-16)
diff --git a/src/readme.txt b/src/readme.txt
index 0d1f0178..b5b0bf43 100644
--- a/src/readme.txt
+++ b/src/readme.txt
@@ -110,17 +110,6 @@ You can report security bugs found in the source code of this plugin through the
__Added__
* Implemented version switching with a new 'Version Switch' section in Settings
-* Added warning and confirmation UI with styled notices and button state management
-
-__Changed__
-
-* Improved error handling and user feedback during version switching
-* Refined button and notice styling for clearer status visibility
-
-__Fixed__
-
-* Fixed admin notice styles to align with WordPress notice behavior
-* Stabilized version switching by moving to a class-based integration and resolving related JS issues
= 3.7.1-beta.1 (2025-10-16) =
From 449b0da3c26f565c45a4205d0f284e4d03b68862 Mon Sep 17 00:00:00 2001
From: Imants
Date: Wed, 22 Oct 2025 10:58:19 +0300
Subject: [PATCH 094/106] fix: version
---
src/code-snippets.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/code-snippets.php b/src/code-snippets.php
index 6ea2edc4..abcf2270 100644
--- a/src/code-snippets.php
+++ b/src/code-snippets.php
@@ -8,7 +8,7 @@
* License: GPL-2.0-or-later
* License URI: license.txt
* Text Domain: code-snippets
- * Version: 3.7.1-beta.2-beta.2
+ * Version: 3.7.1-beta.2
* Requires PHP: 7.4
* Requires at least: 5.0
*
From 502965d6b73492ceea2ffb00b55b90d9330cd1ba Mon Sep 17 00:00:00 2001
From: Imants
Date: Wed, 22 Oct 2025 13:18:37 +0300
Subject: [PATCH 095/106] test: add REST API pagination test for snippets
---
tests/phpunit/test-rest-api.php | 46 +++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 tests/phpunit/test-rest-api.php
diff --git a/tests/phpunit/test-rest-api.php b/tests/phpunit/test-rest-api.php
new file mode 100644
index 00000000..80f11300
--- /dev/null
+++ b/tests/phpunit/test-rest-api.php
@@ -0,0 +1,46 @@
+name = "Snippet $i";
+ $snippet->code = "// code $i";
+ $result = \Code_Snippets\save_snippet( $snippet );
+ $this->assertNotNull( $result );
+ $created_ids[] = $result->id;
+ }
+
+ // Request page 1 with per_page=10
+ $request1 = new WP_REST_Request( 'GET', '/code-snippets/v1/snippets' );
+ $request1->set_param( 'per_page', 10 );
+ $request1->set_param( 'page', 1 );
+ $response1 = rest_get_server()->dispatch( $request1 );
+ $this->assertEquals( 200, $response1->get_status() );
+ $data1 = $response1->get_data();
+ $this->assertCount( 10, $data1 );
+
+ // Request page 2 with per_page=10
+ $request2 = new WP_REST_Request( 'GET', '/code-snippets/v1/snippets' );
+ $request2->set_param( 'per_page', 10 );
+ $request2->set_param( 'page', 2 );
+ $response2 = rest_get_server()->dispatch( $request2 );
+ $this->assertEquals( 200, $response2->get_status() );
+ $data2 = $response2->get_data();
+
+ // Ensure page 2 has the remaining items and is different from page 1
+ $this->assertGreaterThanOrEqual( 1, count( $data2 ) );
+ $this->assertNotEquals( $data1, $data2 );
+
+ // Check pagination headers
+ $this->assertEquals( '15', $response1->get_headers()['X-WP-Total'] );
+ $this->assertEquals( '2', $response1->get_headers()['X-WP-TotalPages'] );
+ }
+}
From fb9de70d656176be7717d4b5e8a69635850f8cc9 Mon Sep 17 00:00:00 2001
From: Imants
Date: Wed, 22 Oct 2025 13:18:51 +0300
Subject: [PATCH 096/106] fix: pagination support to snippets REST API endpoint
---
.../class-snippets-rest-controller.php | 40 +++++++++++++++++--
1 file changed, 36 insertions(+), 4 deletions(-)
diff --git a/src/php/rest-api/class-snippets-rest-controller.php b/src/php/rest-api/class-snippets-rest-controller.php
index 18a1f827..49fbe59d 100644
--- a/src/php/rest-api/class-snippets-rest-controller.php
+++ b/src/php/rest-api/class-snippets-rest-controller.php
@@ -80,6 +80,9 @@ public function register_routes() {
[ 'network' ]
);
+ // Allow standard collection parameters (page, per_page, etc.) on the collection route.
+ $collection_args = array_merge( $network_args, $this->get_collection_params() );
+
register_rest_route(
$this->namespace,
$route,
@@ -88,7 +91,7 @@ public function register_routes() {
'methods' => WP_REST_Server::READABLE,
'callback' => [ $this, 'get_items' ],
'permission_callback' => [ $this, 'get_items_permissions_check' ],
- 'args' => $network_args,
+ 'args' => $collection_args,
],
[
'methods' => WP_REST_Server::CREATABLE,
@@ -193,15 +196,44 @@ public function register_routes() {
* @return WP_REST_Response Response object on success.
*/
public function get_items( $request ): WP_REST_Response {
- $snippets = get_snippets();
- $snippets_data = [];
+ // Respect the optional 'network' param when fetching snippets.
+ $network = $request->get_param( 'network' );
+ $all_snippets = get_snippets( [], $network );
+
+ // Collection params (page, per_page) are provided via route args. Use defaults
+ // from get_collection_params() when not present on the request.
+ $collection_params = $this->get_collection_params();
+ $per_page = (int) $request->get_param( 'per_page' );
+ if ( ! $per_page ) {
+ $per_page = isset( $collection_params['per_page']['default'] ) ? (int) $collection_params['per_page']['default'] : 10;
+ }
+ $per_page = max( 1, $per_page );
+
+ $page = (int) $request->get_param( 'page' );
+ if ( ! $page ) {
+ $page = isset( $collection_params['page']['default'] ) ? (int) $collection_params['page']['default'] : 1;
+ }
+ $page = max( 1, $page );
+
+ $total_items = count( $all_snippets );
+ $total_pages = (int) ceil( $total_items / $per_page );
+
+ // Slice the full list to the requested page.
+ $offset = ( $page - 1 ) * $per_page;
+ $snippets = array_slice( $all_snippets, $offset, $per_page );
+ $snippets_data = [];
foreach ( $snippets as $snippet ) {
$snippet_data = $this->prepare_item_for_response( $snippet, $request );
$snippets_data[] = $this->prepare_response_for_collection( $snippet_data );
}
- return rest_ensure_response( $snippets_data );
+ $response = rest_ensure_response( $snippets_data );
+ // Provide total counts in the response headers like WP core REST responses do.
+ $response->header( 'X-WP-Total', (string) $total_items );
+ $response->header( 'X-WP-TotalPages', (string) $total_pages );
+
+ return $response;
}
/**
From 811be0bea73d4274fe8ac717bb87a3015ebd6b24 Mon Sep 17 00:00:00 2001
From: Imants
Date: Wed, 22 Oct 2025 13:24:52 +0300
Subject: [PATCH 097/106] fix: stylelint
---
src/css/settings.scss | 40 ++++++++++++++++++++--------------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/src/css/settings.scss b/src/css/settings.scss
index 2ff6dc76..e2a040ae 100644
--- a/src/css/settings.scss
+++ b/src/css/settings.scss
@@ -142,7 +142,7 @@ body.js {
}
#target_version {
- min-width: 200px;
+ min-inline-size: 200px;
margin-inline-start: 8px;
}
@@ -158,9 +158,9 @@ body.js {
// Warning box styling
#version-switch-warning {
- margin-top: 20px !important;
+ margin-block-start: 20px !important;
padding: 12px 16px;
- border-left: 4px solid #dba617;
+ border-inline-start: 4px solid #dba617;
background: #fff8e5;
border-radius: 4px;
@@ -183,31 +183,31 @@ body.js {
}
}
- .notice {
- &.notice {
- &-success {
- border-left-color: #00a32a;
- }
+ .notice {
+ &.notice {
+ &-success {
+ border-inline-start-color: #00a32a;
+ }
- &-error {
- border-left-color: #d63638;
- }
+ &-error {
+ border-inline-start-color: #d63638;
+ }
- &-warning {
- border-left-color: #dba617;
- }
+ &-warning {
+ border-inline-start-color: #dba617;
+ }
- &-info {
- border-left-color: #72aee6;
- }
- }
- }
+ &-info {
+ border-inline-start-color: #72aee6;
+ }
+ }
+ }
}
.version-switch-settings {
.form-table {
th {
- width: 180px;
+ inline-size: 180px;
}
}
}
From df8af7b3ad9fd678c0a57a342e86ac3aab2d99cf Mon Sep 17 00:00:00 2001
From: Imants
Date: Wed, 22 Oct 2025 15:10:14 +0300
Subject: [PATCH 098/106] fix: get_items method to support pagination
---
src/php/rest-api/class-snippets-rest-controller.php | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/src/php/rest-api/class-snippets-rest-controller.php b/src/php/rest-api/class-snippets-rest-controller.php
index 49fbe59d..25b6ccdc 100644
--- a/src/php/rest-api/class-snippets-rest-controller.php
+++ b/src/php/rest-api/class-snippets-rest-controller.php
@@ -189,19 +189,17 @@ public function register_routes() {
}
/**
- * Retrieves a collection of snippets.
+ * Retrieves a collection of snippets, with pagination.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response Response object on success.
*/
public function get_items( $request ): WP_REST_Response {
- // Respect the optional 'network' param when fetching snippets.
$network = $request->get_param( 'network' );
$all_snippets = get_snippets( [], $network );
- // Collection params (page, per_page) are provided via route args. Use defaults
- // from get_collection_params() when not present on the request.
+ // Collection params (page, per_page)
$collection_params = $this->get_collection_params();
$per_page = (int) $request->get_param( 'per_page' );
if ( ! $per_page ) {
@@ -229,7 +227,6 @@ public function get_items( $request ): WP_REST_Response {
}
$response = rest_ensure_response( $snippets_data );
- // Provide total counts in the response headers like WP core REST responses do.
$response->header( 'X-WP-Total', (string) $total_items );
$response->header( 'X-WP-TotalPages', (string) $total_pages );
From 93c700a1df02a077103035a007ad881c675688a6 Mon Sep 17 00:00:00 2001
From: Imants
Date: Wed, 22 Oct 2025 15:20:30 +0300
Subject: [PATCH 099/106] fix: remove unused file
---
tests/phpunit/test-rest-api.php | 46 ---------------------------------
1 file changed, 46 deletions(-)
delete mode 100644 tests/phpunit/test-rest-api.php
diff --git a/tests/phpunit/test-rest-api.php b/tests/phpunit/test-rest-api.php
deleted file mode 100644
index 80f11300..00000000
--- a/tests/phpunit/test-rest-api.php
+++ /dev/null
@@ -1,46 +0,0 @@
-name = "Snippet $i";
- $snippet->code = "// code $i";
- $result = \Code_Snippets\save_snippet( $snippet );
- $this->assertNotNull( $result );
- $created_ids[] = $result->id;
- }
-
- // Request page 1 with per_page=10
- $request1 = new WP_REST_Request( 'GET', '/code-snippets/v1/snippets' );
- $request1->set_param( 'per_page', 10 );
- $request1->set_param( 'page', 1 );
- $response1 = rest_get_server()->dispatch( $request1 );
- $this->assertEquals( 200, $response1->get_status() );
- $data1 = $response1->get_data();
- $this->assertCount( 10, $data1 );
-
- // Request page 2 with per_page=10
- $request2 = new WP_REST_Request( 'GET', '/code-snippets/v1/snippets' );
- $request2->set_param( 'per_page', 10 );
- $request2->set_param( 'page', 2 );
- $response2 = rest_get_server()->dispatch( $request2 );
- $this->assertEquals( 200, $response2->get_status() );
- $data2 = $response2->get_data();
-
- // Ensure page 2 has the remaining items and is different from page 1
- $this->assertGreaterThanOrEqual( 1, count( $data2 ) );
- $this->assertNotEquals( $data1, $data2 );
-
- // Check pagination headers
- $this->assertEquals( '15', $response1->get_headers()['X-WP-Total'] );
- $this->assertEquals( '2', $response1->get_headers()['X-WP-TotalPages'] );
- }
-}
From c0aa1a72ee843d9de02027aa2089077bba77066c Mon Sep 17 00:00:00 2001
From: Imants
Date: Wed, 22 Oct 2025 15:24:12 +0300
Subject: [PATCH 100/106] fix(copilot): comment style
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
src/php/rest-api/class-snippets-rest-controller.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/php/rest-api/class-snippets-rest-controller.php b/src/php/rest-api/class-snippets-rest-controller.php
index 25b6ccdc..d6a904f9 100644
--- a/src/php/rest-api/class-snippets-rest-controller.php
+++ b/src/php/rest-api/class-snippets-rest-controller.php
@@ -199,7 +199,7 @@ public function get_items( $request ): WP_REST_Response {
$network = $request->get_param( 'network' );
$all_snippets = get_snippets( [], $network );
- // Collection params (page, per_page)
+ // Collection params (page, per_page).
$collection_params = $this->get_collection_params();
$per_page = (int) $request->get_param( 'per_page' );
if ( ! $per_page ) {
From ff728863e39e54ad1838bc7679dec860fc7dd657 Mon Sep 17 00:00:00 2001
From: Imants
Date: Wed, 22 Oct 2025 15:39:22 +0300
Subject: [PATCH 101/106] fix: improve pagination
---
.../class-snippets-rest-controller.php | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/src/php/rest-api/class-snippets-rest-controller.php b/src/php/rest-api/class-snippets-rest-controller.php
index d6a904f9..6fe58ba9 100644
--- a/src/php/rest-api/class-snippets-rest-controller.php
+++ b/src/php/rest-api/class-snippets-rest-controller.php
@@ -199,20 +199,15 @@ public function get_items( $request ): WP_REST_Response {
$network = $request->get_param( 'network' );
$all_snippets = get_snippets( [], $network );
- // Collection params (page, per_page).
+ // Get collection params (page, per_page).
$collection_params = $this->get_collection_params();
- $per_page = (int) $request->get_param( 'per_page' );
- if ( ! $per_page ) {
- $per_page = isset( $collection_params['per_page']['default'] ) ? (int) $collection_params['per_page']['default'] : 10;
- }
- $per_page = max( 1, $per_page );
+ $per_page_request = (int) $request->get_param( 'per_page' );
+ $per_page = max( 1, $per_page_request ? $per_page_request : (int) $collection_params['per_page']['default'] );
- $page = (int) $request->get_param( 'page' );
- if ( ! $page ) {
- $page = isset( $collection_params['page']['default'] ) ? (int) $collection_params['page']['default'] : 1;
- }
- $page = max( 1, $page );
+ $page_request = (int) $request->get_param( 'page' );
+ $page = max( 1, $page_request ? $page_request : (int) $collection_params['page']['default'] );
+ // Count total items
$total_items = count( $all_snippets );
$total_pages = (int) ceil( $total_items / $per_page );
@@ -221,6 +216,7 @@ public function get_items( $request ): WP_REST_Response {
$snippets = array_slice( $all_snippets, $offset, $per_page );
$snippets_data = [];
+
foreach ( $snippets as $snippet ) {
$snippet_data = $this->prepare_item_for_response( $snippet, $request );
$snippets_data[] = $this->prepare_response_for_collection( $snippet_data );
From e38443222c26b850c47d8abd11bd037c176f7fb9 Mon Sep 17 00:00:00 2001
From: code-snippets-bot <139164393+code-snippets-bot@users.noreply.github.com>
Date: Wed, 22 Oct 2025 13:23:35 +0000
Subject: [PATCH 102/106] chore(release): update changelog for v3.7.1-beta.3
---
CHANGELOG.md | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7b12e762..2885abe9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,20 @@
+
+## [3.7.1-beta.3] (2025-10-22)
+
+### Added
+* Snippets REST API now supports pagination via page and per_page query parameters.
+* Collection responses include pagination metadata headers for total items and total pages.
+
+### Changed
+* Settings UI CSS switched to logical properties for better RTL support and consistent layout.
+
+### Fixed
+* Snippets REST API now correctly respects the network parameter when listing snippets.
+* Pagination logic corrected to reliably slice results and return stable pages.
+
## [3.7.1-beta.2] (2025-10-22)
### Added
From c7d9c1079faf17d9cb6c1a2cfba0db9b8d57da24 Mon Sep 17 00:00:00 2001
From: code-snippets-bot <139164393+code-snippets-bot@users.noreply.github.com>
Date: Wed, 22 Oct 2025 13:23:35 +0000
Subject: [PATCH 103/106] chore(release): update readme for v3.7.1-beta.3
---
src/readme.txt | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/src/readme.txt b/src/readme.txt
index b5b0bf43..55844435 100644
--- a/src/readme.txt
+++ b/src/readme.txt
@@ -105,6 +105,23 @@ You can report security bugs found in the source code of this plugin through the
== Changelog ==
+
+= 3.7.1-beta.3 (2025-10-22) =
+
+__Added__
+
+* Snippets REST API now supports pagination via page and per_page query parameters.
+* Collection responses include pagination metadata headers for total items and total pages.
+
+__Changed__
+
+* Settings UI CSS switched to logical properties for better RTL support and consistent layout.
+
+__Fixed__
+
+* Snippets REST API now correctly respects the network parameter when listing snippets.
+* Pagination logic corrected to reliably slice results and return stable pages.
+
= 3.7.1-beta.2 (2025-10-22) =
__Added__
From e1e12699647b87e817fd555bc72bdc5bc5617007 Mon Sep 17 00:00:00 2001
From: code-snippets-bot <139164393+code-snippets-bot@users.noreply.github.com>
Date: Wed, 22 Oct 2025 13:24:15 +0000
Subject: [PATCH 104/106] chore(release): bump version to v3.7.1-beta.3
---
package-lock.json | 4 ++--
package.json | 2 +-
src/code-snippets.php | 6 +++---
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index a6ff81b7..fe96a6f9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "code-snippets",
- "version": "3.7.1-beta.2",
+ "version": "3.7.1-beta.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "code-snippets",
- "version": "3.7.1-beta.2",
+ "version": "3.7.1-beta.3",
"license": "GPL-2.0-or-later",
"dependencies": {
"@codemirror/fold": "^0.19.4",
diff --git a/package.json b/package.json
index 63237fe4..8d664089 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "code-snippets",
"description": "Manage code snippets running on a WordPress-powered site through a graphical interface.",
"homepage": "https://codesnippets.pro",
- "version": "3.7.1-beta.2",
+ "version": "3.7.1-beta.3",
"main": "src/dist/edit.js",
"directories": {
"test": "tests"
diff --git a/src/code-snippets.php b/src/code-snippets.php
index abcf2270..9f7789c1 100644
--- a/src/code-snippets.php
+++ b/src/code-snippets.php
@@ -8,11 +8,11 @@
* License: GPL-2.0-or-later
* License URI: license.txt
* Text Domain: code-snippets
- * Version: 3.7.1-beta.2
+ * Version: 3.7.1-beta.3-beta.3
* Requires PHP: 7.4
* Requires at least: 5.0
*
- * @version 3.7.1-beta.2
+ * @version 3.7.1-beta.3
* @package Code_Snippets
* @author Shea Bunge
* @copyright 2012-2024 Code Snippets Pro
@@ -37,7 +37,7 @@
*
* @const string
*/
- define( 'CODE_SNIPPETS_VERSION', '3.7.1-beta.2' );
+ define( 'CODE_SNIPPETS_VERSION', '3.7.1-beta.3' );
/**
* The full path to the main file of this plugin.
From 27a80f2edb01c34f79eca51cede8fb75e7c9c08e Mon Sep 17 00:00:00 2001
From: Imants
Date: Wed, 22 Oct 2025 16:27:47 +0300
Subject: [PATCH 105/106] fix: changelog
---
CHANGELOG.md | 7 -------
src/readme.txt | 9 ---------
2 files changed, 16 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2885abe9..5a333535 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,14 +7,7 @@
### Added
* Snippets REST API now supports pagination via page and per_page query parameters.
-* Collection responses include pagination metadata headers for total items and total pages.
-### Changed
-* Settings UI CSS switched to logical properties for better RTL support and consistent layout.
-
-### Fixed
-* Snippets REST API now correctly respects the network parameter when listing snippets.
-* Pagination logic corrected to reliably slice results and return stable pages.
## [3.7.1-beta.2] (2025-10-22)
diff --git a/src/readme.txt b/src/readme.txt
index 55844435..167f9bf3 100644
--- a/src/readme.txt
+++ b/src/readme.txt
@@ -111,16 +111,7 @@ You can report security bugs found in the source code of this plugin through the
__Added__
* Snippets REST API now supports pagination via page and per_page query parameters.
-* Collection responses include pagination metadata headers for total items and total pages.
-__Changed__
-
-* Settings UI CSS switched to logical properties for better RTL support and consistent layout.
-
-__Fixed__
-
-* Snippets REST API now correctly respects the network parameter when listing snippets.
-* Pagination logic corrected to reliably slice results and return stable pages.
= 3.7.1-beta.2 (2025-10-22) =
From 95af256ad459ab4789058bd6712d26e23fd85e4c Mon Sep 17 00:00:00 2001
From: Imants
Date: Wed, 22 Oct 2025 16:27:56 +0300
Subject: [PATCH 106/106] fix: version
---
src/code-snippets.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/code-snippets.php b/src/code-snippets.php
index 9f7789c1..1db3c0bc 100644
--- a/src/code-snippets.php
+++ b/src/code-snippets.php
@@ -8,7 +8,7 @@
* License: GPL-2.0-or-later
* License URI: license.txt
* Text Domain: code-snippets
- * Version: 3.7.1-beta.3-beta.3
+ * Version: 3.7.1-beta.3
* Requires PHP: 7.4
* Requires at least: 5.0
*