Initial commit: WordPress wp-content (themes, plugins, languages)
- Theme: momentry (custom theme with REST API routes) - Plugins: code-snippets (contains all API proxies) - Languages: zh_TW translations - Excludes: cache, backups, uploads, logs
This commit is contained in:
271
plugins/code-snippets/php/settings/class-setting-field.php
Normal file
271
plugins/code-snippets/php/settings/class-setting-field.php
Normal file
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
/**
|
||||
* This file handles rendering the settings fields
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @package Code_Snippets
|
||||
* @subpackage Settings
|
||||
*/
|
||||
|
||||
namespace Code_Snippets\Settings;
|
||||
|
||||
/**
|
||||
* Represents a single setting field
|
||||
*
|
||||
* @property-read string $desc Field description.
|
||||
* @property-read string $label Field label.
|
||||
* @property-read string $type Field type.
|
||||
* @property-read string $name Setting name.
|
||||
*
|
||||
* @property-read int $min Minimum value (for numerical inputs).
|
||||
* @property-read int $max Maximum value(for numerical inputs).
|
||||
* @property-read array<string, string> $options List of options for a select or checkboxes field.
|
||||
* @property-read callable $render_callback Custom function to use when rendering a callback field.
|
||||
* @property-read callable $sanitize_callback Custom function to use when sanitize the setting value.
|
||||
* @property-read mixed $default Default setting value.
|
||||
*
|
||||
* @property-read string $input_name Value of `name` HTML attribute on an input element.
|
||||
* @property-read string $element_id
|
||||
*/
|
||||
class Setting_Field {
|
||||
|
||||
/**
|
||||
* Input field identifier.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $field_id;
|
||||
|
||||
/**
|
||||
* Settings section identifier.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $section;
|
||||
|
||||
/**
|
||||
* List of possible arguments.
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
private array $args = array(
|
||||
'desc' => '',
|
||||
'label' => '',
|
||||
'min' => null,
|
||||
'max' => null,
|
||||
'options' => [],
|
||||
);
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param string $section_id Settings section identifier.
|
||||
* @param string $field_id Setting field identifier.
|
||||
* @param array<string, mixed> $args The setting field attributes.
|
||||
*/
|
||||
public function __construct( string $section_id, string $field_id, array $args ) {
|
||||
$this->field_id = $field_id;
|
||||
$this->section = $section_id;
|
||||
$this->args = array_merge( $this->args, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a single setting attribute.
|
||||
*
|
||||
* @param string $argument Attribute name.
|
||||
*
|
||||
* @return mixed Attribute value.
|
||||
*/
|
||||
public function __get( string $argument ) {
|
||||
|
||||
if ( 'input_name' === $argument ) {
|
||||
return sprintf( '%s[%s][%s]', OPTION_NAME, $this->section, $this->field_id );
|
||||
}
|
||||
|
||||
return $this->args[ $argument ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the saved value for this setting.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function get_saved_value() {
|
||||
return get_setting( $this->section, $this->field_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the setting field
|
||||
*/
|
||||
public function render() {
|
||||
$method_name = 'render_' . $this->type . '_field';
|
||||
|
||||
if ( method_exists( $this, $method_name ) ) {
|
||||
call_user_func( array( $this, $method_name ) );
|
||||
} else {
|
||||
// Error message, not necessary to translate.
|
||||
printf( 'Cannot render a %s field.', esc_html( $this->type ) );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->desc ) {
|
||||
echo '<p class="description">', wp_kses_post( $this->desc ), '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a callback field.
|
||||
*/
|
||||
public function render_callback_field() {
|
||||
if ( ! is_callable( $this->render_callback ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
call_user_func( $this->render_callback, $this->args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a single checkbox field.
|
||||
*
|
||||
* @param string $input_name Input name.
|
||||
* @param string $label Input label.
|
||||
* @param boolean $checked Whether the checkbox should be checked.
|
||||
*/
|
||||
private static function render_checkbox( string $input_name, string $label, bool $checked ) {
|
||||
|
||||
$checkbox = sprintf(
|
||||
'<input type="checkbox" name="%s"%s>',
|
||||
esc_attr( $input_name ),
|
||||
checked( $checked, true, false )
|
||||
);
|
||||
|
||||
$kses = [
|
||||
'input' => [
|
||||
'type' => [],
|
||||
'name' => [],
|
||||
'checked' => [],
|
||||
],
|
||||
];
|
||||
|
||||
if ( $label ) {
|
||||
printf(
|
||||
'<label>%s %s</label>',
|
||||
wp_kses( $checkbox, $kses ),
|
||||
wp_kses_post( $label )
|
||||
);
|
||||
} else {
|
||||
echo wp_kses( $checkbox, $kses );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a checkbox field for a setting
|
||||
*
|
||||
* @return void
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public function render_checkbox_field() {
|
||||
$this->render_checkbox( $this->input_name, $this->label, $this->get_saved_value() ?? false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a checkbox field for a setting
|
||||
*
|
||||
* @return void
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public function render_checkboxes_field() {
|
||||
$saved_value = $this->get_saved_value();
|
||||
$saved_value = is_array( $saved_value ) ? $saved_value : [];
|
||||
|
||||
echo '<fieldset>';
|
||||
printf( '<legend class="screen-reader-text"><span>%s</span></legend>', esc_html( $this->name ) );
|
||||
|
||||
foreach ( $this->options as $option => $label ) {
|
||||
$this->render_checkbox( $this->input_name . "[$option]", $label, in_array( $option, $saved_value, true ) );
|
||||
echo '<br>';
|
||||
}
|
||||
|
||||
echo '</fieldset>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a basic text field for an editor setting.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function render_text_field() {
|
||||
printf(
|
||||
'<input id="%s" type="text" name="%s" value="%s" class="regular-text %s">',
|
||||
esc_attr( $this->element_id ),
|
||||
esc_attr( $this->input_name ),
|
||||
esc_attr( $this->get_saved_value() ),
|
||||
esc_attr( $this->element_id )
|
||||
);
|
||||
|
||||
if ( $this->label ) {
|
||||
echo ' ' . wp_kses_post( $this->label );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a number select field for an editor setting
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private function render_number_field() {
|
||||
printf(
|
||||
'<input type="number" name="%s" value="%s"',
|
||||
esc_attr( $this->input_name ),
|
||||
esc_attr( $this->get_saved_value() )
|
||||
);
|
||||
|
||||
if ( is_numeric( $this->min ) ) {
|
||||
printf( ' min="%d"', intval( $this->min ) );
|
||||
}
|
||||
|
||||
if ( is_numeric( $this->max ) ) {
|
||||
printf( ' max="%d"', intval( $this->max ) );
|
||||
}
|
||||
|
||||
echo '>';
|
||||
|
||||
if ( $this->label ) {
|
||||
echo ' ' . wp_kses_post( $this->label );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a number select field for an editor setting.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
private function render_select_field() {
|
||||
$saved_value = $this->get_saved_value();
|
||||
printf( '<select name="%s">', esc_attr( $this->input_name ) );
|
||||
|
||||
foreach ( $this->options as $option => $option_label ) {
|
||||
printf(
|
||||
'<option value="%s"%s>%s</option>',
|
||||
esc_attr( $option ),
|
||||
selected( $option, $saved_value, false ),
|
||||
esc_html( $option_label )
|
||||
);
|
||||
}
|
||||
|
||||
echo '</select>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a button link.
|
||||
*
|
||||
* @since 3.5.1
|
||||
*/
|
||||
private function render_action_field() {
|
||||
printf(
|
||||
'<button type="submit" name="%s" class="button">%s</button>',
|
||||
esc_attr( $this->input_name ),
|
||||
esc_html( $this->label ? $this->label : $this->name )
|
||||
);
|
||||
}
|
||||
}
|
||||
362
plugins/code-snippets/php/settings/class-version-switch.php
Normal file
362
plugins/code-snippets/php/settings/class-version-switch.php
Normal file
@@ -0,0 +1,362 @@
|
||||
<?php
|
||||
/**
|
||||
* Class-based version switching functionality for the Code Snippets plugin.
|
||||
*
|
||||
* Converted from procedural `version-switch.php` to an OO class `Version_Switch`.
|
||||
*
|
||||
* @package Code_Snippets
|
||||
* @subpackage Settings
|
||||
*/
|
||||
|
||||
namespace Code_Snippets\Settings;
|
||||
|
||||
// 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';
|
||||
|
||||
class Version_Switch {
|
||||
/**
|
||||
* Initialize hook registrations.
|
||||
* Call this after the file is required.
|
||||
*/
|
||||
public static function init(): void {
|
||||
add_action( 'wp_ajax_code_snippets_switch_version', [ __CLASS__, 'ajax_switch_version' ] );
|
||||
add_action( 'wp_ajax_code_snippets_refresh_versions', [ __CLASS__, 'ajax_refresh_versions' ] );
|
||||
}
|
||||
|
||||
public static function get_available_versions(): array {
|
||||
$versions = get_transient( VERSION_CACHE_KEY );
|
||||
|
||||
if ( false === $versions ) {
|
||||
$response = wp_remote_get( WORDPRESS_API_ENDPOINT );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
$data = json_decode( $body, true );
|
||||
|
||||
if ( ! $data || ! isset( $data['versions'] ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Filter out 'trunk' and sort versions
|
||||
$versions = [];
|
||||
foreach ( $data['versions'] as $version => $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();
|
||||
|
||||
?>
|
||||
<div class="code-snippets-version-switch">
|
||||
<p>
|
||||
<strong><?php esc_html_e( 'Current Version:', 'code-snippets' ); ?></strong>
|
||||
<span class="current-version"><?php echo esc_html( $current_version ); ?></span>
|
||||
</p>
|
||||
|
||||
<?php if ( $is_switching ) : ?>
|
||||
<div class="notice notice-info inline">
|
||||
<p><?php esc_html_e( 'Version switch in progress. Please wait...', 'code-snippets' ); ?></p>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<p>
|
||||
<label for="target_version">
|
||||
<?php esc_html_e( 'Switch to Version:', 'code-snippets' ); ?>
|
||||
</label>
|
||||
<select id="target_version" name="target_version" <?php disabled( empty( $available_versions ) ); ?>>
|
||||
<option value=""><?php esc_html_e( 'Select a version...', 'code-snippets' ); ?></option>
|
||||
<?php foreach ( $available_versions as $version_info ) : ?>
|
||||
<option value="<?php echo esc_attr( $version_info['version'] ); ?>"
|
||||
<?php selected( $version_info['version'], $current_version ); ?>>
|
||||
<?php echo esc_html( $version_info['version'] ); ?>
|
||||
<?php if ( $version_info['version'] === $current_version ) : ?>
|
||||
<?php esc_html_e( ' (Current)', 'code-snippets' ); ?>
|
||||
<?php endif; ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<button type="button" id="switch-version-btn" class="button button-secondary" disabled
|
||||
<?php disabled( empty( $available_versions ) ); ?>>
|
||||
<?php esc_html_e( 'Switch Version', 'code-snippets' ); ?>
|
||||
</button>
|
||||
</p>
|
||||
|
||||
<div id="version-switch-result" class="notice" style="display: none;"></div>
|
||||
<?php endif; ?>
|
||||
</div><?php
|
||||
}
|
||||
|
||||
public static function ajax_switch_version(): void {
|
||||
if ( ! wp_verify_nonce( $_POST['nonce'] ?? '', 'code_snippets_version_switch' ) ) {
|
||||
wp_die( __( 'Security check failed.', 'code-snippets' ) );
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'update_plugins' ) ) {
|
||||
wp_send_json_error( [
|
||||
'message' => __( '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 {
|
||||
?>
|
||||
<button type="button" id="refresh-versions-btn" class="button button-secondary">
|
||||
<?php esc_html_e( 'Refresh Available Versions', 'code-snippets' ); ?>
|
||||
</button>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Check for the latest available plugin versions from WordPress.org.', 'code-snippets' ); ?>
|
||||
</p><?php
|
||||
}
|
||||
|
||||
public static function ajax_refresh_versions(): void {
|
||||
if ( ! wp_verify_nonce( $_POST['nonce'] ?? '', 'code_snippets_refresh_versions' ) ) {
|
||||
wp_die( __( 'Security check failed.', 'code-snippets' ) );
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error( [
|
||||
'message' => __( '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 {
|
||||
?>
|
||||
<div id="version-switch-warning" class="notice notice-warning" style="display: none; margin-block-start: 20px;">
|
||||
<p>
|
||||
<strong><?php esc_html_e( 'Warning:', 'code-snippets' ); ?></strong>
|
||||
<?php esc_html_e( 'Switching versions may cause compatibility issues. Always backup your site before switching versions.', 'code-snippets' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize hooks when the file is loaded.
|
||||
Version_Switch::init();
|
||||
132
plugins/code-snippets/php/settings/editor-preview.php
Normal file
132
plugins/code-snippets/php/settings/editor-preview.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
/**
|
||||
* This file handles the editor preview setting
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @package Code_Snippets
|
||||
*/
|
||||
|
||||
namespace Code_Snippets\Settings;
|
||||
|
||||
use function Code_Snippets\code_snippets;
|
||||
use function Code_Snippets\enqueue_code_editor;
|
||||
use function Code_Snippets\get_editor_themes;
|
||||
|
||||
/**
|
||||
* Load the CSS and JavaScript for the editor preview field
|
||||
*/
|
||||
function enqueue_editor_preview_assets() {
|
||||
$plugin = code_snippets();
|
||||
|
||||
enqueue_code_editor( 'php' );
|
||||
|
||||
// Enqueue all editor themes.
|
||||
$themes = get_editor_themes();
|
||||
|
||||
foreach ( $themes as $theme ) {
|
||||
wp_enqueue_style(
|
||||
'code-snippets-editor-theme-' . $theme,
|
||||
plugins_url( "dist/editor-themes/$theme.css", $plugin->file ),
|
||||
[ 'code-editor' ],
|
||||
$plugin->version
|
||||
);
|
||||
}
|
||||
|
||||
// Enqueue the menu scripts.
|
||||
wp_enqueue_script(
|
||||
'code-snippets-settings-menu',
|
||||
plugins_url( 'dist/settings.js', $plugin->file ),
|
||||
[ 'code-snippets-code-editor' ],
|
||||
$plugin->version,
|
||||
true
|
||||
);
|
||||
|
||||
wp_set_script_translations( 'code-snippets-settings-menu', 'code-snippets' );
|
||||
|
||||
// Extract the CodeMirror-specific editor settings.
|
||||
$setting_fields = get_settings_fields();
|
||||
$editor_fields = array();
|
||||
|
||||
foreach ( $setting_fields['editor'] as $name => $field ) {
|
||||
if ( empty( $field['codemirror'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$editor_fields[] = array(
|
||||
'name' => $name,
|
||||
'type' => $field['type'],
|
||||
'codemirror' => addslashes( $field['codemirror'] ),
|
||||
);
|
||||
}
|
||||
|
||||
// Pass the saved options to the external JavaScript file.
|
||||
$inline_script = 'var code_snippets_editor_settings = ' . wp_json_encode( $editor_fields ) . ';';
|
||||
|
||||
wp_add_inline_script( 'code-snippets-settings-menu', $inline_script, 'before' );
|
||||
|
||||
// Provide configuration and simple i18n for the version switch JS module.
|
||||
$version_switch = array(
|
||||
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
||||
'nonce_switch' => wp_create_nonce( 'code_snippets_version_switch' ),
|
||||
'nonce_refresh' => wp_create_nonce( 'code_snippets_refresh_versions' ),
|
||||
);
|
||||
|
||||
$strings = array(
|
||||
'selectDifferent' => esc_html__( 'Please select a different version to switch to.', 'code-snippets' ),
|
||||
'switching' => esc_html__( 'Switching...', 'code-snippets' ),
|
||||
'processing' => esc_html__( 'Processing version switch. Please wait...', 'code-snippets' ),
|
||||
'error' => esc_html__( 'An error occurred.', 'code-snippets' ),
|
||||
'errorSwitch' => esc_html__( 'An error occurred while switching versions. Please try again.', 'code-snippets' ),
|
||||
'refreshing' => esc_html__( 'Refreshing...', 'code-snippets' ),
|
||||
'refreshed' => esc_html__( 'Refreshed!', 'code-snippets' ),
|
||||
);
|
||||
|
||||
wp_add_inline_script( 'code-snippets-settings-menu', 'var code_snippets_version_switch = ' . wp_json_encode( $version_switch ) . '; var __code_snippets_i18n = ' . wp_json_encode( $strings ) . ';', 'before' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the list of code editor themes.
|
||||
*
|
||||
* @return array<string, string> List of editor themes.
|
||||
*/
|
||||
function get_editor_theme_list(): array {
|
||||
$themes = [
|
||||
'default' => __( 'Default', 'code-snippets' ),
|
||||
];
|
||||
|
||||
foreach ( get_editor_themes() as $theme ) {
|
||||
|
||||
// Skip mobile themes.
|
||||
if ( '-mobile' === substr( $theme, -7 ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$themes[ $theme ] = ucwords( str_replace( '-', ' ', $theme ) );
|
||||
}
|
||||
|
||||
return $themes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the editor preview setting
|
||||
*/
|
||||
function render_editor_preview() {
|
||||
$settings = get_settings_values();
|
||||
$settings = $settings['editor'];
|
||||
|
||||
$indent_unit = absint( $settings['indent_unit'] );
|
||||
$tab_size = absint( $settings['tab_size'] );
|
||||
|
||||
$n_tabs = $settings['indent_with_tabs'] ? floor( $indent_unit / $tab_size ) : 0;
|
||||
$n_spaces = $settings['indent_with_tabs'] ? $indent_unit % $tab_size : $indent_unit;
|
||||
|
||||
$indent = str_repeat( "\t", $n_tabs ) . str_repeat( ' ', $n_spaces );
|
||||
|
||||
$code = "add_filter( 'admin_footer_text', function ( \$text ) {\n\n" .
|
||||
$indent . "\$site_name = get_bloginfo( 'name' );\n\n" .
|
||||
$indent . '$text = "Thank you for visiting $site_name.";' . "\n" .
|
||||
$indent . 'return $text;' . "\n" .
|
||||
"} );\n";
|
||||
|
||||
echo '<textarea id="code_snippets_editor_preview">', esc_textarea( $code ), '</textarea>';
|
||||
}
|
||||
263
plugins/code-snippets/php/settings/settings-fields.php
Normal file
263
plugins/code-snippets/php/settings/settings-fields.php
Normal file
@@ -0,0 +1,263 @@
|
||||
<?php
|
||||
/**
|
||||
* Manages the settings field definitions.
|
||||
*
|
||||
* @package Code_Snippets
|
||||
* @subpackage Settings
|
||||
*/
|
||||
|
||||
namespace Code_Snippets\Settings;
|
||||
|
||||
use function Code_Snippets\code_snippets;
|
||||
|
||||
/**
|
||||
* Retrieve the default setting values
|
||||
*
|
||||
* @return array<string, array<string, mixed>>
|
||||
*/
|
||||
function get_default_settings(): array {
|
||||
static $defaults;
|
||||
|
||||
if ( isset( $defaults ) ) {
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
$defaults = [
|
||||
'general' => [
|
||||
'activate_by_default' => true,
|
||||
'enable_tags' => true,
|
||||
'enable_description' => true,
|
||||
'visual_editor_rows' => 5,
|
||||
'list_order' => 'priority-asc',
|
||||
'disable_prism' => false,
|
||||
'hide_upgrade_menu' => false,
|
||||
'complete_uninstall' => false,
|
||||
'enable_flat_files' => false,
|
||||
],
|
||||
'editor' => [
|
||||
'indent_with_tabs' => true,
|
||||
'tab_size' => 4,
|
||||
'indent_unit' => 4,
|
||||
'font_size' => 14,
|
||||
'wrap_lines' => true,
|
||||
'code_folding' => true,
|
||||
'line_numbers' => true,
|
||||
'auto_close_brackets' => true,
|
||||
'highlight_selection_matches' => true,
|
||||
'highlight_active_line' => true,
|
||||
'keymap' => 'default',
|
||||
'theme' => 'default',
|
||||
],
|
||||
'version-switch' => [
|
||||
'selected_version' => '',
|
||||
],
|
||||
'debug' => [
|
||||
'enable_version_change' => false,
|
||||
],
|
||||
];
|
||||
|
||||
$defaults = apply_filters( 'code_snippets_settings_defaults', $defaults );
|
||||
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the settings fields
|
||||
*
|
||||
* @return array<string, array<string, array>>
|
||||
*/
|
||||
function get_settings_fields(): array {
|
||||
static $fields;
|
||||
|
||||
if ( isset( $fields ) ) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$fields = [];
|
||||
|
||||
$fields['debug'] = [
|
||||
'database_update' => [
|
||||
'name' => __( 'Database Table Upgrade', 'code-snippets' ),
|
||||
'type' => 'action',
|
||||
'label' => __( 'Upgrade Database Table', 'code-snippets' ),
|
||||
'desc' => __( 'Use this button to manually upgrade the Code Snippets database table. This action will only affect the snippets table and should be used only when necessary.', 'code-snippets' ),
|
||||
],
|
||||
'reset_caches' => [
|
||||
'name' => __( 'Reset Caches', 'code-snippets' ),
|
||||
'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'] = [
|
||||
'version_switcher' => [
|
||||
'name' => __( 'Switch Version', 'code-snippets' ),
|
||||
'type' => 'callback',
|
||||
'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\\Version_Switch', 'render_refresh_versions_field' ],
|
||||
],
|
||||
'version_warning' => [
|
||||
'name' => '',
|
||||
'type' => 'callback',
|
||||
'render_callback' => [ '\\Code_Snippets\\Settings\\Version_Switch', 'render_version_switch_warning' ],
|
||||
],
|
||||
];
|
||||
|
||||
$fields['general'] = [
|
||||
'activate_by_default' => [
|
||||
'name' => __( 'Activate by Default', 'code-snippets' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( "Make the 'Save and Activate' button the default action when saving a snippet.", 'code-snippets' ),
|
||||
],
|
||||
'enable_tags' => [
|
||||
'name' => __( 'Enable Snippet Tags', 'code-snippets' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Show snippet tags on admin pages.', 'code-snippets' ),
|
||||
],
|
||||
'enable_description' => [
|
||||
'name' => __( 'Enable Snippet Descriptions', 'code-snippets' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Show snippet descriptions on admin pages.', 'code-snippets' ),
|
||||
],
|
||||
'visual_editor_rows' => [
|
||||
'name' => __( 'Description Editor Height', 'code-snippets' ),
|
||||
'type' => 'number',
|
||||
'label' => _x( 'rows', 'unit', 'code-snippets' ),
|
||||
'min' => 0,
|
||||
],
|
||||
'list_order' => [
|
||||
'name' => __( 'Snippets List Order', 'code-snippets' ),
|
||||
'type' => 'select',
|
||||
'desc' => __( 'Default way to order snippets on the All Snippets admin menu.', 'code-snippets' ),
|
||||
'options' => [
|
||||
'priority-asc' => __( 'Priority', 'code-snippets' ),
|
||||
'name-asc' => __( 'Name (A-Z)', 'code-snippets' ),
|
||||
'name-desc' => __( 'Name (Z-A)', 'code-snippets' ),
|
||||
'modified-desc' => __( 'Modified (latest first)', 'code-snippets' ),
|
||||
'modified-asc' => __( 'Modified (oldest first)', 'code-snippets' ),
|
||||
],
|
||||
],
|
||||
'disable_prism' => [
|
||||
'name' => __( 'Disable Syntax Highlighter', 'code-snippets' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Disable syntax highlighting when displaying snippet code on the front-end.', 'code-snippets' ),
|
||||
],
|
||||
];
|
||||
|
||||
if ( ! code_snippets()->licensing->is_licensed() ) {
|
||||
$fields['general']['hide_upgrade_menu'] = [
|
||||
'name' => __( 'Hide Upgrade Notices', 'code-snippets' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Hide notices inviting you to upgrade to Code Snippets Pro.', 'code-snippets' ),
|
||||
];
|
||||
}
|
||||
|
||||
if ( ! is_multisite() || is_main_site() ) {
|
||||
$fields['general']['complete_uninstall'] = [
|
||||
'name' => __( 'Complete Uninstall', 'code-snippets' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'When the plugin is deleted from the Plugins menu, also delete all snippets and plugin settings.', 'code-snippets' ),
|
||||
];
|
||||
}
|
||||
|
||||
$fields['editor'] = [
|
||||
'indent_with_tabs' => [
|
||||
'name' => __( 'Indent With Tabs', 'code-snippets' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Use hard tabs instead of spaces for indentation.', 'code-snippets' ),
|
||||
'codemirror' => 'indentWithTabs',
|
||||
],
|
||||
'tab_size' => [
|
||||
'name' => __( 'Tab Size', 'code-snippets' ),
|
||||
'type' => 'number',
|
||||
'desc' => __( 'The width of a tab character.', 'code-snippets' ),
|
||||
'label' => _x( 'spaces', 'unit', 'code-snippets' ),
|
||||
'codemirror' => 'tabSize',
|
||||
'min' => 0,
|
||||
],
|
||||
'indent_unit' => [
|
||||
'name' => __( 'Indent Unit', 'code-snippets' ),
|
||||
'type' => 'number',
|
||||
'desc' => __( 'The number of spaces to indent a block.', 'code-snippets' ),
|
||||
'label' => _x( 'spaces', 'unit', 'code-snippets' ),
|
||||
'codemirror' => 'indentUnit',
|
||||
'min' => 0,
|
||||
],
|
||||
'font_size' => [
|
||||
'name' => __( 'Font Size', 'code-snippets' ),
|
||||
'type' => 'number',
|
||||
'label' => _x( 'px', 'unit', 'code-snippets' ),
|
||||
'codemirror' => 'fontSize',
|
||||
'min' => 8,
|
||||
'max' => 28,
|
||||
],
|
||||
'wrap_lines' => [
|
||||
'name' => __( 'Wrap Lines', 'code-snippets' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Soft-wrap long lines of code instead of horizontally scrolling.', 'code-snippets' ),
|
||||
'codemirror' => 'lineWrapping',
|
||||
],
|
||||
|
||||
'code_folding' => [
|
||||
'name' => __( 'Code Folding', 'code-snippets' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Allow folding functions or other blocks into a single line.', 'code-snippets' ),
|
||||
'codemirror' => 'foldGutter',
|
||||
],
|
||||
'line_numbers' => [
|
||||
'name' => __( 'Line Numbers', 'code-snippets' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Show line numbers to the left of the editor.', 'code-snippets' ),
|
||||
'codemirror' => 'lineNumbers',
|
||||
],
|
||||
'auto_close_brackets' => [
|
||||
'name' => __( 'Auto Close Brackets', 'code-snippets' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Auto-close brackets and quotes when typed.', 'code-snippets' ),
|
||||
'codemirror' => 'autoCloseBrackets',
|
||||
],
|
||||
'highlight_selection_matches' => [
|
||||
'name' => __( 'Highlight Selection Matches', 'code-snippets' ),
|
||||
'label' => __( 'Highlight all instances of a currently selected word.', 'code-snippets' ),
|
||||
'type' => 'checkbox',
|
||||
'codemirror' => 'highlightSelectionMatches',
|
||||
],
|
||||
'highlight_active_line' => [
|
||||
'name' => __( 'Highlight Active Line', 'code-snippets' ),
|
||||
'label' => __( 'Highlight the line that is currently being edited.', 'code-snippets' ),
|
||||
'type' => 'checkbox',
|
||||
'codemirror' => 'styleActiveLine',
|
||||
],
|
||||
'keymap' => [
|
||||
'name' => __( 'Keymap', 'code-snippets' ),
|
||||
'type' => 'select',
|
||||
'desc' => __( 'The set of keyboard shortcuts to use in the code editor.', 'code-snippets' ),
|
||||
'options' => [
|
||||
'default' => __( 'Default', 'code-snippets' ),
|
||||
'vim' => __( 'Vim', 'code-snippets' ),
|
||||
'emacs' => __( 'Emacs', 'code-snippets' ),
|
||||
'sublime' => __( 'Sublime Text', 'code-snippets' ),
|
||||
],
|
||||
'codemirror' => 'keyMap',
|
||||
],
|
||||
'theme' => [
|
||||
'name' => __( 'Theme', 'code-snippets' ),
|
||||
'type' => 'select',
|
||||
'options' => get_editor_theme_list(),
|
||||
'codemirror' => 'theme',
|
||||
],
|
||||
];
|
||||
|
||||
$fields = apply_filters( 'code_snippets_settings_fields', $fields );
|
||||
|
||||
return $fields;
|
||||
}
|
||||
351
plugins/code-snippets/php/settings/settings.php
Normal file
351
plugins/code-snippets/php/settings/settings.php
Normal file
@@ -0,0 +1,351 @@
|
||||
<?php
|
||||
/**
|
||||
* This file registers the settings
|
||||
*
|
||||
* @package Code_Snippets
|
||||
* @subpackage Settings
|
||||
*/
|
||||
|
||||
namespace Code_Snippets\Settings;
|
||||
|
||||
use Code_Snippets\Welcome_API;
|
||||
use function Code_Snippets\clean_snippets_cache;
|
||||
use function Code_Snippets\code_snippets;
|
||||
use const Code_Snippets\CACHE_GROUP;
|
||||
|
||||
const CACHE_KEY = 'code_snippets_settings';
|
||||
const OPTION_GROUP = 'code-snippets';
|
||||
const OPTION_NAME = 'code_snippets_settings';
|
||||
|
||||
/**
|
||||
* Add a new option for either the current site or the current network
|
||||
*
|
||||
* @param bool $network Whether to add a network-wide option.
|
||||
* @param string $option Name of option to add. Expected to not be SQL-escaped.
|
||||
* @param mixed $value Option value, can be anything. Expected to not be SQL-escaped.
|
||||
*
|
||||
* @return bool False if the option was not added. True if the option was added.
|
||||
*/
|
||||
function add_self_option( bool $network, string $option, $value ): bool {
|
||||
return $network ? add_site_option( $option, $value ) : add_option( $option, $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an option value based on an option name from either the current site or the current network
|
||||
*
|
||||
* @param bool $network Whether to get a network-wide option.
|
||||
* @param string $option Name of option to retrieve. Expected to not be SQL-escaped.
|
||||
* @param mixed $default_value Optional value to return if option doesn't exist. Default false.
|
||||
*
|
||||
* @return mixed Value set for the option.
|
||||
*/
|
||||
function get_self_option( bool $network, string $option, $default_value = false ) {
|
||||
return $network ? get_site_option( $option, $default_value ) : get_option( $option, $default_value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the value of an option that was already added on the current site or the current network
|
||||
*
|
||||
* @param bool $network Whether to update a network-wide option.
|
||||
* @param string $option Name of option. Expected to not be SQL-escaped.
|
||||
* @param mixed $value Option value. Expected to not be SQL-escaped.
|
||||
*
|
||||
* @return bool False if value was not updated. True if value was updated.
|
||||
*/
|
||||
function update_self_option( bool $network, string $option, $value ): bool {
|
||||
return $network ? update_site_option( $option, $value ) : update_option( $option, $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'true' if plugin settings are unified on a multisite installation
|
||||
* under the Network Admin settings menu
|
||||
*
|
||||
* This option is controlled by the "Enable administration menus" setting on the Network Settings menu
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function are_settings_unified(): bool {
|
||||
if ( ! is_multisite() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$menu_perms = get_site_option( 'menu_items', array() );
|
||||
return empty( $menu_perms['snippets_settings'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the setting values from the database.
|
||||
* If a setting does not exist in the database, the default value will be returned.
|
||||
*
|
||||
* @return array<string, array<string, mixed>>
|
||||
*/
|
||||
function get_settings_values(): array {
|
||||
$settings = wp_cache_get( CACHE_KEY, CACHE_GROUP );
|
||||
if ( $settings ) {
|
||||
return $settings;
|
||||
}
|
||||
|
||||
$settings = get_default_settings();
|
||||
$saved = get_self_option( are_settings_unified(), OPTION_NAME, array() );
|
||||
|
||||
foreach ( $settings as $section => $fields ) {
|
||||
if ( isset( $saved[ $section ] ) ) {
|
||||
$settings[ $section ] = array_replace( $fields, $saved[ $section ] );
|
||||
}
|
||||
}
|
||||
|
||||
wp_cache_set( CACHE_KEY, $settings, CACHE_GROUP );
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an individual setting field value
|
||||
*
|
||||
* @param string $section ID of the section the setting belongs to.
|
||||
* @param string $field ID of the setting field.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function get_setting( string $section, string $field ) {
|
||||
$settings = get_settings_values();
|
||||
|
||||
return $settings[ $section ][ $field ] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a single setting to a new value.
|
||||
*
|
||||
* @param string $section ID of the section the setting belongs to.
|
||||
* @param string $field ID of the setting field.
|
||||
* @param mixed $new_value Setting value. Expected to not be SQL-escaped.
|
||||
*
|
||||
* @return bool False if value was not updated. True if value was updated.
|
||||
*/
|
||||
function update_setting( string $section, string $field, $new_value ): bool {
|
||||
$settings = get_settings_values();
|
||||
|
||||
$settings[ $section ][ $field ] = $new_value;
|
||||
|
||||
wp_cache_set( CACHE_KEY, $settings, CACHE_GROUP );
|
||||
return update_self_option( are_settings_unified(), OPTION_NAME, $settings );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the settings sections
|
||||
*
|
||||
* @return array<string, string> Settings sections.
|
||||
*/
|
||||
function get_settings_sections(): array {
|
||||
$sections = array(
|
||||
'general' => __( 'General', 'code-snippets' ),
|
||||
'editor' => __( 'Code Editor', 'code-snippets' ),
|
||||
'debug' => __( 'Debug', '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 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register settings sections, fields, etc
|
||||
*/
|
||||
function register_plugin_settings() {
|
||||
if ( are_settings_unified() ) {
|
||||
if ( ! get_site_option( OPTION_NAME ) ) {
|
||||
add_site_option( OPTION_NAME, get_default_settings() );
|
||||
}
|
||||
} elseif ( ! get_option( OPTION_NAME ) ) {
|
||||
add_option( OPTION_NAME, get_default_settings() );
|
||||
}
|
||||
|
||||
// Register the setting.
|
||||
register_setting(
|
||||
OPTION_GROUP,
|
||||
OPTION_NAME,
|
||||
[ 'sanitize_callback' => __NAMESPACE__ . '\\sanitize_settings' ]
|
||||
);
|
||||
|
||||
// Register settings sections.
|
||||
foreach ( get_settings_sections() as $section_id => $section_name ) {
|
||||
add_settings_section( $section_id, $section_name, '__return_empty_string', 'code-snippets' );
|
||||
}
|
||||
|
||||
// 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 );
|
||||
}
|
||||
}
|
||||
|
||||
// Add editor preview as a field.
|
||||
add_settings_field(
|
||||
'editor_preview',
|
||||
__( 'Editor Preview', 'code-snippets' ),
|
||||
__NAMESPACE__ . '\\render_editor_preview',
|
||||
'code-snippets',
|
||||
'editor'
|
||||
);
|
||||
}
|
||||
|
||||
add_action( 'admin_init', __NAMESPACE__ . '\\register_plugin_settings' );
|
||||
|
||||
/**
|
||||
* Sanitize a single setting value.
|
||||
*
|
||||
* @param array<string, mixed> $field Setting field information.
|
||||
* @param mixed $input_value User input setting value, or null if missing.
|
||||
*
|
||||
* @return mixed Sanitized setting value, or null if unset.
|
||||
*/
|
||||
function sanitize_setting_value( array $field, $input_value ) {
|
||||
switch ( $field['type'] ) {
|
||||
|
||||
case 'checkbox':
|
||||
return 'on' === $input_value;
|
||||
|
||||
case 'number':
|
||||
return intval( $input_value );
|
||||
|
||||
case 'select':
|
||||
$select_options = array_map( 'strval', array_keys( $field['options'] ) );
|
||||
return in_array( strval( $input_value ), $select_options, true ) ? $input_value : null;
|
||||
|
||||
case 'checkboxes':
|
||||
$results = [];
|
||||
|
||||
if ( ! empty( $input_value ) ) {
|
||||
foreach ( $field['options'] as $option_id => $option_label ) {
|
||||
if ( isset( $input_value[ $option_id ] ) && 'on' === $input_value[ $option_id ] ) {
|
||||
$results[] = $option_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
|
||||
case 'text':
|
||||
case 'hidden':
|
||||
return trim( sanitize_text_field( $input_value ) );
|
||||
|
||||
case 'callback':
|
||||
return isset( $field['sanitize_callback'] ) && is_callable( $field['sanitize_callback'] ) ?
|
||||
call_user_func( $field['sanitize_callback'], $input_value ) :
|
||||
null;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process settings actions.
|
||||
*
|
||||
* @param array $input Provided settings input.
|
||||
*
|
||||
* @return array|null New $input value to return, or null to continue with settings update process.
|
||||
*/
|
||||
function process_settings_actions( array $input ): ?array {
|
||||
|
||||
if ( isset( $input['reset_settings'] ) ) {
|
||||
add_settings_error(
|
||||
OPTION_NAME,
|
||||
'settings_reset',
|
||||
__( 'All settings have been reset to their defaults.', 'code-snippets' ),
|
||||
'updated'
|
||||
);
|
||||
|
||||
delete_option( 'code_snippets_cloud_settings' );
|
||||
return [];
|
||||
}
|
||||
|
||||
if ( isset( $input['debug']['database_update'] ) ) {
|
||||
code_snippets()->db->create_or_upgrade_tables();
|
||||
|
||||
add_settings_error(
|
||||
OPTION_NAME,
|
||||
'database_update_done',
|
||||
__( 'Successfully performed database table upgrade.', 'code-snippets' ),
|
||||
'updated'
|
||||
);
|
||||
}
|
||||
|
||||
if ( isset( $input['debug']['reset_caches'] ) ) {
|
||||
Welcome_API::clear_cache();
|
||||
clean_snippets_cache( code_snippets()->db->get_table_name( false ) );
|
||||
|
||||
if ( is_multisite() ) {
|
||||
clean_snippets_cache( code_snippets()->db->get_table_name( true ) );
|
||||
}
|
||||
|
||||
add_settings_error(
|
||||
OPTION_NAME,
|
||||
'snippet_caches_reset',
|
||||
__( 'Successfully reset snippets caches.', 'code-snippets' ),
|
||||
'updated'
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the settings
|
||||
*
|
||||
* @param array<string, array<string, mixed>> $input The received settings.
|
||||
*
|
||||
* @return array<string, array<string, mixed>> The validated settings.
|
||||
*/
|
||||
function sanitize_settings( array $input ): array {
|
||||
wp_cache_delete( CACHE_KEY, CACHE_GROUP );
|
||||
$result = process_settings_actions( $input );
|
||||
|
||||
if ( ! is_null( $result ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$settings = get_settings_values();
|
||||
$updated = false;
|
||||
|
||||
// Don't directly loop through $input as it does not include as deselected checkboxes.
|
||||
foreach ( get_settings_fields() as $section_id => $fields ) {
|
||||
foreach ( $fields as $field_id => $field ) {
|
||||
|
||||
// Fetch the corresponding input value from the posted data.
|
||||
$input_value = $input[ $section_id ][ $field_id ] ?? null;
|
||||
|
||||
// Attempt to sanitize the setting value.
|
||||
$sanitized_value = sanitize_setting_value( $field, $input_value );
|
||||
|
||||
$current_value = $settings[ $section_id ][ $field_id ] ?? null;
|
||||
if ( ! is_null( $sanitized_value ) && $current_value !== $sanitized_value ) {
|
||||
$settings[ $section_id ][ $field_id ] = $sanitized_value;
|
||||
$updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add an updated message.
|
||||
if ( $updated ) {
|
||||
add_settings_error(
|
||||
OPTION_NAME,
|
||||
'settings-saved',
|
||||
__( 'Settings saved.', 'code-snippets' ),
|
||||
'updated'
|
||||
);
|
||||
|
||||
do_action( 'code_snippets/settings_updated', $settings, $input );
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
Reference in New Issue
Block a user