This commit is contained in:
2026-07-02 15:54:39 -06:00
commit 9883323161
17470 changed files with 4470592 additions and 0 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,414 @@
<?php
/**
* This file handles the Site Library.
*
* @since 1.6.0
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
/**
* Do our Site Library.
*/
class GeneratePress_Site_Library {
/**
* Instance.
*
* @access private
* @var object Instance
* @since 1.6
*/
private static $instance;
/**
* Initiator.
*
* @since 1.6
* @return object initialized object of class.
*/
public static function get_instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Get it going.
*/
public function __construct() {
add_action( 'admin_menu', array( $this, 'add_menu' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
add_action( 'generate_export_items', array( $this, 'add_export_checkbox' ) );
add_filter( 'generate_export_data', array( $this, 'do_site_export' ) );
add_filter( 'generate_dashboard_tabs', array( $this, 'add_dashboard_tab' ) );
add_filter( 'generate_dashboard_screens', array( $this, 'add_dashboard_screen' ) );
add_action( 'admin_head', array( $this, 'fix_menu' ) );
}
/**
* Add our menu item.
*/
public function add_menu() {
add_submenu_page(
'themes.php',
__( 'Site Library', 'gp-premium' ),
__( 'Site Library', 'gp-premium' ),
'manage_options',
'generatepress-library',
array( $this, 'library_page' )
);
}
/**
* Set our current menu item as the GeneratePress Dashboard.
*/
public function fix_menu() {
global $parent_file, $submenu_file, $post_type;
$screen = get_current_screen();
if ( 'appearance_page_generatepress-library' === $screen->id ) {
$parent_file = 'themes.php'; // phpcs:ignore -- Override necessary.
$submenu_file = 'generate-options'; // phpcs:ignore -- Override necessary.
}
remove_submenu_page( 'themes.php', 'generatepress-library' );
}
/**
* Add our scripts.
*/
public function enqueue_scripts() {
$screen = get_current_screen();
if ( 'appearance_page_generatepress-library' === $screen->id ) {
wp_enqueue_script(
'generatepress-pro-site-library',
GP_PREMIUM_DIR_URL . 'dist/site-library.js',
array( 'wp-api', 'wp-i18n', 'wp-components', 'wp-element', 'wp-api-fetch', 'wp-util', 'wp-html-entities', 'updates' ),
GP_PREMIUM_VERSION,
true
);
if ( function_exists( 'wp_set_script_translations' ) ) {
wp_set_script_translations( 'generatepress-pro-site-library', 'gp-premium', GP_PREMIUM_DIR_PATH . 'langs' );
}
if ( function_exists( 'wp_get_upload_dir' ) ) {
$uploads_url = wp_get_upload_dir();
} else {
$uploads_url = wp_upload_dir( null, false );
}
wp_localize_script(
'generatepress-pro-site-library',
'gppSiteLibrary',
array(
'homeUrl' => esc_url( home_url() ),
'hasBackup' => ! empty( get_option( '_generatepress_site_library_backup', array() ) ),
'gppVersion' => GP_PREMIUM_VERSION,
'gpVersion' => generate_premium_get_theme_version(),
'generateblocksVersion' => defined( 'GENERATEBLOCKS_VERSION' ) ? GENERATEBLOCKS_VERSION : '',
'isGenerateBlocksProInstalled' => file_exists( WP_PLUGIN_DIR . '/generateblocks-pro/plugin.php' ),
'elementorReplaceUrls' => esc_url( admin_url( 'admin.php?page=elementor-tools#tab-replace_url' ) ),
'uploadsUrl' => $uploads_url['baseurl'],
'isDebugEnabled' => defined( 'WP_DEBUG' ) && true === WP_DEBUG,
)
);
wp_enqueue_style(
'generatepress-pro-site-library',
GP_PREMIUM_DIR_URL . 'dist/site-library.css',
array( 'wp-components' ),
GP_PREMIUM_VERSION
);
if ( ! class_exists( 'GeneratePress_Dashboard' ) ) {
wp_enqueue_style(
'generate-premium-dashboard',
GP_PREMIUM_DIR_URL . 'inc/legacy/assets/dashboard.css',
array(),
GP_PREMIUM_VERSION
);
}
}
}
/**
* Add our page.
*/
public function library_page() {
if ( ! class_exists( 'GeneratePress_Dashboard' ) ) :
?>
<div class="site-library-header">
<div class="site-library-container">
<div class="library-title">
<?php _e( 'GeneratePress Site Library', 'gp-premium' ); ?>
</div>
<div class="library-links">
<a href="https://generatepress.com/support" target="_blank"><?php _e( 'Support', 'gp-premium' ); ?></a>
<a href="https://docs.generatepress.com" target="_blank"><?php _e( 'Documentation', 'gp-premium' ); ?></a>
</div>
</div>
</div>
<?php
endif;
do_action( 'generate_before_site_library' );
?>
<div id="gpp-site-library"></div>
<?php
}
/**
* Add the Sites tab to our Dashboard tabs.
*
* @param array $tabs Existing tabs.
* @return array New tabs.
*/
public function add_dashboard_tab( $tabs ) {
$screen = get_current_screen();
$tabs['Sites'] = array(
'name' => __( 'Site Library', 'gp-premium' ),
'url' => admin_url( 'themes.php?page=generatepress-library' ),
'class' => 'appearance_page_generatepress-library' === $screen->id ? 'active' : '',
'id' => 'gp-site-library-tab',
);
return $tabs;
}
/**
* Tell GeneratePress this is an admin page.
*
* @param array $screens Existing screens.
*/
public function add_dashboard_screen( $screens ) {
$screens[] = 'appearance_page_generatepress-library';
return $screens;
}
/**
* Add our GeneratePress Site export checkbox to the Export module.
*/
public function add_export_checkbox() {
if ( ! apply_filters( 'generate_show_generatepress_site_export_option', false ) ) {
return;
}
?>
<hr style="margin:10px 0;border-bottom:0;" />
<label>
<input type="checkbox" name="module_group[]" value="generatepress-site" />
<?php _ex( 'GeneratePress Site', 'Module name', 'gp-premium' ); ?>
</label>
<?php
}
/**
* Add to our export .json file.
*
* @param array $data The current data being exported.
* @return array Existing and extended data.
*/
public function do_site_export( $data ) {
// Bail if we haven't chosen to export the Site.
if ( ! in_array( 'generatepress-site', $_POST['module_group'] ) ) { // phpcs:ignore -- No processing happening here.
return $data;
}
// Modules.
$modules = GeneratePress_Site_Library_Helper::premium_modules();
$data['modules'] = array();
foreach ( $modules as $name => $key ) {
if ( 'activated' === get_option( $key ) ) {
$data['modules'][ $name ] = $key;
}
}
// Site options.
$data['site_options']['nav_menu_locations'] = get_theme_mod( 'nav_menu_locations' );
$data['site_options']['custom_logo'] = wp_get_attachment_url( get_theme_mod( 'custom_logo' ) );
$data['site_options']['show_on_front'] = get_option( 'show_on_front' );
$data['site_options']['page_on_front'] = get_option( 'page_on_front' );
$data['site_options']['page_for_posts'] = get_option( 'page_for_posts' );
// Elements.
$data['site_options']['element_locations'] = $this->get_elements_locations();
$data['site_options']['element_exclusions'] = $this->get_elements_exclusions();
// Custom CSS.
if ( function_exists( 'wp_get_custom_css_post' ) ) {
$data['custom_css'] = wp_get_custom_css_post()->post_content;
}
// WooCommerce.
if ( is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
$data['site_options']['woocommerce_shop_page_id'] = get_option( 'woocommerce_shop_page_id' );
$data['site_options']['woocommerce_cart_page_id'] = get_option( 'woocommerce_cart_page_id' );
$data['site_options']['woocommerce_checkout_page_id'] = get_option( 'woocommerce_checkout_page_id' );
$data['site_options']['woocommerce_myaccount_page_id'] = get_option( 'woocommerce_myaccount_page_id' );
$data['site_options']['woocommerce_single_image_width'] = get_option( 'woocommerce_single_image_width' );
$data['site_options']['woocommerce_thumbnail_image_width'] = get_option( 'woocommerce_thumbnail_image_width' );
$data['site_options']['woocommerce_thumbnail_cropping'] = get_option( 'woocommerce_thumbnail_cropping' );
$data['site_options']['woocommerce_shop_page_display'] = get_option( 'woocommerce_shop_page_display' );
$data['site_options']['woocommerce_category_archive_display'] = get_option( 'woocommerce_category_archive_display' );
$data['site_options']['woocommerce_default_catalog_orderby'] = get_option( 'woocommerce_default_catalog_orderby' );
}
// Elementor.
if ( is_plugin_active( 'elementor/elementor.php' ) ) {
$data['site_options']['elementor_container_width'] = get_option( 'elementor_container_width' );
$data['site_options']['elementor_cpt_support'] = get_option( 'elementor_cpt_support' );
$data['site_options']['elementor_css_print_method'] = get_option( 'elementor_css_print_method' );
$data['site_options']['elementor_default_generic_fonts'] = get_option( 'elementor_default_generic_fonts' );
$data['site_options']['elementor_disable_color_schemes'] = get_option( 'elementor_disable_color_schemes' );
$data['site_options']['elementor_disable_typography_schemes'] = get_option( 'elementor_disable_typography_schemes' );
$data['site_options']['elementor_editor_break_lines'] = get_option( 'elementor_editor_break_lines' );
$data['site_options']['elementor_exclude_user_roles'] = get_option( 'elementor_exclude_user_roles' );
$data['site_options']['elementor_global_image_lightbox'] = get_option( 'elementor_global_image_lightbox' );
$data['site_options']['elementor_page_title_selector'] = get_option( 'elementor_page_title_selector' );
$data['site_options']['elementor_scheme_color'] = get_option( 'elementor_scheme_color' );
$data['site_options']['elementor_scheme_color-picker'] = get_option( 'elementor_scheme_color-picker' );
$data['site_options']['elementor_scheme_typography'] = get_option( 'elementor_scheme_typography' );
$data['site_options']['elementor_space_between_widgets'] = get_option( 'elementor_space_between_widgets' );
$data['site_options']['elementor_stretched_section_container'] = get_option( 'elementor_stretched_section_container' );
$data['site_options']['elementor_load_fa4_shim'] = get_option( 'elementor_load_fa4_shim' );
$data['site_options']['elementor_active_kit'] = get_option( 'elementor_active_kit' );
}
// Beaver Builder.
if ( is_plugin_active( 'beaver-builder-lite-version/fl-builder.php' ) || is_plugin_active( 'bb-plugin/fl-builder.php' ) ) {
$data['site_options']['_fl_builder_enabled_icons'] = get_option( '_fl_builder_enabled_icons' );
$data['site_options']['_fl_builder_enabled_modules'] = get_option( '_fl_builder_enabled_modules' );
$data['site_options']['_fl_builder_post_types'] = get_option( '_fl_builder_post_types' );
$data['site_options']['_fl_builder_color_presets'] = get_option( '_fl_builder_color_presets' );
$data['site_options']['_fl_builder_services'] = get_option( '_fl_builder_services' );
$data['site_options']['_fl_builder_settings'] = get_option( '_fl_builder_settings' );
$data['site_options']['_fl_builder_user_access'] = get_option( '_fl_builder_user_access' );
$data['site_options']['_fl_builder_enabled_templates'] = get_option( '_fl_builder_enabled_templates' );
}
// Menu Icons.
if ( is_plugin_active( 'menu-icons/menu-icons.php' ) ) {
$data['site_options']['menu-icons'] = get_option( 'menu-icons' );
}
// Ninja Forms.
if ( is_plugin_active( 'ninja-forms/ninja-forms.php' ) ) {
$data['site_options']['ninja_forms_settings'] = get_option( 'ninja_forms_settings' );
}
// Social Warfare.
if ( is_plugin_active( 'social-warfare/social-warfare.php' ) ) {
$data['site_options']['socialWarfareOptions'] = get_option( 'socialWarfareOptions' );
}
// Elements Plus.
if ( is_plugin_active( 'elements-plus/elements-plus.php' ) ) {
$data['site_options']['elements_plus_settings'] = get_option( 'elements_plus_settings' );
}
// Ank Google Map.
if ( is_plugin_active( 'ank-google-map/ank-google-map.php' ) ) {
$data['site_options']['ank_google_map'] = get_option( 'ank_google_map' );
}
// GP Social Share.
if ( is_plugin_active( 'gp-social-share-svg/gp-social-share.php' ) ) {
$data['site_options']['gp_social_settings'] = get_option( 'gp_social_settings' );
}
// Active plugins.
$active_plugins = get_option( 'active_plugins' );
$all_plugins = get_plugins();
$ignore = apply_filters(
'generate_sites_ignore_plugins',
array(
'gp-premium/gp-premium.php',
'widget-importer-exporter/widget-importer-exporter.php',
)
);
foreach ( $ignore as $plugin ) {
unset( $all_plugins[ $plugin ] );
}
$activated_plugins = array();
foreach ( $active_plugins as $p ) {
if ( isset( $all_plugins[ $p ] ) ) {
$activated_plugins[ $all_plugins[ $p ]['Name'] ] = $p;
}
}
$data['plugins'] = $activated_plugins;
return $data;
}
/**
* Get our Element display locations.
*
* @return array
*/
public function get_elements_locations() {
$args = array(
'post_type' => 'gp_elements',
'showposts' => -1,
);
$posts = get_posts( $args );
$new_values = array();
foreach ( $posts as $post ) {
$display_conditions = get_post_meta( $post->ID, '_generate_element_display_conditions', true );
if ( $display_conditions ) {
$new_values[ $post->ID ] = $display_conditions;
}
}
return $new_values;
}
/**
* Get our Element display locations.
*
* @return array
*/
public function get_elements_exclusions() {
$args = array(
'post_type' => 'gp_elements',
'showposts' => -1,
);
$posts = get_posts( $args );
$new_values = array();
foreach ( $posts as $post ) {
$display_conditions = get_post_meta( $post->ID, '_generate_element_exclude_conditions', true );
if ( $display_conditions ) {
$new_values[ $post->ID ] = $display_conditions;
}
}
return $new_values;
}
}
GeneratePress_Site_Library::get_instance();
@@ -0,0 +1,163 @@
<?php
/**
* This file handles Beaver Builder functionality during import.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
/**
* Search Beaver Builder content for images to download.
*
* @since 1.6
*/
class GeneratePress_Sites_Process_Beaver_Builder {
/**
* Constructor
*
* @since 1.6
*/
public function __construct() {
$this->image_importer = new GeneratePress_Sites_Image_Importer();
}
/**
* Import
*
* @since 1.6
* @return void
*/
public function import() {
GeneratePress_Site_Library_Helper::log( '== Start Processing Beaver Builder Images ==' );
$post_ids = GeneratePress_Site_Library_Helper::get_all_posts();
if ( is_array( $post_ids ) ) {
foreach ( $post_ids as $post_id ) {
$this->import_single_post( $post_id );
}
}
}
/**
* Update post meta.
*
* @param integer $post_id Post ID.
* @return void
*/
public function import_single_post( $post_id = 0 ) {
if ( ! empty( $post_id ) ) {
// Get page builder data.
$data = get_post_meta( $post_id, '_fl_builder_data', true );
if ( ! empty( $data ) ) {
foreach ( $data as $key => $el ) {
// Import background images.
if ( 'row' === $el->type || 'column' === $el->type ) {
$data[ $key ]->settings = $this->import_background_images( $el->settings );
}
// Import module images.
if ( 'module' === $el->type ) {
$data[ $key ]->settings = $this->import_module_images( $el->settings );
}
}
// Update page builder data.
update_post_meta( $post_id, '_fl_builder_data', $data );
update_post_meta( $post_id, '_fl_builder_draft', $data );
// Clear all cache.
FLBuilderModel::delete_asset_cache_for_all_posts();
}
}
}
/**
* Import Module Images.
*
* @param object $settings Module settings object.
* @return object
*/
public function import_module_images( $settings ) {
/**
* 1) Set photos.
*/
$settings = $this->import_photo( $settings );
/**
* 2) Set `$settings->data` for Only type 'image-icon'
*
* @todo Remove the condition `'image-icon' === $settings->type` if `$settings->data` is used only for the Image Icon.
*/
if ( isset( $settings->data ) && isset( $settings->photo ) && ! empty( $settings->photo ) && 'image-icon' === $settings->type ) {
$settings->data = FLBuilderPhoto::get_attachment_data( $settings->photo );
}
/**
* 3) Set `list item` module images
*/
if ( isset( $settings->add_list_item ) ) {
foreach ( $settings->add_list_item as $key => $value ) {
$settings->add_list_item[ $key ] = $this->import_photo( $value );
}
}
return $settings;
}
/**
* Helper: Import BG Images.
*
* @param object $settings Row settings object.
* @return object
*/
public function import_background_images( $settings ) {
if ( ! empty( $settings->bg_image ) && ! empty( $settings->bg_image_src ) ) {
$image = array(
'url' => $settings->bg_image_src,
'id' => $settings->bg_image,
);
$downloaded_image = $this->image_importer->import( $image );
$settings->bg_image_src = $downloaded_image['url'];
$settings->bg_image = $downloaded_image['id'];
}
return $settings;
}
/**
* Helper: Import Photo.
*
* @param object $settings Row settings object.
* @return object
*/
public function import_photo( $settings ) {
if ( ! empty( $settings->photo ) && ! empty( $settings->photo_src ) ) {
$image = array(
'url' => $settings->photo_src,
'id' => $settings->photo,
);
$downloaded_image = $this->image_importer->import( $image );
$settings->photo_src = $downloaded_image['url'];
$settings->photo = $downloaded_image['id'];
}
return $settings;
}
}
@@ -0,0 +1,49 @@
<?php
/**
* This file extends the Content Importer.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
/**
* Extend the Importer.
*/
class GeneratePress_Sites_Content_Importer extends GeneratePress\WPContentImporter2\WXRImporter {
/**
* Constructor method.
*
* @param array $options Importer options.
*/
public function __construct( $options = array() ) {
parent::__construct( $options );
// Set current user to $mapping variable.
// Fixes the [WARNING] Could not find the author for ... log warning messages.
$current_user_obj = wp_get_current_user();
$this->mapping['user_slug'][ $current_user_obj->user_login ] = $current_user_obj->ID;
}
/**
* Get all protected variables from the WXR_Importer needed for continuing the import.
*/
public function get_importer_data() {
return array(
'mapping' => $this->mapping,
);
}
/**
* Sets all protected variables from the WXR_Importer needed for continuing the import.
*
* @param array $data with set variables.
*/
public function set_importer_data( $data ) {
// phpcs:ignore -- Commented out code for now.
// $this->mapping = empty( $data['mapping'] ) ? array() : $data['mapping'];
// $this->requires_remapping = empty( $data['requires_remapping'] ) ? array() : $data['requires_remapping'];
}
}
@@ -0,0 +1,200 @@
<?php
/**
* This file handles image imports in the Site Library.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
/**
* Downloads and updates images.
*
* @since 1.6
*/
class GeneratePress_Sites_Image_Importer {
/**
* Images IDs
*
* @var array The Array of already image IDs.
* @since 1.6
*/
private $already_imported_ids = array();
/**
* Constructor
*
* @since 1.6
*/
public function __construct() {
if ( ! function_exists( 'WP_Filesystem' ) ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
}
WP_Filesystem();
}
/**
* Process Image Download
*
* @since 1.6
* @param array $attachments Attachment array.
* @return array Attachment array.
*/
public function process( $attachments ) {
$downloaded_images = array();
foreach ( $attachments as $key => $attachment ) {
$downloaded_images[] = $this->import( $attachment );
}
return $downloaded_images;
}
/**
* Get Hash Image.
*
* @since 1.6
* @param string $attachment_url Attachment URL.
* @return string Hash string.
*/
private function get_hash_image( $attachment_url ) {
return sha1( $attachment_url );
}
/**
* Get Saved Image.
*
* @since 1.6
* @param string $attachment Attachment Data.
* @return string Hash string.
*/
private function get_saved_image( $attachment ) {
global $wpdb;
// Already imported? Then return!
if ( isset( $this->already_imported_ids[ $attachment['id'] ] ) ) {
GeneratePress_Site_Library_Helper::log( 'Successfully replaced: ' . $attachment['url'] );
return $this->already_imported_ids[ $attachment['id'] ];
}
// 1. Is already imported in Batch Import Process?
$post_id = $wpdb->get_var(
$wpdb->prepare(
'SELECT `post_id` FROM `' . $wpdb->postmeta . '`
WHERE `meta_key` = \'_generatepress_sites_image_hash\'
AND `meta_value` = %s
;',
$this->get_hash_image( $attachment['url'] )
)
);
// 2. Is image already imported though XML?
if ( empty( $post_id ) ) {
// Get file name without extension.
// To check it exist in attachment.
$filename = preg_replace( '/\\.[^.\\s]{3,4}$/', '', basename( $attachment['url'] ) );
$post_id = $wpdb->get_var(
$wpdb->prepare(
'SELECT `post_id` FROM `' . $wpdb->postmeta . '`
WHERE `meta_key` = \'_wp_attached_file\'
AND `meta_value` LIKE %s
;',
'%' . $filename . '%'
)
);
GeneratePress_Site_Library_Helper::log( 'Successfully replaced: ' . $attachment['url'] );
}
if ( $post_id ) {
$new_attachment = array(
'id' => $post_id,
'url' => wp_get_attachment_url( $post_id ),
);
$this->already_imported_ids[ $attachment['id'] ] = $new_attachment;
return $new_attachment;
}
return false;
}
/**
* Import Image
*
* @since 1.6
* @param array $attachment Attachment array.
* @return array Attachment array.
*/
public function import( $attachment ) {
$saved_image = $this->get_saved_image( $attachment );
if ( $saved_image ) {
return $saved_image;
}
$file_content = wp_remote_retrieve_body( wp_safe_remote_get( $attachment['url'] ) );
// Empty file content?
if ( empty( $file_content ) ) {
GeneratePress_Site_Library_Helper::log( 'Failed to replace: ' . $attachment['url'] );
GeneratePress_Site_Library_Helper::log( 'Error: Failed wp_remote_retrieve_body().' );
return $attachment;
}
// Extract the file name and extension from the URL.
$filename = basename( $attachment['url'] );
$upload = wp_upload_bits(
$filename,
null,
$file_content
);
$post = array(
'post_title' => $filename,
'guid' => $upload['url'],
);
$info = wp_check_filetype( $upload['file'] );
if ( $info ) {
$post['post_mime_type'] = $info['type'];
} else {
// For now just return the origin attachment.
return $attachment;
}
$post_id = wp_insert_attachment( $post, $upload['file'] );
wp_update_attachment_metadata(
$post_id,
wp_generate_attachment_metadata( $post_id, $upload['file'] )
);
update_post_meta( $post_id, '_generatepress_sites_image_hash', $this->get_hash_image( $attachment['url'] ) );
$new_attachment = array(
'id' => $post_id,
'url' => $upload['url'],
);
GeneratePress_Site_Library_Helper::log( 'Successfully replaced: ' . $attachment['url'] );
$this->already_imported_ids[ $attachment['id'] ] = $new_attachment;
return $new_attachment;
}
}
@@ -0,0 +1,275 @@
<?php
/**
* This file handles the widget imports.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
/**
* Widget importer class.
*/
class GeneratePress_Sites_Widget_Importer {
/**
* Instance.
*
* @var $_instance
*/
private static $_instance = null; // phpcs:ignore -- Want the underscore.
/**
* Get our instance.
*/
public static function instance() {
if ( ! isset( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Available widgets
*
* Gather site's widgets into array with ID base, name, etc.
* Used by export and import functions.
*
* @since 0.4
* @global array $wp_registered_widget_updates
* @return array Widget information
*/
public function wie_available_widgets() {
global $wp_registered_widget_controls;
$widget_controls = $wp_registered_widget_controls;
$available_widgets = array();
foreach ( $widget_controls as $widget ) {
// No duplicates.
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'];
}
}
return apply_filters( 'wie_available_widgets', $available_widgets ); // phpcs:ignore -- Keep the plugin prefix.
}
/**
* Import widget JSON data
*
* @since 0.4
* @global array $wp_registered_sidebars
* @param object $data JSON widget data from .wie file.
* @return array Results array
*/
public function wie_import_data( $data ) {
global $wp_registered_sidebars;
// Have valid data?
// If no data or could not decode.
if ( empty( $data ) || ! is_object( $data ) ) {
wp_die(
esc_html__( 'Import data could not be read. Please try a different file.', 'widget-importer-exporter' ),
'',
array(
'back_link' => true,
)
);
}
// Hook before import.
do_action( 'wie_before_import' ); // phpcs:ignore -- Keep the plugin prefix.
$data = apply_filters( 'wie_import_data', $data ); // phpcs:ignore -- Keep the plugin prefix.
// Get all available widgets site supports.
$available_widgets = $this->wie_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 = esc_html__( 'Widget area does not exist in theme (using Inactive)', 'widget-importer-exporter' );
}
// Result for sidebar
// Sidebar name if theme supports it; otherwise ID.
$results[ $sidebar_id ]['name'] = ! empty( $wp_registered_sidebars[ $sidebar_id ]['name'] ) ? $wp_registered_sidebars[ $sidebar_id ]['name'] : $sidebar_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 = esc_html__( 'Site does not support widget', 'widget-importer-exporter' ); // 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.
$widget = apply_filters( 'wie_widget_settings', $widget ); // phpcs:ignore -- Keep the plugin prefix.
// 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( wp_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).
$widget = apply_filters( 'wie_widget_settings_array', $widget ); // phpcs:ignore -- Keep the plugin prefix.
// 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, true ) && (array) $widget === $check_widget ) {
$fail = true;
$widget_message_type = 'warning';
// Explain why widget not imported.
$widget_message = esc_html__( 'Widget already exists', 'widget-importer-exporter' );
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.
// Which sidebars have which widgets, get fresh every time.
$sidebars_widgets = get_option( 'sidebars_widgets' );
// Avoid rarely fatal error when the option is an empty string
// https://github.com/stevengliebe/widget-importer-exporter/pull/11.
if ( ! $sidebars_widgets ) {
$sidebars_widgets = array();
}
// Use ID number from new widget instance.
$new_instance_id = $id_base . '-' . $new_instance_id_number;
// Add new instance to sidebar.
$sidebars_widgets[ $use_sidebar_id ][] = $new_instance_id;
// Save the amended data.
update_option( 'sidebars_widgets', $sidebars_widgets );
// 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,
);
do_action( 'wie_after_widget_import', $after_widget_import ); // phpcs:ignore -- Keep the plugin prefix.
// Success message.
if ( $sidebar_available ) {
$widget_message_type = 'success';
$widget_message = esc_html__( 'Imported', 'widget-importer-exporter' );
} else {
$widget_message_type = 'warning';
$widget_message = esc_html__( 'Imported to Inactive', 'widget-importer-exporter' );
}
}
// 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'] : esc_html__( 'No Title', 'widget-importer-exporter' ); // 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.
do_action( 'wie_after_import' ); // phpcs:ignore -- Keep the plugin prefix.
// Return results.
return apply_filters( 'wie_import_results', $results ); // phpcs:ignore -- Keep the plugin prefix.
}
}
@@ -0,0 +1,138 @@
<?php
namespace GeneratePress\WPContentImporter2;
/**
* 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 WPImporterLogger {
/**
* System is unusable.
*
* @param string $message
* @param array $context
* @return null
*/
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
* @param array $context
* @return null
*/
public function alert( $message, array $context = array() ) {
return $this->log( 'alert', $message, $context );
}
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
* @return null
*/
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
* @param array $context
* @return null
*/
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
* @param array $context
* @return null
*/
public function warning( $message, array $context = array() ) {
return $this->log( 'warning', $message, $context );
}
/**
* Normal but significant events.
*
* @param string $message
* @param array $context
* @return null
*/
public function notice( $message, array $context = array() ) {
return $this->log( 'notice', $message, $context );
}
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param array $context
* @return null
*/
public function info( $message, array $context = array() ) {
return $this->log( 'info', $message, $context );
}
/**
* Detailed debug information.
*
* @param string $message
* @param array $context
* @return null
*/
public function debug( $message, array $context = array() ) {
return $this->log( 'debug', $message, $context );
}
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
* @return null
*/
public function log( $level, $message, array $context = array() ) {
$this->messages[] = array(
'timestamp' => time(),
'level' => $level,
'message' => $message,
'context' => $context,
);
}
}
@@ -0,0 +1,16 @@
<?php
namespace GeneratePress\WPContentImporter2;
class 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