first commit without licensingg

This commit is contained in:
kbe
2025-08-21 14:40:43 +02:00
commit fa8d4e58a4
130 changed files with 82163 additions and 0 deletions

View File

@@ -0,0 +1,185 @@
<?php
/**
* Class for the customizer importer.
*
* Code is mostly from the Customizer Export/Import plugin.
*
* @see https://wordpress.org/plugins/customizer-export-import/
* @package Revision
*/
/**
* Customizer Importer
*/
class CSCO_Customizer_Importer {
/**
* Import customizer.
*
* @param array $data The data.
*/
public static function import( $data ) {
// Try to import the customizer settings.
return self::import_customizer_options( $data );
}
/**
* Imports uploaded mods and calls WordPress core customize_save actions so
* themes that hook into them can act before mods are saved to the database.
*
* Update: WP core customize_save actions were removed, because of some errors.
*
* @param array $data The data.
* @return void|WP_Error
*/
public static function import_customizer_options( $data ) {
// Setup global vars.
global $wp_customize;
// Data check.
if ( ! is_array( $data ) || ! isset( $data['mods'] ) ) {
return new WP_Error(
'customizer_import_data_error',
esc_html__( 'Error: The customizer import file is not in a correct format. Please make sure to use the correct customizer import file.', 'revision' )
);
}
/**
* Import images.
*
* The csco_customizer_import_images hook.
*
* @since 1.0.0
*/
if ( apply_filters( 'csco_customizer_import_images', true ) ) {
$data['mods'] = self::import_customizer_images( $data['mods'] );
}
// Import custom options.
if ( isset( $data['options'] ) ) {
// Require modified customizer options class.
if ( ! class_exists( 'WP_Customize_Setting' ) ) {
require_once ABSPATH . 'wp-includes/class-wp-customize-setting.php';
}
if ( ! class_exists( 'CSCO_Customizer_Option' ) ) {
require_once get_theme_file_path( '/core/theme-demos/import/class-customizer-option.php' );
}
foreach ( $data['options'] as $option_key => $option_value ) {
$option = new CSCO_Customizer_Option( $wp_customize, $option_key, array(
'default' => '',
'type' => 'option',
'capability' => 'edit_theme_options',
) );
$option->import( $option_value );
}
}
/**
* The csco_enable_wp_customize_save_hooks hook.
*
* @since 1.0.0
*/
$use_wp_customize_save_hooks = apply_filters( 'csco_enable_wp_customize_save_hooks', false );
if ( $use_wp_customize_save_hooks ) {
/**
* The customize_save hook.
*
* @since 1.0.0
*/
do_action( 'customize_save', $wp_customize );
}
// Import mods.
if ( isset( $data['mods'] ) && $data['mods'] ) {
foreach ( $data['mods'] as $key => & $value ) {
if ( $use_wp_customize_save_hooks ) {
/**
* The customize_save_{$key} hook.
*
* @since 1.0.0
*/
do_action( 'customize_save_' . $key, $wp_customize );
}
// Save the mod.
set_theme_mod( $key, $value );
}
}
// Import mods Adobe Fonts.
if ( isset( $data['mods_adobe'] ) && $data['mods_adobe'] ) {
foreach ( $data['mods_adobe'] as $key => & $value ) {
if ( $use_wp_customize_save_hooks ) {
/**
* The customize_save_{$key} hook.
*
* @since 1.0.0
*/
do_action( 'customize_save_' . $key, $wp_customize );
}
$token = get_option( 'powerkit_typekit_fonts_token' );
$kit = get_option( 'powerkit_typekit_fonts_kit' );
$kit_fonts = get_option( 'pk_typekit_' . $kit . '_s' );
$families = ( $kit_fonts ) ? $kit_fonts['kit']['families'] : false;
$font_found = false;
// Search for the font slug from a theme_mod in the active Adobe font kit.
if ( isset( $value['font-family'] ) && $families ) {
foreach ( $families as $k => $v ) {
if ( isset( $v['slug'] ) && $value['font-family'] === $v['slug'] ) {
$font_found = true;
break;
}
if ( isset( $v['css_names'][0] ) && $value['font-family'] === $v['css_names'][0] ) {
$font_found = true;
break;
}
}
}
// Set default font family.
if ( is_array( $value ) && ( ! $token || ! $kit || ! $font_found ) ) {
$value['font-family'] = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif';
}
// Save the mod.
set_theme_mod( $key, $value );
}
}
if ( $use_wp_customize_save_hooks ) {
/**
* The customize_save_after hook.
*
* @since 1.0.0
*/
do_action( 'customize_save_after', $wp_customize );
}
}
/**
* Helper function: Customizer import - imports images for settings saved as mods.
*
* @param array $mods An array of customizer mods.
* @return array The mods array with any new import data.
*/
private static function import_customizer_images( $mods ) {
foreach ( $mods as $key => $val ) {
if ( CSCO_Manager_Import::is_image_url( $val ) ) {
$data = CSCO_Manager_Import::import_custom_image( $val );
if ( ! is_wp_error( $data ) ) {
$mods[ $key ] = $data->url;
}
}
}
return $mods;
}
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* A class that extends WP_Customize_Setting so we can access
* the protected updated method when importing options.
*
* Used in the Customizer importer.
*
* @since 1.0.0
* @package Revision
*/
final class CSCO_Customizer_Option extends WP_Customize_Setting {
/**
* Import an option value for this setting.
*
* @since 1.0.0
* @param mixed $value The option value.
* @return void
*/
public function import( $value ) {
$this->update( $value );
}
}

View File

@@ -0,0 +1,901 @@
<?php
/**
* Manager Import.
*
* @package Revision
*/
/**
* Manager Import Class
*/
class CSCO_Manager_Import {
/**
* Singleton instance
*
* @var CSCO_Manager_Import
*/
private static $instance;
/**
* Sites Server API URL
*
* @var string
*/
public $api_url;
/**
* Get singleton instance.
*
* @return CSCO_Manager_Import
*/
public static function instance() {
if ( is_null( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Time in milliseconds, marking the beginning of the import.
*
* @var float
*/
private $microtime;
/**
* Class constructor
*/
public function __construct() {
add_action( 'after_setup_theme', array( $this, 'init' ) );
}
/**
* Initialize plugin.
*/
public function init() {
add_action( 'upload_mimes', array( $this, 'add_custom_mimes' ) );
add_filter( 'wp_check_filetype_and_ext', array( $this, 'real_mime_type_for_xml' ), 10, 4 );
add_filter( 'admin_init', array( $this, 'ajax_runtime_hide_errors' ), 0 );
add_filter( 'query', array( $this, 'ajax_wpdb_hide_errors' ), 0 );
add_action( 'wp_ajax_csco_import_plugin', array( $this, 'ajax_import_plugin' ) );
add_action( 'wp_ajax_csco_import_contents', array( $this, 'ajax_import_contents' ) );
add_action( 'wp_ajax_csco_import_customizer', array( $this, 'ajax_import_customizer' ) );
add_action( 'wp_ajax_csco_import_widgets', array( $this, 'ajax_import_widgets' ) );
add_action( 'wp_ajax_csco_import_options', array( $this, 'ajax_import_options' ) );
add_action( 'wp_ajax_csco_import_finish', array( $this, 'ajax_import_finish' ) );
}
/**
* Pre Plugin Setup
*/
public function pre_plugin_setup() {
/* Woocommerce */
add_filter( 'woocommerce_prevent_automatic_wizard_redirect', '__return_false' );
add_filter( 'woocommerce_enable_setup_wizard', '__return_false' );
/* Elementor */
set_transient( 'elementor_activation_redirect', false );
}
/**
* Helper function: Import image.
*
* @param string $url Image url.
* @param bool $retina Support retina.
* @return array The import data.
*/
public static function import_custom_image( $url, $retina = true ) {
$data = self::sideload_image( $url );
if ( $retina ) {
// Upload @2x image.
self::sideload_image(
str_replace( array( '.jpg', '.jpeg', '.png', '.gif', '.webp' ),
array( '@2x.jpg', '@2x.jpeg', '@2x.png', '@2x.gif', '@2x.webp' ),
$url
)
);
}
if ( ! is_wp_error( $data ) ) {
return $data;
}
}
/**
* Taken from the core media_sideload_image function and
* modified to return an array of data instead of html.
*
* @param string $file The image file path.
* @return array An array of image data.
*/
public static function sideload_image( $file ) {
$data = new stdClass();
if ( ! function_exists( 'media_handle_sideload' ) ) {
call_user_func( 'require_once', ABSPATH . 'wp-admin/includes/media.php' );
call_user_func( 'require_once', ABSPATH . 'wp-admin/includes/file.php' );
call_user_func( 'require_once', ABSPATH . 'wp-admin/includes/image.php' );
}
if ( ! empty( $file ) ) {
// Set variables for storage, fix file filename for query strings.
preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png|webp)\b/i', $file, $matches );
$file_array = array();
$file_array['name'] = basename( $matches[0] );
// Download file to temp location.
$file_array['tmp_name'] = download_url( $file );
// If error storing temporarily, return the error.
if ( is_wp_error( $file_array['tmp_name'] ) ) {
return $file_array['tmp_name'];
}
// Do the validation and storage stuff.
$id = media_handle_sideload( $file_array, 0 );
// If error storing permanently, unlink.
if ( is_wp_error( $id ) ) {
unlink( $file_array['tmp_name'] );
return $id;
}
// Build the object to return.
$meta = wp_get_attachment_metadata( $id );
$data->attachment_id = $id;
$data->url = wp_get_attachment_url( $id );
$data->thumbnail_url = wp_get_attachment_thumb_url( $id );
$data->height = $meta['height'];
$data->width = $meta['width'];
}
return $data;
}
/**
* Checks to see whether a string is an image url or not.
*
* @param string $string The string to check.
* @return bool Whether the string is an image url or not.
*/
public static function is_image_url( $string = '' ) {
if ( is_string( $string ) ) {
if ( preg_match( '/\.(jpg|jpeg|png|gif|webp)/i', $string ) ) {
return true;
}
}
return false;
}
/**
* Add custom mimes for the uploader.
*
* @param array $mimes The mimes.
*/
public function add_custom_mimes( $mimes ) {
// Allow XML files.
$mimes['xml'] = 'text/xml';
// Allow JSON files.
$mimes['json'] = 'application/json';
return $mimes;
}
/**
* Filters the "real" file type of the given file.
*
* @param array $wp_check_filetype_and_ext The wp_check_filetype_and_ext.
* @param string $file The file.
* @param string $filename The filename.
* @param array $mimes The mimes.
*/
public function real_mime_type_for_xml( $wp_check_filetype_and_ext, $file, $filename, $mimes ) {
if ( '.xml' === substr( $filename, -4 ) ) {
$wp_check_filetype_and_ext['ext'] = 'xml';
$wp_check_filetype_and_ext['type'] = 'text/xml';
}
return $wp_check_filetype_and_ext;
}
/**
* Get plugin status.
*
* @param string $plugin_path Plugin path.
*/
public function get_plugin_status( $plugin_path ) {
if ( ! current_user_can( 'install_plugins' ) ) {
return;
}
if ( ! file_exists( WP_PLUGIN_DIR . '/' . $plugin_path ) ) {
return 'not_installed';
} elseif ( in_array( $plugin_path, (array) get_option( 'active_plugins', array() ), true ) || is_plugin_active_for_network( $plugin_path ) ) {
return 'active';
} else {
return 'inactive';
}
}
/**
* Install a plugin.
*
* @param string $plugin_slug Plugin slug.
*/
public function install_plugin( $plugin_slug ) {
if ( ! current_user_can( 'install_plugins' ) ) {
return;
}
if ( ! function_exists( 'plugins_api' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
}
if ( ! class_exists( 'WP_Upgrader' ) ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
}
if ( false === filter_var( $plugin_slug, FILTER_VALIDATE_URL ) ) {
$api = plugins_api(
'plugin_information',
array(
'slug' => $plugin_slug,
'fields' => array(
'short_description' => false,
'sections' => false,
'requires' => false,
'rating' => false,
'ratings' => false,
'downloaded' => false,
'last_updated' => false,
'added' => false,
'tags' => false,
'compatibility' => false,
'homepage' => false,
'donate_link' => false,
),
)
);
$download_link = $api->download_link;
} else {
$download_link = $plugin_slug;
}
// Use AJAX upgrader skin instead of plugin installer skin.
// ref: function wp_ajax_install_plugin().
$upgrader = new Plugin_Upgrader( new WP_Ajax_Upgrader_Skin() );
$this->pre_plugin_setup();
$install = $upgrader->install( $download_link );
if ( false === $install ) {
return false;
} else {
return true;
}
}
/**
* Activate a plugin.
*
* @param string $plugin_path Plugin path.
*/
public function activate_plugin( $plugin_path ) {
if ( ! current_user_can( 'install_plugins' ) ) {
return false;
}
$this->pre_plugin_setup();
$activate = activate_plugin( $plugin_path, '', false, true );
if ( is_wp_error( $activate ) ) {
return false;
} else {
return true;
}
}
/**
* Detect ajax import.
*/
public function is_ajax_import() {
if ( __return_false() ) {
check_ajax_referer();
}
$current_action = __return_empty_string();
if ( isset( $_REQUEST['action'] ) ) {
$current_action = sanitize_text_field( $_REQUEST['action'] );
}
if ( preg_match( '/csco_import/', $current_action ) ) {
return $current_action;
}
}
/**
* Hide errors for wpdb
*
* @param object $query The query.
*/
public function ajax_wpdb_hide_errors( $query ) {
global $wpdb;
if ( $this->is_ajax_import() ) {
$wpdb->hide_errors();
}
return $query;
}
/**
* Hide errors for runtime
*/
public function ajax_runtime_hide_errors() {
call_user_func( 'ini_set', 'display_errors', 'Off' );
}
/**
* Ajax import start
*/
public function ajax_import_start() {
ob_start();
}
/**
* Ajax import end
*/
public function ajax_import_end() {
ob_end_flush();
}
/**
* Sends a JSON response back to an Ajax request, indicating failure.
*
* @param mixed $data Data to encode as JSON, then print and die.
*/
public function send_json_error( $data = null ) {
$log = trim( ob_get_clean() );
if ( $log ) {
$data .= sprintf( '%s', PHP_EOL . $log );
}
wp_send_json_error( $data );
}
/**
* Sends a JSON response back to an Ajax request, indicating success.
*
* @param mixed $data Data to encode as JSON, then print and die.
*/
public function send_json_success( $data = null ) {
$log = trim( ob_get_clean() );
if ( $log ) {
$data .= sprintf( '%s', PHP_EOL . $log );
}
wp_send_json_success( $data );
}
/**
* AJAX callback to install and activate a plugin.
*/
public function ajax_import_plugin() {
set_time_limit( 0 );
$this->ajax_import_start();
check_ajax_referer( 'nonce', 'nonce' );
if ( ! isset( $_POST['plugin_slug'] ) || ! sanitize_text_field( $_POST['plugin_slug'] ) ) {
$this->send_json_error( esc_html__( 'Unknown slug in a plugin.', 'revision' ) );
}
if ( ! isset( $_POST['plugin_path'] ) || ! sanitize_text_field( $_POST['plugin_path'] ) ) {
$this->send_json_error( esc_html__( 'Unknown path in a plugin.', 'revision' ) );
}
$plugin_slug = sanitize_text_field( $_POST['plugin_slug'] );
$plugin_path = sanitize_text_field( $_POST['plugin_path'] );
if ( ! current_user_can( 'install_plugins' ) ) {
$this->send_json_error( esc_html__( 'Insufficient permissions to install the plugin.', 'revision' ) );
}
if ( 'not_installed' === $this->get_plugin_status( $plugin_path ) ) {
$this->install_plugin( $plugin_slug );
$this->activate_plugin( $plugin_path );
} elseif ( 'inactive' === $this->get_plugin_status( $plugin_path ) ) {
$this->activate_plugin( $plugin_path );
}
if ( 'active' === $this->get_plugin_status( $plugin_path ) ) {
$this->send_json_success();
}
/**
* The csco_import_plugin hook.
*
* @since 1.0.0
*/
do_action( 'csco_import_plugin', $plugin_slug, $plugin_path );
$this->send_json_error( esc_html__( 'Failed to initialize or activate importer plugin.', 'revision' ) );
$this->ajax_import_end();
}
/**
* AJAX callback to import contents and media files from contents.xml.
*/
public function ajax_import_contents() {
$this->ajax_import_start();
check_ajax_referer( 'nonce', 'nonce' );
$import_type = 'default';
if ( ! isset( $_POST['url'] ) || ! sanitize_text_field( $_POST['url'] ) ) {
$this->send_json_error( esc_html__( 'The url address of the demo content is not specified.', 'revision' ) );
}
if ( isset( $_POST['type'] ) && sanitize_text_field( $_POST['type'] ) ) {
$import_type = sanitize_text_field( $_POST['type'] );
}
$file_url = sanitize_text_field( $_POST['url'] );
$xml_file_hash_id = 'csco_importer_data_' . md5( $file_url );
$xml_file_path = get_transient( $xml_file_hash_id );
if ( ! $xml_file_path ) {
if ( ! current_user_can( 'edit_theme_options' ) ) {
$this->send_json_error( esc_html__( 'You are not permitted to import contents.', 'revision' ) );
}
if ( ! isset( $file_url ) ) {
$this->send_json_error( esc_html__( 'No XML file specified.', 'revision' ) );
}
/**
* Download contents.xml
*/
if ( ! function_exists( 'download_url' ) ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
}
$url = wp_unslash( $file_url );
$timeout_seconds = 5;
add_filter( 'https_ssl_verify', '__return_false' );
// Download file to temp dir.
$temp_file = download_url( $url, $timeout_seconds );
add_filter( 'https_local_ssl_verify', '__return_false' );
if ( is_wp_error( $temp_file ) ) {
$this->send_json_error( $temp_file->get_error_message() );
}
// Array based on $_FILE as seen in PHP file uploads.
$file_args = array(
'name' => basename( $url ),
'tmp_name' => $temp_file,
'error' => 0,
'size' => filesize( $temp_file ),
);
$overrides = array(
// This tells WordPress to not look for the POST form
// fields that would normally be present. Default is true.
// Since the file is being downloaded from a remote server,
// there will be no form fields.
'test_form' => false,
// Setting this to false lets WordPress allow empty files not recommended.
'test_size' => true,
// A properly uploaded file will pass this test.
// There should be no reason to override this one.
'test_upload' => true,
'mimes' => array(
'xml' => 'text/xml',
),
);
// Move the temporary file into the uploads directory.
$download_response = wp_handle_sideload( $file_args, $overrides );
// Error when downloading XML file.
if ( isset( $download_response['error'] ) ) {
$this->send_json_error( $download_response['error'] );
}
// Define the downloaded contents.xml file path.
$xml_file_path = $download_response['file'];
set_transient( $xml_file_hash_id, $xml_file_path, HOUR_IN_SECONDS );
}
/**
* Import content and media files using WXR Importer.
*/
if ( ! class_exists( 'WP_Importer' ) ) {
if ( ! defined( 'WP_LOAD_IMPORTERS' ) ) {
define( 'WP_LOAD_IMPORTERS', true );
}
require_once ABSPATH . 'wp-admin/includes/class-wp-importer.php';
}
/**
* Import Core.
*/
require_once get_theme_file_path( '/core/theme-demos/import/wp-content-importer-v2/WPImporterLogger.php' );
require_once get_theme_file_path( '/core/theme-demos/import/wp-content-importer-v2/WPImporterLoggerCLI.php' );
require_once get_theme_file_path( '/core/theme-demos/import/wp-content-importer-v2/WXRImportInfo.php' );
require_once get_theme_file_path( '/core/theme-demos/import/wp-content-importer-v2/WXRImporter.php' );
require_once get_theme_file_path( '/core/theme-demos/import/wp-content-importer-v2/Logger.php' );
/**
* Prepare the importer.
*/
// Time to run the import!
set_time_limit( 0 );
$this->microtime = microtime( true );
// Are we allowed to create users?
add_filter( 'wxr_importer.pre_process.user', '__return_null' );
// Check, if we need to send another AJAX request and set the importing author to the current user.
add_filter( 'wxr_importer.pre_process.post', array( $this, 'ajax_request_maybe' ) );
// Set the WordPress Importer v2 as the importer used in this plugin.
// More: https://github.com/humanmade/WordPress-Importer.
$importer = new CSCO_WXRImporter( array(
'fetch_attachments' => true,
'default_author' => get_current_user_id(),
) );
/**
* Logger options for the logger used in the importer.
*
* The csco_logger_options hook.
*
* @since 1.0.0
*/
$logger_options = apply_filters( 'csco_logger_options', array(
'logger_min_level' => 'warning',
) );
// Configure logger instance and set it to the importer.
$logger = new CSCO_Logger();
$logger->min_level = $logger_options['logger_min_level'];
// Set logger.
$importer->set_logger( $logger );
/**
* Process import.
*/
$importer->import( $xml_file_path );
// Is error ?.
if ( is_wp_error( $importer ) ) {
$this->send_json_error( $importer->get_error_message() );
}
if ( $logger->error_output ) {
$this->send_json_error( $logger->error_output );
}
/**
* The csco_import_contents hook.
*
* @since 1.0.0
*/
do_action( 'csco_import_contents' );
/**
* Return successful AJAX.
*/
$this->send_json_success();
$this->ajax_import_end();
}
/**
* Check if we need to create a new AJAX request, so that server does not timeout.
*
* @param array $data current post data.
* @return array
*/
public function ajax_request_maybe( $data ) {
$time = microtime( true ) - $this->microtime;
/**
* We should make a new ajax call, if the time is right.
*
* The csco_time_for_one_ajax_call hook.
*
* @since 1.0.0
*/
if ( $time > apply_filters( 'csco_time_for_one_ajax_call', 22 ) ) {
$response = array(
'success' => true,
'status' => 'newAJAX',
'message' => 'Time for new AJAX request!: ' . $time,
);
// Send the request for a new AJAX call.
wp_send_json( $response );
}
// Set importing author to the current user.
// Fixes the [WARNING] Could not find the author for ... log warning messages.
$current_user_obj = wp_get_current_user();
$data['post_author'] = $current_user_obj->user_login;
return $data;
}
/**
* AJAX callback to import customizer settings from customizer.json.
*/
public function ajax_import_customizer() {
set_time_limit( 0 );
$this->ajax_import_start();
check_ajax_referer( 'nonce', 'nonce' );
if ( ! isset( $_POST['url'] ) || ! sanitize_text_field( $_POST['url'] ) ) {
$this->send_json_error( esc_html__( 'The url address of the demo content is not specified.', 'revision' ) );
}
$file_url = sanitize_text_field( $_POST['url'] );
if ( ! current_user_can( 'edit_theme_options' ) ) {
$this->send_json_error( esc_html__( 'You are not permitted to import customizer.', 'revision' ) );
}
if ( ! isset( $file_url ) ) {
$this->send_json_error( esc_html__( 'No customizer JSON file specified.', 'revision' ) );
}
/**
* Process customizer.json.
*/
// Get JSON data from customizer.json.
$raw = wp_remote_get( wp_unslash( $file_url ), array(
'sslverify' => false,
) );
// Abort if customizer.json response code is not successful.
if ( 200 !== wp_remote_retrieve_response_code( $raw ) ) {
$this->send_json_error();
}
// Decode raw JSON string to associative array.
$data = json_decode( wp_remote_retrieve_body( $raw ), true );
$customizer = new CSCO_Customizer_Importer();
// Import.
$results = $customizer->import( $data );
if ( is_wp_error( $results ) ) {
$error_message = $results->get_error_message();
$this->send_json_error( $error_message );
}
/**
* The csco_import_customizer hook.
*
* @since 1.0.0
*/
do_action( 'csco_import_customizer', $data );
/**
* Return successful AJAX.
*/
$this->send_json_success();
$this->ajax_import_end();
}
/**
* AJAX callback to import widgets on all sidebars from widgets.json.
*/
public function ajax_import_widgets() {
set_time_limit( 0 );
$this->ajax_import_start();
check_ajax_referer( 'nonce', 'nonce' );
if ( ! isset( $_POST['url'] ) || ! sanitize_text_field( $_POST['url'] ) ) {
$this->send_json_error( esc_html__( 'The url address of the demo content is not specified.', 'revision' ) );
}
$file_url = sanitize_text_field( $_POST['url'] );
if ( ! current_user_can( 'edit_theme_options' ) ) {
$this->send_json_error( esc_html__( 'You are not permitted to import widgets.', 'revision' ) );
}
if ( ! isset( $file_url ) ) {
$this->send_json_error( esc_html__( 'No widgets WIE file specified.', 'revision' ) );
}
/**
* Process widgets.json.
*/
// Get JSON data from widgets.json.
$raw = wp_remote_get( wp_unslash( $file_url ), array(
'sslverify' => false,
) );
// Abort if customizer.json response code is not successful.
if ( 200 !== (int) wp_remote_retrieve_response_code( $raw ) ) {
$this->send_json_error();
}
// Decode raw JSON string to associative array.
$data = json_decode( wp_remote_retrieve_body( $raw ) );
$widgets = new CSCO_Widget_Importer();
// Import.
$results = $widgets->import( $data );
if ( is_wp_error( $results ) ) {
$error_message = $results->get_error_message();
$this->send_json_error( $error_message );
}
/**
* The csco_import_widgets hook.
*
* @since 1.0.0
*/
do_action( 'csco_import_widgets' );
/**
* Return successful AJAX.
*/
$this->send_json_success();
$this->ajax_import_end();
}
/**
* AJAX callback to import other options from options.json.
*/
public function ajax_import_options() {
set_time_limit( 0 );
$this->ajax_import_start();
check_ajax_referer( 'nonce', 'nonce' );
if ( ! isset( $_POST['url'] ) || ! sanitize_text_field( $_POST['url'] ) ) {
$this->send_json_error( esc_html__( 'The url address of the demo content is not specified.', 'revision' ) );
}
$file_url = sanitize_text_field( $_POST['url'] );
if ( ! current_user_can( 'edit_theme_options' ) ) {
$this->send_json_error( esc_html__( 'You are not permitted to import options.', 'revision' ) );
}
if ( ! isset( $file_url ) ) {
$this->send_json_error( esc_html__( 'No options JSON file specified.', 'revision' ) );
}
/**
* Process options.json.
*/
// Get JSON data from options.json.
$raw = wp_remote_get( wp_unslash( $file_url ), array(
'sslverify' => false,
) );
// Abort if customizer.json response code is not successful.
if ( 200 !== (int) wp_remote_retrieve_response_code( $raw ) ) {
$this->send_json_error();
}
// Decode raw JSON string to associative array.
$array = json_decode( wp_remote_retrieve_body( $raw ), true );
/**
* Import options to DB.
*/
foreach ( $array as $key => $value ) {
// Skip option key with "__" prefix, because it will be treated specifically via the action hook.
if ( '__' === substr( $key, 0, 2 ) ) {
continue;
}
// Insert to options table.
update_option( $key, $value );
}
/**
* The csco_import_options hook.
*
* @since 1.0.0
*/
do_action( 'csco_import_options', $array );
/**
* Return successful AJAX.
*/
$this->send_json_success();
$this->ajax_import_end();
}
/**
* AJAX callback to finish import.
*/
public function ajax_import_finish() {
set_time_limit( 0 );
$this->ajax_import_start();
/**
* The csco_finish_import hook.
*
* @since 1.0.0
*/
do_action( 'csco_finish_import' );
/**
* Return successful AJAX.
*/
$this->send_json_success();
$this->ajax_import_end();
}
}
new CSCO_Manager_Import();

View File

@@ -0,0 +1,317 @@
<?php
/**
* Class for the widget importer.
*
* Code is mostly from the Widget Importer & Exporter plugin.
*
* @see https://wordpress.org/plugins/widget-importer-exporter/
* @package Revision
*/
/**
* Widget Importer
*/
class CSCO_Widget_Importer {
/**
* Import widgets from WIE or JSON file.
*
* @param array $data The data.
*/
public static function import( $data ) {
// Import widgets and return result.
return self::import_data( $data );
}
/**
* Import widget JSON data
*
* @global array $wp_registered_sidebars
* @param object $data JSON widget data.
* @return array $results
*/
private static function import_data( $data ) {
global $wp_registered_sidebars;
// Have valid data? If no data or could not decode.
if ( empty( $data ) || ! is_object( $data ) ) {
return new WP_Error(
'corrupted_widget_import_data',
__( 'Error: Widget import data could not be read. Please try a different file.', 'revision' )
);
}
/**
* Hook before import.
*
* The csco_widget_importer_before_widgets_import hook.
*
* @since 1.0.0
*/
do_action( 'csco_widget_importer_before_widgets_import' );
/**
* The csco_before_widgets_import_data hook.
*
* @since 1.0.0
*/
$data = apply_filters( 'csco_before_widgets_import_data', $data );
// Get all available widgets site supports.
$available_widgets = self::available_widgets();
// Get all existing widget instances.
$widget_instances = array();
foreach ( $available_widgets as $widget_data ) {
$widget_instances[ $widget_data['id_base'] ] = get_option( 'widget_' . $widget_data['id_base'] );
}
// Begin results.
$results = array();
// Loop import data's sidebars.
foreach ( $data as $sidebar_id => $widgets ) {
// Skip inactive widgets (should not be in export file).
if ( 'wp_inactive_widgets' === $sidebar_id ) {
continue;
}
// Check if sidebar is available on this site. Otherwise add widgets to inactive, and say so.
if ( isset( $wp_registered_sidebars[ $sidebar_id ] ) ) {
$sidebar_available = true;
$use_sidebar_id = $sidebar_id;
$sidebar_message_type = 'success';
$sidebar_message = '';
} else {
$sidebar_available = false;
$use_sidebar_id = 'wp_inactive_widgets'; // Add to inactive if sidebar does not exist in theme.
$sidebar_message_type = 'error';
$sidebar_message = __( 'Sidebar does not exist in theme (moving widget to Inactive)', 'revision' );
}
// Result for sidebar.
$results[ $sidebar_id ]['name'] = ! empty( $wp_registered_sidebars[ $sidebar_id ]['name'] ) ? $wp_registered_sidebars[ $sidebar_id ]['name'] : $sidebar_id; // Sidebar name if theme supports it; otherwise ID.
$results[ $sidebar_id ]['message_type'] = $sidebar_message_type;
$results[ $sidebar_id ]['message'] = $sidebar_message;
$results[ $sidebar_id ]['widgets'] = array();
// Loop widgets.
foreach ( $widgets as $widget_instance_id => $widget ) {
$fail = false;
// Get id_base (remove -# from end) and instance ID number.
$id_base = preg_replace( '/-[0-9]+$/', '', $widget_instance_id );
$instance_id_number = str_replace( $id_base . '-', '', $widget_instance_id );
// Does site support this widget?
if ( ! $fail && ! isset( $available_widgets[ $id_base ] ) ) {
$fail = true;
$widget_message_type = 'error';
$widget_message = __( 'Site does not support widget', 'revision' ); // Explain why widget not imported.
}
// Filter to modify settings object before conversion to array and import.
// Leave this filter here for backwards compatibility with manipulating objects (before conversion to array below).
// Ideally the newer wie_widget_settings_array below will be used instead of this.
/**
* Filter to modify settings object before conversion to array and import.
* Leave this filter here for backwards compatibility with manipulating objects (before conversion to array below).
* Ideally the newer wie_widget_settings_array below will be used instead of this.
*
* The csco_widget_settings hook.
*
* @since 1.0.0
*/
$widget = apply_filters( 'csco_widget_settings', $widget ); // Object.
// Convert multidimensional objects to multidimensional arrays.
// Some plugins like Jetpack Widget Visibility store settings as multidimensional arrays.
// Without this, they are imported as objects and cause fatal error on Widgets page.
// If this creates problems for plugins that do actually intend settings in objects then may need to consider other approach: https://wordpress.org/support/topic/problem-with-array-of-arrays.
// It is probably much more likely that arrays are used than objects, however.
$widget = json_decode( json_encode( $widget ), true );
/**
* Filter to modify settings array.
* This is preferred over the older wie_widget_settings filter above.
* Do before identical check because changes may make it identical to end result (such as URL replacements).
*
* The csco_widget_settings_array hook.
*
* @since 1.0.0
*/
$widget = apply_filters( 'csco_widget_settings_array', $widget );
// Does widget with identical settings already exist in same sidebar?
if ( ! $fail && isset( $widget_instances[ $id_base ] ) ) {
// Get existing widgets in this sidebar.
$sidebars_widgets = get_option( 'sidebars_widgets' );
$sidebar_widgets = isset( $sidebars_widgets[ $use_sidebar_id ] ) ? $sidebars_widgets[ $use_sidebar_id ] : array(); // Check Inactive if that's where will go.
// Loop widgets with ID base.
$single_widget_instances = ! empty( $widget_instances[ $id_base ] ) ? $widget_instances[ $id_base ] : array();
foreach ( $single_widget_instances as $check_id => $check_widget ) {
// Is widget in same sidebar and has identical settings?
if ( in_array( "$id_base-$check_id", $sidebar_widgets ) && (array) $widget == $check_widget ) {
$fail = true;
$widget_message_type = 'warning';
$widget_message = __( 'Widget already exists', 'revision' ); // Explain why widget not imported.
break;
}
}
}
// No failure.
if ( ! $fail ) {
// Add widget instance.
$single_widget_instances = get_option( 'widget_' . $id_base ); // All instances for that widget ID base, get fresh every time.
$single_widget_instances = ! empty( $single_widget_instances ) ? $single_widget_instances : array( '_multiwidget' => 1 ); // Start fresh if have to.
$single_widget_instances[] = $widget; // Add it.
// Get the key it was given.
end( $single_widget_instances );
$new_instance_id_number = key( $single_widget_instances );
// If key is 0, make it 1.
// When 0, an issue can occur where adding a widget causes data from other widget to load, and the widget doesn't stick (reload wipes it).
if ( '0' === strval( $new_instance_id_number ) ) {
$new_instance_id_number = 1;
$single_widget_instances[ $new_instance_id_number ] = $single_widget_instances[0];
unset( $single_widget_instances[0] );
}
// Move _multiwidget to end of array for uniformity.
if ( isset( $single_widget_instances['_multiwidget'] ) ) {
$multiwidget = $single_widget_instances['_multiwidget'];
unset( $single_widget_instances['_multiwidget'] );
$single_widget_instances['_multiwidget'] = $multiwidget;
}
// Update option with new widget.
update_option( 'widget_' . $id_base, $single_widget_instances );
// Assign widget instance to sidebar.
$sidebars_widgets = get_option( 'sidebars_widgets' ); // Which sidebars have which widgets, get fresh every time.
// Avoid rarely fatal error when the option is an empty string
// https://github.com/churchthemes/widget-importer-exporter/pull/11.
if ( ! $sidebars_widgets ) {
$sidebars_widgets = array();
}
$new_instance_id = $id_base . '-' . $new_instance_id_number; // Use ID number from new widget instance.
$sidebars_widgets[ $use_sidebar_id ][] = $new_instance_id; // Add new instance to sidebar.
update_option( 'sidebars_widgets', $sidebars_widgets ); // Save the amended data.
// After widget import action.
$after_widget_import = array(
'sidebar' => $use_sidebar_id,
'sidebar_old' => $sidebar_id,
'widget' => $widget,
'widget_type' => $id_base,
'widget_id' => $new_instance_id,
'widget_id_old' => $widget_instance_id,
'widget_id_num' => $new_instance_id_number,
'widget_id_num_old' => $instance_id_number,
);
/**
* The csco_widget_importer_after_single_widget_import hook.
*
* @since 1.0.0
*/
do_action( 'csco_widget_importer_after_single_widget_import', $after_widget_import );
// Success message.
if ( $sidebar_available ) {
$widget_message_type = 'success';
$widget_message = __( 'Imported', 'revision' );
} else {
$widget_message_type = 'warning';
$widget_message = __( 'Imported to Inactive', 'revision' );
}
}
// Result for widget instance.
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['name'] = isset( $available_widgets[ $id_base ]['name'] ) ? $available_widgets[ $id_base ]['name'] : $id_base; // Widget name or ID if name not available (not supported by site).
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['title'] = ! empty( $widget['title'] ) ? $widget['title'] : __( 'No Title', 'revision' ); // Show "No Title" if widget instance is untitled.
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message_type'] = $widget_message_type;
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message'] = $widget_message;
}
}
/**
* Hook after import.
*
* The csco_widget_importer_after_widgets_import hook.
*
* @since 1.0.0
*/
do_action( 'csco_widget_importer_after_widgets_import' );
/**
* Return results.
*
* The csco_widget_import_results hook.
*
* @since 1.0.0
*/
return apply_filters( 'csco_widget_import_results', $results );
}
/**
* Available widgets.
*
* Gather site's widgets into array with ID base, name, etc.
*
* @global array $wp_registered_widget_controls
* @return array $available_widgets, Widget information
*/
private static function available_widgets() {
global $wp_registered_widget_controls;
$widget_controls = $wp_registered_widget_controls;
$available_widgets = array();
foreach ( $widget_controls as $widget ) {
if ( ! empty( $widget['id_base'] ) && ! isset( $available_widgets[ $widget['id_base'] ] ) ) {
$available_widgets[ $widget['id_base'] ]['id_base'] = $widget['id_base'];
$available_widgets[ $widget['id_base'] ]['name'] = $widget['name'];
}
}
/**
* The csco_available_widgets hook.
*
* @since 1.0.0
*/
return apply_filters( 'csco_available_widgets', $available_widgets );
}
/**
* Format results for log file
*
* @param array $results widget import results.
*/
private static function format_results_for_log( $results ) {
if ( empty( $results ) ) {
esc_html_e( 'No results for widget import!', 'revision' );
}
// Loop sidebars.
foreach ( $results as $sidebar ) {
echo esc_html( $sidebar['name'] ) . ' : ' . esc_html( $sidebar['message'] ) . PHP_EOL . PHP_EOL;
// Loop widgets.
foreach ( $sidebar['widgets'] as $widget ) {
echo esc_html( $widget['name'] ) . ' - ' . esc_html( $widget['title'] ) . ' - ' . esc_html( $widget['message'] ) . PHP_EOL;
}
echo PHP_EOL;
}
}
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* Logger Class
*
* @package Revision
*/
/**
* Logger Class
*/
class CSCO_Logger extends CSCO_WPImporterLoggerCLI {
/**
* Variable for front-end error display.
*
* @var string
*/
public $error_output = '';
/**
* Overwritten log function from CSCO_WP_Importer_Logger_CLI.
*
* Logs with an arbitrary level.
*
* @param mixed $level level of reporting.
* @param string $message log message.
* @param array $context context to the log message.
*/
public function log( $level, $message, array $context = array() ) {
// Save error messages for front-end display.
$this->error_output( $level, $message, $context = array() );
if ( $this->level_to_numeric( $level ) < $this->level_to_numeric( $this->min_level ) ) {
return;
}
}
/**
* Save messages for error output.
* Only the messages greater then Error.
*
* @param mixed $level level of reporting.
* @param string $message log message.
* @param array $context context to the log message.
*/
public function error_output( $level, $message, array $context = array() ) {
if ( $this->level_to_numeric( $level ) < $this->level_to_numeric( 'error' ) ) {
return;
}
$this->error_output .= sprintf( '[%s] %s<br>', strtoupper( $level ), $message );
}
}

View File

@@ -0,0 +1,126 @@
<?php
/**
* Describes a logger instance
*
* Based on PSR-3: http://www.php-fig.org/psr/psr-3/
*
* The message MUST be a string or object implementing __toString().
*
* The message MAY contain placeholders in the form: {foo} where foo
* will be replaced by the context data in key "foo".
*
* The context array can contain arbitrary data, the only assumption that
* can be made by implementors is that if an Exception instance is given
* to produce a stack trace, it MUST be in a key named "exception".
*
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
* for the full interface specification.
*/
class CSCO_WPImporterLogger {
/**
* System is unusable.
*
* @param string $message The message.
* @param array $context The context.
*/
public function emergency( $message, array $context = array() ) {
return $this->log( 'emergency', $message, $context );
}
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message The message.
* @param array $context The context.
*/
public function alert( $message, array $context = array() ) {
return $this->log( 'alert', $message, $context );
}
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message The message.
* @param array $context The context.
*/
public function critical( $message, array $context = array() ) {
return $this->log( 'critical', $message, $context );
}
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* @param string $message The message.
* @param array $context The context.
*/
public function error( $message, array $context = array() ) {
return $this->log( 'error', $message, $context );
}
/**
* Exceptional occurrences that are not errors.
*
* Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong.
*
* @param string $message The message.
* @param array $context The context.
*/
public function warning( $message, array $context = array() ) {
return $this->log( 'warning', $message, $context );
}
/**
* Normal but significant events.
*
* @param string $message The message.
* @param array $context The context.
*/
public function notice( $message, array $context = array() ) {
return $this->log( 'notice', $message, $context );
}
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message The message.
* @param array $context The context.
*/
public function info( $message, array $context = array() ) {
return $this->log( 'info', $message, $context );
}
/**
* Detailed debug information.
*
* @param string $message The message.
* @param array $context The context.
*/
public function debug( $message, array $context = array() ) {
return $this->log( 'debug', $message, $context );
}
/**
* Logs with an arbitrary level.
*
* @param mixed $level The level.
* @param string $message The message.
* @param array $context The context.
*/
public function log( $level, $message, array $context = array() ) {
$this->messages[] = array(
'timestamp' => time(),
'level' => $level,
'message' => $message,
'context' => $context,
);
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* WP Importer Logger CLI Class
*
* @package Revision
*/
/**
* WP Importer Logger CLI Class
*/
class CSCO_WPImporterLoggerCLI extends CSCO_WPImporterLogger {
public $min_level = 'notice';
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
* @return null
*/
public function log( $level, $message, array $context = array() ) {
if ( $this->level_to_numeric( $level ) < $this->level_to_numeric( $this->min_level ) ) {
return;
}
call_user_func( 'printf', '[%s] %s' . PHP_EOL, strtoupper( $level ), $message );
}
public static function level_to_numeric( $level ) {
$levels = array(
'emergency' => 8,
'alert' => 7,
'critical' => 6,
'error' => 5,
'warning' => 4,
'notice' => 3,
'info' => 2,
'debug' => 1,
);
if ( ! isset( $levels[ $level ] ) ) {
return 0;
}
return $levels[ $level ];
}
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* WP Importer Info Class
*/
/**
* WP Importer Info Class
*/
class CSCO_WXRImportInfo {
public $home;
public $siteurl;
public $title;
public $users = array();
public $post_count = 0;
public $media_count = 0;
public $comment_count = 0;
public $term_count = 0;
public $generator = '';
public $version;
}

File diff suppressed because it is too large Load Diff