File manager - Edit - /home/premiey/www/wp-includes/images/media/importers.tar
Back
class-astra-site-options-import.php 0000666 00000020352 15166147456 0013462 0 ustar 00 <?php /** * Customizer Site options importer class. * * @since 1.0.0 * @package Astra Addon */ if ( ! defined( 'ABSPATH' ) ) { exit; } /** * Customizer Site options importer class. * * @since 1.0.0 */ class Astra_Site_Options_Import { /** * Instance of Astra_Site_Options_Importer * * @since 1.0.0 * @var (Object) Astra_Site_Options_Importer */ private static $instance = null; /** * Instanciate Astra_Site_Options_Importer * * @since 1.0.0 * @return (Object) Astra_Site_Options_Importer */ public static function instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Site Options * * @since 1.0.2 * * @return array List of defined array. */ private static function site_options() { return array( 'custom_logo', 'nav_menu_locations', 'show_on_front', 'page_on_front', 'page_for_posts', // Plugin: Elementor. 'elementor_container_width', 'elementor_cpt_support', 'elementor_css_print_method', 'elementor_default_generic_fonts', 'elementor_disable_color_schemes', 'elementor_disable_typography_schemes', 'elementor_editor_break_lines', 'elementor_exclude_user_roles', 'elementor_global_image_lightbox', 'elementor_page_title_selector', 'elementor_scheme_color', 'elementor_scheme_color-picker', 'elementor_scheme_typography', 'elementor_space_between_widgets', 'elementor_stretched_section_container', 'elementor_load_fa4_shim', 'elementor_active_kit', // Plugin: Beaver Builder. '_fl_builder_enabled_icons', '_fl_builder_enabled_modules', '_fl_builder_post_types', '_fl_builder_color_presets', '_fl_builder_services', '_fl_builder_settings', '_fl_builder_user_access', '_fl_builder_enabled_templates', // Plugin: WooCommerce. // Pages. 'woocommerce_shop_page_title', 'woocommerce_cart_page_title', 'woocommerce_checkout_page_title', 'woocommerce_myaccount_page_title', 'woocommerce_edit_address_page_title', 'woocommerce_view_order_page_title', 'woocommerce_change_password_page_title', 'woocommerce_logout_page_title', // Account & Privacy. 'woocommerce_enable_guest_checkout', 'woocommerce_enable_checkout_login_reminder', 'woocommerce_enable_signup_and_login_from_checkout', 'woocommerce_enable_myaccount_registration', 'woocommerce_registration_generate_username', // Plugin: Easy Digital Downloads - EDD. 'edd_settings', // Plugin: WPForms. 'wpforms_settings', // Categories. 'woocommerce_product_cat', // Plugin: LearnDash LMS. 'learndash_settings_theme_ld30', 'learndash_settings_courses_themes', // Astra Theme Global Color Palette and Typography Preset options. 'astra-color-palettes', 'astra-typography-presets', ); } /** * Import site options. * * @since 1.0.2 Updated option if exist in defined option array 'site_options()'. * * @since 1.0.0 * * @param (Array) $options Array of site options to be imported from the demo. */ public function import_options( $options = array() ) { if ( ! isset( $options ) ) { return; } foreach ( $options as $option_name => $option_value ) { // Is option exist in defined array site_options()? if ( null !== $option_value ) { // Is option exist in defined array site_options()? if ( in_array( $option_name, self::site_options(), true ) ) { switch ( $option_name ) { // Set WooCommerce page ID by page Title. case 'woocommerce_shop_page_title': case 'woocommerce_cart_page_title': case 'woocommerce_checkout_page_title': case 'woocommerce_myaccount_page_title': case 'woocommerce_edit_address_page_title': case 'woocommerce_view_order_page_title': case 'woocommerce_change_password_page_title': case 'woocommerce_logout_page_title': $this->update_woocommerce_page_id_by_option_value( $option_name, $option_value ); break; case 'page_for_posts': case 'page_on_front': $this->update_page_id_by_option_value( $option_name, $option_value ); break; // nav menu locations. case 'nav_menu_locations': $this->set_nav_menu_locations( $option_value ); break; // import WooCommerce category images. case 'woocommerce_product_cat': $this->set_woocommerce_product_cat( $option_value ); break; // insert logo. case 'custom_logo': $this->insert_logo( $option_value ); break; case 'elementor_active_kit': if ( '' !== $option_value ) { $this->set_elementor_kit(); } break; default: update_option( $option_name, $option_value ); break; } } } } } /** * Update post option * * @since 2.2.2 * * @return void */ private function set_elementor_kit() { // Update Elementor Theme Kit Option. $args = array( 'post_type' => 'elementor_library', 'post_status' => 'publish', 'numberposts' => 1, 'meta_query' => array( //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Setting elementor kit. WP Query would have been expensive. array( 'key' => '_astra_sites_imported_post', 'value' => '1', ), array( 'key' => '_elementor_template_type', 'value' => 'kit', ), ), ); $query = get_posts( $args ); if ( ! empty( $query ) && isset( $query[0] ) && isset( $query[0]->ID ) ) { update_option( 'elementor_active_kit', $query[0]->ID ); } } /** * Update post option * * @since 1.0.2 * * @param string $option_name Option name. * @param mixed $option_value Option value. * @return void */ private function update_page_id_by_option_value( $option_name, $option_value ) { if ( empty( $option_value ) ) { return; } $page = get_page_by_title( $option_value ); if ( is_object( $page ) ) { update_option( $option_name, $page->ID ); } } /** * Update WooCommerce page ids. * * @since 1.1.6 * * @param string $option_name Option name. * @param mixed $option_value Option value. * @return void */ private function update_woocommerce_page_id_by_option_value( $option_name, $option_value ) { $option_name = str_replace( '_title', '_id', $option_name ); $this->update_page_id_by_option_value( $option_name, $option_value ); } /** * In WP nav menu is stored as ( 'menu_location' => 'menu_id' ); * In export we send 'menu_slug' like ( 'menu_location' => 'menu_slug' ); * In import we set 'menu_id' from menu slug like ( 'menu_location' => 'menu_id' ); * * @since 1.0.0 * @param array $nav_menu_locations Array of nav menu locations. */ private function set_nav_menu_locations( $nav_menu_locations = array() ) { $menu_locations = array(); // Update menu locations. if ( isset( $nav_menu_locations ) ) { foreach ( $nav_menu_locations as $menu => $value ) { $term = get_term_by( 'slug', $value, 'nav_menu' ); if ( is_object( $term ) ) { $menu_locations[ $menu ] = $term->term_id; } } set_theme_mod( 'nav_menu_locations', $menu_locations ); } } /** * Set WooCommerce category images. * * @since 1.1.4 * * @param array $cats Array of categories. */ private function set_woocommerce_product_cat( $cats = array() ) { if ( isset( $cats ) ) { foreach ( $cats as $key => $cat ) { if ( ! empty( $cat['slug'] ) && ! empty( $cat['thumbnail_src'] ) ) { $downloaded_image = Astra_Sites_Image_Importer::get_instance()->import( array( 'url' => $cat['thumbnail_src'], 'id' => 0, ) ); if ( $downloaded_image['id'] ) { $term = get_term_by( 'slug', $cat['slug'], 'product_cat' ); if ( is_object( $term ) ) { update_term_meta( $term->term_id, 'thumbnail_id', $downloaded_image['id'] ); } } } } } } /** * Insert Logo By URL * * @since 1.0.0 * @param string $image_url Logo URL. * @return void */ private function insert_logo( $image_url = '' ) { $downloaded_image = Astra_Sites_Image_Importer::get_instance()->import( array( 'url' => $image_url, 'id' => 0, ) ); if ( $downloaded_image['id'] ) { Astra_WXR_Importer::instance()->track_post( $downloaded_image['id'] ); set_theme_mod( 'custom_logo', $downloaded_image['id'] ); } } } class-astra-customizer-import.php 0000666 00000002145 15166147456 0013231 0 ustar 00 <?php /** * Customizer Data importer class. * * @since 1.0.0 * @package Astra Addon */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Customizer Data importer class. * * @since 1.0.0 */ class Astra_Customizer_Import { /** * Instance of Astra_Customizer_Import * * @since 1.0.0 * @var Astra_Customizer_Import */ private static $instance = null; /** * Instantiate Astra_Customizer_Import * * @since 1.0.0 * @return (Object) Astra_Customizer_Import */ public static function instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Import customizer options. * * @since 1.0.0 * * @param (Array) $options customizer options from the demo. */ public function import( $options ) { // Update Astra Theme customizer settings. if ( isset( $options['astra-settings'] ) ) { update_option( 'astra-settings', $options['astra-settings'] ); } // Add Custom CSS. if ( isset( $options['custom-css'] ) ) { wp_update_custom_css_post( $options['custom-css'] ); } } } wxr-importer/class-wp-importer-logger.php 0000666 00000010001 15166147456 0014614 0 ustar 00 <?php /** * WordPress Importer * https://github.com/humanmade/WordPress-Importer * * Released under the GNU General Public License v2.0 * https://github.com/humanmade/WordPress-Importer/blob/master/LICENSE * * 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. * * @package WordPress Importer */ if ( ! class_exists( 'WP_Importer_Logger' ) ) : /** * WP Importer Log */ class WP_Importer_Logger { /** * System is unusable. * * @param string $message Error message. * @param array $context Error 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 Error message. * @param array $context Error 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 Error message. * @param array $context Error 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 Error message. * @param array $context Error 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 Error message. * @param array $context Error context. * @return null */ public function warning( $message, array $context = array() ) { return $this->log( 'warning', $message, $context ); } /** * Normal but significant events. * * @param string $message Error message. * @param array $context Error 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 Error message. * @param array $context Error context. * @return null */ public function info( $message, array $context = array() ) { return $this->log( 'info', $message, $context ); } /** * Detailed debug information. * * @param string $message Error message. * @param array $context Error context. * @return null */ public function debug( $message, array $context = array() ) { return $this->log( 'debug', $message, $context ); } /** * Logs with an arbitrary level. * * @param mixed $level Error level. * @param string $message Error message. * @param array $context Error context. * @return void */ public function log( $level, $message, array $context = array() ) { $this->messages[] = array( 'timestamp' => time(), 'level' => $level, 'message' => $message, 'context' => $context, ); } } endif; wxr-importer/class-astra-wxr-importer.php 0000666 00000041504 15166147456 0014655 0 ustar 00 <?php /** * Class Astra WXR Importer * * @since 1.0.0 * @package Astra Addon */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * All the PHPCS errors are ignored in this file as it is a third party file. * Forked from WP importer v2 - https://github.com/humanmade/WordPress-Importer */ /** * Class Astra WXR Importer * * @since 1.0.0 */ class Astra_WXR_Importer { /** * Instance of Astra_WXR_Importer * * @since 1.0.0 * @var Astra_WXR_Importer */ private static $instance = null; /** * Instantiate Astra_WXR_Importer * * @since 1.0.0 * @return (Object) Astra_WXR_Importer. */ public static function instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Constructor. * * @since 1.0.0 */ private function __construct() { require_once ABSPATH . '/wp-admin/includes/class-wp-importer.php'; require_once ASTRA_SITES_DIR . 'inc/importers/wxr-importer/class-wp-importer-logger.php'; require_once ASTRA_SITES_DIR . 'inc/importers/wxr-importer/class-wp-importer-logger-serversentevents.php'; require_once ASTRA_SITES_DIR . 'inc/importers/wxr-importer/class-wxr-importer.php'; require_once ASTRA_SITES_DIR . 'inc/importers/wxr-importer/class-wxr-import-info.php'; add_filter( 'upload_mimes', array( $this, 'custom_upload_mimes' ) ); //phpcs:ignore WordPressVIPMinimum.Hooks.RestrictedHooks.upload_mimes -- Added this to allow upload of SVG files. add_action( 'wp_ajax_astra-wxr-import', array( $this, 'sse_import' ) ); add_filter( 'wxr_importer.pre_process.user', '__return_null' ); add_filter( 'wp_import_post_data_processed', array( $this, 'pre_post_data' ), 10, 2 ); add_filter( 'wxr_importer.pre_process.post', array( $this, 'pre_process_post' ), 10, 4 ); if ( version_compare( get_bloginfo( 'version' ), '5.1.0', '>=' ) ) { add_filter( 'wp_check_filetype_and_ext', array( $this, 'real_mime_types_5_1_0' ), 10, 5 ); } else { add_filter( 'wp_check_filetype_and_ext', array( $this, 'real_mime_types' ), 10, 4 ); } } /** * Track Imported Post * * @param int $post_id Post ID. * @param array $data Raw data imported for the post. * @return void */ public function track_post( $post_id = 0, $data = array() ) { Astra_Sites_Importer_Log::add( 'Inserted - Post ' . $post_id . ' - ' . get_post_type( $post_id ) . ' - ' . get_the_title( $post_id ) ); update_post_meta( $post_id, '_astra_sites_imported_post', true ); update_post_meta( $post_id, '_astra_sites_enable_for_batch', true ); // Set the full width template for the pages. if ( isset( $data['post_type'] ) && 'page' === $data['post_type'] ) { $is_elementor_page = get_post_meta( $post_id, '_elementor_version', true ); $theme_status = Astra_Sites::get_instance()->get_theme_status(); if ( 'installed-and-active' !== $theme_status && $is_elementor_page ) { update_post_meta( $post_id, '_wp_page_template', 'elementor_header_footer' ); } } elseif ( isset( $data['post_type'] ) && 'attachment' === $data['post_type'] ) { $remote_url = isset( $data['guid'] ) ? $data['guid'] : ''; $attachment_hash_url = Astra_Sites_Image_Importer::get_instance()->get_hash_image( $remote_url ); if ( ! empty( $attachment_hash_url ) ) { update_post_meta( $post_id, '_astra_sites_image_hash', $attachment_hash_url ); update_post_meta( $post_id, '_elementor_source_image_hash', $attachment_hash_url ); } } } /** * Track Imported Term * * @param int $term_id Term ID. * @return void */ public function track_term( $term_id ) { $term = get_term( $term_id ); if ( $term ) { Astra_Sites_Importer_Log::add( 'Inserted - Term ' . $term_id . ' - ' . wp_json_encode( $term ) ); } update_term_meta( $term_id, '_astra_sites_imported_term', true ); } /** * Pre Post Data * * @since 2.1.0 * * @param array $postdata Post data. * @param array $data Post data. * @return array Post data. */ public function pre_post_data( $postdata, $data ) { // Skip GUID field which point to the https://websitedemos.net. $postdata['guid'] = ''; return $postdata; } /** * Pre Process Post * * @since 1.2.12 * * @param array $data Post data. (Return empty to skip.). * @param array $meta Meta data. * @param array $comments Comments on the post. * @param array $terms Terms on the post. */ public function pre_process_post( $data, $meta, $comments, $terms ) { if ( isset( $data['post_content'] ) ) { $meta_data = wp_list_pluck( $meta, 'key' ); $is_attachment = ( 'attachment' === $data['post_type'] ) ? true : false; $is_elementor_page = in_array( '_elementor_version', $meta_data, true ); $is_beaver_builder_page = in_array( '_fl_builder_enabled', $meta_data, true ); $is_brizy_page = in_array( 'brizy_post_uid', $meta_data, true ); $disable_post_content = apply_filters( 'astra_sites_pre_process_post_disable_content', ( $is_attachment || $is_elementor_page || $is_beaver_builder_page || $is_brizy_page ) ); // If post type is `attachment OR // If page contain Elementor, Brizy or Beaver Builder meta then skip this page. if ( $disable_post_content ) { $data['post_content'] = ''; } else { /** * Gutenberg Content Data Fix * * Gutenberg encode the page content. In import process the encoded characterless e.g. <, > are * decoded into HTML tag and it break the Gutenberg render markup. * * Note: We have not check the post is created with Gutenberg or not. We have imported other sites * and confirm that this works for every other page builders too. */ $data['post_content'] = wp_slash( $data['post_content'] ); } } return $data; } /** * Different MIME type of different PHP version * * Filters the "real" file type of the given file. * * @since 1.2.9 * * @param array $defaults File data array containing 'ext', 'type', and * 'proper_filename' keys. * @param string $file Full path to the file. * @param string $filename The name of the file (may differ from $file due to * $file being in a tmp directory). * @param array $mimes Key is the file extension with value as the mime type. * @param string $real_mime Real MIME type of the uploaded file. */ public function real_mime_types_5_1_0( $defaults, $file, $filename, $mimes, $real_mime ) { return $this->real_mimes( $defaults, $filename ); } /** * Different MIME type of different PHP version * * Filters the "real" file type of the given file. * * @since 1.2.9 * * @param array $defaults File data array containing 'ext', 'type', and * 'proper_filename' keys. * @param string $file Full path to the file. * @param string $filename The name of the file (may differ from $file due to * $file being in a tmp directory). * @param array $mimes Key is the file extension with value as the mime type. */ public function real_mime_types( $defaults, $file, $filename, $mimes ) { return $this->real_mimes( $defaults, $filename ); } /** * Real Mime Type * * @since 1.2.15 * * @param array $defaults File data array containing 'ext', 'type', and * 'proper_filename' keys. * @param string $filename The name of the file (may differ from $file due to * $file being in a tmp directory). */ public function real_mimes( $defaults, $filename ) { // Set EXT and real MIME type only for the file name `wxr.xml`. if ( strpos( $filename, 'wxr' ) !== false ) { $defaults['ext'] = 'xml'; $defaults['type'] = 'text/xml'; } // Set EXT and real MIME type only for the file name `wpforms.json` or `wpforms-{page-id}.json`. if ( ( strpos( $filename, 'wpforms' ) !== false ) || ( strpos( $filename, 'cartflows' ) !== false ) || ( strpos( $filename, 'spectra' ) !== false ) ) { $defaults['ext'] = 'json'; $defaults['type'] = 'text/plain'; } return $defaults; } /** * Set GUID as per the attachment URL which avoid duplicate images issue due to the different GUID. * * @param array $data Post data. (Return empty to skip). * @param array $meta Meta data. * @param array $comments Comments on the post. * @param array $terms Terms on the post. */ public function fix_image_duplicate_issue( $data, $meta, $comments, $terms ) { $remote_url = ! empty( $data['attachment_url'] ) ? $data['attachment_url'] : $data['guid']; $data['guid'] = $remote_url; return $data; } /** * Enable the WP_Image_Editor_GD library. * * @since 2.2.3 * @param array $editors Image editors library list. * @return array */ public function enable_wp_image_editor_gd( $editors ) { $gd_editor = 'WP_Image_Editor_GD'; $editors = array_diff( $editors, array( $gd_editor ) ); array_unshift( $editors, $gd_editor ); return $editors; } /** * Constructor. * * @since 1.1.0 * @since 1.4.0 The `$xml_url` was added. * * @param string $xml_url XML file URL. */ public function sse_import( $xml_url = '' ) { if ( wp_doing_ajax() ) { // Verify Nonce. check_ajax_referer( 'astra-sites', '_ajax_nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error(); } // Start the event stream. header( 'Content-Type: text/event-stream, charset=UTF-8' ); // Turn off PHP output compression. $previous = error_reporting( error_reporting() ^ E_WARNING ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting -- 3rd party library. ini_set( 'output_buffering', 'off' ); //phpcs:ignore WordPress.PHP.IniSet.Risky -- 3rd party library. ini_set( 'zlib.output_compression', false ); //phpcs:ignore WordPress.PHP.IniSet.Risky -- 3rd party library. error_reporting( $previous ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting -- 3rd party library. if ( $GLOBALS['is_nginx'] ) { // Setting this header instructs Nginx to disable fastcgi_buffering // and disable gzip for this request. header( 'X-Accel-Buffering: no' ); header( 'Content-Encoding: none' ); } // 2KB padding for IE. echo esc_html( ':' . str_repeat( ' ', 2048 ) . "\n\n" ); } $xml_id = isset( $_REQUEST['xml_id'] ) ? absint( $_REQUEST['xml_id'] ) : ''; if ( ! empty( $xml_id ) ) { $xml_url = get_attached_file( $xml_id ); } if ( empty( $xml_url ) ) { exit; } // Time to run the import! set_time_limit( 0 ); // Ensure we're not buffered. wp_ob_end_flush_all(); flush(); do_action( 'astra_sites_before_sse_import' ); // Enable default GD library. add_filter( 'wp_image_editors', array( $this, 'enable_wp_image_editor_gd' ) ); // Change GUID image URL. add_filter( 'wxr_importer.pre_process.post', array( $this, 'fix_image_duplicate_issue' ), 10, 4 ); // Are we allowed to create users? add_filter( 'wxr_importer.pre_process.user', '__return_null' ); // Keep track of our progress. add_action( 'wxr_importer.processed.post', array( $this, 'imported_post' ), 10, 2 ); add_action( 'wxr_importer.process_failed.post', array( $this, 'imported_post' ), 10, 2 ); add_action( 'wxr_importer.process_already_imported.post', array( $this, 'already_imported_post' ), 10, 2 ); add_action( 'wxr_importer.process_skipped.post', array( $this, 'already_imported_post' ), 10, 2 ); add_action( 'wxr_importer.processed.comment', array( $this, 'imported_comment' ) ); add_action( 'wxr_importer.process_already_imported.comment', array( $this, 'imported_comment' ) ); add_action( 'wxr_importer.processed.term', array( $this, 'imported_term' ) ); add_action( 'wxr_importer.process_failed.term', array( $this, 'imported_term' ) ); add_action( 'wxr_importer.process_already_imported.term', array( $this, 'imported_term' ) ); add_action( 'wxr_importer.processed.user', array( $this, 'imported_user' ) ); add_action( 'wxr_importer.process_failed.user', array( $this, 'imported_user' ) ); // Keep track of our progress. add_action( 'wxr_importer.processed.post', array( $this, 'track_post' ), 10, 2 ); add_action( 'wxr_importer.processed.term', array( $this, 'track_term' ) ); // Flush once more. flush(); $importer = $this->get_importer(); $response = $importer->import( $xml_url ); // Let the browser know we're done. $complete = array( 'action' => 'complete', 'error' => false, ); if ( is_wp_error( $response ) ) { $complete['error'] = $response->get_error_message(); } $this->emit_sse_message( $complete ); if ( wp_doing_ajax() ) { exit; } } /** * Add .xml files as supported format in the uploader. * * @since 1.1.5 Added SVG file support. * * @since 1.0.0 * * @param array $mimes Already supported mime types. */ public function custom_upload_mimes( $mimes ) { // Allow SVG files. $mimes['svg'] = 'image/svg+xml'; $mimes['svgz'] = 'image/svg+xml'; // Allow XML files. $mimes['xml'] = 'text/xml'; // Allow JSON files. $mimes['json'] = 'application/json'; return $mimes; } /** * Start the xml import. * * @since 1.0.0 * @since 2.1.0 Added $post_id argument which is the downloaded XML file attachment ID. * * @param string $path Absolute path to the XML file. * @param int $post_id Uploaded XML file ID. */ public function get_xml_data( $path, $post_id ) { $args = array( 'action' => 'astra-wxr-import', 'id' => '1', '_ajax_nonce' => wp_create_nonce( 'astra-sites' ), 'xml_id' => $post_id, ); $url = add_query_arg( urlencode_deep( $args ), admin_url( 'admin-ajax.php', 'relative' ) ); $data = $this->get_data( $path ); return array( 'count' => array( 'posts' => $data->post_count, 'media' => $data->media_count, 'users' => count( $data->users ), 'comments' => $data->comment_count, 'terms' => $data->term_count, ), 'url' => $url, 'strings' => array( 'complete' => __( 'Import complete!', 'astra-sites' ), ), ); } /** * Get XML data. * * @since 1.1.0 * @param string $url Downloaded XML file absolute URL. * @return array XML file data. */ public function get_data( $url ) { $importer = $this->get_importer(); $data = $importer->get_preliminary_information( $url ); if ( is_wp_error( $data ) ) { return $data; } return $data; } /** * Get Importer * * @since 1.1.0 * @return object Importer object. */ public function get_importer() { $options = apply_filters( 'astra_sites_xml_import_options', array( 'update_attachment_guids' => true, 'fetch_attachments' => true, 'default_author' => get_current_user_id(), ) ); $importer = new WXR_Importer( $options ); $logger = new WP_Importer_Logger_ServerSentEvents(); $importer->set_logger( $logger ); return $importer; } /** * Send message when a post has been imported. * * @since 1.1.0 * @param int $id Post ID. * @param array $data Post data saved to the DB. */ public function imported_post( $id, $data ) { $this->emit_sse_message( array( 'action' => 'updateDelta', 'type' => ( 'attachment' === $data['post_type'] ) ? 'media' : 'posts', 'delta' => 1, ) ); } /** * Send message when a post is marked as already imported. * * @since 1.1.0 * @param array $data Post data saved to the DB. */ public function already_imported_post( $data ) { $this->emit_sse_message( array( 'action' => 'updateDelta', 'type' => ( 'attachment' === $data['post_type'] ) ? 'media' : 'posts', 'delta' => 1, ) ); } /** * Send message when a comment has been imported. * * @since 1.1.0 */ public function imported_comment() { $this->emit_sse_message( array( 'action' => 'updateDelta', 'type' => 'comments', 'delta' => 1, ) ); } /** * Send message when a term has been imported. * * @since 1.1.0 */ public function imported_term() { $this->emit_sse_message( array( 'action' => 'updateDelta', 'type' => 'terms', 'delta' => 1, ) ); } /** * Send message when a user has been imported. * * @since 1.1.0 */ public function imported_user() { $this->emit_sse_message( array( 'action' => 'updateDelta', 'type' => 'users', 'delta' => 1, ) ); } /** * Emit a Server-Sent Events message. * * @since 1.1.0 * @param mixed $data Data to be JSON-encoded and sent in the message. */ public function emit_sse_message( $data ) { if ( wp_doing_ajax() ) { echo "event: message\n"; echo 'data: ' . wp_json_encode( $data ) . "\n\n"; // Extra padding. echo esc_html( ':' . str_repeat( ' ', 2048 ) . "\n\n" ); } flush(); } } Astra_WXR_Importer::instance(); wxr-importer/class-wxr-import-info.php 0000666 00000002162 15166147456 0014144 0 ustar 00 <?php /** * WordPress Importer * https://github.com/humanmade/WordPress-Importer * * Released under the GNU General Public License v2.0 * https://github.com/humanmade/WordPress-Importer/blob/master/LICENSE * * @since 2.0.0 * * @package WordPress Importer */ if ( ! class_exists( 'WXR_Import_Info' ) ) { /** * Import Info * * @since 2.0.0 */ class WXR_Import_Info { /** * Home * * @var Home */ public $home; /** * Siteurl * * @var Site URL */ public $siteurl; /** * Title * * @var Title */ public $title; /** * Users * * @var Users */ public $users = array(); /** * Post_count * * @var Post Count */ public $post_count = 0; /** * Media Count * * @var Media Count */ public $media_count = 0; /** * Comment Count * * @var Comment Count */ public $comment_count = 0; /** * Term Count * * @var Term Count */ public $term_count = 0; /** * Generator * * @var Generator */ public $generator = ''; /** * Version * * @var Version */ public $version; } } wxr-importer/class-wxr-importer.php 0000666 00000242462 15166147456 0013553 0 ustar 00 <?php /** * WordPress Importer * * @package WXR Importer * * WordPress Importer * https://github.com/humanmade/WordPress-Importer * * Released under the GNU General Public License v2.0 * https://github.com/humanmade/WordPress-Importer/blob/master/LICENSE */ /** * All the PHPCS errors are ignored in this file as it is a third party file. * Forked from WP importer v2 - https://github.com/humanmade/WordPress-Importer */ /** * WXR Importer */ if ( ! class_exists( 'WXR_Importer' ) && class_exists( 'WP_Importer' ) ) : /** * WXR Importer */ class WXR_Importer extends WP_Importer { /** * Maximum supported WXR version */ const MAX_WXR_VERSION = '1.2'; /** * Regular expression for checking if a post references an attachment * * Note: This is a quick, weak check just to exclude text-only posts. More * vigorous checking is done later to verify. */ const REGEX_HAS_ATTACHMENT_REFS = '! ( # Match anything with an image or attachment class class=[\'"].*?\b(wp-image-\d+|attachment-[\w\-]+)\b | # Match anything that looks like an upload URL src=[\'"][^\'"]*( [0-9]{4}/[0-9]{2}/[^\'"]+\.(jpg|jpeg|png|gif|svg) | content/uploads[^\'"]+ )[\'"] )!ix'; /** * Version of WXR we're importing. * * Defaults to 1.0 for compatibility. Typically overridden by a * `<wp:wxr_version>` tag at the start of the file. * * @var string */ protected $version = '1.0'; // information to import from WXR file. /** * Categories * * @var array */ protected $categories = array(); /** * Tags * * @var array */ protected $tags = array(); /** * Base Url * * @var string */ protected $base_url = ''; // TODO: REMOVE THESE. /** * Processed Terms * * @var array */ protected $processed_terms = array(); /** * Processed Posts * * @var array */ protected $processed_posts = array(); /** * Processed Menu Items * * @var array */ protected $processed_menu_items = array(); /** * Menu Item Orphans * * @var array */ protected $menu_item_orphans = array(); /** * Missing Menu Items * * @var array */ protected $missing_menu_items = array(); // NEW STYLE. /** * Mapping * * @var array */ protected $mapping = array(); /** * Requires Remapping * * @var array */ protected $requires_remapping = array(); /** * Exists * * @var array */ protected $exists = array(); /** * User Slug Override * * @var array */ protected $user_slug_override = array(); /** * Url Remap * * @var array */ protected $url_remap = array(); /** * Featured Images * * @var array */ protected $featured_images = array(); /** * Logger instance. * * @var WP_Importer_Logger */ protected $logger; /** * Constructor * * @param array $options {. * @var bool $prefill_existing_posts Should we prefill `post_exists` calls? (True prefills and uses more memory, false checks once per imported post and takes longer. Default is true.). * @var bool $prefill_existing_comments Should we prefill `comment_exists` calls? (True prefills and uses more memory, false checks once per imported comment and takes longer. Default is true.). * @var bool $prefill_existing_terms Should we prefill `term_exists` calls? (True prefills and uses more memory, false checks once per imported term and takes longer. Default is true.). * @var bool $update_attachment_guids Should attachment GUIDs be updated to the new URL? (True updates the GUID, which keeps compatibility with v1, false doesn't update, and allows deduplication and reimporting. Default is false.). * @var bool $fetch_attachments Fetch attachments from the remote server. (True fetches and creates attachment posts, false skips attachments. Default is false.). * @var bool $aggressive_url_search Should we search/replace for URLs aggressively? (True searches all posts' content for old URLs and replaces, false checks for `<img class="wp-image-*">` only. Default is false.). * @var int $default_author User ID to use if author is missing or invalid. (Default is null, which leaves posts unassigned.). * } */ public function __construct( $options = array() ) { // Initialize some important variables. $empty_types = array( 'post' => array(), 'comment' => array(), 'term' => array(), 'user' => array(), ); $this->mapping = $empty_types; $this->mapping['user_slug'] = array(); $this->mapping['term_id'] = array(); $this->requires_remapping = $empty_types; $this->exists = $empty_types; $this->options = wp_parse_args( $options, array( 'prefill_existing_posts' => true, 'prefill_existing_comments' => true, 'prefill_existing_terms' => true, 'update_attachment_guids' => false, 'fetch_attachments' => false, 'aggressive_url_search' => false, 'default_author' => null, ) ); } /** * Set Logger * * @param object $logger Logger object. */ public function set_logger( $logger ) { $this->logger = $logger; } /** * Get a stream reader for the file. * * @param string $file Path to the XML file. * @return XMLReader|WP_Error Reader instance on success, error otherwise. */ protected function get_reader( $file ) { // Avoid loading external entities for security. $old_value = null; $reader = new XMLReader(); $status = $reader->open( $file ); if ( ! $status ) { return new WP_Error( 'wxr_importer.cannot_parse', __( 'Could not open the file for parsing', 'wordpress-importer' ) ); } return $reader; } /** * The main controller for the actual import stage. * * @param string $file Path to the WXR file for importing. */ public function get_preliminary_information( $file ) { // Let's run the actual importer now, woot. $reader = $this->get_reader( $file ); if ( is_wp_error( $reader ) ) { return $reader; } // Set the version to compatibility mode first. $this->version = '1.0'; // Start parsing! $data = new WXR_Import_Info(); while ( $reader->read() ) { // Only deal with element opens. if ( XMLReader::ELEMENT !== $reader->nodeType ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. continue; } switch ( $reader->name ) { case 'wp:wxr_version': // Upgrade to the correct version. $this->version = $reader->readString(); if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) { $this->logger->warning( sprintf( /* translators: %1$s is WXR version, %2$s is max supported WXR version. */ __( 'This WXR file (version %1$s) is newer than the importer (version %2$s) and may not be supported. Please consider updating.', 'wordpress-importer' ), $this->version, self::MAX_WXR_VERSION ) ); } // Handled everything in this node, move on to the next. $reader->next(); break; case 'generator': $data->generator = $reader->readString(); $reader->next(); break; case 'title': $data->title = $reader->readString(); $reader->next(); break; case 'wp:base_site_url': $data->siteurl = $reader->readString(); $reader->next(); break; case 'wp:base_blog_url': $data->home = $reader->readString(); $reader->next(); break; case 'wp:author': $node = $reader->expand(); $parsed = $this->parse_author_node( $node ); if ( is_wp_error( $parsed ) ) { $this->log_error( $parsed ); // Skip the rest of this post. $reader->next(); break; } $data->users[] = $parsed; // Handled everything in this node, move on to the next. $reader->next(); break; case 'item': $node = $reader->expand(); $parsed = $this->parse_post_node( $node ); if ( is_wp_error( $parsed ) ) { $this->log_error( $parsed ); // Skip the rest of this post. $reader->next(); break; } if ( 'attachment' === $parsed['data']['post_type'] ) { $data->media_count++; } else { $data->post_count++; } $data->comment_count += count( $parsed['comments'] ); // Handled everything in this node, move on to the next. $reader->next(); break; case 'wp:category': case 'wp:tag': case 'wp:term': $data->term_count++; // Handled everything in this node, move on to the next. $reader->next(); break; } } $data->version = $this->version; return $data; } /** * The main controller for the actual import stage. * * @param string $file Path to the WXR file for importing. */ public function parse_authors( $file ) { // Let's run the actual importer now, woot. $reader = $this->get_reader( $file ); if ( is_wp_error( $reader ) ) { return $reader; } // Set the version to compatibility mode first. $this->version = '1.0'; // Start parsing! $authors = array(); while ( $reader->read() ) { // Only deal with element opens. if ( XMLReader::ELEMENT !== $reader->nodeType ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. continue; } switch ( $reader->name ) { case 'wp:wxr_version': // Upgrade to the correct version. $this->version = $reader->readString(); if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) { $this->logger->warning( sprintf( /* translators: %1$s is WXR version, %2$s is max supported WXR version. */ __( 'This WXR file (version %1$s) is newer than the importer (version %2$s) and may not be supported. Please consider updating.', 'wordpress-importer' ), $this->version, self::MAX_WXR_VERSION ) ); } // Handled everything in this node, move on to the next. $reader->next(); break; case 'wp:author': $node = $reader->expand(); $parsed = $this->parse_author_node( $node ); if ( is_wp_error( $parsed ) ) { $this->log_error( $parsed ); // Skip the rest of this post. $reader->next(); break; } $authors[] = $parsed; // Handled everything in this node, move on to the next. $reader->next(); break; } } return $authors; } /** * The main controller for the actual import stage. * * @param string $file Path to the WXR file for importing. */ public function import( $file ) { add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) ); add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) ); //phpcs:ignore WordPressVIPMinimum.Hooks.RestrictedHooks.http_request_timeout -- We need this to avoid timeout on slow servers while installing theme, plugin etc. $result = $this->import_start( $file ); if ( is_wp_error( $result ) ) { return $result; } // Let's run the actual importer now, woot. $reader = $this->get_reader( $file ); if ( is_wp_error( $reader ) ) { return $reader; } // Set the version to compatibility mode first. $this->version = '1.0'; // Reset other variables. $this->base_url = ''; // Start parsing! while ( $reader->read() ) { // Only deal with element opens. if ( XMLReader::ELEMENT !== $reader->nodeType ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. continue; } switch ( $reader->name ) { case 'wp:wxr_version': // Upgrade to the correct version. $this->version = $reader->readString(); if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) { $this->logger->warning( sprintf( /* translators: %1$s is WXR version, %2$s is max supported WXR version. */ __( 'This WXR file (version %1$s) is newer than the importer (version %2$s) and may not be supported. Please consider updating.', 'wordpress-importer' ), $this->version, self::MAX_WXR_VERSION ) ); } // Handled everything in this node, move on to the next. $reader->next(); break; case 'wp:base_site_url': $this->base_url = $reader->readString(); // Handled everything in this node, move on to the next. $reader->next(); break; case 'item': $node = $reader->expand(); $parsed = $this->parse_post_node( $node ); if ( is_wp_error( $parsed ) ) { $this->log_error( $parsed ); // Skip the rest of this post. $reader->next(); break; } $this->process_post( $parsed['data'], $parsed['meta'], $parsed['comments'], $parsed['terms'] ); // Handled everything in this node, move on to the next. $reader->next(); break; case 'wp:author': $node = $reader->expand(); $parsed = $this->parse_author_node( $node ); if ( is_wp_error( $parsed ) ) { $this->log_error( $parsed ); // Skip the rest of this post. $reader->next(); break; } $status = $this->process_author( $parsed['data'], $parsed['meta'] ); if ( is_wp_error( $status ) ) { $this->log_error( $status ); } // Handled everything in this node, move on to the next. $reader->next(); break; case 'wp:category': $node = $reader->expand(); $parsed = $this->parse_term_node( $node, 'category' ); if ( is_wp_error( $parsed ) ) { $this->log_error( $parsed ); // Skip the rest of this post. $reader->next(); break; } $status = $this->process_term( $parsed['data'], $parsed['meta'] ); // Handled everything in this node, move on to the next. $reader->next(); break; case 'wp:tag': $node = $reader->expand(); $parsed = $this->parse_term_node( $node, 'tag' ); if ( is_wp_error( $parsed ) ) { $this->log_error( $parsed ); // Skip the rest of this post. $reader->next(); break; } $status = $this->process_term( $parsed['data'], $parsed['meta'] ); // Handled everything in this node, move on to the next. $reader->next(); break; case 'wp:term': $node = $reader->expand(); $parsed = $this->parse_term_node( $node ); if ( is_wp_error( $parsed ) ) { $this->log_error( $parsed ); // Skip the rest of this post. $reader->next(); break; } $status = $this->process_term( $parsed['data'], $parsed['meta'] ); // Handled everything in this node, move on to the next. $reader->next(); break; default: // Skip this node, probably handled by something already. break; } } // Now that we've done the main processing, do any required // post-processing and remapping. $this->post_process(); if ( $this->options['aggressive_url_search'] ) { $this->replace_attachment_urls_in_content(); } // phpcs:disable // $this->remap_featured_images(); // phpcs:enable $this->import_end(); } /** * Log an error instance to the logger. * * @param WP_Error $error Error instance to log. */ protected function log_error( WP_Error $error ) { $this->logger->warning( $error->get_error_message() ); // Log the data as debug info too. $data = $error->get_error_data(); if ( ! empty( $data ) ) { $this->logger->debug( var_export( $data, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export -- 3rd party library. } } /** * Parses the WXR file and prepares us for the task of processing parsed data * * @param string $file Path to the WXR file for importing. */ protected function import_start( $file ) { if ( ! is_file( $file ) ) { return new WP_Error( 'wxr_importer.file_missing', __( 'The file does not exist, please try again.', 'wordpress-importer' ) ); } // Suspend bunches of stuff in WP core. wp_defer_term_counting( true ); wp_defer_comment_counting( true ); wp_suspend_cache_invalidation( true ); // Prefill exists calls if told to. if ( $this->options['prefill_existing_posts'] ) { $this->prefill_existing_posts(); } if ( $this->options['prefill_existing_comments'] ) { $this->prefill_existing_comments(); } if ( $this->options['prefill_existing_terms'] ) { $this->prefill_existing_terms(); } /** * Begin the import. * * Fires before the import process has begun. If you need to suspend * caching or heavy processing on hooks, do so here. */ do_action( 'import_start' ); } /** * Performs post-import cleanup of files and the cache */ protected function import_end() { // Re-enable stuff in core. wp_suspend_cache_invalidation( false ); wp_cache_flush(); foreach ( get_taxonomies() as $tax ) { delete_option( "{$tax}_children" ); _get_term_hierarchy( $tax ); } wp_defer_term_counting( false ); wp_defer_comment_counting( false ); /** * Complete the import. * * Fires after the import process has finished. If you need to update * your cache or re-enable processing, do so here. */ do_action( 'import_end' ); } /** * Set the user mapping. * * @param array $mapping List of map arrays (containing `old_slug`, `old_id`, `new_id`). */ public function set_user_mapping( $mapping ) { foreach ( $mapping as $map ) { if ( empty( $map['old_slug'] ) || empty( $map['old_id'] ) || empty( $map['new_id'] ) ) { $this->logger->warning( __( 'Invalid author mapping', 'wordpress-importer' ) ); $this->logger->debug( var_export( $map, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export -- 3rd party library. continue; } $old_slug = $map['old_slug']; $old_id = $map['old_id']; $new_id = $map['new_id']; $this->mapping['user'][ $old_id ] = $new_id; $this->mapping['user_slug'][ $old_slug ] = $new_id; } } /** * Set the user slug overrides. * * Allows overriding the slug in the import with a custom/renamed version. * * @param string[] $overrides Map of old slug to new slug. */ public function set_user_slug_overrides( $overrides ) { foreach ( $overrides as $original => $renamed ) { $this->user_slug_override[ $original ] = $renamed; } } /** * Parse a post node into post data. * * @param DOMElement $node Parent node of post data (typically `item`). * @return array|WP_Error Post data array on success, error otherwise. */ protected function parse_post_node( $node ) { $data = array(); $meta = array(); $comments = array(); $terms = array(); foreach ( $node->childNodes as $child ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. // We only care about child elements. if ( XML_ELEMENT_NODE !== $child->nodeType ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. continue; } switch ( $child->tagName ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. case 'wp:post_type': $data['post_type'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'title': $data['post_title'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'guid': $data['guid'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'dc:creator': $data['post_author'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'content:encoded': $data['post_content'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'excerpt:encoded': $data['post_excerpt'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:post_id': $data['post_id'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:post_date': $data['post_date'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:post_date_gmt': $data['post_date_gmt'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:comment_status': $data['comment_status'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:ping_status': $data['ping_status'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:post_name': $data['post_name'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:status': $data['post_status'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. if ( 'auto-draft' === $data['post_status'] ) { // Bail now. return new WP_Error( 'wxr_importer.post.cannot_import_draft', __( 'Cannot import auto-draft posts' ), $data ); } break; case 'wp:post_parent': $data['post_parent'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:menu_order': $data['menu_order'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:post_password': $data['post_password'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:is_sticky': $data['is_sticky'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:attachment_url': $data['attachment_url'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:postmeta': $meta_item = $this->parse_meta_node( $child ); if ( ! empty( $meta_item ) ) { $meta[] = $meta_item; } break; case 'wp:comment': $comment_item = $this->parse_comment_node( $child ); if ( ! empty( $comment_item ) ) { $comments[] = $comment_item; } break; case 'category': $term_item = $this->parse_category_node( $child ); if ( ! empty( $term_item ) ) { $terms[] = $term_item; } break; } } return compact( 'data', 'meta', 'comments', 'terms' ); } /** * Create new posts based on import information * * Posts marked as having a parent which doesn't exist will become top level items. * Doesn't create a new post if: the post type doesn't exist, the given post ID * is already noted as imported or a post with the same title and date already exists. * Note that new/updated terms, comments and meta are imported for the last of the above. * * @param array $data Post data. (Return empty to skip.). * @param array $meta Meta data. * @param array $comments Comments on the post. * @param array $terms Terms on the post. */ protected function process_post( $data, $meta, $comments, $terms ) { /** * Pre-process post data. * * @param array $data Post data. (Return empty to skip.) * @param array $meta Meta data. * @param array $comments Comments on the post. * @param array $terms Terms on the post. */ $data = apply_filters( 'wxr_importer.pre_process.post', $data, $meta, $comments, $terms ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores -- 3rd party library. if ( empty( $data ) ) { return false; } $original_id = isset( $data['post_id'] ) ? (int) $data['post_id'] : 0; $parent_id = isset( $data['post_parent'] ) ? (int) $data['post_parent'] : 0; $author_id = isset( $data['post_author'] ) ? (int) $data['post_author'] : 0; // Have we already processed this? if ( isset( $this->mapping['post'][ $original_id ] ) ) { return; } // If post status as 'dp-rewrite-republish' OR trash OR draft then skip. if ( 'dp-rewrite-republish' === $data['post_status'] || 'draft' === $data['post_status'] || 'trash' === $data['post_status'] ) { return; } $post_type_object = get_post_type_object( $data['post_type'] ); // Is this type even valid? if ( ! $post_type_object ) { $this->logger->warning( sprintf( /* translators: %1$s is the import message, %2$s is post type. */ __( 'Failed to import "%1$s": Invalid post type %2$s', 'wordpress-importer' ), $data['post_title'], $data['post_type'] ) ); return false; } $post_exists = $this->post_exists( $data ); if ( $post_exists ) { $message = sprintf( /* translators: %1$s single post type, %2$s is post title. */ __( '%1$s "%2$s" already exists.', 'wordpress-importer' ), $post_type_object->labels->singular_name, $data['post_title'] ); $this->logger->info( $message ); /** * Post processing already imported. * * @param array $data Raw data imported for the post. */ do_action( 'wxr_importer.process_already_imported.post', $data ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores -- 3rd party library. // Even though this post already exists, new comments might need importing. $this->process_comments( $comments, $original_id, $data, $post_exists ); return false; } // Map the parent post, or mark it as one we need to fix. $requires_remapping = false; if ( $parent_id ) { if ( isset( $this->mapping['post'][ $parent_id ] ) ) { $data['post_parent'] = $this->mapping['post'][ $parent_id ]; } else { $meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id, ); $requires_remapping = true; $data['post_parent'] = 0; } } // Map the author, or mark it as one we need to fix. $author = sanitize_user( $data['post_author'], true ); if ( empty( $author ) ) { // Missing or invalid author, use default if available. $data['post_author'] = $this->options['default_author']; } elseif ( isset( $this->mapping['user_slug'][ $author ] ) ) { $data['post_author'] = $this->mapping['user_slug'][ $author ]; } else { $meta[] = array( 'key' => '_wxr_import_user_slug', 'value' => $author, ); $requires_remapping = true; $data['post_author'] = (int) get_current_user_id(); } // Does the post look like it contains attachment images? if ( preg_match( self::REGEX_HAS_ATTACHMENT_REFS, $data['post_content'] ) ) { $meta[] = array( 'key' => '_wxr_import_has_attachment_refs', 'value' => true, ); $requires_remapping = true; } // Whitelist to just the keys we allow. $postdata = array( 'import_id' => $data['post_id'], ); $allowed = array( 'post_author' => true, 'post_date' => true, 'post_date_gmt' => true, 'post_content' => true, 'post_excerpt' => true, 'post_title' => true, 'post_status' => true, 'post_name' => true, 'comment_status' => true, 'ping_status' => true, 'guid' => true, 'post_parent' => true, 'menu_order' => true, 'post_type' => true, 'post_password' => true, ); foreach ( $data as $key => $value ) { if ( ! isset( $allowed[ $key ] ) ) { continue; } $postdata[ $key ] = $data[ $key ]; } $postdata = apply_filters( 'wp_import_post_data_processed', $postdata, $data ); if ( 'attachment' === $postdata['post_type'] ) { if ( ! $this->options['fetch_attachments'] ) { $this->logger->notice( sprintf( /* translators: %s is post title */ __( 'Skipping attachment "%s", fetching attachments disabled' ), $data['post_title'] ) ); /** * Post processing skipped. * * @param array $data Raw data imported for the post. * @param array $meta Raw meta data, already processed by {@see process_post_meta}. */ do_action( 'wxr_importer.process_skipped.post', $data, $meta ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores -- 3rd party library. return false; } $remote_url = ! empty( $data['attachment_url'] ) ? $data['attachment_url'] : $data['guid']; $post_id = $this->process_attachment( $postdata, $meta, $remote_url ); } else { $post_id = wp_insert_post( $postdata, true ); do_action( 'wp_import_insert_post', $post_id, $original_id, $postdata, $data ); } if ( is_wp_error( $post_id ) ) { $this->logger->error( sprintf( /* translators: %1$s is the post title, %2$s is post type. */ __( 'Failed to import "%1$s" (%2$s)', 'wordpress-importer' ), $data['post_title'], $post_type_object->labels->singular_name ) ); $this->logger->debug( $post_id->get_error_message() ); /** * Post processing failed. * * @param WP_Error $post_id Error object. * @param array $data Raw data imported for the post. * @param array $meta Raw meta data, already processed by {@see process_post_meta}. * @param array $comments Raw comment data, already processed by {@see process_comments}. * @param array $terms Raw term data, already processed. */ do_action( 'wxr_importer.process_failed.post', $post_id, $data, $meta, $comments, $terms ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores -- 3rd party library. return false; } // Ensure stickiness is handled correctly too. if ( '1' === $data['is_sticky'] ) { stick_post( $post_id ); } // map pre-import ID to local ID. $this->mapping['post'][ $original_id ] = (int) $post_id; if ( $requires_remapping ) { $this->requires_remapping['post'][ $post_id ] = true; } $this->mark_post_exists( $data, $post_id ); $this->logger->info( sprintf( /* translators: %1$s is the post title, %2$s is post type. */ __( 'Imported "%1$s" (%2$s)', 'wordpress-importer' ), $data['post_title'], $post_type_object->labels->singular_name ) ); $this->logger->debug( sprintf( /* translators: %1$s is the original post id, %2$s is old post id. */ __( 'Post %1$d remapped to %2$d', 'wordpress-importer' ), $original_id, $post_id ) ); // Handle the terms too. $terms = apply_filters( 'wp_import_post_terms', $terms, $post_id, $data ); if ( ! empty( $terms ) ) { $term_ids = array(); foreach ( $terms as $term ) { $taxonomy = $term['taxonomy']; $key = sha1( $taxonomy . ':' . $term['slug'] ); if ( isset( $this->mapping['term'][ $key ] ) ) { $term_ids[ $taxonomy ][] = (int) $this->mapping['term'][ $key ]; } else { $meta[] = array( 'key' => '_wxr_import_term', 'value' => $term, ); $requires_remapping = true; } } foreach ( $term_ids as $tax => $ids ) { $tt_ids = wp_set_post_terms( $post_id, $ids, $tax ); do_action( 'wp_import_set_post_terms', $tt_ids, $ids, $tax, $post_id, $data ); } } $this->process_comments( $comments, $post_id, $data ); $this->process_post_meta( $meta, $post_id, $data ); if ( 'nav_menu_item' === $data['post_type'] ) { $this->process_menu_item_meta( $post_id, $data, $meta ); } /** * Post processing completed. * * @param int $post_id New post ID. * @param array $data Raw data imported for the post. * @param array $meta Raw meta data, already processed by {@see process_post_meta}. * @param array $comments Raw comment data, already processed by {@see process_comments}. * @param array $terms Raw term data, already processed. */ do_action( 'wxr_importer.processed.post', $post_id, $data, $meta, $comments, $terms ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores -- 3rd party library. } /** * Attempt to create a new menu item from import data * * Fails for draft, orphaned menu items and those without an associated nav_menu * or an invalid nav_menu term. If the post type or term object which the menu item * represents doesn't exist then the menu item will not be imported (waits until the * end of the import to retry again before discarding). * * @param int $post_id New post ID. * @param array $data Raw data imported for the post. * @param array $meta Raw meta data, already processed by {@see process_post_meta}. */ protected function process_menu_item_meta( $post_id, $data, $meta ) { $item_type = get_post_meta( $post_id, '_menu_item_type', true ); $original_object_id = get_post_meta( $post_id, '_menu_item_object_id', true ); $object_id = null; $this->logger->debug( sprintf( 'Processing menu item %s', $item_type ) ); $requires_remapping = false; switch ( $item_type ) { case 'taxonomy': if ( isset( $this->mapping['term_id'][ $original_object_id ] ) ) { $object_id = $this->mapping['term_id'][ $original_object_id ]; } else { add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) ); $requires_remapping = true; } break; case 'post_type': if ( isset( $this->mapping['post'][ $original_object_id ] ) ) { $object_id = $this->mapping['post'][ $original_object_id ]; } else { add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) ); $requires_remapping = true; } break; case 'custom': // Custom refers to itself, wonderfully easy. $object_id = $post_id; break; default: // associated object is missing or not imported yet, we'll retry later. $this->missing_menu_items[] = $item; $this->logger->debug( 'Unknown menu item type' ); break; } if ( $requires_remapping ) { $this->requires_remapping['post'][ $post_id ] = true; } if ( empty( $object_id ) ) { // Nothing needed here. return; } $this->logger->debug( sprintf( 'Menu item %d mapped to %d', $original_object_id, $object_id ) ); update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $object_id ) ); } /** * If fetching attachments is enabled then attempt to create a new attachment * * @param array $post Attachment post details from WXR. * @param string $meta Raw meta data, already processed by {@see process_post_meta}. * @param string $remote_url URL to fetch attachment from. * @return int|WP_Error Post ID on success, WP_Error otherwise. */ protected function process_attachment( $post, $meta, $remote_url ) { // try to use _wp_attached file for upload folder placement to ensure the same location as the export site // e.g. location is 2003/05/image.jpg but the attachment post_date is 2010/09, see media_handle_upload(). $post['upload_date'] = $post['post_date']; foreach ( $meta as $meta_item ) { if ( '_wp_attached_file' !== $meta_item['key'] ) { continue; } if ( preg_match( '%^[0-9]{4}/[0-9]{2}%', $meta_item['value'], $matches ) ) { $post['upload_date'] = $matches[0]; } break; } // if the URL is absolute, but does not contain address, then upload it assuming base_site_url. if ( preg_match( '|^/[\w\W]+$|', $remote_url ) ) { $remote_url = rtrim( $this->base_url, '/' ) . $remote_url; } $upload = $this->fetch_remote_file( $remote_url, $post ); if ( is_wp_error( $upload ) ) { return $upload; } $info = wp_check_filetype( $upload['file'] ); if ( ! $info ) { return new WP_Error( 'attachment_processing_error', __( 'Invalid file type', 'wordpress-importer' ) ); } $post['post_mime_type'] = $info['type']; // WP really likes using the GUID for display. Allow updating it. // See https://core.trac.wordpress.org/ticket/33386. if ( $this->options['update_attachment_guids'] ) { $post['guid'] = $upload['url']; } $post_id = wp_insert_attachment( $post, $upload['file'] ); if ( is_wp_error( $post_id ) ) { return $post_id; } $attachment_metadata = wp_generate_attachment_metadata( $post_id, $upload['file'] ); wp_update_attachment_metadata( $post_id, $attachment_metadata ); // Map this image URL later if we need to. $this->url_remap[ $remote_url ] = $upload['url']; // If we have a HTTPS URL, ensure the HTTP URL gets replaced too. if ( substr( $remote_url, 0, 8 ) === 'https://' ) { $insecure_url = 'http' . substr( $remote_url, 5 ); $this->url_remap[ $insecure_url ] = $upload['url']; } return $post_id; } /** * Parse a meta node into meta data. * * @param DOMElement $node Parent node of meta data (typically `wp:postmeta` or `wp:commentmeta`). * @return array|null Meta data array on success, or null on error. */ protected function parse_meta_node( $node ) { foreach ( $node->childNodes as $child ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. // We only care about child elements. if ( XML_ELEMENT_NODE !== $child->nodeType ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. continue; } switch ( $child->tagName ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. case 'wp:meta_key': $key = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:meta_value': $value = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; } } if ( empty( $key ) || empty( $value ) ) { return null; } return compact( 'key', 'value' ); } /** * Process and import post meta items. * * @param array $meta List of meta data arrays. * @param int $post_id Post to associate with. * @param array $post Post data. * @return int|WP_Error Number of meta items imported on success, error otherwise. */ protected function process_post_meta( $meta, $post_id, $post ) { if ( empty( $meta ) ) { return true; } foreach ( $meta as $meta_item ) { /** * Pre-process post meta data. * * @param array $meta_item Meta data. (Return empty to skip.) * @param int $post_id Post the meta is attached to. */ $meta_item = apply_filters( 'wxr_importer.pre_process.post_meta', $meta_item, $post_id ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores -- 3rd party library. if ( empty( $meta_item ) ) { return false; } $key = apply_filters( 'import_post_meta_key', $meta_item['key'], $post_id, $post ); $value = false; if ( '_edit_last' === $key ) { $value = intval( $meta_item['value'] ); if ( ! isset( $this->mapping['user'][ $value ] ) ) { // Skip! continue; } $value = $this->mapping['user'][ $value ]; } if ( $key ) { // export gets meta straight from the DB so could have a serialized string. if ( ! $value ) { $value = maybe_unserialize( $meta_item['value'] ); } add_post_meta( $post_id, $key, $value ); do_action( 'import_post_meta', $post_id, $key, $value ); // if the post has a featured image, take note of this in case of remap. if ( '_thumbnail_id' === $key ) { $this->featured_images[ $post_id ] = (int) $value; } } } return true; } /** * Parse a comment node into comment data. * * @param DOMElement $node Parent node of comment data (typically `wp:comment`). * @return array Comment data array. */ protected function parse_comment_node( $node ) { $data = array( 'commentmeta' => array(), ); foreach ( $node->childNodes as $child ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. // We only care about child elements. if ( XML_ELEMENT_NODE !== $child->nodeType ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. continue; } switch ( $child->tagName ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. case 'wp:comment_id': $data['comment_id'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:comment_author': $data['comment_author'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:comment_author_email': $data['comment_author_email'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:comment_author_IP': $data['comment_author_IP'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:comment_author_url': $data['comment_author_url'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:comment_user_id': $data['comment_user_id'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:comment_date': $data['comment_date'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:comment_date_gmt': $data['comment_date_gmt'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:comment_content': $data['comment_content'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:comment_approved': $data['comment_approved'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:comment_type': $data['comment_type'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:comment_parent': $data['comment_parent'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:commentmeta': $meta_item = $this->parse_meta_node( $child ); if ( ! empty( $meta_item ) ) { $data['commentmeta'][] = $meta_item; } break; } } return $data; } /** * Process and import comment data. * * @param array $comments List of comment data arrays. * @param int $post_id Post to associate with. * @param array $post Post data. * @param boolean $post_exists Post exist status. * @return int|WP_Error Number of comments imported on success, error otherwise. */ protected function process_comments( $comments, $post_id, $post, $post_exists = false ) { $comments = apply_filters( 'wp_import_post_comments', $comments, $post_id, $post ); if ( empty( $comments ) ) { return 0; } $num_comments = 0; // Sort by ID to avoid excessive remapping later. usort( $comments, array( $this, 'sort_comments_by_id' ) ); foreach ( $comments as $key => $comment ) { /** * Pre-process comment data * * @param array $comment Comment data. (Return empty to skip.) * @param int $post_id Post the comment is attached to. */ $comment = apply_filters( 'wxr_importer.pre_process.comment', $comment, $post_id ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores -- 3rd party library. if ( empty( $comment ) ) { return false; } $original_id = isset( $comment['comment_id'] ) ? (int) $comment['comment_id'] : 0; $parent_id = isset( $comment['comment_parent'] ) ? (int) $comment['comment_parent'] : 0; $author_id = isset( $comment['comment_user_id'] ) ? (int) $comment['comment_user_id'] : 0; // if this is a new post we can skip the comment_exists() check // TODO: Check comment_exists for performance. if ( $post_exists ) { $existing = $this->comment_exists( $comment ); if ( $existing ) { /** * Comment processing already imported. * * @param array $comment Raw data imported for the comment. */ do_action( 'wxr_importer.process_already_imported.comment', $comment ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores -- 3rd party library. $this->mapping['comment'][ $original_id ] = $existing; continue; } } // Remove meta from the main array. $meta = isset( $comment['commentmeta'] ) ? $comment['commentmeta'] : array(); unset( $comment['commentmeta'] ); // Map the parent comment, or mark it as one we need to fix. $requires_remapping = false; if ( $parent_id ) { if ( isset( $this->mapping['comment'][ $parent_id ] ) ) { $comment['comment_parent'] = $this->mapping['comment'][ $parent_id ]; } else { // Prepare for remapping later. $meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id, ); $requires_remapping = true; // Wipe the parent for now. $comment['comment_parent'] = 0; } } // Map the author, or mark it as one we need to fix. if ( $author_id ) { if ( isset( $this->mapping['user'][ $author_id ] ) ) { $comment['user_id'] = $this->mapping['user'][ $author_id ]; } else { // Prepare for remapping later. $meta[] = array( 'key' => '_wxr_import_user', 'value' => $author_id, ); $requires_remapping = true; // Wipe the user for now. $comment['user_id'] = 0; } } // Run standard core filters. $comment['comment_post_ID'] = $post_id; $comment = wp_filter_comment( $comment ); // wp_insert_comment expects slashed data. $comment_id = wp_insert_comment( wp_slash( $comment ) ); $this->mapping['comment'][ $original_id ] = $comment_id; if ( $requires_remapping ) { $this->requires_remapping['comment'][ $comment_id ] = true; } $this->mark_comment_exists( $comment, $comment_id ); /** * Comment has been imported. * * @param int $comment_id New comment ID * @param array $comment Comment inserted (`comment_id` item refers to the original ID) * @param int $post_id Post parent of the comment * @param array $post Post data */ do_action( 'wp_import_insert_comment', $comment_id, $comment, $post_id, $post ); // Process the meta items. foreach ( $meta as $meta_item ) { $value = maybe_unserialize( $meta_item['value'] ); add_comment_meta( $comment_id, wp_slash( $meta_item['key'] ), wp_slash( $value ) ); } /** * Post processing completed. * * @param int $post_id New post ID. * @param array $comment Raw data imported for the comment. * @param array $meta Raw meta data, already processed by {@see process_post_meta}. * @param array $post_id Parent post ID. */ do_action( 'wxr_importer.processed.comment', $comment_id, $comment, $meta, $post_id ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores -- 3rd party library. $num_comments++; } return $num_comments; } /** * Parse Category Node * * @param object $node Category Node. * @return array */ protected function parse_category_node( $node ) { $data = array( // Default taxonomy to "category", since this is a `<category>` tag. 'taxonomy' => 'category', ); $meta = array(); if ( $node->hasAttribute( 'domain' ) ) { $data['taxonomy'] = $node->getAttribute( 'domain' ); } if ( $node->hasAttribute( 'nicename' ) ) { $data['slug'] = $node->getAttribute( 'nicename' ); } $data['name'] = $node->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. if ( empty( $data['slug'] ) ) { return null; } // Just for extra compatibility. if ( 'tag' === $data['taxonomy'] ) { $data['taxonomy'] = 'post_tag'; } return $data; } /** * Callback for `usort` to sort comments by ID * * @param array $a Comment data for the first comment. * @param array $b Comment data for the second comment. * @return int */ public static function sort_comments_by_id( $a, $b ) { if ( empty( $a['comment_id'] ) ) { return 1; } if ( empty( $b['comment_id'] ) ) { return -1; } return $a['comment_id'] - $b['comment_id']; } /** * Parse Author Node * * @param object $node Author Node. * @return array */ protected function parse_author_node( $node ) { $data = array(); $meta = array(); foreach ( $node->childNodes as $child ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. // We only care about child elements. if ( XML_ELEMENT_NODE !== $child->nodeType ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. continue; } switch ( $child->tagName ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. case 'wp:author_login': $data['user_login'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:author_id': $data['ID'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:author_email': $data['user_email'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:author_display_name': $data['display_name'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:author_first_name': $data['first_name'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; case 'wp:author_last_name': $data['last_name'] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. break; } } return compact( 'data', 'meta' ); } /** * Process Author * * @param array $data User data. (Return empty to skip.). * @param array $meta Meta data. * @return boolean */ protected function process_author( $data, $meta ) { /** * Pre-process user data. * * @param array $data User data. (Return empty to skip.) * @param array $meta Meta data. */ $data = apply_filters( 'wxr_importer.pre_process.user', $data, $meta ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores -- 3rd party library. if ( empty( $data ) ) { return false; } // Have we already handled this user? $original_id = isset( $data['ID'] ) ? $data['ID'] : 0; $original_slug = $data['user_login']; if ( isset( $this->mapping['user'][ $original_id ] ) ) { $existing = $this->mapping['user'][ $original_id ]; // Note the slug mapping if we need to too. if ( ! isset( $this->mapping['user_slug'][ $original_slug ] ) ) { $this->mapping['user_slug'][ $original_slug ] = $existing; } return false; } if ( isset( $this->mapping['user_slug'][ $original_slug ] ) ) { $existing = $this->mapping['user_slug'][ $original_slug ]; // Ensure we note the mapping too. $this->mapping['user'][ $original_id ] = $existing; return false; } // Allow overriding the user's slug. $login = $original_slug; if ( isset( $this->user_slug_override[ $login ] ) ) { $login = $this->user_slug_override[ $login ]; } $userdata = array( 'user_login' => sanitize_user( $login, true ), 'user_pass' => wp_generate_password(), ); $allowed = array( 'user_email' => true, 'display_name' => true, 'first_name' => true, 'last_name' => true, ); foreach ( $data as $key => $value ) { if ( ! isset( $allowed[ $key ] ) ) { continue; } $userdata[ $key ] = $data[ $key ]; } $user_id = wp_insert_user( wp_slash( $userdata ) ); if ( is_wp_error( $user_id ) ) { $this->logger->error( sprintf( /* translators: %s user login name */ __( 'Failed to import user "%s"', 'wordpress-importer' ), $userdata['user_login'] ) ); $this->logger->debug( $user_id->get_error_message() ); /** * User processing failed. * * @param WP_Error $user_id Error object. * @param array $userdata Raw data imported for the user. */ do_action( 'wxr_importer.process_failed.user', $user_id, $userdata ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores -- 3rd party library. return false; } if ( $original_id ) { $this->mapping['user'][ $original_id ] = $user_id; } $this->mapping['user_slug'][ $original_slug ] = $user_id; $this->logger->info( sprintf( /* translators: %s user login name */ __( 'Imported user "%s"', 'wordpress-importer' ), $userdata['user_login'] ) ); $this->logger->debug( sprintf( /* translators: %1$s original user Id, %2$s old user Id. */ __( 'User %1$d remapped to %2$d', 'wordpress-importer' ), $original_id, $user_id ) ); // TODO: Implement meta handling once WXR includes it. /** * User processing completed. * * @param int $user_id New user ID. * @param array $userdata Raw data imported for the user. */ do_action( 'wxr_importer.processed.user', $user_id, $userdata ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores -- 3rd party library. } /** * Process Term * * @param object $node Term node. * @param string $type Term type. * @return array */ protected function parse_term_node( $node, $type = 'term' ) { $data = array(); $meta = array(); $tag_name = array( 'id' => 'wp:term_id', 'taxonomy' => 'wp:term_taxonomy', 'slug' => 'wp:term_slug', 'parent' => 'wp:term_parent', 'name' => 'wp:term_name', 'description' => 'wp:term_description', ); $taxonomy = null; // Special casing! switch ( $type ) { case 'category': $tag_name['slug'] = 'wp:category_nicename'; $tag_name['parent'] = 'wp:category_parent'; $tag_name['name'] = 'wp:cat_name'; $tag_name['description'] = 'wp:category_description'; $tag_name['taxonomy'] = null; $data['taxonomy'] = 'category'; break; case 'tag': $tag_name['slug'] = 'wp:tag_slug'; $tag_name['parent'] = null; $tag_name['name'] = 'wp:tag_name'; $tag_name['description'] = 'wp:tag_description'; $tag_name['taxonomy'] = null; $data['taxonomy'] = 'post_tag'; break; } foreach ( $node->childNodes as $child ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. // We only care about child elements. if ( XML_ELEMENT_NODE !== $child->nodeType ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. continue; } $key = array_search( $child->tagName, $tag_name ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. if ( $key ) { $data[ $key ] = $child->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- 3rd party library. } } if ( empty( $data['taxonomy'] ) ) { return null; } // Compatibility with WXR 1.0. if ( 'tag' === $data['taxonomy'] ) { $data['taxonomy'] = 'post_tag'; } return compact( 'data', 'meta' ); } /** * Process Term * * @param array $data Term data. (Return empty to skip.). * @param array $meta Meta data. * @return boolean */ protected function process_term( $data, $meta ) { /** * Pre-process term data. * * @param array $data Term data. (Return empty to skip.) * @param array $meta Meta data. */ $data = apply_filters( 'wxr_importer.pre_process.term', $data, $meta ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores -- 3rd party library. if ( empty( $data ) ) { return false; } $original_id = isset( $data['id'] ) ? (int) $data['id'] : 0; $parent_id = isset( $data['parent'] ) ? (int) $data['parent'] : 0; $mapping_key = sha1( $data['taxonomy'] . ':' . $data['slug'] ); $existing = $this->term_exists( $data ); if ( $existing ) { /** * Term processing already imported. * * @param array $data Raw data imported for the term. */ do_action( 'wxr_importer.process_already_imported.term', $data ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores -- 3rd party library. $this->mapping['term'][ $mapping_key ] = $existing; $this->mapping['term_id'][ $original_id ] = $existing; return false; } // WP really likes to repeat itself in export files. if ( isset( $this->mapping['term'][ $mapping_key ] ) ) { return false; } $termdata = array(); $allowed = array( 'slug' => true, 'description' => true, ); // Map the parent comment, or mark it as one we need to fix // TODO: add parent mapping and remapping. // phpcs:disable /* $requires_remapping = false; if ( $parent_id ) { if ( isset( $this->mapping['term'][ $parent_id ] ) ) { $data['parent'] = $this->mapping['term'][ $parent_id ]; } else { // Prepare for remapping later $meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id ); $requires_remapping = true; // Wipe the parent for now $data['parent'] = 0; } }*/ // phpcs:enable foreach ( $data as $key => $value ) { if ( ! isset( $allowed[ $key ] ) ) { continue; } $termdata[ $key ] = $data[ $key ]; } $result = wp_insert_term( $data['name'], $data['taxonomy'], $termdata ); if ( is_wp_error( $result ) ) { $this->logger->warning( sprintf( /* translators: %1$s is the taxonomy, %2$s is taxonomy name. */ __( 'Failed to import %1$s %2$s', 'wordpress-importer' ), $data['taxonomy'], $data['name'] ) ); $this->logger->debug( $result->get_error_message() ); do_action( 'wp_import_insert_term_failed', $result, $data ); /** * Term processing failed. * * @param WP_Error $result Error object. * @param array $data Raw data imported for the term. * @param array $meta Meta data supplied for the term. */ do_action( 'wxr_importer.process_failed.term', $result, $data, $meta ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores -- 3rd party library. return false; } $term_id = $result['term_id']; $this->mapping['term'][ $mapping_key ] = $term_id; $this->mapping['term_id'][ $original_id ] = $term_id; $this->logger->info( sprintf( /* translators: %1$s is the taxonomy name, %2$s is taxonomy. */ __( 'Imported "%1$s" (%2$s)', 'wordpress-importer' ), $data['name'], $data['taxonomy'] ) ); $this->logger->debug( sprintf( /* translators: %1$s is term original id, %2$s is term id. */ __( 'Term %1$d remapped to %2$d', 'wordpress-importer' ), $original_id, $term_id ) ); do_action( 'wp_import_insert_term', $term_id, $data ); /** * Term processing completed. * * @param int $term_id New term ID. * @param array $data Raw data imported for the term. */ do_action( 'wxr_importer.processed.term', $term_id, $data ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores -- 3rd party library. } /** * Attempt to download a remote file attachment * * @param string $url URL of item to fetch. * @param array $post Attachment details. * @return array|WP_Error Local file location details on success, WP_Error otherwise. */ protected function fetch_remote_file( $url, $post ) { // extract the file name and extension from the url. $file_name = basename( $url ); // get placeholder file in the upload dir with a unique, sanitized filename. $upload = wp_upload_bits( $file_name, null, '', $post['upload_date'] ); if ( $upload['error'] ) { return new WP_Error( 'upload_dir_error', $upload['error'] ); } // fetch the remote url and write it to the placeholder file. $response = wp_remote_get( $url, array( 'stream' => true, 'filename' => $upload['file'], ) ); // request failed. if ( is_wp_error( $response ) ) { unlink( $upload['file'] ); //phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.file_ops_unlink -- 3rd party library. return $response; } $code = (int) wp_remote_retrieve_response_code( $response ); // make sure the fetch was successful. if ( 200 !== $code ) { unlink( $upload['file'] ); //phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.file_ops_unlink -- 3rd party library. return new WP_Error( 'import_file_error', sprintf( /* translators: %1$s is error code, %2$s is error code header, %3$s is url. */ __( 'Remote server returned %1$d %2$s for %3$s', 'wordpress-importer' ), $code, get_status_header_desc( $code ), $url ) ); } $filesize = filesize( $upload['file'] ); $headers = wp_remote_retrieve_headers( $response ); if ( isset( $headers['content-length'] ) && $filesize !== (int) $headers['content-length'] ) { unlink( $upload['file'] ); //phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.file_ops_unlink -- 3rd party library. return new WP_Error( 'import_file_error', __( 'Remote file is incorrect size', 'wordpress-importer' ) ); } if ( 0 === $filesize ) { unlink( $upload['file'] ); //phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.file_ops_unlink -- 3rd party library. return new WP_Error( 'import_file_error', __( 'Zero size file downloaded', 'wordpress-importer' ) ); } $max_size = (int) $this->max_attachment_size(); if ( ! empty( $max_size ) && $filesize > $max_size ) { unlink( $upload['file'] ); //phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.file_ops_unlink -- 3rd party library. /* translators: %s max file size. */ $message = sprintf( __( 'Remote file is too large, limit is %s', 'wordpress-importer' ), size_format( $max_size ) ); return new WP_Error( 'import_file_error', $message ); } return $upload; } /** * Post process */ protected function post_process() { // Time to tackle any left-over bits. if ( ! empty( $this->requires_remapping['post'] ) ) { $this->post_process_posts( $this->requires_remapping['post'] ); } if ( ! empty( $this->requires_remapping['comment'] ) ) { $this->post_process_comments( $this->requires_remapping['comment'] ); } } /** * Post Process Posts * * @param array $todo Todo items. * @return void */ protected function post_process_posts( $todo ) { foreach ( $todo as $post_id => $_ ) { $this->logger->debug( sprintf( // Note: title intentionally not used to skip extra processing. // for when debug logging is off. /* translators: %d is post id. */ __( 'Running post-processing for post %d', 'wordpress-importer' ), $post_id ) ); $data = array(); $parent_id = get_post_meta( $post_id, '_wxr_import_parent', true ); if ( ! empty( $parent_id ) ) { // Have we imported the parent now? if ( isset( $this->mapping['post'][ $parent_id ] ) ) { $data['post_parent'] = $this->mapping['post'][ $parent_id ]; } else { $this->logger->warning( sprintf( /* translators: %1$s is post title, %2$s is post id. */ __( 'Could not find the post parent for "%1$s" (post #%2$d)', 'wordpress-importer' ), get_the_title( $post_id ), $post_id ) ); $this->logger->debug( sprintf( /* translators: %1$d is post id, %2$d is parent post id. */ __( 'Post %1$d was imported with parent %2$d, but could not be found', 'wordpress-importer' ), $post_id, $parent_id ) ); } } $author_slug = get_post_meta( $post_id, '_wxr_import_user_slug', true ); if ( ! empty( $author_slug ) ) { // Have we imported the user now? if ( isset( $this->mapping['user_slug'][ $author_slug ] ) ) { $data['post_author'] = $this->mapping['user_slug'][ $author_slug ]; } else { $this->logger->warning( sprintf( /* translators: %1$s is the post title, %2$s is post id. */ __( 'Could not find the author for "%1$s" (post #%2$d)', 'wordpress-importer' ), get_the_title( $post_id ), $post_id ) ); $this->logger->debug( sprintf( /* translators: %1$d is post id, %2$s is author slug. */ __( 'Post %1$d was imported with author "%2$s", but could not be found', 'wordpress-importer' ), $post_id, $author_slug ) ); } } $has_attachments = get_post_meta( $post_id, '_wxr_import_has_attachment_refs', true ); if ( ! empty( $has_attachments ) ) { $post = get_post( $post_id ); $content = $post->post_content; // Replace all the URLs we've got. $new_content = str_replace( array_keys( $this->url_remap ), $this->url_remap, $content ); if ( $new_content !== $content ) { $data['post_content'] = $new_content; } } if ( get_post_type( $post_id ) === 'nav_menu_item' ) { $this->post_process_menu_item( $post_id ); } // Do we have updates to make? if ( empty( $data ) ) { $this->logger->debug( sprintf( /* translators: %d is post id. */ __( 'Post %d was marked for post-processing, but none was required.', 'wordpress-importer' ), $post_id ) ); continue; } // Run the update. $data['ID'] = $post_id; $data = wp_slash( $data ); $result = wp_update_post( $data, true ); if ( is_wp_error( $result ) ) { $this->logger->warning( sprintf( /* translators: %1$s is the post title, %2$s is post id. */ __( 'Could not update "%1$s" (post #%2$d) with mapped data', 'wordpress-importer' ), get_the_title( $post_id ), $post_id ) ); $this->logger->debug( $result->get_error_message() ); continue; } // Clear out our temporary meta keys. delete_post_meta( $post_id, '_wxr_import_parent' ); delete_post_meta( $post_id, '_wxr_import_user_slug' ); delete_post_meta( $post_id, '_wxr_import_has_attachment_refs' ); } } /** * Post process menu item * * @param int $post_id Post id. * @return mixed */ protected function post_process_menu_item( $post_id ) { $menu_object_id = get_post_meta( $post_id, '_wxr_import_menu_item', true ); if ( empty( $menu_object_id ) ) { // No processing needed! return; } $menu_item_type = get_post_meta( $post_id, '_menu_item_type', true ); switch ( $menu_item_type ) { case 'taxonomy': if ( isset( $this->mapping['term_id'][ $menu_object_id ] ) ) { $menu_object = $this->mapping['term_id'][ $menu_object_id ]; } break; case 'post_type': if ( isset( $this->mapping['post'][ $menu_object_id ] ) ) { $menu_object = $this->mapping['post'][ $menu_object_id ]; } break; default: // Cannot handle this. return; } if ( ! empty( $menu_object ) ) { update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $menu_object ) ); } else { $this->logger->warning( sprintf( /* translators: %1$s is the post title, %2$s is post id. */ __( 'Could not find the menu object for "%1$s" (post #%2$d)', 'wordpress-importer' ), get_the_title( $post_id ), $post_id ) ); $this->logger->debug( sprintf( /* translators: %1$s is post id, %2$s is post object id, %3$s is menu type. */ __( 'Post %1$d was imported with object "%2$d" of type "%3$s", but could not be found', 'wordpress-importer' ), $post_id, $menu_object_id, $menu_item_type ) ); } delete_post_meta( $post_id, '_wxr_import_menu_item' ); } /** * Post process comments * * @param array $todo Todo items. * @return void */ protected function post_process_comments( $todo ) { foreach ( $todo as $comment_id => $_ ) { $data = array(); $parent_id = get_comment_meta( $comment_id, '_wxr_import_parent', true ); if ( ! empty( $parent_id ) ) { // Have we imported the parent now? if ( isset( $this->mapping['comment'][ $parent_id ] ) ) { $data['comment_parent'] = $this->mapping['comment'][ $parent_id ]; } else { $this->logger->warning( sprintf( /* translators: %d is comment id. */ __( 'Could not find the comment parent for comment #%d', 'wordpress-importer' ), $comment_id ) ); $this->logger->debug( sprintf( /* translators: %1$s is comment id, %2$s is parent comment id. */ __( 'Comment %1$d was imported with parent %2$d, but could not be found', 'wordpress-importer' ), $comment_id, $parent_id ) ); } } $author_id = get_comment_meta( $comment_id, '_wxr_import_user', true ); if ( ! empty( $author_id ) ) { // Have we imported the user now? if ( isset( $this->mapping['user'][ $author_id ] ) ) { $data['user_id'] = $this->mapping['user'][ $author_id ]; } else { $this->logger->warning( sprintf( /* translators: %d is comment id. */ __( 'Could not find the author for comment #%d', 'wordpress-importer' ), $comment_id ) ); $this->logger->debug( sprintf( /* translators: %1$d is comment id, %2$d is author id. */ __( 'Comment %1$d was imported with author %2$d, but could not be found', 'wordpress-importer' ), $comment_id, $author_id ) ); } } // Do we have updates to make? if ( empty( $data ) ) { continue; } // Run the update. $data['comment_ID'] = $comment_ID; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase -- 3rd party library. $result = wp_update_comment( wp_slash( $data ) ); if ( empty( $result ) ) { $this->logger->warning( sprintf( /* translators: %d is comment id. */ __( 'Could not update comment #%d with mapped data', 'wordpress-importer' ), $comment_id ) ); continue; } // Clear out our temporary meta keys. delete_comment_meta( $comment_id, '_wxr_import_parent' ); delete_comment_meta( $comment_id, '_wxr_import_user' ); } } /** * Use stored mapping information to update old attachment URLs */ protected function replace_attachment_urls_in_content() { global $wpdb; // make sure we do the longest urls first, in case one is a substring of another. uksort( $this->url_remap, array( $this, 'cmpr_strlen' ) ); foreach ( $this->url_remap as $from_url => $to_url ) { // remap urls in post_content. $query = $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url ); $wpdb->query( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- 3rd party library. // remap enclosure urls. $query = $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url ); $result = $wpdb->query( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- 3rd party library. } } /** * Update _thumbnail_id meta to new, imported attachment IDs */ public function remap_featured_images() { // cycle through posts that have a featured image. foreach ( $this->featured_images as $post_id => $value ) { if ( isset( $this->processed_posts[ $value ] ) ) { $new_id = $this->processed_posts[ $value ]; // only update if there's a difference. if ( $new_id !== $value ) { update_post_meta( $post_id, '_thumbnail_id', $new_id ); } } } } /** * Decide if the given meta key maps to information we will want to import * * @param string $key The meta key to check. * @return string|bool The key if we do want to import, false if not. */ public function is_valid_meta_key( $key ) { // skip attachment metadata since we'll regenerate it from scratch // skip _edit_lock as not relevant for import. if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) ) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict -- 3rd party library. return false; } return $key; } /** * Decide what the maximum file size for downloaded attachments is. * Default is 0 (unlimited), can be filtered via import_attachment_size_limit * * @return int Maximum attachment file size to import */ protected function max_attachment_size() { return apply_filters( 'import_attachment_size_limit', 0 ); } /** * Added to http_request_timeout filter to force timeout at 60 seconds during import * * @param string $val Timeout value. * @access public * @return int 60 */ public function bump_request_timeout( $val ) { return 60; } /** * Return the difference in length between two strings. * * @param string $a String one. * @param string $b String two. * @return string */ public function cmpr_strlen( $a, $b ) { return strlen( $b ) - strlen( $a ); } /** * Prefill existing post data. * * This preloads all GUIDs into memory, allowing us to avoid hitting the * database when we need to check for existence. With larger imports, this * becomes prohibitively slow to perform SELECT queries on each. * * By preloading all this data into memory, it's a constant-time lookup in * PHP instead. However, this does use a lot more memory, so for sites doing * small imports onto a large site, it may be a better tradeoff to use * on-the-fly checking instead. */ protected function prefill_existing_posts() { global $wpdb; $posts = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts}" ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- 3rd party library. foreach ( $posts as $item ) { $this->exists['post'][ $item->guid ] = $item->ID; } } /** * Does the post exist? * * @param array $data Post data to check against. * @return int|bool Existing post ID if it exists, false otherwise. */ protected function post_exists( $data ) { // Constant-time lookup if we prefilled. $exists_key = $data['guid']; if ( $this->options['prefill_existing_posts'] ) { return isset( $this->exists['post'][ $exists_key ] ) ? $this->exists['post'][ $exists_key ] : false; } // No prefilling, but might have already handled it. if ( isset( $this->exists['post'][ $exists_key ] ) ) { return $this->exists['post'][ $exists_key ]; } // Still nothing, try post_exists, and cache it. $exists = post_exists( $data['post_title'], $data['post_content'], $data['post_date'], $data['post_type'] ); $this->exists['post'][ $exists_key ] = $exists; return $exists; } /** * Mark the post as existing. * * @param array $data Post data to mark as existing. * @param int $post_id Post ID. */ protected function mark_post_exists( $data, $post_id ) { $exists_key = $data['guid']; $this->exists['post'][ $exists_key ] = $post_id; } /** * Prefill existing comment data. * * @see self::prefill_existing_posts() for justification of why this exists. */ protected function prefill_existing_comments() { global $wpdb; $posts = $wpdb->get_results( "SELECT comment_ID, comment_author, comment_date FROM {$wpdb->comments}" ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- 3rd party library. foreach ( $posts as $item ) { $exists_key = sha1( $item->comment_author . ':' . $item->comment_date ); $this->exists['comment'][ $exists_key ] = $item->comment_ID; } } /** * Does the comment exist? * * @param array $data Comment data to check against. * @return int|bool Existing comment ID if it exists, false otherwise. */ protected function comment_exists( $data ) { $exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] ); // Constant-time lookup if we prefilled. if ( $this->options['prefill_existing_comments'] ) { return isset( $this->exists['comment'][ $exists_key ] ) ? $this->exists['comment'][ $exists_key ] : false; } // No prefilling, but might have already handled it. if ( isset( $this->exists['comment'][ $exists_key ] ) ) { return $this->exists['comment'][ $exists_key ]; } // Still nothing, try comment_exists, and cache it. $exists = comment_exists( $data['comment_author'], $data['comment_date'] ); $this->exists['comment'][ $exists_key ] = $exists; return $exists; } /** * Mark the comment as existing. * * @param array $data Comment data to mark as existing. * @param int $comment_id Comment ID. */ protected function mark_comment_exists( $data, $comment_id ) { $exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] ); $this->exists['comment'][ $exists_key ] = $comment_id; } /** * Prefill existing term data. * * @see self::prefill_existing_posts() for justification of why this exists. */ protected function prefill_existing_terms() { global $wpdb; $query = "SELECT t.term_id, tt.taxonomy, t.slug FROM {$wpdb->terms} AS t"; $query .= " JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id"; $terms = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- 3rd party library. foreach ( $terms as $item ) { $exists_key = sha1( $item->taxonomy . ':' . $item->slug ); $this->exists['term'][ $exists_key ] = $item->term_id; } } /** * Does the term exist? * * @param array $data Term data to check against. * @return int|bool Existing term ID if it exists, false otherwise. */ protected function term_exists( $data ) { $exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] ); // Constant-time lookup if we prefilled. if ( $this->options['prefill_existing_terms'] ) { return isset( $this->exists['term'][ $exists_key ] ) ? $this->exists['term'][ $exists_key ] : false; } // No prefilling, but might have already handled it. if ( isset( $this->exists['term'][ $exists_key ] ) ) { return $this->exists['term'][ $exists_key ]; } // Still nothing, try comment_exists, and cache it. $exists = term_exists( $data['slug'], $data['taxonomy'] ); if ( is_array( $exists ) ) { $exists = $exists['term_id']; } $this->exists['term'][ $exists_key ] = $exists; return $exists; } /** * Mark the term as existing. * * @param array $data Term data to mark as existing. * @param int $term_id Term ID. */ protected function mark_term_exists( $data, $term_id ) { $exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] ); $this->exists['term'][ $exists_key ] = $term_id; } } endif; wxr-importer/class-wp-importer-logger-serversentevents.php 0000666 00000003374 15166147456 0020256 0 ustar 00 <?php /** * WordPress Importer * https://github.com/humanmade/WordPress-Importer * * Released under the GNU General Public License v2.0 * https://github.com/humanmade/WordPress-Importer/blob/master/LICENSE * * @since 2.0.0 * * @package WordPress Importer */ if ( ! class_exists( 'WP_Importer_Logger_ServerSentEvents' ) && class_exists( 'WP_Importer_Logger' ) ) { /** * Import Log ServerSendEvents * * @since 2.0.0 */ class WP_Importer_Logger_ServerSentEvents extends WP_Importer_Logger { /** * Logs with an arbitrary level. * * @param mixed $level Log level. * @param string $message Log message. * @param array $context Log context. * @return void */ public function log( $level, $message, array $context = array() ) { $data = compact( 'level', 'message' ); switch ( $level ) { case 'emergency': case 'alert': case 'critical': case 'error': case 'warning': case 'notice': case 'info': if ( defined( 'WP_CLI' ) ) { if ( isset( $data['message'] ) && ! empty( $data['message'] ) ) { WP_CLI::line( $data['message'] ); } else { WP_CLI::line( wp_json_encode( $data ) ); } } else { echo "event: log\n"; echo 'data: ' . wp_json_encode( $data ) . "\n\n"; } flush(); break; case 'debug': if ( defined( 'IMPORT_DEBUG' ) && IMPORT_DEBUG ) { if ( defined( 'WP_CLI' ) ) { if ( isset( $data['message'] ) && ! empty( $data['message'] ) ) { WP_CLI::line( $data['message'] ); } else { WP_CLI::line( wp_json_encode( $data ) ); } } else { echo "event: log\n"; echo 'data: ' . wp_json_encode( $data ) . "\n\n"; } flush(); break; } break; } } } } batch-processing/class-astra-sites-batch-processing.php 0000666 00000075146 15166147456 0017343 0 ustar 00 <?php /** * Batch Processing * * @package Astra Sites * @since 1.0.14 */ if ( ! class_exists( 'Astra_Sites_Batch_Processing' ) ) : /** * Astra_Sites_Batch_Processing * * @since 1.0.14 */ class Astra_Sites_Batch_Processing { /** * Instance * * @since 1.0.14 * @var object Class object. * @access private */ private static $instance; /** * Process All * * @since 1.0.14 * @var object Class object. * @access public */ public static $process_all; /** * Last Export Checksums * * @since 2.0.0 * @var object Class object. * @access public */ public $last_export_checksums; /** * Sites Importer * * @since 2.0.0 * @var object Class object. * @access public */ public static $process_site_importer; /** * Process Single Page * * @since 2.0.0 * @var object Class object. * @access public */ public static $process_single; /** * Initiator * * @since 1.0.14 * @return object initialized object of class. */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Constructor * * @since 1.0.14 */ public function __construct() { $this->includes(); // Start image importing after site import complete. add_filter( 'astra_sites_image_importer_skip_image', array( $this, 'skip_image' ), 10, 2 ); add_action( 'astra_sites_import_complete', array( $this, 'start_process' ) ); add_action( 'astra_sites_process_single', array( $this, 'start_process_single' ) ); if ( current_user_can( 'manage_options' ) ) { add_action( 'admin_init', array( $this, 'start_importer' ) ); } add_action( 'wp_ajax_astra-sites-update-library', array( $this, 'update_library' ) ); add_action( 'wp_ajax_astra-sites-update-library-complete', array( $this, 'update_library_complete' ) ); add_action( 'wp_ajax_astra-sites-import-all-categories-and-tags', array( $this, 'import_all_categories_and_tags' ) ); add_action( 'wp_ajax_astra-sites-import-all-categories', array( $this, 'import_all_categories' ) ); add_action( 'wp_ajax_astra-sites-import-block-categories', array( $this, 'import_block_categories' ) ); add_action( 'wp_ajax_astra-sites-import-page-builders', array( $this, 'import_page_builders' ) ); add_action( 'wp_ajax_astra-sites-import-blocks', array( $this, 'import_blocks' ) ); add_action( 'wp_ajax_astra-sites-get-sites-request-count', array( $this, 'sites_requests_count' ) ); add_action( 'wp_ajax_astra-sites-get-blocks-request-count', array( $this, 'blocks_requests_count' ) ); add_action( 'wp_ajax_astra-sites-import-sites', array( $this, 'import_sites' ) ); add_action( 'wp_ajax_astra-sites-get-all-categories', array( $this, 'get_all_categories' ) ); add_action( 'wp_ajax_astra-sites-get-all-categories-and-tags', array( $this, 'get_all_categories_and_tags' ) ); add_action( 'astra_sites_site_import_batch_complete', array( $this, 'sync_batch_complete' ) ); } /** * Update the latest checksum after all the import batch processes are done. */ public function sync_batch_complete() { Astra_Sites_Importer::get_instance()->update_latest_checksums(); } /** * Include Files * * @since 2.5.0 */ public function includes() { // Core Helpers - Image. // @todo This file is required for Elementor. // Once we implement our logic for updating elementor data then we'll delete this file. require_once ABSPATH . 'wp-admin/includes/image.php'; // Core Helpers - Image Downloader. require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/helpers/class-astra-sites-image-importer.php'; // Core Helpers - Batch Processing. require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/helpers/class-wp-async-request.php'; require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/helpers/class-wp-background-process.php'; require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/helpers/class-wp-background-process-astra.php'; require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/helpers/class-wp-background-process-astra-single.php'; require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/helpers/class-wp-background-process-astra-site-importer.php'; // Prepare Widgets. require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-widgets.php'; // Prepare Page Builders. require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-beaver-builder.php'; require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-elementor.php'; require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-gutenberg.php'; require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-brizy.php'; // Prepare Misc. require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-misc.php'; // Prepare Customizer. require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-customizer.php'; // Process Importer. require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-importer.php'; self::$process_all = new WP_Background_Process_Astra(); self::$process_single = new WP_Background_Process_Astra_Single(); self::$process_site_importer = new WP_Background_Process_Astra_Site_Importer(); } /** * Import All Categories * * @since 2.6.22 * @return void */ public function import_all_categories() { check_ajax_referer( 'astra-sites', '_ajax_nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( 'You are not allowed to perform this action', 'astra-sites' ); } Astra_Sites_Batch_Processing_Importer::get_instance()->import_all_categories(); wp_send_json_success(); } /** * Import All Categories and Tags * * @since 2.6.22 * @return void */ public function import_all_categories_and_tags() { check_ajax_referer( 'astra-sites', '_ajax_nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( 'You are not allowed to perform this action', 'astra-sites' ); } Astra_Sites_Batch_Processing_Importer::get_instance()->import_all_categories_and_tags(); wp_send_json_success(); } /** * Import Block Categories * * @since 2.0.0 * @return void */ public function import_block_categories() { check_ajax_referer( 'astra-sites', '_ajax_nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( 'You are not allowed to perform this action', 'astra-sites' ); } Astra_Sites_Batch_Processing_Importer::get_instance()->import_block_categories(); wp_send_json_success(); } /** * Import Page Builders * * @since 2.0.0 * @return void */ public function import_page_builders() { check_ajax_referer( 'astra-sites', '_ajax_nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( 'You are not allowed to perform this action', 'astra-sites' ); } Astra_Sites_Batch_Processing_Importer::get_instance()->import_page_builders(); wp_send_json_success(); } /** * Import Blocks * * @since 2.0.0 * @return void */ public function import_blocks() { check_ajax_referer( 'astra-sites', '_ajax_nonce' ); if ( ! current_user_can( 'edit_posts' ) ) { wp_send_json_error(); } $page_no = isset( $_POST['page_no'] ) ? absint( $_POST['page_no'] ) : ''; if ( $page_no ) { $sites_and_pages = Astra_Sites_Batch_Processing_Importer::get_instance()->import_blocks( $page_no ); wp_send_json_success(); } wp_send_json_error(); } /** * Import Sites * * @since 2.0.0 * @return void */ public function import_sites() { check_ajax_referer( 'astra-sites', '_ajax_nonce' ); if ( ! current_user_can( 'edit_posts' ) ) { wp_send_json_error(); } $page_no = isset( $_POST['page_no'] ) ? absint( $_POST['page_no'] ) : ''; if ( $page_no ) { $sites_and_pages = Astra_Sites_Batch_Processing_Importer::get_instance()->import_sites( $page_no ); $page_builder_keys = wp_list_pluck( $sites_and_pages, 'astra-site-page-builder' ); $default_page_builder = Astra_Sites_Page::get_instance()->get_setting( 'page_builder' ); $current_page_builder_sites = array(); foreach ( $page_builder_keys as $site_id => $page_builder ) { if ( $default_page_builder === $page_builder ) { $current_page_builder_sites[ $site_id ] = $sites_and_pages[ $site_id ]; } } wp_send_json_success( $current_page_builder_sites ); } wp_send_json_error(); } /** * Sites Requests Count * * @since 2.0.0 * @return void */ public function sites_requests_count() { check_ajax_referer( 'astra-sites', '_ajax_nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( 'You are not allowed to perform this action', 'astra-sites' ); } // Get count. $total_requests = $this->get_total_requests(); if ( $total_requests ) { wp_send_json_success( $total_requests ); } wp_send_json_error(); } /** * Blocks Requests Count * * @since 2.1.0 * @return void */ public function blocks_requests_count() { check_ajax_referer( 'astra-sites', '_ajax_nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( 'You are not allowed to perform this action', 'astra-sites' ); } // Get count. $total_requests = $this->get_total_blocks_requests(); if ( $total_requests ) { wp_send_json_success( $total_requests ); } wp_send_json_error(); } /** * Update Library Complete * * @since 2.0.0 * @return void */ public function update_library_complete() { check_ajax_referer( 'astra-sites', '_ajax_nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error(); } Astra_Sites_Importer::get_instance()->update_latest_checksums(); do_action( 'starter_templates_save_sites_count_as_per_page_builder' ); update_site_option( 'astra-sites-batch-is-complete', 'no', 'no' ); update_site_option( 'astra-sites-manual-sync-complete', 'yes', 'no' ); wp_send_json_success(); } /** * Get Last Exported Checksum Status * * @since 2.0.0 * @return string Checksums Status. */ public function get_last_export_checksums() { $old_last_export_checksums = get_site_option( 'astra-sites-last-export-checksums', '' ); $new_last_export_checksums = $this->set_last_export_checksums(); $checksums_status = 'no'; if ( empty( $old_last_export_checksums ) ) { $checksums_status = 'yes'; } if ( $new_last_export_checksums !== $old_last_export_checksums ) { $checksums_status = 'yes'; } return apply_filters( 'astra_sites_checksums_status', $checksums_status ); } /** * Set Last Exported Checksum * * @since 2.0.0 * @return string Checksums Status. */ public function set_last_export_checksums() { if ( ! empty( $this->last_export_checksums ) ) { return $this->last_export_checksums; } $api_args = array( 'timeout' => 60, ); $response = wp_remote_get( trailingslashit( Astra_Sites::get_instance()->get_api_domain() ) . 'wp-json/astra-sites/v1/get-last-export-checksums', $api_args ); if ( ! is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) === 200 ) { $result = json_decode( wp_remote_retrieve_body( $response ), true ); // Set last export checksums. if ( ! empty( $result['last_export_checksums'] ) ) { update_site_option( 'astra-sites-last-export-checksums-latest', $result['last_export_checksums'], 'no' ); $this->last_export_checksums = $result['last_export_checksums']; } } return $this->last_export_checksums; } /** * Update Library * * @since 2.0.0 * @return void */ public function update_library() { check_ajax_referer( 'astra-sites', '_ajax_nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error(); } if ( 'no' === $this->get_last_export_checksums() ) { wp_send_json_success( 'updated' ); } wp_send_json_success(); } /** * Start Importer * * @since 2.0.0 * @return void */ public function start_importer() { $process_sync = apply_filters( 'astra_sites_initial_sync', true ); if ( ! $process_sync ) { return; } $is_fresh_site = get_site_option( 'astra-sites-fresh-site', '' ); if ( empty( $is_fresh_site ) && '' === $is_fresh_site ) { $dir = ASTRA_SITES_DIR . 'inc/json'; // First time user save the data of sites, pages, categories etc from the JSON file. $list_files = $this->get_default_assets(); foreach ( $list_files as $key => $file_name ) { if ( file_exists( $dir . '/' . $file_name . '.json' ) ) { $data = Astra_Sites::get_instance()->get_filesystem()->get_contents( $dir . '/' . $file_name . '.json' ); if ( ! empty( $data ) ) { update_site_option( $file_name, json_decode( $data, true ) ); } } } // Also, Trigger the batch to get latest data. // If batch failed then user have at least the data from the JSON file. update_site_option( 'astra-sites-fresh-site', 'no' ); } $this->process_import(); } /** * Json Files Names. * * @since 2.6.1 * @return array */ public function get_default_assets() { return array( 'astra-blocks-1', 'astra-sites-site-category', 'astra-sites-all-site-categories', 'astra-blocks-4', 'astra-sites-page-builders', 'astra-blocks-3', 'astra-blocks-2', 'astra-blocks-categories', 'astra-sites-requests', 'astra-sites-and-pages-page-1', 'astra-sites-and-pages-page-2', 'astra-sites-and-pages-page-3', 'astra-sites-and-pages-page-4', 'astra-sites-and-pages-page-5', 'astra-sites-and-pages-page-6', 'astra-sites-and-pages-page-7', 'astra-sites-and-pages-page-8', 'astra-sites-and-pages-page-9', 'astra-sites-and-pages-page-10', 'astra-sites-and-pages-page-11', 'astra-sites-and-pages-page-12', 'astra-sites-and-pages-page-13', 'astra-sites-and-pages-page-14', 'astra-sites-and-pages-page-15', 'astra-sites-and-pages-page-16', 'astra-sites-and-pages-page-17', 'astra-sites-and-pages-page-18', 'astra-sites-and-pages-page-19', 'astra-sites-and-pages-page-20', 'astra-sites-and-pages-page-21', 'astra-sites-and-pages-page-22', 'astra-sites-and-pages-page-23', 'astra-sites-and-pages-page-24', ); } /** * Process Batch * * @since 2.0.0 * @return mixed */ public function process_batch() { $process_sync = apply_filters( 'astra_sites_process_sync_batch', true ); if ( ! $process_sync ) { return; } if ( 'no' === $this->get_last_export_checksums() ) { $this->log( 'Library is up to date!' ); if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Library is up to date!' ); } return; } $status = Astra_Sites_Page::get_instance()->test_cron(); if ( is_wp_error( $status ) ) { astra_sites_error_log( 'Error! Batch Not Start due to disabled cron events!' ); update_site_option( 'astra-sites-batch-status-string', 'Error! Batch Not Start due to disabled cron events!', 'no' ); if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Error! Batch Not Start due to disabled cron events!' ); } else { // For non- WP CLI request return to prevent the request. return; } } $this->log( 'Sync Library Started!' ); // Added the categories and tags. $this->log( 'Added All Categories and tags in queue.' ); if ( defined( 'WP_CLI' ) ) { Astra_Sites_Batch_Processing_Importer::get_instance()->import_all_categories_and_tags(); } else { self::$process_site_importer->push_to_queue( array( 'instance' => Astra_Sites_Batch_Processing_Importer::get_instance(), 'method' => 'import_all_categories_and_tags', ) ); } // Added the categories. $this->log( 'Added All Site Categories in queue.' ); if ( defined( 'WP_CLI' ) ) { Astra_Sites_Batch_Processing_Importer::get_instance()->import_all_categories(); } else { self::$process_site_importer->push_to_queue( array( 'instance' => Astra_Sites_Batch_Processing_Importer::get_instance(), 'method' => 'import_all_categories', ) ); } // Added the page_builders. $this->log( 'Added page builders in queue.' ); if ( defined( 'WP_CLI' ) ) { Astra_Sites_Batch_Processing_Importer::get_instance()->import_page_builders(); } else { self::$process_site_importer->push_to_queue( array( 'instance' => Astra_Sites_Batch_Processing_Importer::get_instance(), 'method' => 'import_page_builders', ) ); } // Get count. $total_requests = $this->get_total_blocks_requests(); if ( $total_requests ) { $this->log( 'BLOCK: Total Blocks Requests ' . $total_requests ); for ( $page = 1; $page <= $total_requests; $page++ ) { $this->log( 'BLOCK: Added page ' . $page . ' in queue.' ); if ( defined( 'WP_CLI' ) ) { Astra_Sites_Batch_Processing_Importer::get_instance()->import_blocks( $page ); } else { self::$process_site_importer->push_to_queue( array( 'page' => $page, 'instance' => Astra_Sites_Batch_Processing_Importer::get_instance(), 'method' => 'import_blocks', ) ); } } } // Added the categories. $this->log( 'Added Block Categories in queue.' ); if ( defined( 'WP_CLI' ) ) { Astra_Sites_Batch_Processing_Importer::get_instance()->import_block_categories(); } else { self::$process_site_importer->push_to_queue( array( 'instance' => Astra_Sites_Batch_Processing_Importer::get_instance(), 'method' => 'import_block_categories', ) ); } // Get count. $total_requests = $this->get_total_requests(); if ( $total_requests ) { $this->log( 'Total Requests ' . $total_requests ); for ( $page = 1; $page <= $total_requests; $page++ ) { $this->log( 'Added page ' . $page . ' in queue.' ); if ( defined( 'WP_CLI' ) ) { Astra_Sites_Batch_Processing_Importer::get_instance()->import_sites( $page ); } else { self::$process_site_importer->push_to_queue( array( 'page' => $page, 'instance' => Astra_Sites_Batch_Processing_Importer::get_instance(), 'method' => 'import_sites', ) ); } } } if ( defined( 'WP_CLI' ) ) { $this->log( 'Sync Process Complete.' ); } else { // Dispatch Queue. $this->log( 'Dispatch the Queue!' ); self::$process_site_importer->save()->dispatch(); } } /** * Log * * @since 2.0.0 * * @param string $message Log message. * @return void. */ public function log( $message = '' ) { if ( defined( 'WP_CLI' ) ) { WP_CLI::line( $message ); } else { astra_sites_error_log( $message ); update_site_option( 'astra-sites-batch-status-string', $message, 'no' ); } } /** * Process Import * * @since 2.0.0 * * @return mixed Null if process is already started. */ public function process_import() { $process_sync = apply_filters( 'astra_sites_process_auto_sync_library', true ); if ( ! $process_sync ) { return; } // Batch is already started? Then return. $status = get_site_option( 'astra-sites-batch-status' ); if ( 'in-process' === $status ) { return; } // Check batch expiry. $expired = get_site_transient( 'astra-sites-import-check' ); if ( false !== $expired ) { return; } // For 1 week. set_site_transient( 'astra-sites-import-check', 'true', apply_filters( 'astra_sites_sync_check_time', WEEK_IN_SECONDS ) ); update_site_option( 'astra-sites-batch-status', 'in-process' ); // Process batch. $this->process_batch(); } /** * Get Total Requests * * @return integer */ public function get_total_requests() { astra_sites_error_log( 'Getting Total Pages' ); update_site_option( 'astra-sites-batch-status-string', 'Getting Total Pages', 'no' ); $api_args = array( 'timeout' => 60, ); $response = wp_remote_get( trailingslashit( Astra_Sites::get_instance()->get_api_domain() ) . 'wp-json/astra-sites/v1/get-total-pages/?per_page=15', $api_args ); if ( ! is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) === 200 ) { $total_requests = json_decode( wp_remote_retrieve_body( $response ), true ); if ( isset( $total_requests['pages'] ) ) { $this->log( 'Updated requests ' . $total_requests['pages'] ); update_site_option( 'astra-sites-requests', $total_requests['pages'], 'no' ); do_action( 'astra_sites_sync_get_total_pages', $total_requests['pages'] ); return $total_requests['pages']; } } astra_sites_error_log( 'Request Failed! Still Calling..' ); update_site_option( 'astra-sites-batch-status-string', 'Request Failed! Still Calling..', 'no' ); } /** * Get Blocks Total Requests * * @return integer */ public function get_total_blocks_requests() { astra_sites_error_log( 'BLOCK: Getting Total Blocks' ); update_site_option( 'astra-sites-batch-status-string', 'Getting Total Blocks', 'no' ); $api_args = array( 'timeout' => 60, ); $query_args = array( 'page_builder' => 'elementor', 'wireframe' => 'yes', ); $api_url = add_query_arg( $query_args, trailingslashit( Astra_Sites::get_instance()->get_api_domain() ) . 'wp-json/astra-blocks/v1/get-blocks-count/' ); $response = wp_remote_get( $api_url, $api_args ); if ( ! is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) === 200 ) { $total_requests = json_decode( wp_remote_retrieve_body( $response ), true ); if ( isset( $total_requests['pages'] ) ) { astra_sites_error_log( 'BLOCK: Updated requests ' . $total_requests['pages'] ); update_site_option( 'astra-blocks-batch-status-string', 'Updated requests ' . $total_requests['pages'], 'no' ); update_site_option( 'astra-blocks-requests', $total_requests['pages'], 'no' ); do_action( 'astra_sites_sync_blocks_requests', $total_requests['pages'] ); return $total_requests['pages']; } } astra_sites_error_log( 'BLOCK: Request Failed! Still Calling..' ); update_site_option( 'astra-blocks-batch-status-string', 'Request Failed! Still Calling..', 'no' ); } /** * Start Single Page Import * * @param int $page_id Page ID . * @since 2.0.0 * @return void */ public function start_process_single( $page_id ) { astra_sites_error_log( '=================== ' . Astra_Sites_White_Label::get_instance()->get_white_label_name( ASTRA_SITES_NAME ) . ' - Single Page - Importing Images for Blog name \'' . get_the_title( $page_id ) . '\' (' . $page_id . ') ===================' ); $default_page_builder = Astra_Sites_Page::get_instance()->get_setting( 'page_builder' ); if ( 'gutenberg' === $default_page_builder ) { // Add "gutenberg" in import [queue]. self::$process_single->push_to_queue( array( 'page_id' => $page_id, 'instance' => Astra_Sites_Batch_Processing_Gutenberg::get_instance(), ) ); } // Add "brizy" in import [queue]. if ( 'brizy' === $default_page_builder && is_plugin_active( 'brizy/brizy.php' ) ) { // Add "gutenberg" in import [queue]. self::$process_single->push_to_queue( array( 'page_id' => $page_id, 'instance' => Astra_Sites_Batch_Processing_Brizy::get_instance(), ) ); } // Add "bb-plugin" in import [queue]. if ( 'beaver-builder' === $default_page_builder && ( is_plugin_active( 'beaver-builder-lite-version/fl-builder.php' ) || is_plugin_active( 'bb-plugin/fl-builder.php' ) ) ) { // Add "gutenberg" in import [queue]. self::$process_single->push_to_queue( array( 'page_id' => $page_id, 'instance' => Astra_Sites_Batch_Processing_Beaver_Builder::get_instance(), ) ); } // Add "elementor" in import [queue]. if ( 'elementor' === $default_page_builder ) { // @todo Remove required `allow_url_fopen` support. if ( ini_get( 'allow_url_fopen' ) ) { if ( is_plugin_active( 'elementor/elementor.php' ) ) { // !important, Clear the cache after images import. \Elementor\Plugin::$instance->posts_css_manager->clear_cache(); $import = new \Elementor\TemplateLibrary\Astra_Sites_Batch_Processing_Elementor(); self::$process_single->push_to_queue( array( 'page_id' => $page_id, 'instance' => $import, ) ); } } else { astra_sites_error_log( 'Couldn\'t not import image due to allow_url_fopen() is disabled!' ); } } // Dispatch Queue. self::$process_single->save()->dispatch(); } /** * Skip Image from Batch Processing. * * @since 1.0.14 * * @param boolean $can_process Batch process image status. * @param array $attachment Batch process image input. * @return boolean */ public function skip_image( $can_process, $attachment ) { if ( isset( $attachment['url'] ) && ! empty( $attachment['url'] ) ) { // If image URL contain current site URL? then return true to skip that image from import. if ( strpos( $attachment['url'], site_url() ) !== false ) { return true; } if ( strpos( $attachment['url'], 'brainstormforce.com' ) !== false || strpos( $attachment['url'], 'wpastra.com' ) !== false || strpos( $attachment['url'], 'sharkz.in' ) !== false || strpos( $attachment['url'], 'websitedemos.net' ) !== false ) { return false; } } return true; } /** * Start Image Import * * @since 1.0.14 * * @return void */ public function start_process() { set_transient( 'astra_sites_batch_process_started', 'yes', HOUR_IN_SECONDS ); /** WordPress Plugin Administration API */ require_once ABSPATH . 'wp-admin/includes/plugin.php'; require_once ABSPATH . 'wp-admin/includes/update.php'; $this->includes(); $wxr_id = get_site_option( 'astra_sites_imported_wxr_id', 0 ); if ( $wxr_id ) { wp_delete_attachment( $wxr_id, true ); Astra_Sites_Importer_Log::add( 'Deleted Temporary WXR file ' . $wxr_id ); delete_option( 'astra_sites_imported_wxr_id' ); Astra_Sites_Importer_Log::add( 'Option `astra_sites_imported_wxr_id` Deleted.' ); } $classes = array(); Astra_Sites_Importer_Log::add( 'Batch Process Started..' ); Astra_Sites_Importer_Log::add( Astra_Sites_White_Label::get_instance()->get_white_label_name( ASTRA_SITES_NAME ) . ' - Importing Images for Blog name \'' . get_bloginfo( 'name' ) . '\' (' . get_current_blog_id() . ')' ); // Add "widget" in import [queue]. $classes[] = Astra_Sites_Batch_Processing_Widgets::get_instance(); // Add "gutenberg" in import [queue]. $classes[] = Astra_Sites_Batch_Processing_Gutenberg::get_instance(); // Add "brizy" in import [queue]. if ( is_plugin_active( 'brizy/brizy.php' ) ) { $classes[] = Astra_Sites_Batch_Processing_Brizy::get_instance(); } // Add "bb-plugin" in import [queue]. // Add "beaver-builder-lite-version" in import [queue]. if ( is_plugin_active( 'beaver-builder-lite-version/fl-builder.php' ) || is_plugin_active( 'bb-plugin/fl-builder.php' ) ) { $classes[] = Astra_Sites_Batch_Processing_Beaver_Builder::get_instance(); } // Add "elementor" in import [queue]. // @todo Remove required `allow_url_fopen` support. if ( ini_get( 'allow_url_fopen' ) && is_plugin_active( 'elementor/elementor.php' ) ) { $import = new \Elementor\TemplateLibrary\Astra_Sites_Batch_Processing_Elementor(); $classes[] = $import; } // Add "astra-addon" in import [queue]. if ( is_plugin_active( 'astra-addon/astra-addon.php' ) ) { $classes[] = Astra_Sites_Compatibility_Astra_Pro::get_instance(); } // Add "misc" in import [queue]. $classes[] = Astra_Sites_Batch_Processing_Misc::get_instance(); // Add "customizer" in import [queue]. $classes[] = Astra_Sites_Batch_Processing_Customizer::get_instance(); if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Batch Process Started..' ); // Process all classes. foreach ( $classes as $key => $class ) { if ( method_exists( $class, 'import' ) ) { $class->import(); } } WP_CLI::line( 'Batch Process Complete!' ); } else { // Add all classes to batch queue. foreach ( $classes as $key => $class ) { self::$process_all->push_to_queue( $class ); } // Dispatch Queue. self::$process_all->save()->dispatch(); } } /** * Get all post id's * * @since 1.0.14 * * @param array $post_types Post types. * @return array */ public static function get_pages( $post_types = array() ) { if ( $post_types ) { $args = array( 'post_type' => $post_types, // Query performance optimization. 'fields' => 'ids', 'no_found_rows' => true, 'post_status' => 'publish', 'posts_per_page' => -1, ); $query = new WP_Query( $args ); // Have posts? if ( $query->have_posts() ) : return $query->posts; endif; } return null; } /** * Get Supporting Post Types.. * * @since 1.3.7 * @param integer $feature Feature. * @return array */ public static function get_post_types_supporting( $feature ) { global $_wp_post_type_features; $post_types = array_keys( wp_filter_object_list( $_wp_post_type_features, array( $feature => true ) ) ); return $post_types; } /** * Get all categories. * * @return void */ public function get_all_categories() { if ( ! defined( 'WP_CLI' ) && wp_doing_ajax() ) { if ( ! current_user_can( 'customize' ) ) { wp_send_json_error( __( 'You are not allowed to perform this action', 'astra-sites' ) ); } $all_categories = get_site_option( 'astra-sites-all-site-categories', array() ); wp_send_json_success( $all_categories ); } wp_send_json_error( __( 'You are not allowed to perform this action.', 'astra-sites' ) ); } /** * Get all categories and tags. * * @return void */ public function get_all_categories_and_tags() { if ( ! defined( 'WP_CLI' ) && wp_doing_ajax() ) { if ( ! current_user_can( 'customize' ) ) { wp_send_json_error( __( 'You are not allowed to perform this action', 'astra-sites' ) ); } $all_categories_and_tags = get_site_option( 'astra-sites-all-site-categories-and-tags', array() ); wp_send_json_success( $all_categories_and_tags ); } wp_send_json_error( __( 'You are not allowed to perform this action.', 'astra-sites' ) ); } } /** * Kicking this off by calling 'get_instance()' method */ Astra_Sites_Batch_Processing::get_instance(); endif; batch-processing/class-astra-sites-batch-processing-customizer.php 0000666 00000003336 15166147456 0021535 0 ustar 00 <?php /** * Customizer batch import tasks. * * @package Astra Sites * @since 3.0.22 */ /** * Astra_Sites_Batch_Processing_Customizer * * @since 3.0.22 */ class Astra_Sites_Batch_Processing_Customizer { /** * Instance * * @since 3.0.22 * @access private * @var object Class object. */ private static $instance; /** * Initiator * * @since 3.0.22 * @return object initialized object of class. */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Constructor * * @since 3.0.22 */ public function __construct() {} /** * Import * * @since 3.0.22 * @return void */ public function import() { if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Processing "Customizer" Batch Import' ); } Astra_Sites_Importer_Log::add( '---- Processing batch process for Customizer start ----' ); self::images_download(); Astra_Sites_Importer_Log::add( '---- Processing batch process for Customizer done ----' ); } /** * Downloads images from customizer. */ public static function images_download() { $options = get_option( 'astra-settings', array() ); array_walk_recursive( $options, function ( &$value ) { if ( ! is_array( $value ) && astra_sites_is_valid_image( $value ) ) { $downloaded_image = Astra_Sites_Image_Importer::get_instance()->import( array( 'url' => $value, 'id' => 0, ) ); $value = $downloaded_image['url']; } } ); // Updated settings. update_option( 'astra-settings', $options ); } } /** * Kicking this off by calling 'get_instance()' method */ Astra_Sites_Batch_Processing_Customizer::get_instance(); batch-processing/class-astra-sites-batch-processing-misc.php 0000666 00000007063 15166147456 0020265 0 ustar 00 <?php /** * Misc batch import tasks. * * @package Astra Sites * @since 1.1.6 */ if ( ! class_exists( 'Astra_Sites_Batch_Processing_Misc' ) ) : /** * Astra_Sites_Batch_Processing_Misc * * @since 1.1.6 */ class Astra_Sites_Batch_Processing_Misc { /** * Instance * * @since 1.1.6 * @access private * @var object Class object. */ private static $instance; /** * Initiator * * @since 1.1.6 * @return object initialized object of class. */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Constructor * * @since 1.1.6 */ public function __construct() {} /** * Import * * @since 1.1.6 * @return void */ public function import() { if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Processing "MISC" Batch Import' ); } Astra_Sites_Importer_Log::add( '---- Processing MISC ----' ); self::fix_nav_menus(); self::image_processing(); } /** * Import Module Images. * * @return object */ public static function fix_nav_menus() { if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Setting Nav Menus' ); } // Not found site data, then return. $demo_data = get_option( 'astra_sites_import_data', array() ); if ( ! isset( $demo_data['astra-post-data-mapping'] ) ) { return; } // Not found/empty XML URL, then return. $xml_url = ( isset( $demo_data['astra-site-wxr-path'] ) ) ? esc_url( $demo_data['astra-site-wxr-path'] ) : ''; if ( empty( $xml_url ) ) { return; } // Not empty site URL, then return. $site_url = strpos( $xml_url, '/wp-content' ); if ( false === $site_url ) { return; } // Get remote site URL. $site_url = substr( $xml_url, 0, $site_url ); $post_ids = self::get_menu_post_ids(); if ( is_array( $post_ids ) ) { foreach ( $post_ids as $post_id ) { if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Post ID: ' . $post_id ); } Astra_Sites_Importer_Log::add( 'Post ID: ' . $post_id ); $menu_url = get_post_meta( $post_id, '_menu_item_url', true ); if ( $menu_url ) { $menu_url = str_replace( $site_url, site_url(), $menu_url ); update_post_meta( $post_id, '_menu_item_url', $menu_url ); } } } } /** * Process Images with the metadata. * * @since 3.0.20 * @return void */ public static function image_processing() { Astra_Sites_Importer_Log::add( '---- Processing Images Metadata ----' ); $all_attachments = get_option( 'st_attachments', array() ); if ( empty( $all_attachments ) ) { return; } foreach ( $all_attachments as $attachment_id ) { $file = get_attached_file( $attachment_id ); if ( false !== $file ) { wp_generate_attachment_metadata( $attachment_id, $file ); } } update_option( 'st_attachments', array(), 'no' ); Astra_Sites_Importer_Log::add( '---- Processing Images Metadata Completed ----' ); } /** * Get all post id's * * @since 1.1.6 * * @return array */ public static function get_menu_post_ids() { $args = array( 'post_type' => 'nav_menu_item', // Query performance optimization. 'fields' => 'ids', 'no_found_rows' => true, 'post_status' => 'any', ); $query = new WP_Query( $args ); // Have posts? if ( $query->have_posts() ) : return $query->posts; endif; return null; } } /** * Kicking this off by calling 'get_instance()' method */ Astra_Sites_Batch_Processing_Misc::get_instance(); endif; batch-processing/class-astra-sites-batch-processing-elementor.php 0000666 00000010765 15166147456 0021327 0 ustar 00 <?php /** * Elementor Importer * * @package Astra Sites */ namespace Elementor\TemplateLibrary; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } // If plugin - 'Elementor' not exist then return. if ( ! class_exists( '\Elementor\Plugin' ) ) { return; } use Elementor\Core\Base\Document; use Elementor\Core\Editor\Editor; use Elementor\DB; use Elementor\Core\Settings\Manager as SettingsManager; use Elementor\Core\Settings\Page\Model; use Elementor\Modules\Library\Documents\Library_Document; use Elementor\Plugin; use Elementor\Utils; /** * Elementor template library local source. * * Elementor template library local source handler class is responsible for * handling local Elementor templates saved by the user locally on his site. * * @since 1.2.13 Added compatibility for Elemetnor v2.5.0 * @since 1.0.0 */ class Astra_Sites_Batch_Processing_Elementor extends Source_Local { /** * Import * * @since 1.0.14 * @return void */ public function import() { if ( defined( 'WP_CLI' ) ) { \WP_CLI::line( 'Processing "Elementor" Batch Import' ); } \Astra_Sites_Importer_Log::add( '---- Processing WordPress Posts / Pages - for Elementor ----' ); $post_types = \Astra_Sites_Batch_Processing::get_post_types_supporting( 'elementor' ); if ( defined( 'WP_CLI' ) ) { \WP_CLI::line( 'For post types: ' . implode( ', ', $post_types ) ); } if ( empty( $post_types ) && ! is_array( $post_types ) ) { return; } $post_ids = \Astra_Sites_Batch_Processing::get_pages( $post_types ); if ( empty( $post_ids ) && ! is_array( $post_ids ) ) { return; } foreach ( $post_ids as $post_id ) { $this->import_single_post( $post_id ); } } /** * Update post meta. * * @since 1.0.14 * @param integer $post_id Post ID. * @return void */ public function import_single_post( $post_id = 0 ) { $is_elementor_post = get_post_meta( $post_id, '_elementor_version', true ); if ( ! $is_elementor_post ) { return; } // Is page imported with Starter Sites? // If not then skip batch process. $imported_from_demo_site = get_post_meta( $post_id, '_astra_sites_enable_for_batch', true ); if ( ! $imported_from_demo_site ) { return; } if ( defined( 'WP_CLI' ) ) { \WP_CLI::line( 'Elementor - Processing page: ' . $post_id ); } \Astra_Sites_Importer_Log::add( '---- Processing WordPress Page - for Elementor ---- "' . $post_id . '"' ); if ( ! empty( $post_id ) ) { $data = get_post_meta( $post_id, '_elementor_data', true ); \Astra_Sites_Importer_Log::add( wp_json_encode( $data ) ); if ( ! empty( $data ) ) { // Update WP form IDs. $ids_mapping = get_option( 'astra_sites_wpforms_ids_mapping', array() ); \Astra_Sites_Importer_Log::add( wp_json_encode( $ids_mapping ) ); if ( $ids_mapping ) { foreach ( $ids_mapping as $old_id => $new_id ) { $data = str_replace( '[wpforms id=\"' . $old_id, '[wpforms id=\"' . $new_id, $data ); $data = str_replace( '"select_form":"' . $old_id, '"select_form":"' . $new_id, $data ); $data = str_replace( '"form_id":"' . $old_id, '"form_id":"' . $new_id, $data ); } } if ( ! is_array( $data ) ) { $data = json_decode( $data, true ); } \Astra_Sites_Importer_Log::add( wp_json_encode( $data ) ); $document = Plugin::$instance->documents->get( $post_id ); if ( $document ) { $data = $document->get_elements_raw_data( $data, true ); } // Import the data. $data = $this->process_export_import_content( $data, 'on_import' ); // Replace the site urls. $demo_data = get_option( 'astra_sites_import_data', array() ); \Astra_Sites_Importer_Log::add( wp_json_encode( $demo_data ) ); if ( isset( $demo_data['astra-site-url'] ) ) { $data = wp_json_encode( $data, true ); if ( ! empty( $data ) ) { $site_url = get_site_url(); $site_url = str_replace( '/', '\/', $site_url ); $demo_site_url = 'https:' . $demo_data['astra-site-url']; $demo_site_url = str_replace( '/', '\/', $demo_site_url ); $data = str_replace( $demo_site_url, $site_url, $data ); $data = json_decode( $data, true ); } } // Update processed meta. update_metadata( 'post', $post_id, '_elementor_data', $data ); update_metadata( 'post', $post_id, '_astra_sites_hotlink_imported', true ); // !important, Clear the cache after images import. Plugin::$instance->files_manager->clear_cache(); } // Clean the post excerpt. astra_sites_empty_post_excerpt( $post_id ); } } } batch-processing/class-astra-sites-batch-processing-gutenberg.php 0000666 00000020224 15166147456 0021306 0 ustar 00 <?php /** * Batch Processing * * @package Astra Sites * @since 1.2.14 */ if ( ! class_exists( 'Astra_Sites_Batch_Processing_Gutenberg' ) ) : /** * Astra Sites Batch Processing Brizy * * @since 1.2.14 */ class Astra_Sites_Batch_Processing_Gutenberg { /** * Instance * * @since 1.2.14 * @access private * @var object Class object. */ private static $instance; /** * Initiator * * @since 1.2.14 * @return object initialized object of class. */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Constructor * * @since 1.2.14 */ public function __construct() {} /** * Allowed tags for the batch update process. * * @param array $allowedposttags Array of default allowable HTML tags. * @param string|array $context The context for which to retrieve tags. Allowed values are 'post', * 'strip', 'data', 'entities', or the name of a field filter such as * 'pre_user_description'. * @return array Array of allowed HTML tags and their allowed attributes. */ public function allowed_tags_and_attributes( $allowedposttags, $context ) { // Keep only for 'post' contenxt. if ( 'post' === $context ) { // <svg> tag and attributes. $allowedposttags['svg'] = array( 'xmlns' => true, 'viewbox' => true, ); // <path> tag and attributes. $allowedposttags['path'] = array( 'd' => true, ); } return $allowedposttags; } /** * Import * * @since 1.2.14 * @return void */ public function import() { // Allow the SVG tags in batch update process. add_filter( 'wp_kses_allowed_html', array( $this, 'allowed_tags_and_attributes' ), 10, 2 ); if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Processing "Gutenberg" Batch Import' ); } Astra_Sites_Importer_Log::add( '---- Processing WordPress Posts / Pages - for "Gutenberg" ----' ); $post_types = apply_filters( 'astra_sites_gutenberg_batch_process_post_types', array( 'page', 'wp_block' ) ); if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'For post types: ' . implode( ', ', $post_types ) ); } $post_ids = Astra_Sites_Batch_Processing::get_pages( $post_types ); if ( empty( $post_ids ) && ! is_array( $post_ids ) ) { return; } 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 ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Gutenberg - Processing page: ' . $post_id ); } // Is page imported with Starter Sites? // If not then skip batch process. $imported_from_demo_site = get_post_meta( $post_id, '_astra_sites_enable_for_batch', true ); if ( ! $imported_from_demo_site ) { return; } $is_elementor_page = get_post_meta( $post_id, '_elementor_version', true ); $is_beaver_builder_page = get_post_meta( $post_id, '_fl_builder_enabled', true ); $is_brizy_page = get_post_meta( $post_id, 'brizy_post_uid', true ); // If page contain Elementor, Brizy or Beaver Builder meta then skip this page. if ( $is_elementor_page || $is_beaver_builder_page || $is_brizy_page ) { return; } Astra_Sites_Importer_Log::add( '---- Processing WordPress Page - for Gutenberg ---- "' . $post_id . '"' ); $ids_mapping = get_option( 'astra_sites_wpforms_ids_mapping', array() ); // Post content. $content = get_post_field( 'post_content', $post_id ); // Empty mapping? Then return. if ( ! empty( $ids_mapping ) ) { // Replace ID's. foreach ( $ids_mapping as $old_id => $new_id ) { $content = str_replace( '[wpforms id=\"' . $old_id, '[wpforms id=\"' . $new_id, $content ); $content = str_replace( '{\"formId\":\"' . $old_id . '\"}', '{\"formId\":\"' . $new_id . '\"}', $content ); } } // This replaces the category ID in UAG Post blocks. $site_options = get_option( 'astra_sites_import_data', array() ); if ( isset( $site_options['astra-site-taxonomy-mapping'] ) ) { $tax_mapping = $site_options['astra-site-taxonomy-mapping']; if ( isset( $tax_mapping['post'] ) ) { $catogory_mapping = ( isset( $tax_mapping['post']['category'] ) ) ? $tax_mapping['post']['category'] : array(); if ( is_array( $catogory_mapping ) && ! empty( $catogory_mapping ) ) { foreach ( $catogory_mapping as $key => $value ) { $this_site_term = get_term_by( 'slug', $value['slug'], 'category' ); if ( ! is_wp_error( $this_site_term ) && $this_site_term ) { $content = str_replace( '"categories":"' . $value['id'], '"categories":"' . $this_site_term->term_id, $content ); $content = str_replace( '{"categories":[{"id":' . $value['id'], '{"categories":[{"id":' . $this_site_term->term_id, $content ); $content = str_replace( 'categories/' . $value['id'], 'categories/' . $this_site_term->term_id, $content ); $content = str_replace( 'categories=' . $value['id'], 'categories=' . $this_site_term->term_id, $content ); } } } } } // # Tweak // Gutenberg break block markup from render. Because the '&' is updated in database with '&' and it // expects as 'u0026amp;'. So, Converted '&' with 'u0026amp;'. // // @todo This affect for normal page content too. Detect only Gutenberg pages and process only on it. // $content = str_replace( '&', "\u0026amp;", $content ); $content = $this->get_content( $content ); // Update content. wp_update_post( array( 'ID' => $post_id, 'post_content' => $content, 'post_excerpt' => '', ) ); } /** * Download and Replace hotlink images * * @since 2.0.0 * * @param string $content Mixed post content. * @return array Hotlink image array. */ public function get_content( $content = '' ) { // Extract all links. preg_match_all( '#\bhttps?://[^,\s()<>]+(?:\([\w\d]+\)|([^,[:punct:]\s]|/))#', $content, $match ); $all_links = array_unique( $match[0] ); // Not have any link. if ( empty( $all_links ) ) { return $content; } $link_mapping = array(); $image_links = array(); $other_links = array(); // Extract normal and image links. foreach ( $all_links as $key => $link ) { if ( astra_sites_is_valid_image( $link ) ) { // Get all image links. // Avoid *-150x, *-300x and *-1024x images. if ( false === strpos( $link, '-150x' ) && false === strpos( $link, '-300x' ) && false === strpos( $link, '-1024x' ) ) { $image_links[] = $link; } } else { // Collect other links. $other_links[] = $link; } } // Step 1: Download images. if ( ! empty( $image_links ) ) { foreach ( $image_links as $key => $image_url ) { // Download remote image. $image = array( 'url' => $image_url, 'id' => 0, ); $downloaded_image = Astra_Sites_Image_Importer::get_instance()->import( $image ); // Old and New image mapping links. $link_mapping[ $image_url ] = $downloaded_image['url']; } } // Step 2: Replace the demo site URL with live site URL. if ( ! empty( $other_links ) ) { $demo_data = get_option( 'astra_sites_import_data', array() ); if ( isset( $demo_data['astra-site-url'] ) ) { $site_url = get_site_url(); foreach ( $other_links as $key => $link ) { $link_mapping[ $link ] = str_replace( 'https:' . $demo_data['astra-site-url'], $site_url, $link ); } } } // Step 3: Replace mapping links. foreach ( $link_mapping as $old_url => $new_url ) { $content = str_replace( $old_url, $new_url, $content ); // Replace the slashed URLs if any exist. $old_url = str_replace( '/', '/\\', $old_url ); $new_url = str_replace( '/', '/\\', $new_url ); $content = str_replace( $old_url, $new_url, $content ); } return $content; } } /** * Kicking this off by calling 'get_instance()' method */ Astra_Sites_Batch_Processing_Gutenberg::get_instance(); endif; batch-processing/class-astra-sites-batch-processing-beaver-builder.php 0000666 00000016735 15166147456 0022230 0 ustar 00 <?php /** * Batch Processing * * @package Astra Sites * @since 1.0.14 */ if ( ! class_exists( 'Astra_Sites_Batch_Processing_Beaver_Builder' ) ) : /** * Astra_Sites_Batch_Processing_Beaver_Builder * * @since 1.0.14 */ class Astra_Sites_Batch_Processing_Beaver_Builder { /** * Instance * * @since 1.0.14 * @access private * @var object Class object. */ private static $instance; /** * Initiator * * @since 1.0.14 * @return object initialized object of class. */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Constructor * * @since 1.0.14 */ public function __construct() { } /** * Import * * @since 1.0.14 * @return void */ public function import() { if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Processing "Beaver Builder" Batch Import' ); } Astra_Sites_Importer_Log::add( '---- Processing WordPress Posts / Pages - for Beaver Builder ----' ); if ( ! is_callable( 'FLBuilderModel::get_post_types' ) ) { return; } $post_types = FLBuilderModel::get_post_types( 'post-types' ); if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'For post types: ' . implode( ', ', $post_types ) ); } if ( empty( $post_types ) && ! is_array( $post_types ) ) { return; } $post_ids = Astra_Sites_Batch_Processing::get_pages( $post_types ); if ( empty( $post_ids ) && ! is_array( $post_ids ) ) { return; } 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 ) { $is_bb_post = get_post_meta( $post_id, '_fl_builder_enabled', true ); if ( ! $is_bb_post ) { return; } // Is page imported with Starter Sites? // If not then skip batch process. $imported_from_demo_site = get_post_meta( $post_id, '_astra_sites_enable_for_batch', true ); if ( ! $imported_from_demo_site ) { return; } if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Beaver Builder - Processing page: ' . $post_id ); } Astra_Sites_Importer_Log::add( '---- Processing WordPress Page - for Beaver Builder ---- "' . $post_id . '"' ); 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 ) { // Update 'row' images. if ( 'row' === $el->type ) { $data[ $key ]->settings = self::update_row( $el->settings ); } // Update 'module' images. if ( 'module' === $el->type ) { $data[ $key ]->settings = self::update_module( $el->settings ); } // Update 'column' images. if ( 'column' === $el->type ) { $data[ $key ]->settings = self::update_column( $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(); } // Clean the post excerpt. astra_sites_empty_post_excerpt( $post_id ); } } /** * Import Module Images. * * @param object $settings Module settings object. * @return object */ public static function update_module( $settings ) { // 1) Set photos. $settings = self::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 ); } if ( 'uabb-wp-forms-styler' === $settings->type ) { astra_sites_error_log( '--------WP Form Styler ID replacement start-------' ); $ids_mapping = get_option( 'astra_sites_wpforms_ids_mapping', array() ); if ( $ids_mapping ) { // Update WP form IDs. foreach ( $ids_mapping as $old_id => $new_id ) { if ( isset( $settings->wp_form_id ) && $old_id === $settings->wp_form_id ) { astra_sites_error_log( '--------WP Form Styler ID ' . $old_id . ' replaced to ' . $new_id . '-------' ); $settings->wp_form_id = $new_id; } } } astra_sites_error_log( '--------WP Form Styler ID replacement done-------' ); } // 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 ] = self::import_photo( $value ); } } // 4) Set `list item` module images. if ( isset( $settings->text ) ) { $settings->text = self::get_wpforms_mapping( $settings->text ); } elseif ( isset( $settings->html ) ) { $settings->html = self::get_wpforms_mapping( $settings->html ); } return $settings; } /** * Replace WP Forms shortcode. * * @since 2.0.0 * @param string $content Content. * @return string Content. */ private static function get_wpforms_mapping( $content = '' ) { $ids_mapping = get_option( 'astra_sites_wpforms_ids_mapping', array() ); astra_sites_error_log( wp_json_encode( $ids_mapping ) ); if ( $ids_mapping ) { // Update WP form IDs. foreach ( $ids_mapping as $old_id => $new_id ) { $content = str_replace( '[wpforms id="' . $old_id, '[wpforms id="' . $new_id, $content ); } } return $content; } /** * Import Column Images. * * @param object $settings Column settings object. * @return object */ public static function update_column( $settings ) { // 1) Set BG Images. $settings = self::import_bg_image( $settings ); return $settings; } /** * Import Row Images. * * @param object $settings Row settings object. * @return object */ public static function update_row( $settings ) { // 1) Set BG Images. $settings = self::import_bg_image( $settings ); return $settings; } /** * Helper: Import BG Images. * * @param object $settings Row settings object. * @return object */ public static function import_bg_image( $settings ) { if ( ( ! empty( $settings->bg_image ) && ! empty( $settings->bg_image_src ) ) ) { $image = array( 'url' => $settings->bg_image_src, 'id' => $settings->bg_image, ); $downloaded_image = Astra_Sites_Image_Importer::get_instance()->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 static function import_photo( $settings ) { if ( ! empty( $settings->photo ) && ! empty( $settings->photo_src ) ) { $image = array( 'url' => $settings->photo_src, 'id' => $settings->photo, ); $downloaded_image = Astra_Sites_Image_Importer::get_instance()->import( $image ); $settings->photo_src = $downloaded_image['url']; $settings->photo = $downloaded_image['id']; } return $settings; } } /** * Kicking this off by calling 'get_instance()' method */ Astra_Sites_Batch_Processing_Beaver_Builder::get_instance(); endif; batch-processing/class-astra-sites-batch-processing-widgets.php 0000666 00000010557 15166147456 0021002 0 ustar 00 <?php /** * Batch Processing * * @package Astra Sites * @since 1.0.14 */ if ( ! class_exists( 'Astra_Sites_Batch_Processing_Widgets' ) ) : /** * Astra_Sites_Batch_Processing_Widgets * * @since 1.0.14 */ class Astra_Sites_Batch_Processing_Widgets { /** * WP Forms. * * @since 2.6.22 * @var object Class object. */ public $wpforms_ids_mapping; /** * Instance * * @since 1.0.14 * @access private * @var object Class object. */ private static $instance; /** * Initiator * * @since 1.0.14 * @return object initialized object of class. */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Constructor * * @since 1.0.14 */ public function __construct() { } /** * Import * * @since 1.0.14 * @return void */ public function import() { if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Importing Widgets Data' ); } // Catch mapping data. $this->wpforms_ids_mapping = get_option( 'astra_sites_wpforms_ids_mapping', array() ); // Process image widget data. $this->widget_media_image(); // Process text widget data. $this->widget_text(); // Process WP Forms widget data. $this->widget_wpform(); } /** * Widget WP Forms * * @since 3.1.3 * @return void */ public function widget_wpform() { $data = get_option( 'widget_wpforms-widget', null ); if ( empty( $data ) ) { return; } Astra_Sites_Importer_Log::add( '---- Processing Contact Form Mapping from WP Forms Widgets -----' ); foreach ( $data as $key => $value ) { if ( isset( $value['form_id'] ) && ! empty( $value['form_id'] ) ) { $content = $value['form_id']; // Empty mapping? Then return. if ( ! empty( $this->wpforms_ids_mapping ) ) { // Replace ID's. foreach ( $this->wpforms_ids_mapping as $old_id => $new_id ) { if ( $old_id === $content ) { $content = $new_id; } } } $data[ $key ]['form_id'] = $content; if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Updating Contact Form Mapping from WP Forms Widgets' ); } } } update_option( 'widget_wpforms-widget', $data ); } /** * Widget Text * * @since 2.6.22 * @return void */ public function widget_text() { $data = get_option( 'widget_text', null ); if ( empty( $data ) ) { return; } Astra_Sites_Importer_Log::add( '---- Processing Contact Form Mapping from Text Widgets -----' ); foreach ( $data as $key => $value ) { if ( isset( $value['text'] ) && ! empty( $value['text'] ) ) { $content = $value['text']; // Empty mapping? Then return. if ( ! empty( $this->wpforms_ids_mapping ) ) { // Replace ID's. foreach ( $this->wpforms_ids_mapping as $old_id => $new_id ) { $content = str_replace( '[wpforms id="' . $old_id, '[wpforms id="' . $new_id, $content ); $content = str_replace( '{"formId":"' . $old_id . '"}', '{"formId":"' . $new_id . '"}', $content ); } } $data[ $key ]['text'] = $content; if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Updating Contact Form Mapping from Text Widgets' ); } } } update_option( 'widget_text', $data ); } /** * Widget Media Image * * @since 1.0.14 * @return void */ public function widget_media_image() { $data = get_option( 'widget_media_image', null ); if ( empty( $data ) ) { return; } Astra_Sites_Importer_Log::add( '---- Processing Images from Widgets -----' ); foreach ( $data as $key => $value ) { if ( isset( $value['url'] ) && isset( $value['attachment_id'] ) ) { $image = array( 'url' => $value['url'], 'id' => $value['attachment_id'], ); $downloaded_image = Astra_Sites_Image_Importer::get_instance()->import( $image ); $data[ $key ]['url'] = $downloaded_image['url']; $data[ $key ]['attachment_id'] = $downloaded_image['id']; if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Importing Widgets Image: ' . $value['url'] . ' | New Image ' . $downloaded_image['url'] ); } } } update_option( 'widget_media_image', $data ); } } /** * Kicking this off by calling 'get_instance()' method */ Astra_Sites_Batch_Processing_Widgets::get_instance(); endif; batch-processing/class-astra-sites-batch-processing-importer.php 0000666 00000033443 15166147456 0021174 0 ustar 00 <?php /** * Batch Processing * * @package Astra Sites * @since 2.0.0 */ if ( ! class_exists( 'Astra_Sites_Batch_Processing_Importer' ) ) : /** * Astra_Sites_Batch_Processing_Importer * * @since 1.0.14 */ class Astra_Sites_Batch_Processing_Importer { /** * Instance * * @since 1.0.14 * @access private * @var object Class object. */ private static $instance; /** * Initiator * * @since 1.0.14 * @return object initialized object of class. */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Constructor * * @since 1.0.14 */ public function __construct() { } /** * Import All Categories and Tags * * @since 2.6.22 * @return void */ public function import_all_categories_and_tags() { astra_sites_error_log( 'Requesting Site Categories' ); update_site_option( 'astra-sites-batch-status-string', 'Requesting Site Categories', 'no' ); $api_args = array( 'timeout' => 30, ); $request = wp_remote_get( trailingslashit( Astra_Sites::get_instance()->get_api_domain() ) . 'wp-content/uploads/all-site-categories.json', $api_args ); if ( ! is_wp_error( $request ) && 200 === (int) wp_remote_retrieve_response_code( $request ) ) { $cats = json_decode( wp_remote_retrieve_body( $request ), true ); if ( isset( $cats['code'] ) ) { $message = isset( $cats['message'] ) ? $cats['message'] : ''; if ( ! empty( $message ) ) { astra_sites_error_log( 'HTTP Request Error: ' . $message ); } else { astra_sites_error_log( 'HTTP Request Error!' ); } } else { update_site_option( 'astra-sites-all-site-categories-and-tags', $cats, 'no' ); do_action( 'astra_sites_sync_all_site_categories_and_tags', $cats ); } } astra_sites_error_log( 'Site Categories Imported Successfully!' ); update_site_option( 'astra-sites-batch-status-string', 'Site Categories Imported Successfully!', 'no' ); } /** * Import All Categories and Tags * * @since 2.6.22 * @return void */ public function import_all_categories() { astra_sites_error_log( 'Requesting Site Categories' ); update_site_option( 'astra-sites-batch-status-string', 'Requesting Site Categories', 'no' ); $api_args = array( 'timeout' => 30, ); $request = wp_remote_get( trailingslashit( Astra_Sites::get_instance()->get_api_domain() ) . 'wp-json/wp/v2/astra-sites-site-category/?hide_empty=true&_fields=id,name,slug&per_page=100', $api_args ); if ( ! is_wp_error( $request ) && 200 === (int) wp_remote_retrieve_response_code( $request ) ) { $cats = json_decode( wp_remote_retrieve_body( $request ), true ); if ( isset( $cats['code'] ) ) { $message = isset( $cats['message'] ) ? $cats['message'] : ''; if ( ! empty( $message ) ) { astra_sites_error_log( 'HTTP Request Error: ' . $message ); } else { astra_sites_error_log( 'HTTP Request Error!' ); } } else { update_site_option( 'astra-sites-all-site-categories', $cats, 'no' ); do_action( 'astra_sites_sync_all_site_categories', $cats ); } } astra_sites_error_log( 'Site Categories Imported Successfully!' ); update_site_option( 'astra-sites-batch-status-string', 'Site Categories Imported Successfully!', 'no' ); } /** * Import Categories * * @since 2.0.0 * @return void */ public function import_site_categories() { astra_sites_error_log( 'Requesting Site Categories' ); update_site_option( 'astra-sites-batch-status-string', 'Requesting Site Categories', 'no' ); $api_args = array( 'timeout' => 30, ); $categories_request = wp_remote_get( trailingslashit( Astra_Sites::get_instance()->get_api_domain() ) . 'wp-json/wp/v2/astra-sites-site-category/?hide_empty=true&_fields=id,name,slug&per_page=100', $api_args ); if ( ! is_wp_error( $categories_request ) && 200 === (int) wp_remote_retrieve_response_code( $categories_request ) ) { $categories = json_decode( wp_remote_retrieve_body( $categories_request ), true ); if ( isset( $categories['code'] ) ) { $message = isset( $categories['message'] ) ? $categories['message'] : ''; if ( ! empty( $message ) ) { astra_sites_error_log( 'HTTP Request Error: ' . $message ); } else { astra_sites_error_log( 'HTTP Request Error!' ); } } else { update_site_option( 'astra-sites-categories', $categories, 'no' ); do_action( 'astra_sites_sync_categories', $categories ); } } astra_sites_error_log( 'Site Categories Imported Successfully!' ); update_site_option( 'astra-sites-batch-status-string', 'Site Categories Imported Successfully!', 'no' ); } /** * Import Block Categories * * @since 2.0.0 * @return void */ public function import_block_categories() { astra_sites_error_log( 'Requesting Block Categories' ); update_site_option( 'astra-sites-batch-status-string', 'Requesting Block Categories', 'no' ); $api_args = array( 'timeout' => 30, ); $tags_request = wp_remote_get( trailingslashit( Astra_Sites::get_instance()->get_api_domain() ) . 'wp-json/wp/v2/blocks-category/?_fields=id,name,slug&per_page=100&hide_empty=1', $api_args ); if ( ! is_wp_error( $tags_request ) && 200 === (int) wp_remote_retrieve_response_code( $tags_request ) ) { $tags = json_decode( wp_remote_retrieve_body( $tags_request ), true ); if ( isset( $tags['code'] ) ) { $message = isset( $tags['message'] ) ? $tags['message'] : ''; if ( ! empty( $message ) ) { astra_sites_error_log( 'HTTP Request Error: ' . $message ); } else { astra_sites_error_log( 'HTTP Request Error!' ); } } else { $categories = array(); foreach ( $tags as $key => $value ) { $categories[ $value['id'] ] = $value; } update_site_option( 'astra-blocks-categories', $categories, 'no' ); do_action( 'astra_sites_sync_blocks_categories', $categories ); } } astra_sites_error_log( 'Block Categories Imported Successfully!' ); update_site_option( 'astra-sites-batch-status-string', 'Categories Imported Successfully!', 'no' ); } /** * Import Page Builders * * @since 2.0.0 * @return void */ public function set_license_page_builder() { astra_sites_error_log( 'Requesting License Page Builders' ); $url = add_query_arg( array( '_fields' => 'id,name,slug', 'site_url' => get_site_url(), 'purchase_key' => Astra_Sites::get_instance()->get_license_key(), 'only_allow_page_builders' => 'true', ), trailingslashit( Astra_Sites::get_instance()->get_api_domain() ) . 'wp-json/wp/v2/astra-site-page-builder/' ); $api_args = array( 'timeout' => 30, ); $page_builder_request = wp_remote_get( $url, $api_args ); if ( ! is_wp_error( $page_builder_request ) && 200 === (int) wp_remote_retrieve_response_code( $page_builder_request ) ) { $page_builders = json_decode( wp_remote_retrieve_body( $page_builder_request ), true ); if ( isset( $page_builders['code'] ) ) { $message = isset( $page_builders['message'] ) ? $page_builders['message'] : ''; if ( ! empty( $message ) ) { astra_sites_error_log( 'HTTP Request Error: ' . $message ); } else { astra_sites_error_log( 'HTTP Request Error!' ); } } else { // Set mini agency page builder. $page_builder_slugs = wp_list_pluck( $page_builders, 'slug' ); if ( in_array( 'elementor', $page_builder_slugs ) && ! in_array( 'beaver-builder', $page_builder_slugs ) ) { update_option( 'astra-sites-license-page-builder', 'elementor', 'no' ); astra_sites_error_log( 'Set "Elementor" as License Page Builder' ); } elseif ( in_array( 'beaver-builder', $page_builder_slugs ) && ! in_array( 'elementor', $page_builder_slugs ) ) { update_option( 'astra-sites-license-page-builder', 'beaver-builder', 'no' ); astra_sites_error_log( 'Set "Beaver Builder" as License Page Builder' ); } else { update_option( 'astra-sites-license-page-builder', '', 'no' ); astra_sites_error_log( 'Not Set Any License Page Builder' ); } } } } /** * Import Page Builders * * @since 2.0.0 * @return void */ public function import_page_builders() { astra_sites_error_log( 'Requesting Page Builders' ); update_site_option( 'astra-sites-batch-status-string', 'Requesting Page Builders', 'no' ); $purchase_key = Astra_Sites::get_instance()->get_license_key(); $site_url = get_site_url(); $api_args = array( 'timeout' => 30, ); $page_builder_request = wp_remote_get( trailingslashit( Astra_Sites::get_instance()->get_api_domain() ) . 'wp-json/wp/v2/astra-site-page-builder/?_fields=id,name,slug&site_url=' . $site_url . '&purchase_key=' . $purchase_key, $api_args ); if ( ! is_wp_error( $page_builder_request ) && 200 === (int) wp_remote_retrieve_response_code( $page_builder_request ) ) { $page_builders = json_decode( wp_remote_retrieve_body( $page_builder_request ), true ); if ( isset( $page_builders['code'] ) ) { $message = isset( $page_builders['message'] ) ? $page_builders['message'] : ''; if ( ! empty( $message ) ) { astra_sites_error_log( 'HTTP Request Error: ' . $message ); } else { astra_sites_error_log( 'HTTP Request Error!' ); } } else { update_site_option( 'astra-sites-page-builders', $page_builders, 'no' ); do_action( 'astra_sites_sync_page_builders', $page_builders ); } } astra_sites_error_log( 'Page Builders Imported Successfully!' ); update_site_option( 'astra-sites-batch-status-string', 'Page Builders Imported Successfully!', 'no' ); } /** * Import Blocks * * @since 2.0.0 * @param integer $page Page number. * @return void */ public function import_blocks( $page = 1 ) { astra_sites_error_log( 'BLOCK: -------- ACTUAL IMPORT --------' ); $api_args = array( 'timeout' => 30, ); $all_blocks = array(); astra_sites_error_log( 'BLOCK: Requesting ' . $page ); update_site_option( 'astra-blocks-batch-status-string', 'Requesting for blocks page - ' . $page, 'no' ); $query_args = apply_filters( 'astra_sites_blocks_query_args', array( 'page_builder' => 'elementor', 'per_page' => 100, 'page' => $page, 'wireframe' => 'yes', ) ); $api_url = add_query_arg( $query_args, trailingslashit( Astra_Sites::get_instance()->get_api_domain() ) . 'wp-json/astra-blocks/v1/blocks/' ); $response = wp_remote_get( $api_url, $api_args ); if ( ! is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) === 200 ) { $astra_blocks = json_decode( wp_remote_retrieve_body( $response ), true ); if ( isset( $astra_blocks['code'] ) ) { $message = isset( $astra_blocks['message'] ) ? $astra_blocks['message'] : ''; if ( ! empty( $message ) ) { astra_sites_error_log( 'HTTP Request Error: ' . $message ); } else { astra_sites_error_log( 'HTTP Request Error!' ); } } else { astra_sites_error_log( 'BLOCK: Storing data for page ' . $page . ' in option astra-blocks-' . $page ); update_site_option( 'astra-blocks-batch-status-string', 'Storing data for page ' . $page . ' in option astra-blocks-' . $page, 'no' ); update_site_option( 'astra-blocks-' . $page, $astra_blocks, 'no' ); do_action( 'astra_sites_sync_blocks', $page, $astra_blocks ); } } else { astra_sites_error_log( 'BLOCK: API Error: ' . $response->get_error_message() ); } astra_sites_error_log( 'BLOCK: Complete storing data for blocks ' . $page ); update_site_option( 'astra-blocks-batch-status-string', 'Complete storing data for page ' . $page, 'no' ); } /** * Import * * @since 1.0.14 * @since 2.0.0 Added page no. * * @param integer $page Page number. * @return array */ public function import_sites( $page = 1 ) { $api_args = array( 'timeout' => 30, ); $sites_and_pages = array(); astra_sites_error_log( 'Requesting ' . $page ); update_site_option( 'astra-sites-batch-status-string', 'Requesting ' . $page, 'no' ); $query_args = apply_filters( 'astra_sites_import_sites_query_args', array( 'per_page' => 15, 'page' => $page, ) ); $api_url = add_query_arg( $query_args, trailingslashit( Astra_Sites::get_instance()->get_api_domain() ) . 'wp-json/astra-sites/v1/sites-and-pages/' ); $response = wp_remote_get( $api_url, $api_args ); if ( ! is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) === 200 ) { $sites_and_pages = json_decode( wp_remote_retrieve_body( $response ), true ); if ( isset( $sites_and_pages['code'] ) ) { $message = isset( $sites_and_pages['message'] ) ? $sites_and_pages['message'] : ''; if ( ! empty( $message ) ) { astra_sites_error_log( 'HTTP Request Error: ' . $message ); } else { astra_sites_error_log( 'HTTP Request Error!' ); } } else { astra_sites_error_log( 'Storing data for page ' . $page . ' in option astra-sites-and-pages-page-' . $page ); update_site_option( 'astra-sites-batch-status-string', 'Storing data for page ' . $page . ' in option astra-sites-and-pages-page-' . $page, 'no' ); update_site_option( 'astra-sites-and-pages-page-' . $page, $sites_and_pages, 'no' ); do_action( 'astra_sites_sync_sites_and_pages', $page, $sites_and_pages ); } } else { astra_sites_error_log( 'API Error: ' . $response->get_error_message() ); } astra_sites_error_log( 'Complete storing data for page ' . $page ); update_site_option( 'astra-sites-batch-status-string', 'Complete storing data for page ' . $page, 'no' ); return $sites_and_pages; } } /** * Kicking this off by calling 'get_instance()' method */ Astra_Sites_Batch_Processing_Importer::get_instance(); endif; batch-processing/class-astra-sites-batch-processing-brizy.php 0000666 00000006544 15166147456 0020474 0 ustar 00 <?php /** * Batch Processing * * @package Astra Sites * @since 1.2.14 */ if ( ! class_exists( 'Astra_Sites_Batch_Processing_Brizy' ) ) : /** * Astra Sites Batch Processing Brizy * * @since 1.2.14 */ class Astra_Sites_Batch_Processing_Brizy { /** * Instance * * @since 1.2.14 * @access private * @var object Class object. */ private static $instance; /** * Initiator * * @since 1.2.14 * @return object initialized object of class. */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Constructor * * @since 1.2.14 */ public function __construct() {} /** * Import * * @since 1.2.14 * @return void */ public function import() { if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Processing "Brizy" Batch Import' ); } Astra_Sites_Importer_Log::add( '---- Processing WordPress Posts / Pages - for "Brizy" ----' ); if ( ! is_callable( 'Brizy_Editor_Storage_Common::instance' ) ) { return; } $post_types = Brizy_Editor_Storage_Common::instance()->get( 'post-types' ); if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'For post types: ' . implode( ', ', $post_types ) ); } if ( empty( $post_types ) && ! is_array( $post_types ) ) { return; } $post_ids = Astra_Sites_Batch_Processing::get_pages( $post_types ); if ( empty( $post_ids ) && ! is_array( $post_ids ) ) { return; } 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 ) { $is_brizy_post = get_post_meta( $post_id, 'brizy_post_uid', true ); if ( ! $is_brizy_post ) { return; } // Is page imported with Starter Sites? // If not then skip batch process. $imported_from_demo_site = get_post_meta( $post_id, '_astra_sites_enable_for_batch', true ); if ( ! $imported_from_demo_site ) { return; } if ( defined( 'WP_CLI' ) ) { WP_CLI::line( 'Brizy - Processing page: ' . $post_id ); } astra_sites_error_log( '---- Processing WordPress Page - for "Brizy" ---- "' . $post_id . '"' ); $ids_mapping = get_option( 'astra_sites_wpforms_ids_mapping', array() ); $json_value = null; $post = Brizy_Editor_Post::get( (int) $post_id ); $editor_data = $post->get_editor_data(); // Empty mapping? Then return. if ( ! empty( $ids_mapping ) ) { // Update WPForm IDs. astra_sites_error_log( '---- Processing WP Forms Mapping ----' ); astra_sites_error_log( $ids_mapping ); foreach ( $ids_mapping as $old_id => $new_id ) { $editor_data = str_replace( '[wpforms id=\"' . $old_id, '[wpforms id=\"' . $new_id, $editor_data ); } } $post->set_editor_data( $editor_data ); $post->set_needs_compile( $post->get_needs_compile() ); $post->set_editor_version( BRIZY_EDITOR_VERSION ); $post->set_compiler_version( BRIZY_EDITOR_VERSION ); $post->set_plugin_version( BRIZY_VERSION ); $post->saveStorage(); $post->savePost(); // Clean the post excerpt. astra_sites_empty_post_excerpt( $post_id ); } } /** * Kicking this off by calling 'get_instance()' method */ Astra_Sites_Batch_Processing_Brizy::get_instance(); endif; batch-processing/helpers/class-wp-background-process.php 0000666 00000027147 15166147456 0017532 0 ustar 00 <?php /** * WP Background Process * https://github.com/A5hleyRich/wp-background-processing * * Released under the GNU General Public License v2.0 * https://github.com/deliciousbrains/wp-background-processing/blob/master/license.txt * * @see https://github.com/A5hleyRich/wp-background-processing/ * @package WP-Background-Processing */ if ( ! class_exists( 'WP_Background_Process' ) ) { /** * Abstract WP_Background_Process class. * * @abstract * @extends WP_Async_Request */ abstract class WP_Background_Process extends WP_Async_Request { /** * Action * * (default value: 'background_process') * * @var string * @access protected */ protected $action = 'background_process'; /** * Start time of current process. * * (default value: 0) * * @var int * @access protected */ protected $start_time = 0; /** * Cron_hook_identifier * * @var mixed * @access protected */ protected $cron_hook_identifier; /** * Cron_interval_identifier * * @var mixed * @access protected */ protected $cron_interval_identifier; /** * Initiate new background process */ public function __construct() { parent::__construct(); $this->cron_hook_identifier = $this->identifier . '_cron'; $this->cron_interval_identifier = $this->identifier . '_cron_interval'; add_action( $this->cron_hook_identifier, array( $this, 'handle_cron_healthcheck' ) ); add_filter( 'cron_schedules', array( $this, 'schedule_cron_healthcheck' ) ); // phpcs:ignore WordPress.WP.CronInterval.ChangeDetected -- Adding Every 5 mintures to existing schedules. } /** * Dispatch * * @return mixed dispatch event. */ public function dispatch() { // Schedule the cron healthcheck. $this->schedule_event(); // Perform remote post. return parent::dispatch(); } /** * Push to queue * * @param mixed $data Data. * * @return $this */ public function push_to_queue( $data ) { $this->data[] = $data; return $this; } /** * Save queue * * @return $this */ public function save() { $key = $this->generate_key(); if ( ! empty( $this->data ) ) { update_site_option( $key, $this->data, 'no' ); } return $this; } /** * Update queue * * @param string $key Key. * @param array $data Data. * * @return $this */ public function update( $key, $data ) { if ( ! empty( $data ) ) { update_site_option( $key, $data, 'no' ); } return $this; } /** * Delete queue * * @param string $key Key. * * @return $this */ public function delete( $key ) { delete_site_option( $key ); return $this; } /** * Generate key * * Generates a unique key based on microtime. Queue items are * given a unique key so that they can be merged upon save. * * @param int $length Length. * * @return string */ protected function generate_key( $length = 64 ) { $unique = md5( microtime() . wp_rand() ); $prepend = $this->identifier . '_batch_'; return substr( $prepend . $unique, 0, $length ); } /** * Maybe process queue * * Checks whether data exists within the queue and that * the process is not already running. */ public function maybe_handle() { // Don't lock up other requests while processing. session_write_close(); //phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.session_session_write_close -- 3rd party library. if ( $this->is_process_running() ) { // Background process already running. wp_die(); } if ( $this->is_queue_empty() ) { // No data to process. wp_die(); } check_ajax_referer( $this->identifier, 'nonce' ); $this->handle(); wp_die(); } /** * Is queue empty * * @return bool */ protected function is_queue_empty() { global $wpdb; $table = $wpdb->options; $column = 'option_name'; if ( is_multisite() ) { $table = $wpdb->sitemeta; $column = 'meta_key'; } $key = $this->identifier . '_batch_%'; $count = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- WP Query would have been expensive. Finding if the batch process Queue is empty or not. $wpdb->prepare( // phpcs:disable " SELECT COUNT(*) FROM {$table} WHERE {$column} LIKE %s ", $key // phpcs:enable ) ); return ( $count > 0 ) ? false : true; } /** * Is process running * * Check whether the current process is already running * in a background process. */ protected function is_process_running() { if ( get_site_transient( $this->identifier . '_process_lock' ) ) { // Process already running. return true; } return false; } /** * Lock process * * Lock the process so that multiple instances can't run simultaneously. * Override if applicable, but the duration should be greater than that * defined in the time_exceeded() method. */ protected function lock_process() { $this->start_time = time(); // Set start time of current process. $lock_duration = ( property_exists( $this, 'queue_lock_time' ) ) ? $this->queue_lock_time : 60; // 1 minute $lock_duration = apply_filters( $this->identifier . '_queue_lock_time', $lock_duration ); set_site_transient( $this->identifier . '_process_lock', microtime(), $lock_duration ); } /** * Unlock process * * Unlock the process so that other instances can spawn. * * @return $this */ protected function unlock_process() { delete_site_transient( $this->identifier . '_process_lock' ); return $this; } /** * Get batch * * @return stdClass Return the first batch from the queue */ protected function get_batch() { global $wpdb; $table = $wpdb->options; $column = 'option_name'; $key_column = 'option_id'; $value_column = 'option_value'; if ( is_multisite() ) { $table = $wpdb->sitemeta; $column = 'meta_key'; $key_column = 'meta_id'; $value_column = 'meta_value'; } $key = $this->identifier . '_batch_%'; $query = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- WP Query would have been expensive. Reading all the batch processes. $wpdb->prepare( // phpcs:disable " SELECT * FROM {$table} WHERE {$column} LIKE %s ORDER BY {$key_column} ASC LIMIT 1 ", $key // phpcs:enable ) ); $batch = new stdClass(); $batch->key = $query->$column; $batch->data = maybe_unserialize( $query->$value_column ); return $batch; } /** * Handle * * Pass each queue item to the task handler, while remaining * within server memory and time limit constraints. */ protected function handle() { $this->lock_process(); do { $batch = $this->get_batch(); foreach ( $batch->data as $key => $value ) { $task = $this->task( $value ); if ( false !== $task ) { $batch->data[ $key ] = $task; } else { unset( $batch->data[ $key ] ); } if ( $this->time_exceeded() || $this->memory_exceeded() ) { // Batch limits reached. break; } } // Update or delete current batch. if ( ! empty( $batch->data ) ) { $this->update( $batch->key, $batch->data ); } else { $this->delete( $batch->key ); } } while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() ); $this->unlock_process(); // Start next batch or complete process. if ( ! $this->is_queue_empty() ) { $this->dispatch(); } else { $this->complete(); } wp_die(); } /** * Memory exceeded * * Ensures the batch process never exceeds 90% * of the maximum WordPress memory. * * @return bool */ protected function memory_exceeded() { $memory_limit = $this->get_memory_limit() * 0.9; // 90% of max memory $current_memory = memory_get_usage( true ); $return = false; if ( $current_memory >= $memory_limit ) { $return = true; } return apply_filters( $this->identifier . '_memory_exceeded', $return ); } /** * Get memory limit * * @return int */ protected function get_memory_limit() { if ( function_exists( 'ini_get' ) ) { $memory_limit = ini_get( 'memory_limit' ); } else { // Sensible default. $memory_limit = '128M'; } if ( ! $memory_limit || -1 === $memory_limit ) { // Unlimited, set to 32GB. $memory_limit = '32000M'; } return intval( $memory_limit ) * 1024 * 1024; } /** * Time exceeded. * * Ensures the batch never exceeds a sensible time limit. * A timeout limit of 30s is common on shared hosting. * * @return bool */ protected function time_exceeded() { $finish = $this->start_time + apply_filters( $this->identifier . '_default_time_limit', 20 ); // 20 seconds $return = false; if ( time() >= $finish ) { $return = true; } return apply_filters( $this->identifier . '_time_exceeded', $return ); } /** * Complete. * * Override if applicable, but ensure that the below actions are * performed, or, call parent::complete(). */ protected function complete() { // Unschedule the cron healthcheck. $this->clear_scheduled_event(); } /** * Schedule cron healthcheck * * @access public * @param mixed $schedules Schedules. * @return mixed */ public function schedule_cron_healthcheck( $schedules ) { $interval = apply_filters( $this->identifier . '_cron_interval', 5 ); if ( property_exists( $this, 'cron_interval' ) ) { $interval = apply_filters( $this->identifier . '_cron_interval', $this->cron_interval_identifier ); } // Adds every 5 minutes to the existing schedules. $schedules[ $this->identifier . '_cron_interval' ] = array( 'interval' => MINUTE_IN_SECONDS * $interval, /* translators: %d are the minutes. */ 'display' => sprintf( __( 'Every %d Minutes', 'astra-sites' ), $interval ), ); return $schedules; } /** * Handle cron healthcheck * * Restart the background process if not already running * and data exists in the queue. */ public function handle_cron_healthcheck() { if ( $this->is_process_running() ) { // Background process already running. exit; } if ( $this->is_queue_empty() ) { // No data to process. $this->clear_scheduled_event(); exit; } $this->handle(); exit; } /** * Schedule event */ protected function schedule_event() { if ( ! wp_next_scheduled( $this->cron_hook_identifier ) ) { wp_schedule_event( time(), $this->cron_interval_identifier, $this->cron_hook_identifier ); } } /** * Clear scheduled event */ protected function clear_scheduled_event() { $timestamp = wp_next_scheduled( $this->cron_hook_identifier ); if ( $timestamp ) { wp_unschedule_event( $timestamp, $this->cron_hook_identifier ); } } /** * Cancel Process * * Stop processing queue items, clear cronjob and delete batch. */ public function cancel_process() { if ( ! $this->is_queue_empty() ) { $batch = $this->get_batch(); $this->delete( $batch->key ); wp_clear_scheduled_hook( $this->cron_hook_identifier ); } } /** * Task * * Override this method to perform any actions required on each * queue item. Return the modified item for further processing * in the next pass through. Or, return false to remove the * item from the queue. * * @param mixed $item Queue item to iterate over. * * @return mixed */ abstract protected function task( $item ); } } batch-processing/helpers/class-wp-background-process-astra-single.php 0000666 00000002441 15166147456 0022107 0 ustar 00 <?php /** * Single Page Background Process * * @package Astra Sites * @since 2.0.0 */ if ( class_exists( 'WP_Background_Process' ) ) : /** * Image Background Process * * @since 2.0.0 */ class WP_Background_Process_Astra_Single extends WP_Background_Process { /** * Image Process * * @var string */ protected $action = 'astra_sites_single_page'; /** * Task * * Override this method to perform any actions required on each * queue item. Return the modified item for further processing * in the next pass through. Or, return false to remove the * item from the queue. * * @since 2.0.0 * * @param object $object Queue item object. * @return mixed */ protected function task( $object ) { $page_id = $object['page_id']; $process = $object['instance']; if ( method_exists( $process, 'import_single_post' ) ) { $process->import_single_post( $page_id ); } return false; } /** * Complete * * Override if applicable, but ensure that the below actions are * performed, or, call parent::complete(). * * @since 2.0.0 */ protected function complete() { astra_sites_error_log( 'Complete' ); parent::complete(); do_action( 'astra_sites_single_page_batch_process_complete' ); } } endif; batch-processing/helpers/class-wp-background-process-astra-site-importer.php 0000666 00000006202 15166147456 0023430 0 ustar 00 <?php /** * Single Page Background Process * * @package Astra Sites * @since 2.0.0 */ if ( class_exists( 'WP_Background_Process' ) ) : /** * Image Background Process * * @since 2.0.0 */ class WP_Background_Process_Astra_Site_Importer extends WP_Background_Process { /** * Image Process * * @var string */ protected $action = 'astra_site_importer'; /** * Task * * Override this method to perform any actions required on each * queue item. Return the modified item for further processing * in the next pass through. Or, return false to remove the * item from the queue. * * @since 2.0.0 * * @param object $object Queue item object. * @return mixed */ protected function task( $object ) { $process = $object['instance']; $method = $object['method']; if ( 'import_page_builders' === $method ) { astra_sites_error_log( '-------- Importing Page Builders --------' ); update_site_option( 'astra-sites-batch-status-string', 'Importing Page Builders', 'no' ); $process->import_page_builders(); } elseif ( 'import_all_categories_and_tags' === $method ) { astra_sites_error_log( '-------- Importing All Categories and Tags --------' ); update_site_option( 'astra-sites-batch-status-string', 'Importing All Categories and Tags', 'no' ); $process->import_all_categories_and_tags(); } elseif ( 'import_all_categories' === $method ) { astra_sites_error_log( '-------- Importing All Categories --------' ); update_site_option( 'astra-sites-batch-status-string', 'Importing All Categories', 'no' ); $process->import_all_categories(); } elseif ( 'import_sites' === $method ) { astra_sites_error_log( '-------- Importing Sites --------' ); $page = $object['page']; astra_sites_error_log( 'Inside Batch ' . $page ); update_site_option( 'astra-sites-batch-status-string', 'Inside Batch ' . $page, 'no' ); $process->import_sites( $page ); } elseif ( 'import_blocks' === $method ) { astra_sites_error_log( '-------- Importing Blocks --------' ); $page = $object['page']; astra_sites_error_log( 'Inside Batch ' . $page ); update_site_option( 'astra-sites-batch-status-string', 'Inside Batch ' . $page, 'no' ); $process->import_blocks( $page ); } elseif ( 'import_block_categories' === $method ) { astra_sites_error_log( '-------- Importing Blocks Categories --------' ); update_site_option( 'astra-sites-batch-status-string', 'Importing Blocks Categories', 'no' ); $process->import_block_categories(); } return false; } /** * Complete * * Override if applicable, but ensure that the below actions are * performed, or, call parent::complete(). * * @since 2.0.0 */ protected function complete() { parent::complete(); astra_sites_error_log( esc_html__( 'All processes are complete', 'astra-sites' ) ); update_site_option( 'astra-sites-batch-status-string', 'All processes are complete', 'no' ); delete_site_option( 'astra-sites-batch-status' ); update_site_option( 'astra-sites-batch-is-complete', 'yes', 'no' ); do_action( 'astra_sites_site_import_batch_complete' ); } } endif; batch-processing/helpers/class-wp-async-request.php 0000666 00000006477 15166147456 0016545 0 ustar 00 <?php /** * WP Background Process * https://github.com/A5hleyRich/wp-background-processing * * Released under the GNU General Public License v2.0 * https://github.com/deliciousbrains/wp-background-processing/blob/master/license.txt * * @see https://github.com/A5hleyRich/wp-background-processing/ * @package WP-Background-Processing */ if ( ! class_exists( 'WP_Async_Request' ) ) { /** * Abstract WP_Async_Request class. * * @abstract */ abstract class WP_Async_Request { /** * Prefix * * (default value: 'wp') * * @var string * @access protected */ protected $prefix = 'wp'; /** * Action * * (default value: 'async_request') * * @var string * @access protected */ protected $action = 'async_request'; /** * Identifier * * @var mixed * @access protected */ protected $identifier; /** * Data * * (default value: array()) * * @var array * @access protected */ protected $data = array(); /** * Initiate new async request */ public function __construct() { $this->identifier = $this->prefix . '_' . $this->action; add_action( 'wp_ajax_' . $this->identifier, array( $this, 'maybe_handle' ) ); add_action( 'wp_ajax_nopriv_' . $this->identifier, array( $this, 'maybe_handle' ) ); } /** * Set data used during the request * * @param array $data Data. * * @return $this */ public function data( $data ) { $this->data = $data; return $this; } /** * Dispatch the async request * * @return array|WP_Error */ public function dispatch() { $url = add_query_arg( $this->get_query_args(), $this->get_query_url() ); $args = $this->get_post_args(); return wp_remote_post( esc_url_raw( $url ), $args ); } /** * Get query args * * @return array */ protected function get_query_args() { if ( property_exists( $this, 'query_args' ) ) { return $this->query_args; } return array( 'action' => $this->identifier, 'nonce' => wp_create_nonce( $this->identifier ), ); } /** * Get query URL * * @return string */ protected function get_query_url() { if ( property_exists( $this, 'query_url' ) ) { return $this->query_url; } return admin_url( 'admin-ajax.php' ); } /** * Get post args * * @return array */ protected function get_post_args() { if ( property_exists( $this, 'post_args' ) ) { return $this->post_args; } return array( 'timeout' => 0.01, 'blocking' => false, 'body' => $this->data, 'cookies' => $_COOKIE, //phpcs:ignore WordPressVIPMinimum.Variables.RestrictedVariables.cache_constraints___COOKIE -- 3rd party library. 'sslverify' => apply_filters( 'https_local_ssl_verify', false ), ); } /** * Maybe handle * * Check for correct nonce and pass to handler. */ public function maybe_handle() { // Don't lock up other requests while processing. session_write_close(); //phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.session_session_write_close -- 3rd party library. check_ajax_referer( $this->identifier, 'nonce' ); $this->handle(); wp_die(); } /** * Handle * * Override this method to perform any actions required * during the async request. */ abstract protected function handle(); } } batch-processing/helpers/class-wp-background-process-astra.php 0000666 00000002403 15166147456 0020626 0 ustar 00 <?php /** * Image Background Process * * @package Astra Sites * @since 1.0.11 */ if ( class_exists( 'WP_Background_Process' ) ) : /** * Image Background Process * * @since 1.0.11 */ class WP_Background_Process_Astra extends WP_Background_Process { /** * Image Process * * @var string */ protected $action = 'image_process'; /** * Task * * Override this method to perform any actions required on each * queue item. Return the modified item for further processing * in the next pass through. Or, return false to remove the * item from the queue. * * @since 1.0.11 * * @param object $process Queue item object. * @return mixed */ protected function task( $process ) { if ( method_exists( $process, 'import' ) ) { $process->import(); } return false; } /** * Complete * * Override if applicable, but ensure that the below actions are * performed, or, call parent::complete(). * * @since 1.0.11 */ protected function complete() { parent::complete(); Astra_Sites_Importer_Log::add( 'Batch Process Complete!' ); do_action( 'astra_sites_batch_process_complete' ); // Delete Log file. delete_option( 'astra_sites_recent_import_log_file' ); } } endif; batch-processing/helpers/class-astra-sites-image-importer.php 0000666 00000015352 15166147456 0020464 0 ustar 00 <?php /** * Image Importer * * @see https://github.com/elementor/elementor/blob/master/includes/template-library/classes/class-import-images.php * * => How to use? * * $image = array( * 'url' => '<image-url>', * 'id' => '<image-id>', * ); * * $downloaded_image = Astra_Sites_Image_Importer::get_instance()->import( $image ); * * @package Astra Sites * @since 1.0.14 */ if ( ! class_exists( 'Astra_Sites_Image_Importer' ) ) : /** * Astra Sites Image Importer * * @since 1.0.14 */ class Astra_Sites_Image_Importer { /** * Instance * * @since 1.0.14 * @var object Class object. * @access private */ private static $instance; /** * Images IDs * * @var array The Array of already image IDs. * @since 1.0.14 */ private $already_imported_ids = array(); /** * Initiator * * @since 1.0.14 * @return object initialized object of class. */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Constructor * * @since 1.0.14 */ public function __construct() { if ( ! function_exists( 'WP_Filesystem' ) ) { require_once ABSPATH . 'wp-admin/includes/file.php'; } WP_Filesystem(); } /** * Process Image Download * * @since 1.0.14 * @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.0.14 * @param string $attachment_url Attachment URL. * @return string Hash string. */ public function get_hash_image( $attachment_url ) { return sha1( $attachment_url ); } /** * Get Saved Image. * * @since 1.0.14 * @param string $attachment Attachment Data. * @return string Hash string. */ private function get_saved_image( $attachment ) { if ( apply_filters( 'astra_sites_image_importer_skip_image', false, $attachment ) ) { Astra_Sites_Importer_Log::add( 'BATCH - SKIP Image - {from filter} - ' . $attachment['url'] . ' - Filter name `astra_sites_image_importer_skip_image`.' ); return array( 'status' => true, 'attachment' => $attachment, ); } global $wpdb; // 1. Is already imported in Batch Import Process? $post_id = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- We are checking if this image is already processed. WO_Query would have been overkill. $wpdb->prepare( 'SELECT `post_id` FROM `' . $wpdb->postmeta . '` WHERE `meta_key` = \'_astra_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 = basename( $attachment['url'] ); // Find the attachment by meta value. // Code reused from Elementor plugin. $post_id = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- We are checking if this attachment is already processed. WO_Query would have been overkill. $wpdb->prepare( "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_wp_attached_file' AND meta_value LIKE %s", '%/' . $filename . '%' ) ); Astra_Sites_Importer_Log::add( 'BATCH - SKIP Image {already imported from xml} - ' . $attachment['url'] ); } if ( $post_id ) { $new_attachment = array( 'id' => $post_id, 'url' => wp_get_attachment_url( $post_id ), ); $this->already_imported_ids[] = $post_id; return array( 'status' => true, 'attachment' => $new_attachment, ); } return array( 'status' => false, 'attachment' => $attachment, ); } /** * Import Image * * @since 1.0.14 * @param array $attachment Attachment array. * @return array Attachment array. */ public function import( $attachment ) { if ( isset( $attachment['url'] ) && ! astra_sites_is_valid_url( $attachment['url'] ) ) { return $attachment; } Astra_Sites_Importer_Log::add( 'Source - ' . $attachment['url'] ); $saved_image = $this->get_saved_image( $attachment ); Astra_Sites_Importer_Log::add( 'Log - ' . wp_json_encode( $saved_image['attachment'] ) ); if ( $saved_image['status'] ) { return $saved_image['attachment']; } $file_content = wp_remote_retrieve_body( wp_safe_remote_get( $attachment['url'], array( 'timeout' => '60', 'sslverify' => false, ) ) ); // Empty file content? if ( empty( $file_content ) ) { Astra_Sites_Importer_Log::add( 'BATCH - FAIL Image {Error: Failed wp_remote_retrieve_body} - ' . $attachment['url'] ); return $attachment; } // Extract the file name and extension from the URL. $filename = basename( $attachment['url'] ); $upload = wp_upload_bits( $filename, null, $file_content ); astra_sites_error_log( $filename ); astra_sites_error_log( wp_json_encode( $upload ) ); $post = array( 'post_title' => $filename, 'guid' => $upload['url'], ); astra_sites_error_log( wp_json_encode( $post ) ); $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, '_astra_sites_image_hash', $this->get_hash_image( $attachment['url'] ) ); Astra_WXR_Importer::instance()->track_post( $post_id ); $new_attachment = array( 'id' => $post_id, 'url' => $upload['url'], ); Astra_Sites_Importer_Log::add( 'BATCH - SUCCESS Image {Imported} - ' . $new_attachment['url'] ); $this->already_imported_ids[] = $post_id; return $new_attachment; } /** * Is Image URL * * @since 1.3.10 * * @param string $url URL. * @return boolean */ public function is_image_url( $url = '' ) { if ( empty( $url ) ) { return false; } if ( astra_sites_is_valid_image( $url ) ) { return true; } return false; } } /** * Kicking this off by calling 'get_instance()' method */ Astra_Sites_Image_Importer::get_instance(); endif; class-astra-sites-helper.php 0000666 00000023126 15166147456 0012123 0 ustar 00 <?php /** * Astra Site Helper * * @since 1.0.0 * @package Astra Sites */ if ( ! class_exists( 'Astra_Sites_Helper' ) ) : /** * Astra_Sites_Helper * * @since 1.0.0 */ class Astra_Sites_Helper { /** * Instance * * @access private * @var object Instance * @since 1.0.0 */ private static $instance; /** * Initiator * * @since 1.0.0 * @return object initialized object of class. */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Constructor * * @since 1.0.0 */ public function __construct() { add_filter( 'wie_import_data', array( $this, 'custom_menu_widget' ) ); add_filter( 'wp_prepare_attachment_for_js', array( $this, 'add_svg_image_support' ), 10, 3 ); } /** * Add svg image support * * @since 1.1.5 * * @param array $response Attachment response. * @param object $attachment Attachment object. * @param array $meta Attachment meta data. */ public function add_svg_image_support( $response, $attachment, $meta ) { if ( ! function_exists( 'simplexml_load_file' ) ) { return $response; } if ( ! empty( $response['sizes'] ) ) { return $response; } if ( 'image/svg+xml' !== $response['mime'] ) { return $response; } $svg_path = get_attached_file( $attachment->ID ); $dimensions = self::get_svg_dimensions( $svg_path ); $response['sizes'] = array( 'full' => array( 'url' => $response['url'], 'width' => $dimensions->width, 'height' => $dimensions->height, 'orientation' => $dimensions->width > $dimensions->height ? 'landscape' : 'portrait', ), ); return $response; } /** * Get SVG Dimensions * * @since 1.1.5 * * @param string $svg SVG file path. * @return array Return SVG file height & width for valid SVG file. */ public static function get_svg_dimensions( $svg ) { $svg = simplexml_load_file( $svg ); if ( false === $svg ) { $width = '0'; $height = '0'; } else { $attributes = $svg->attributes(); $width = (string) $attributes->width; $height = (string) $attributes->height; } return (object) array( 'width' => $width, 'height' => $height, ); } /** * Custom Menu Widget * * In widget export we set the nav menu slug instead of ID. * So, In import process we check get menu id by slug and set * it in import widget process. * * @since 1.0.7 * * @param object $all_sidebars Widget data. * @return object Set custom menu id by slug. */ public function custom_menu_widget( $all_sidebars ) { // Get current menu ID & Slugs. $menu_locations = array(); $nav_menus = (object) wp_get_nav_menus(); if ( isset( $nav_menus ) ) { foreach ( $nav_menus as $menu_key => $menu ) { if ( is_object( $menu ) ) { $menu_locations[ $menu->term_id ] = $menu->slug; } } } // Import widget data. $all_sidebars = (object) $all_sidebars; foreach ( $all_sidebars as $widgets_key => $widgets ) { foreach ( $widgets as $widget_key => $widget ) { // Found slug in current menu list. if ( isset( $widget->nav_menu ) ) { $menu_id = array_search( $widget->nav_menu, $menu_locations, true ); if ( ! empty( $menu_id ) ) { $all_sidebars->$widgets_key->$widget_key->nav_menu = $menu_id; } } } } return $all_sidebars; } /** * Download File Into Uploads Directory * * @since 2.1.0 Added $overrides argument to override the uploaded file actions. * * @param string $file Download File URL. * @param array $overrides Upload file arguments. * @param int $timeout_seconds Timeout in downloading the XML file in seconds. * @return array Downloaded file data. */ public static function download_file( $file = '', $overrides = array(), $timeout_seconds = 300 ) { // Gives us access to the download_url() and wp_handle_sideload() functions. require_once ABSPATH . 'wp-admin/includes/file.php'; // Download file to temp dir. $temp_file = download_url( $file, $timeout_seconds ); // WP Error. if ( is_wp_error( $temp_file ) ) { return array( 'success' => false, 'data' => $temp_file->get_error_message(), ); } // Array based on $_FILE as seen in PHP file uploads. $file_args = array( 'name' => basename( $file ), 'tmp_name' => $temp_file, 'error' => 0, 'size' => filesize( $temp_file ), ); $defaults = array( // Tells WordPress to not look for the POST form // fields that would normally be present as // we downloaded the file from a remote server, so there // will be no form fields // Default is true. 'test_form' => false, // Setting this to false lets WordPress allow empty files, not recommended. // Default is true. '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', 'json' => 'text/plain', ), ); $overrides = wp_parse_args( $overrides, $defaults ); // Move the temporary file into the uploads directory. $results = wp_handle_sideload( $file_args, $overrides ); astra_sites_error_log( wp_json_encode( $results ) ); if ( isset( $results['error'] ) ) { return array( 'success' => false, 'data' => $results, ); } // Success. return array( 'success' => true, 'data' => $results, ); } /** * Downloads an image from the specified URL. * * Taken from the core media_sideload_image() function and * modified to return an array of data instead of html. * * @since 1.0.10 * * @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' ) ) { require_once ABSPATH . 'wp-admin/includes/media.php'; require_once ABSPATH . 'wp-admin/includes/file.php'; 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|svg|gif|png)\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'] ); //phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.file_ops_unlink -- Deleting the file from temp location. 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 = isset( $meta['height'] ) ? $meta['height'] : ''; $data->width = isset( $meta['width'] ) ? $meta['width'] : ''; } return $data; } /** * Extract image URLs and other URLs from a given HTML content. * * @since 2.6.10 * * @param string $content HTML content string. * @return array Array of URLS. */ public static function extract_segregated_urls( $content ) { // Extract all links. preg_match_all( '#\bhttps?://[^,\s()<>]+(?:\([\w\d]+\)|([^,[:punct:]\s]|/))#', $content, $match ); $extracts = array( 'image' => array(), 'other' => array(), ); $all_links = array_unique( $match[0] ); // Not have any link. if ( empty( $all_links ) ) { return array(); } $image_links = array(); $other_links = array(); // Extract normal and image links. foreach ( $all_links as $key => $link ) { if ( preg_match( '/^((https?:\/\/)|(www\.))([a-z0-9-].?)+(:[0-9]+)?\/[\w\-]+\.(jpg|png|gif|jpeg)\/?$/i', $link ) ) { // Get all image links. // Avoid *-150x, *-300x and *-1024x images. if ( false === strpos( $link, '-150x' ) && false === strpos( $link, '-300x' ) && false === strpos( $link, '-1024x' ) ) { $image_links[] = $link; } } else { // Collect other links. $other_links[] = $link; } } $extracts['image'] = $image_links; $extracts['other'] = $other_links; return $extracts; } /** * Get the client IP address. * * @since 2.6.4 */ public static function get_client_ip() { $ipaddress = ''; if ( getenv( 'HTTP_CLIENT_IP' ) ) { $ipaddress = getenv( 'HTTP_CLIENT_IP' ); } elseif ( getenv( 'HTTP_X_FORWARDED_FOR' ) ) { $ipaddress = getenv( 'HTTP_X_FORWARDED_FOR' ); } elseif ( getenv( 'HTTP_X_FORWARDED' ) ) { $ipaddress = getenv( 'HTTP_X_FORWARDED' ); } elseif ( getenv( 'HTTP_FORWARDED_FOR' ) ) { $ipaddress = getenv( 'HTTP_FORWARDED_FOR' ); } elseif ( getenv( 'HTTP_FORWARDED' ) ) { $ipaddress = getenv( 'HTTP_FORWARDED' ); } elseif ( getenv( 'REMOTE_ADDR' ) ) { $ipaddress = getenv( 'REMOTE_ADDR' ); } else { $ipaddress = 'UNKNOWN'; } return $ipaddress; } } /** * Kicking this off by calling 'get_instance()' method */ Astra_Sites_Helper::get_instance(); endif; class-astra-widget-importer.php 0000666 00000024626 15166147456 0012647 0 ustar 00 <?php /** * Widget Importer Exporter * https://github.com/churchthemes/widget-importer-exporter * * Released under the GNU General Public License v2.0 * https://github.com/churchthemes/widget-importer-exporter/blob/master/license.txt * * Widget Data exporter class. * * @since 2.0.0 * @package Astra Sites */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Widget Data exporter class. */ class Astra_Widget_Importer { /** * Instance of Astra_Widget_Importer * * @var Astra_Widget_Importer */ private static $instance = null; /** * Instance * * @return object */ 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 ) { if ( ! empty( $widget['id_base'] ) && ! isset( $available_widgets[ $widget['id_base'] ] ) ) { // no dupes. $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 ); } /** * 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 import_widgets_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.', 'astra-sites' ), '', array( 'back_link' => true, ) ); } // Hook before import. do_action( 'wie_before_import' ); $data = apply_filters( 'wie_import_data', $data ); // 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)', 'astra-sites' ); } // 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 = esc_html__( 'Site does not support widget', 'astra-sites' ); // 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 ); // 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( 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 ); // 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'; $widget_message = esc_html__( 'Widget already exists', 'astra-sites' ); // 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. $result = 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, ); do_action( 'wie_after_widget_import', $after_widget_import ); // Success message. if ( $sidebar_available ) { $widget_message_type = 'success'; $widget_message = esc_html__( 'Imported', 'astra-sites' ); } else { $widget_message_type = 'warning'; $widget_message = esc_html__( 'Imported to Inactive', 'astra-sites' ); } } // 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', 'astra-sites' ); // 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' ); // Return results. return apply_filters( 'wie_import_results', $results ); } }
| ver. 1.4 |
Github
|
.
| PHP 5.4.45 | Generation time: 0.01 |
proxy
|
phpinfo
|
Settings