From d263c52dbe05c89bf3974bf409e7303a48156ce6 Mon Sep 17 00:00:00 2001
From: Imants
Date: Fri, 22 Aug 2025 11:54:22 +0300
Subject: [PATCH 01/16] 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 02/16] 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 03/16] 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 04/16] 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 05/16] 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 06/16] 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 07/16] 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 08/16] 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 09/16] 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 13/16] 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 14/16] 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 15/16] 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 16/16] 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 {