first commit

This commit is contained in:
Ryan Ariana
2024-05-06 11:04:37 +07:00
commit aee061ddba
7322 changed files with 2918816 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
<?php
namespace Elementor\App\AdminMenuItems;
use Elementor\Core\Admin\Menu\Interfaces\Admin_Menu_Item;
use Elementor\TemplateLibrary\Source_Local;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
class Theme_Builder_Menu_Item implements Admin_Menu_Item {
public function is_visible() {
return true;
}
public function get_parent_slug() {
return Source_Local::ADMIN_MENU_SLUG;
}
public function get_label() {
return esc_html__( 'Theme Builder', 'elementor' );
}
public function get_capability() {
return 'manage_options';
}
}

View File

@@ -0,0 +1,270 @@
<?php
namespace Elementor\App;
use Elementor\App\AdminMenuItems\Theme_Builder_Menu_Item;
use Elementor\Core\Admin\Menu\Admin_Menu_Manager;
use Elementor\Modules\WebCli\Module as WebCLIModule;
use Elementor\Core\Base\App as BaseApp;
use Elementor\Core\Settings\Manager as SettingsManager;
use Elementor\Plugin;
use Elementor\TemplateLibrary\Source_Local;
use Elementor\User;
use Elementor\Utils;
use Elementor\Core\Utils\Promotions\Filtered_Promotions_Manager;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
class App extends BaseApp {
const PAGE_ID = 'elementor-app';
/**
* Get module name.
*
* Retrieve the module name.
*
* @since 3.0.0
* @access public
*
* @return string Module name.
*/
public function get_name() {
return 'app';
}
public function get_base_url() {
return admin_url( 'admin.php?page=' . self::PAGE_ID . '&ver=' . ELEMENTOR_VERSION );
}
private function register_admin_menu( Admin_Menu_Manager $admin_menu ) {
$admin_menu->register( static::PAGE_ID, new Theme_Builder_Menu_Item() );
}
public function fix_submenu( $menu ) {
global $submenu;
if ( is_multisite() && is_network_admin() ) {
return $menu;
}
// Non admin role / custom wp menu.
if ( empty( $submenu[ Source_Local::ADMIN_MENU_SLUG ] ) ) {
return $menu;
}
// Hack to add a link to sub menu.
foreach ( $submenu[ Source_Local::ADMIN_MENU_SLUG ] as &$item ) {
if ( self::PAGE_ID === $item[2] ) {
$item[2] = $this->get_settings( 'menu_url' ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$item[4] = 'elementor-app-link'; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
}
}
return $menu;
}
public function is_current() {
return ( ! empty( $_GET['page'] ) && self::PAGE_ID === $_GET['page'] );
}
public function admin_init() {
do_action( 'elementor/app/init', $this );
// Add the introduction and user settings only when it is needed (when loading the app and not in the editor or admin pages)
$this->set_settings( 'user', [
'introduction' => (object) User::get_introduction_meta(),
'is_administrator' => current_user_can( 'manage_options' ),
'restrictions' => Plugin::$instance->role_manager->get_user_restrictions_array(),
] );
$this->enqueue_assets();
// Setup default heartbeat options
// TODO: Enable heartbeat.
add_filter( 'heartbeat_settings', function( $settings ) {
$settings['interval'] = 15;
return $settings;
} );
$this->render();
die;
}
protected function get_init_settings() {
$referer = wp_get_referer();
return [
'menu_url' => $this->get_base_url() . '#site-editor/promotion',
'assets_url' => ELEMENTOR_ASSETS_URL,
'pages_url' => admin_url( 'edit.php?post_type=page' ),
'return_url' => $referer ? $referer : admin_url(),
'hasPro' => Utils::has_pro(),
'admin_url' => admin_url(),
'login_url' => wp_login_url(),
'base_url' => $this->get_base_url(),
'promotion' => Filtered_Promotions_Manager::get_filtered_promotion_data(
[ 'upgrade_url' => 'https://go.elementor.com/go-pro-theme-builder/' ],
'elementor/site-editor/promotion',
'upgrade_url'
),
];
}
private function render() {
require __DIR__ . '/view.php';
}
/**
* Get Elementor UI theme preference.
*
* Retrieve the user UI theme preference as defined by editor preferences manager.
*
* @since 3.0.0
* @access private
*
* @return string Preferred UI theme.
*/
private function get_elementor_ui_theme_preference() {
$editor_preferences = SettingsManager::get_settings_managers( 'editorPreferences' );
return $editor_preferences->get_model()->get_settings( 'ui_theme' );
}
/**
* Enqueue dark theme detection script.
*
* Enqueues an inline script that detects user-agent settings for dark mode and adds a complimentary class to the body tag.
*
* @since 3.0.0
* @access private
*/
private function enqueue_dark_theme_detection_script() {
if ( 'auto' === $this->get_elementor_ui_theme_preference() ) {
wp_add_inline_script( 'elementor-app',
'if ( window.matchMedia && window.matchMedia( `(prefers-color-scheme: dark)` ).matches )
{ document.body.classList.add( `eps-theme-dark` ); }' );
}
}
private function enqueue_assets() {
Plugin::$instance->init_common();
/** @var WebCLIModule $web_cli */
$web_cli = Plugin::$instance->modules_manager->get_modules( 'web-cli' );
$web_cli->register_scripts();
Plugin::$instance->common->register_scripts();
wp_register_style(
'select2',
$this->get_css_assets_url( 'e-select2', 'assets/lib/e-select2/css/' ),
[],
'4.0.6-rc.1'
);
Plugin::$instance->common->register_styles();
wp_register_style(
'select2',
ELEMENTOR_ASSETS_URL . 'lib/e-select2/css/e-select2.css',
[],
'4.0.6-rc.1'
);
wp_enqueue_style(
'elementor-app',
$this->get_css_assets_url( 'app', null, 'default', true ),
[
'select2',
'elementor-icons',
'elementor-common',
'select2',
],
ELEMENTOR_VERSION
);
wp_enqueue_script(
'elementor-app-packages',
$this->get_js_assets_url( 'app-packages' ),
[
'wp-i18n',
'react',
],
ELEMENTOR_VERSION,
true
);
wp_register_script(
'select2',
$this->get_js_assets_url( 'e-select2.full', 'assets/lib/e-select2/js/' ),
[
'jquery',
],
'4.0.6-rc.1',
true
);
wp_enqueue_script(
'elementor-app',
$this->get_js_assets_url( 'app' ),
[
'wp-url',
'wp-i18n',
'react',
'react-dom',
'select2',
],
ELEMENTOR_VERSION,
true
);
$this->enqueue_dark_theme_detection_script();
wp_set_script_translations( 'elementor-app-packages', 'elementor' );
wp_set_script_translations( 'elementor-app', 'elementor' );
$this->print_config();
}
public function enqueue_app_loader() {
wp_enqueue_script(
'elementor-app-loader',
$this->get_js_assets_url( 'app-loader' ),
[
'elementor-common',
],
ELEMENTOR_VERSION,
true
);
$this->print_config( 'elementor-app-loader' );
}
public function __construct() {
$this->add_component( 'site-editor', new Modules\SiteEditor\Module() );
if ( current_user_can( 'manage_options' ) || Utils::is_wp_cli() ) {
$this->add_component( 'import-export', new Modules\ImportExport\Module() );
// Kit library is depended on import-export
$this->add_component( 'kit-library', new Modules\KitLibrary\Module() );
}
$this->add_component( 'onboarding', new Modules\Onboarding\Module() );
add_action( 'elementor/admin/menu/register', function ( Admin_Menu_Manager $admin_menu ) {
$this->register_admin_menu( $admin_menu );
}, Source_Local::ADMIN_MENU_PRIORITY + 10 );
// Happens after WP plugin page validation.
add_filter( 'add_menu_classes', [ $this, 'fix_submenu' ] );
if ( $this->is_current() ) {
add_action( 'admin_init', [ $this, 'admin_init' ], 0 );
} else {
add_action( 'elementor/common/after_register_scripts', [ $this, 'enqueue_app_loader' ] );
}
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Elementor\App\Modules\ImportExport\Compatibility;
use Elementor\App\Modules\ImportExport\Import;
use Elementor\Core\Base\Base_Object;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
abstract class Base_Adapter {
/**
* @param array $manifest_data
* @param array $meta
* @return false
*/
public static function is_compatibility_needed( array $manifest_data, array $meta ) {
return false;
}
public function adapt_manifest( array $manifest_data ) {
return $manifest_data;
}
public function adapt_site_settings( array $site_settings, array $manifest_data, $path ) {
return $site_settings;
}
public function adapt_template( array $template_data, array $template_settings ) {
return $template_data;
}
}

View File

@@ -0,0 +1,82 @@
<?php
namespace Elementor\App\Modules\ImportExport\Compatibility;
use Elementor\App\Modules\ImportExport\Utils as ImportExportUtils;
use Elementor\Plugin;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class Envato extends Base_Adapter {
public static function is_compatibility_needed( array $manifest_data, array $meta ) {
return ! empty( $manifest_data['manifest_version'] );
}
public function adapt_manifest( array $manifest_data ) {
$templates = $manifest_data['templates'];
$manifest_data['templates'] = [];
foreach ( $templates as $template ) {
// Envato store their global kit styles as a 'global.json' template file.
// We need to be able to know the path to this specifc 'global.json' since it functions as the site-settings.json
$is_global = ! empty( $template['metadata']['template_type'] ) && 'global-styles' === $template['metadata']['template_type'];
if ( $is_global ) {
// Adding the path of the 'global.json' template to the manifest which will be used in the future.
$manifest_data['path-to-envto-site-settings'] = $template['source'];
// Getting the site-settings because Envato stores them in one of the posts.
$kit = Plugin::$instance->kits_manager->get_active_kit();
$kit_tabs = $kit->get_tabs();
unset( $kit_tabs['settings-site-identity'] );
$manifest_data['site-settings'] = array_keys( $kit_tabs );
continue;
}
// Evanto uses "type" instead of "doc_type"
$template['doc_type'] = $template['type'];
// Evanto uses for "name" instead of "title"
$template['title'] = $template['name'];
// Envato specifying an exact path to the template rather than using its "ID" as an index.
// This extracts the "file name" part out of our exact source list and we treat that as an ID.
$file_name_without_extension = str_replace( '.json', '', basename( $template['source'] ) );
// Append the template to the global list:
$manifest_data['templates'][ $file_name_without_extension ] = $template;
}
$manifest_data['name'] = $manifest_data['title'];
return $manifest_data;
}
public function adapt_site_settings( array $site_settings, array $manifest_data, $path ) {
if ( empty( $manifest_data['path-to-envto-site-settings'] ) ) {
return $site_settings;
}
$global_file_path = $path . $manifest_data['path-to-envto-site-settings'];
$global_file_data = ImportExportUtils::read_json_file( $global_file_path );
return [
'settings' => $global_file_data['page_settings'],
];
}
public function adapt_template( array $template_data, array $template_settings ) {
if ( ! empty( $template_data['metadata']['elementor_pro_conditions'] ) ) {
foreach ( $template_data['metadata']['elementor_pro_conditions'] as $condition ) {
list ( $type, $name, $sub_name, $sub_id ) = array_pad( explode( '/', $condition ), 4, '' );
$template_data['import_settings']['conditions'][] = compact( 'type', 'name', 'sub_name', 'sub_id' );
}
}
return $template_data;
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Elementor\App\Modules\ImportExport\Compatibility;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class Kit_Library extends Base_Adapter {
public static function is_compatibility_needed( array $manifest_data, array $meta ) {
return ! empty( $meta['referrer'] ) && 'kit-library' === $meta['referrer'];
}
public function adapt_manifest( array $manifest_data ) {
if ( ! empty( $manifest_data['content']['page'] ) ) {
foreach ( $manifest_data['content']['page'] as & $page ) {
$page['thumbnail'] = false;
}
}
if ( ! empty( $manifest_data['templates'] ) ) {
foreach ( $manifest_data['templates'] as & $template ) {
$template['thumbnail'] = false;
}
}
return $manifest_data;
}
}

View File

@@ -0,0 +1,909 @@
<?php
namespace Elementor\App\Modules\ImportExport;
use Elementor\App\Modules\ImportExport\Processes\Export;
use Elementor\App\Modules\ImportExport\Processes\Import;
use Elementor\App\Modules\ImportExport\Processes\Revert;
use Elementor\Core\Base\Module as BaseModule;
use Elementor\Core\Common\Modules\Ajax\Module as Ajax;
use Elementor\Core\Files\Uploads_Manager;
use Elementor\Modules\System_Info\Reporters\Server;
use Elementor\Plugin;
use Elementor\Tools;
use Elementor\Utils as ElementorUtils;
use Elementor\App\Modules\ImportExport\Utils as ImportExportUtils;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
/**
* Import Export Module
*
* Responsible for initializing Elementor App functionality
*/
class Module extends BaseModule {
const FORMAT_VERSION = '2.0';
const EXPORT_TRIGGER_KEY = 'elementor_export_kit';
const UPLOAD_TRIGGER_KEY = 'elementor_upload_kit';
const IMPORT_TRIGGER_KEY = 'elementor_import_kit';
const IMPORT_RUNNER_TRIGGER_KEY = 'elementor_import_kit__runner';
const REFERRER_KIT_LIBRARY = 'kit-library';
const REFERRER_LOCAL = 'local';
const PLUGIN_PERMISSIONS_ERROR_KEY = 'plugin-installation-permissions-error';
const KIT_LIBRARY_ERROR_KEY = 'invalid-kit-library-zip-error';
const NO_WRITE_PERMISSIONS_KEY = 'no-write-permissions';
const THIRD_PARTY_ERROR = 'third-party-error';
const DOMDOCUMENT_MISSING = 'domdocument-missing';
const OPTION_KEY_ELEMENTOR_IMPORT_SESSIONS = 'elementor_import_sessions';
const OPTION_KEY_ELEMENTOR_REVERT_SESSIONS = 'elementor_revert_sessions';
const META_KEY_ELEMENTOR_IMPORT_SESSION_ID = '_elementor_import_session_id';
const META_KEY_ELEMENTOR_EDIT_MODE = '_elementor_edit_mode';
const IMPORT_PLUGINS_ACTION = 'import-plugins';
/**
* Assigning the export process to a property, so we can use the process from outside the class.
*
* @var Export
*/
public $export;
/**
* Assigning the import process to a property, so we can use the process from outside the class.
*
* @var Import
*/
public $import;
/**
* Assigning the revert process to a property, so we can use the process from outside the class.
*
* @var Revert
*/
public $revert;
/**
* Get name.
*
* @access public
*
* @return string
*/
public function get_name() {
return 'import-export';
}
public function __construct() {
$this->register_actions();
if ( ElementorUtils::is_wp_cli() ) {
\WP_CLI::add_command( 'elementor kit', WP_CLI::class );
}
( new Usage() )->register();
$this->revert = new Revert();
}
public function get_init_settings() {
if ( ! Plugin::$instance->app->is_current() ) {
return [];
}
return $this->get_config_data();
}
/**
* Register the import/export tab in elementor tools.
*/
public function register_settings_tab( Tools $tools ) {
$tools->add_tab( 'import-export-kit', [
'label' => esc_html__( 'Import / Export Kit', 'elementor' ),
'sections' => [
'intro' => [
'label' => esc_html__( 'Template Kits', 'elementor' ),
'callback' => function() {
$this->render_import_export_tab_content();
},
'fields' => [],
],
],
] );
}
/**
* Render the import/export tab content.
*/
private function render_import_export_tab_content() {
$intro_text_link = sprintf( '<a href="https://go.elementor.com/wp-dash-import-export-general/" target="_blank">%s</a>', esc_html__( 'Learn more', 'elementor' ) );
$intro_text = sprintf(
/* translators: 1: New line break, 2: Learn more link. */
__( 'Design sites faster with a template kit that contains some or all components of a complete site, like templates, content & site settings.%1$sYou can import a kit and apply it to your site, or export the elements from this site to be used anywhere else. %2$s', 'elementor' ),
'<br>',
$intro_text_link
);
$content_data = [
'export' => [
'title' => esc_html__( 'Export a Template Kit', 'elementor' ),
'button' => [
'url' => Plugin::$instance->app->get_base_url() . '#/export',
'text' => esc_html__( 'Start Export', 'elementor' ),
],
'description' => esc_html__( 'Bundle your whole site - or just some of its elements - to be used for another website.', 'elementor' ),
'link' => [
'url' => 'https://go.elementor.com/wp-dash-import-export-export-flow/',
'text' => esc_html__( 'Learn More', 'elementor' ),
],
],
'import' => [
'title' => esc_html__( 'Import a Template Kit', 'elementor' ),
'button' => [
'url' => Plugin::$instance->app->get_base_url() . '#/import',
'text' => esc_html__( 'Start Import', 'elementor' ),
],
'description' => esc_html__( 'Apply the design and settings of another site to this one.', 'elementor' ),
'link' => [
'url' => 'https://go.elementor.com/wp-dash-import-export-import-flow/',
'text' => esc_html__( 'Learn More', 'elementor' ),
],
],
];
$last_imported_kit = $this->revert->get_last_import_session();
$penultimate_imported_kit = $this->revert->get_penultimate_import_session();
$user_date_format = get_option( 'date_format' );
$user_time_format = get_option( 'time_format' );
$date_format = $user_date_format . ' ' . $user_time_format;
$should_show_revert_section = $this->should_show_revert_section( $last_imported_kit );
if ( $should_show_revert_section ) {
if ( ! empty( $penultimate_imported_kit ) ) {
$revert_text = sprintf(
esc_html__( 'Remove all the content and site settings that came with "%1$s" on %2$s %3$s and revert to the site setting that came with "%4$s" on %5$s.', 'elementor' ),
! empty( $last_imported_kit['kit_title'] ) ? $last_imported_kit['kit_title'] : esc_html__( 'imported kit', 'elementor' ),
gmdate( $date_format, $last_imported_kit['start_timestamp'] ),
'<br>',
! empty( $penultimate_imported_kit['kit_title'] ) ? $penultimate_imported_kit['kit_title'] : esc_html__( 'imported kit', 'elementor' ),
gmdate( $date_format, $penultimate_imported_kit['start_timestamp'] )
);
} else {
$revert_text = sprintf(
esc_html__( 'Remove all the content and site settings that came with "%1$s" on %2$s.%3$s Your original site settings will be restored.', 'elementor' ),
! empty( $last_imported_kit['kit_title'] ) ? $last_imported_kit['kit_title'] : esc_html__( 'imported kit', 'elementor' ),
gmdate( $date_format, $last_imported_kit['start_timestamp'] ),
'<br>'
);
}
}
?>
<div class="tab-import-export-kit__content">
<p class="tab-import-export-kit__info"><?php ElementorUtils::print_unescaped_internal_string( $intro_text ); ?></p>
<div class="tab-import-export-kit__wrapper">
<?php foreach ( $content_data as $data ) { ?>
<div class="tab-import-export-kit__container">
<div class="tab-import-export-kit__box">
<h2><?php ElementorUtils::print_unescaped_internal_string( $data['title'] ); ?></h2>
<a href="<?php ElementorUtils::print_unescaped_internal_string( $data['button']['url'] ); ?>" class="elementor-button e-primary">
<?php ElementorUtils::print_unescaped_internal_string( $data['button']['text'] ); ?>
</a>
</div>
<p><?php ElementorUtils::print_unescaped_internal_string( $data['description'] ); ?></p>
<a href="<?php ElementorUtils::print_unescaped_internal_string( $data['link']['url'] ); ?>" target="_blank"><?php ElementorUtils::print_unescaped_internal_string( $data['link']['text'] ); ?></a>
</div>
<?php } ?>
</div>
<?php
if ( $should_show_revert_section ) {
$link_attributes = [
'href' => $this->get_revert_href(),
'id' => 'elementor-import-export__revert_kit',
'class' => 'button',
];
?>
<div class="tab-import-export-kit__revert">
<h2>
<?php ElementorUtils::print_unescaped_internal_string( esc_html__( 'Remove the most recent Kit', 'elementor' ) ); ?>
</h2>
<p class="tab-import-export-kit__info">
<?php ElementorUtils::print_unescaped_internal_string( $revert_text ); ?>
</p>
<?php $this->render_last_kit_thumbnail( $last_imported_kit ); ?>
<a <?php ElementorUtils::print_html_attributes( $link_attributes ); ?> >
<?php ElementorUtils::print_unescaped_internal_string( esc_html__( 'Remove Kit', 'elementor' ) ); ?>
</a>
</div>
<?php } ?>
</div>
<?php
}
private function get_revert_href(): string {
$admin_post_url = admin_url( 'admin-post.php?action=elementor_revert_kit' );
$nonced_admin_post_url = wp_nonce_url( $admin_post_url, 'elementor_revert_kit' );
return $this->maybe_add_referrer_param( $nonced_admin_post_url );
}
/**
* Checks if referred by a kit and adds the referrer ID to the href
*
* @param string $href
*
* @return string
*/
private function maybe_add_referrer_param( string $href ): string {
$param_name = 'referrer_kit';
if ( empty( $_GET[ $param_name ] ) ) {
return $href;
}
return add_query_arg( $param_name, sanitize_key( $_GET[ $param_name ] ), $href );
}
/**
* Render the last kit thumbnail if exists
*
* @param $last_imported_kit
*
* @return void
*/
private function render_last_kit_thumbnail( $last_imported_kit ) {
if ( empty( $last_imported_kit['kit_thumbnail'] ) ) {
return;
}
?>
<div class="tab-import-export-kit__kit-item-row">
<article class="tab-import-export-kit__kit-item">
<header>
<h3>
<?php echo esc_html( $last_imported_kit['kit_title'] ); ?>
</h3>
</header>
<img
src="<?php echo esc_url( $last_imported_kit['kit_thumbnail'] ); ?>"
alt="<?php echo esc_attr( $last_imported_kit['kit_title'] ); ?>"
loading="lazy"
>
</article>
</div>
<?php
}
/**
* Upload a kit zip file and get the kit data.
*
* Assigning the Import process to the 'import' property,
* so it will be available to use in different places such as: WP_Cli, Pro, etc.
*
* @param string $file Path to the file.
* @param string $referrer Referrer of the file 'local' or 'kit-library'.
* @return array
* @throws \Exception
*/
public function upload_kit( $file, $referrer ) {
$this->ensure_writing_permissions();
$this->import = new Import( $file, [ 'referrer' => $referrer ] );
return [
'session' => $this->import->get_session_id(),
'manifest' => $this->import->get_manifest(),
'conflicts' => $this->import->get_settings_conflicts(),
];
}
/**
* Import a kit by session_id.
* Upload and import a kit by kit zip file.
*
* If the split_to_chunks flag is true, the process won't start
* It will initialize the import process and return the session_id and the runners.
*
* Assigning the Import process to the 'import' property,
* so it will be available to use in different places such as: WP_Cli, Pro, etc.
*
* @param string $path Path to the file or session_id.
* @param array $settings Settings the import use to determine which content to import.
* (e.g: include, selected_plugins, selected_cpt, selected_override_conditions, etc.)
* @param bool $split_to_chunks Determine if the import process should be split into chunks.
* @return array
* @throws \Exception
*/
public function import_kit( string $path, array $settings, bool $split_to_chunks = false ): array {
$this->ensure_writing_permissions();
$this->ensure_DOMDocument_exists();
$this->import = new Import( $path, $settings );
$this->import->register_default_runners();
remove_filter( 'elementor/document/save/data', [ Plugin::$instance->modules_manager->get_modules( 'content-sanitizer' ), 'sanitize_content' ] );
do_action( 'elementor/import-export/import-kit', $this->import );
if ( $split_to_chunks ) {
$this->import->init_import_session( true );
return [
'session' => $this->import->get_session_id(),
'runners' => $this->import->get_runners_name(),
];
}
return $this->import->run();
}
/**
* Resuming import process by re-creating the import instance and running the specific runner.
*
* @param string $session_id The id off the import session.
* @param string $runner_name The specific runner that we want to run.
*
* @return array Two types of response.
* 1. The status and the runner name.
* 2. The imported data. (Only if the runner is the last one in the import process)
* @throws \Exception
*/
public function import_kit_by_runner( string $session_id, string $runner_name ): array {
// Check session_id
$this->import = Import::from_session( $session_id );
$runners = $this->import->get_runners_name();
$run = $this->import->run_runner( $runner_name );
if ( end( $runners ) === $run['runner'] ) {
return $this->import->get_imported_data();
}
return $run;
}
/**
* Export a kit.
*
* Assigning the Export process to the 'export' property,
* so it will be available to use in different places such as: WP_Cli, Pro, etc.
*
* @param array $settings Settings the export use to determine which content to export.
* (e.g: include, kit_info, selected_plugins, selected_cpt, etc.)
* @return array
* @throws \Exception
*/
public function export_kit( array $settings ) {
$this->ensure_writing_permissions();
$this->export = new Export( $settings );
$this->export->register_default_runners();
do_action( 'elementor/import-export/export-kit', $this->export );
return $this->export->run();
}
/**
* Handle revert kit ajax request.
*/
public function revert_last_imported_kit() {
$this->revert = new Revert();
$this->revert->register_default_runners();
do_action( 'elementor/import-export/revert-kit', $this->revert );
$this->revert->run();
}
/**
* Handle revert last imported kit ajax request.
*/
public function handle_revert_last_imported_kit() {
check_admin_referer( 'elementor_revert_kit' );
$this->revert_last_imported_kit();
wp_safe_redirect( admin_url( 'admin.php?page=' . Tools::PAGE_ID . '#tab-import-export-kit' ) );
die;
}
/**
* Register appropriate actions.
*/
private function register_actions() {
add_action( 'admin_init', function() {
if ( wp_doing_ajax() &&
isset( $_POST['action'] ) &&
wp_verify_nonce( ElementorUtils::get_super_global_value( $_POST, '_nonce' ), Ajax::NONCE_KEY ) &&
current_user_can( 'manage_options' )
) {
$this->maybe_handle_ajax();
}
} );
add_action( 'admin_post_elementor_revert_kit', [ $this, 'handle_revert_last_imported_kit' ] );
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
$page_id = Tools::PAGE_ID;
add_action( "elementor/admin/after_create_settings/{$page_id}", [ $this, 'register_settings_tab' ] );
// TODO 18/04/2023 : This needs to be moved to the runner itself after https://elementor.atlassian.net/browse/HTS-434 is done.
if ( self::IMPORT_PLUGINS_ACTION === ElementorUtils::get_super_global_value( $_SERVER, 'HTTP_X_ELEMENTOR_ACTION' ) ) {
add_filter( 'woocommerce_create_pages', [ $this, 'empty_pages' ], 10, 0 );
}
// TODO ^^^
}
/**
* Prevent the creation of the default WooCommerce pages (Cart, Checkout, etc.)
*
* TODO 18/04/2023 : This needs to be moved to the runner itself after https://elementor.atlassian.net/browse/HTS-434 is done.
* @return array
*/
public function empty_pages(): array {
return [];
}
private function ensure_writing_permissions() {
$server = new Server();
$paths_to_check = [
Server::KEY_PATH_WP_CONTENT_DIR => $server->get_system_path( Server::KEY_PATH_WP_CONTENT_DIR ),
Server::KEY_PATH_UPLOADS_DIR => $server->get_system_path( Server::KEY_PATH_UPLOADS_DIR ),
Server::KEY_PATH_ELEMENTOR_UPLOADS_DIR => $server->get_system_path( Server::KEY_PATH_ELEMENTOR_UPLOADS_DIR ),
];
$permissions = $server->get_paths_permissions( $paths_to_check );
// WP Content dir has to be exists and writable.
if ( ! $permissions[ Server::KEY_PATH_WP_CONTENT_DIR ]['write'] ) {
throw new \Error( self::NO_WRITE_PERMISSIONS_KEY );
}
// WP Uploads dir has to be exists and writable.
if ( ! $permissions[ Server::KEY_PATH_UPLOADS_DIR ]['write'] ) {
throw new \Error( self::NO_WRITE_PERMISSIONS_KEY );
}
// Elementor uploads dir permissions is divided to 2 cases:
// 1. If the dir exists, it has to be writable.
// 2. If the dir doesn't exist, the parent dir has to be writable (wp uploads dir), so we can create it.
if ( $permissions[ Server::KEY_PATH_ELEMENTOR_UPLOADS_DIR ]['exists'] && ! $permissions[ Server::KEY_PATH_ELEMENTOR_UPLOADS_DIR ]['write'] ) {
throw new \Error( self::NO_WRITE_PERMISSIONS_KEY );
}
}
private function ensure_DOMDocument_exists() {
if ( ! class_exists( 'DOMDocument' ) ) {
throw new \Error( self::DOMDOCUMENT_MISSING );
}
}
/**
* Enqueue admin scripts
*/
public function enqueue_scripts() {
wp_enqueue_script(
'elementor-import-export-admin',
$this->get_js_assets_url( 'import-export-admin' ),
[ 'elementor-common' ],
ELEMENTOR_VERSION,
true
);
wp_localize_script(
'elementor-import-export-admin',
'elementorImportExport',
[
'lastImportedSession' => $this->revert->get_last_import_session(),
'appUrl' => Plugin::$instance->app->get_base_url() . '#/kit-library',
]
);
}
/**
* Assign each ajax action to a method.
*/
private function maybe_handle_ajax() {
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$action = ElementorUtils::get_super_global_value( $_POST, 'action' );
try {
switch ( $action ) {
case static::EXPORT_TRIGGER_KEY:
$this->handle_export_kit();
break;
case static::UPLOAD_TRIGGER_KEY:
$this->handle_upload_kit();
break;
case static::IMPORT_TRIGGER_KEY:
$this->handle_import_kit();
break;
case static::IMPORT_RUNNER_TRIGGER_KEY:
$this->handle_import_kit__runner();
break;
default:
break;
}
} catch ( \Error $e ) {
if ( isset( $this->import ) ) {
$this->import->finalize_import_session_option();
}
Plugin::$instance->logger->get_logger()->error( $e->getMessage(), [
'meta' => [
'trace' => $e->getTraceAsString(),
],
] );
if ( isset( $this->import ) && $this->is_third_party_class( $e->getTrace()[0]['class'] ) ) {
wp_send_json_error( self::THIRD_PARTY_ERROR, 500 );
}
wp_send_json_error( $e->getMessage(), 500 );
}
}
/**
* Handle upload kit ajax request.
*/
private function handle_upload_kit() {
// PHPCS - A URL that should contain special chars (auth headers information).
$file_url = isset( $_POST['e_import_file'] )
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
? wp_unslash( $_POST['e_import_file'] )
: '';
// Import from kit library
if ( ! empty( $file_url ) ) {
if (
! wp_verify_nonce( ElementorUtils::get_super_global_value( $_POST, 'e_kit_library_nonce' ), 'kit-library-import' )
) {
throw new \Error( 'Invalid kit library nonce.' );
}
if ( ! filter_var( $file_url, FILTER_VALIDATE_URL ) || 0 !== strpos( $file_url, 'http' ) ) {
throw new \Error( static::KIT_LIBRARY_ERROR_KEY );
}
$remote_zip_request = wp_remote_get( $file_url );
if ( is_wp_error( $remote_zip_request ) ) {
Plugin::$instance->logger->get_logger()->error( $remote_zip_request->get_error_message() );
throw new \Error( static::KIT_LIBRARY_ERROR_KEY );
}
if ( 200 !== $remote_zip_request['response']['code'] ) {
Plugin::$instance->logger->get_logger()->error( $remote_zip_request['response']['message'] );
throw new \Error( static::KIT_LIBRARY_ERROR_KEY );
}
$file_name = Plugin::$instance->uploads_manager->create_temp_file( $remote_zip_request['body'], 'kit.zip' );
$referrer = static::REFERRER_KIT_LIBRARY;
} else {
// PHPCS - Already validated in caller function.
$file_name = ElementorUtils::get_super_global_value( $_FILES, 'e_import_file' )['tmp_name'];
$referrer = static::REFERRER_LOCAL;
}
Plugin::$instance->logger->get_logger()->info( 'Uploading Kit: ', [
'meta' => [
'kit_id' => ElementorUtils::get_super_global_value( $_POST, 'kit_id' ),
'referrer' => $referrer,
],
] );
$uploaded_kit = $this->upload_kit( $file_name, $referrer );
$session_dir = $uploaded_kit['session'];
$manifest = $uploaded_kit['manifest'];
$conflicts = $uploaded_kit['conflicts'];
if ( ! empty( $file_url ) ) {
Plugin::$instance->uploads_manager->remove_file_or_dir( dirname( $file_name ) );
}
if ( isset( $manifest['plugins'] ) && ! current_user_can( 'install_plugins' ) ) {
throw new \Error( static::PLUGIN_PERMISSIONS_ERROR_KEY );
}
$result = [
'session' => $session_dir,
'manifest' => $manifest,
];
if ( ! empty( $conflicts ) ) {
$result['conflicts'] = $conflicts;
} else {
// Moved into the IE process \Elementor\App\Modules\ImportExport\Processes\Import::get_default_settings_conflicts
// TODO: remove in 3.10.0
$result = apply_filters( 'elementor/import/stage_1/result', $result );
}
wp_send_json_success( $result );
}
/**
* Handle import kit ajax request.
*/
private function handle_import_kit() {
// PHPCS - Already validated in caller function
$settings = json_decode( ElementorUtils::get_super_global_value( $_POST, 'data' ), true ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
$tmp_folder_id = $settings['session'];
$import = $this->import_kit( $tmp_folder_id, $settings, true );
// get_settings_config() added manually because the frontend Ajax request doesn't trigger the get_init_settings().
$import['configData'] = $this->get_config_data();
Plugin::$instance->logger->get_logger()->info(
sprintf( 'Selected import runners: %1$s',
implode( ', ', $import['runners'] )
)
);
wp_send_json_success( $import );
}
/**
* Handle ajax request for running specific runner in the import kit process.
*/
private function handle_import_kit__runner() {
// PHPCS - Already validated in caller function
$settings = json_decode( ElementorUtils::get_super_global_value( $_POST, 'data' ), true ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
$session_id = $settings['session'];
$runner = $settings['runner'];
$import = $this->import_kit_by_runner( $session_id, $runner );
// get_settings_config() added manually because the frontend Ajax request doesn't trigger the get_init_settings().
$import['configData'] = $this->get_config_data();
if ( ! empty( $import['status'] ) ) {
Plugin::$instance->logger->get_logger()->info(
sprintf( 'Import runner completed: %1$s %2$s',
$import['runner'],
( 'success' === $import['status'] ? '✓' : '✗' )
)
);
}
wp_send_json_success( $import );
}
/**
* Handle export kit ajax request.
*/
private function handle_export_kit() {
// PHPCS - Already validated in caller function
$settings = json_decode( ElementorUtils::get_super_global_value( $_POST, 'data' ), true ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
$export = $this->export_kit( $settings );
$file_name = $export['file_name'];
$file = ElementorUtils::file_get_contents( $file_name );
if ( ! $file ) {
throw new \Error( 'Could not read the exported file.' );
}
Plugin::$instance->uploads_manager->remove_file_or_dir( dirname( $file_name ) );
$result = [
'manifest' => $export['manifest'],
'file' => base64_encode( $file ),
];
wp_send_json_success( $result );
}
/**
* Get config data that will be exposed to the frontend.
*/
private function get_config_data() {
$export_nonce = wp_create_nonce( 'elementor_export' );
$export_url = add_query_arg( [ '_nonce' => $export_nonce ], Plugin::$instance->app->get_base_url() );
return [
'exportURL' => $export_url,
'summaryTitles' => $this->get_summary_titles(),
'builtinWpPostTypes' => ImportExportUtils::get_builtin_wp_post_types(),
'elementorPostTypes' => ImportExportUtils::get_elementor_post_types(),
'isUnfilteredFilesEnabled' => Uploads_Manager::are_unfiltered_uploads_enabled(),
'elementorHomePageUrl' => $this->get_elementor_home_page_url(),
'recentlyEditedElementorPageUrl' => $this->get_recently_edited_elementor_page_url(),
'tools_url' => Tools::get_url(),
'importSessions' => Revert::get_import_sessions(),
'lastImportedSession' => $this->revert->get_last_import_session(),
];
}
/**
* Get labels of Elementor document types, Elementor Post types, WordPress Post types and Custom Post types.
*/
private function get_summary_titles() {
$summary_titles = [];
$document_types = Plugin::$instance->documents->get_document_types();
foreach ( $document_types as $name => $document_type ) {
$summary_titles['templates'][ $name ] = [
'single' => $document_type::get_title(),
'plural' => $document_type::get_plural_title(),
];
}
$elementor_post_types = ImportExportUtils::get_elementor_post_types();
$wp_builtin_post_types = ImportExportUtils::get_builtin_wp_post_types();
$post_types = array_merge( $elementor_post_types, $wp_builtin_post_types );
foreach ( $post_types as $post_type ) {
$post_type_object = get_post_type_object( $post_type );
$summary_titles['content'][ $post_type ] = [
'single' => $post_type_object->labels->singular_name ?? '',
'plural' => $post_type_object->label ?? '',
];
}
$custom_post_types = ImportExportUtils::get_registered_cpt_names();
if ( ! empty( $custom_post_types ) ) {
foreach ( $custom_post_types as $custom_post_type ) {
$custom_post_types_object = get_post_type_object( $custom_post_type );
// CPT data appears in two arrays:
// 1. content object: in order to show the export summary when completed in getLabel function
$summary_titles['content'][ $custom_post_type ] = [
'single' => $custom_post_types_object->labels->singular_name ?? '',
'plural' => $custom_post_types_object->label ?? '',
];
// 2. customPostTypes object: in order to actually export the data
$summary_titles['content']['customPostTypes'][ $custom_post_type ] = [
'single' => $custom_post_types_object->labels->singular_name ?? '',
'plural' => $custom_post_types_object->label ?? '',
];
}
}
$active_kit = Plugin::$instance->kits_manager->get_active_kit();
foreach ( $active_kit->get_tabs() as $key => $tab ) {
$summary_titles['site-settings'][ $key ] = $tab->get_title();
}
return $summary_titles;
}
public function should_show_revert_section( $last_imported_kit ) {
if ( empty( $last_imported_kit ) ) {
return false;
}
// TODO: BC - remove in the future
// The 'templates' runner was in core and moved to the Pro plugin. (Part of it still exits in the Core for BC)
// The runner that is in the core version is missing the revert functionality,
// therefore we shouldn't display the revert section if the import process done with the core version.
$is_import_templates_ran = isset( $last_imported_kit['runners']['templates'] );
if ( $this->has_pro() && $is_import_templates_ran ) {
$has_imported_templates = ! empty( $last_imported_kit['runners']['templates'] );
return $has_imported_templates;
}
return true;
}
public function has_pro(): bool {
return ElementorUtils::has_pro();
}
private function get_elementor_editor_home_page_url() {
if ( 'page' !== get_option( 'show_on_front' ) ) {
return '';
}
$frontpage_id = get_option( 'page_on_front' );
return $this->get_elementor_editor_page_url( $frontpage_id );
}
private function get_elementor_home_page_url() {
if ( 'page' !== get_option( 'show_on_front' ) ) {
return '';
}
$frontpage_id = get_option( 'page_on_front' );
return $this->get_elementor_page_url( $frontpage_id );
}
private function get_recently_edited_elementor_page_url() {
$query = ElementorUtils::get_recently_edited_posts_query( [ 'posts_per_page' => 1 ] );
if ( ! isset( $query->post ) ) {
return '';
}
return $this->get_elementor_page_url( $query->post->ID );
}
private function get_recently_edited_elementor_editor_page_url() {
$query = ElementorUtils::get_recently_edited_posts_query( [ 'posts_per_page' => 1 ] );
if ( ! isset( $query->post ) ) {
return '';
}
return $this->get_elementor_editor_page_url( $query->post->ID );
}
private function get_elementor_document( $page_id ) {
$document = Plugin::$instance->documents->get( $page_id );
if ( ! $document || ! $document->is_built_with_elementor() ) {
return false;
}
return $document;
}
private function get_elementor_page_url( $page_id ) {
$document = $this->get_elementor_document( $page_id );
return $document ? $document->get_preview_url() : '';
}
private function get_elementor_editor_page_url( $page_id ) {
$document = $this->get_elementor_document( $page_id );
return $document ? $document->get_edit_url() : '';
}
/**
* @param string $class
*
* @return bool
*/
public function is_third_party_class( $class ) {
$allowed_classes = [
'Elementor\\',
'ElementorPro\\',
'WP_',
'wp_',
];
foreach ( $allowed_classes as $allowed_class ) {
if ( str_starts_with( $class, $allowed_class ) ) {
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,334 @@
<?php
namespace Elementor\App\Modules\ImportExport\Processes;
use Elementor\App\Modules\ImportExport\Module;
use Elementor\App\Modules\ImportExport\Utils;
use Elementor\Core\Utils\Str;
use Elementor\Plugin;
use Elementor\App\Modules\ImportExport\Runners\Export\Elementor_Content;
use Elementor\App\Modules\ImportExport\Runners\Export\Export_Runner_Base;
use Elementor\App\Modules\ImportExport\Runners\Export\Plugins;
use Elementor\App\Modules\ImportExport\Runners\Export\Site_Settings;
use Elementor\App\Modules\ImportExport\Runners\Export\Taxonomies;
use Elementor\App\Modules\ImportExport\Runners\Export\Templates;
use Elementor\App\Modules\ImportExport\Runners\Export\Wp_Content;
class Export {
const ZIP_ARCHIVE_MODULE_MISSING = 'zip-archive-module-is-missing';
/**
* @var Export_Runner_Base[]
*/
protected $runners = [];
/**
* Selected content types to export.
*
* @var array
*/
private $settings_include;
/**
* The kit information. (e.g: title, description)
*
* @var array $export_data
*/
private $settings_kit_info;
/**
* Selected plugins to export.
* Contains the plugins essential data for export. (e.g: name, path, version, etc.)
*
* @var array
*/
private $settings_selected_plugins;
/**
* Selected custom post types to export.
*
* @var array
*/
private $settings_selected_custom_post_types;
/**
* The output data of the export process.
* Will be written into the manifest.json file.
*
* @var array
*/
private $manifest_data;
/**
* The zip archive object.
*
* @var \ZipArchive
*/
private $zip;
public function __construct( $settings = [] ) {
$this->settings_include = ! empty( $settings['include'] ) ? $settings['include'] : null;
$this->settings_kit_info = ! empty( $settings['kitInfo'] ) ? $settings['kitInfo'] : null;
$this->settings_selected_plugins = isset( $settings['plugins'] ) ? $settings['plugins'] : null;
$this->settings_selected_custom_post_types = isset( $settings['selectedCustomPostTypes'] ) ? $settings['selectedCustomPostTypes'] : null;
}
/**
* Register a runner.
*
* @param Export_Runner_Base $runner_instance
*/
public function register( Export_Runner_Base $runner_instance ) {
$this->runners[ $runner_instance::get_name() ] = $runner_instance;
}
public function register_default_runners() {
$this->register( new Site_Settings() );
$this->register( new Plugins() );
$this->register( new Templates() );
$this->register( new Taxonomies() );
$this->register( new Elementor_Content() );
$this->register( new Wp_Content() );
}
/**
* Execute the export process.
*
* @return array The export data output.
*
* @throws \Exception If no export runners have been specified.
*/
public function run() {
if ( empty( $this->runners ) ) {
throw new \Exception( 'Couldnt execute the export process because no export runners have been specified. Try again by specifying export runners.' );
}
$this->set_default_settings();
$this->init_zip_archive();
$this->init_manifest_data();
$data = [
'include' => $this->settings_include,
'selected_plugins' => $this->settings_selected_plugins,
'selected_custom_post_types' => $this->settings_selected_custom_post_types,
];
foreach ( $this->runners as $runner ) {
if ( $runner->should_export( $data ) ) {
$export_result = $runner->export( $data );
$this->handle_export_result( $export_result );
}
}
$this->add_json_file( 'manifest', $this->manifest_data );
$zip_file_name = $this->zip->filename;
$this->zip->close();
return [
'manifest' => $this->manifest_data,
'file_name' => $zip_file_name,
];
}
/**
* Set default settings for the export.
*/
private function set_default_settings() {
if ( ! is_array( $this->get_settings_include() ) ) {
$this->settings_include( $this->get_default_settings_include() );
}
if ( ! is_array( $this->get_settings_kit_info() ) ) {
$this->settings_kit_info( $this->get_default_settings_kit_info() );
}
if ( ! is_array( $this->get_settings_selected_custom_post_types() ) && in_array( 'content', $this->settings_include, true ) ) {
$this->settings_selected_custom_post_types( $this->get_default_settings_custom_post_types() );
}
if ( ! is_array( $this->get_settings_selected_plugins() ) && in_array( 'plugins', $this->settings_include, true ) ) {
$this->settings_selected_plugins( $this->get_default_settings_selected_plugins() );
}
}
public function settings_include( $include ) {
$this->settings_include = $include;
}
public function get_settings_include() {
return $this->settings_include;
}
private function settings_kit_info( $kit_info ) {
$this->settings_kit_info = $kit_info;
}
private function get_settings_kit_info() {
return $this->settings_kit_info;
}
public function settings_selected_custom_post_types( $selected_custom_post_types ) {
$this->settings_selected_custom_post_types = $selected_custom_post_types;
}
public function get_settings_selected_custom_post_types() {
return $this->settings_selected_custom_post_types;
}
public function settings_selected_plugins( $plugins ) {
$this->settings_selected_plugins = $plugins;
}
public function get_settings_selected_plugins() {
return $this->settings_selected_plugins;
}
/**
* Get the default settings of which content types should be exported.
*
* @return array
*/
private function get_default_settings_include() {
return [ 'templates', 'content', 'settings', 'plugins' ];
}
/**
* Get the default settings of the kit info.
*
* @return array
*/
private function get_default_settings_kit_info() {
return [
'title' => 'kit',
'description' => '',
];
}
/**
* Get the default settings of the plugins that should be exported.
*
* @return array{name: string, plugin:string, pluginUri: string, version: string}
*/
private function get_default_settings_selected_plugins() {
$installed_plugins = Plugin::$instance->wp->get_plugins();
return $installed_plugins->map( function ( $item, $key ) {
return [
'name' => $item['Name'],
'plugin' => $key,
'pluginUri' => $item['PluginURI'],
'version' => $item['Version'],
];
} )->all();
}
/**
* Get the default settings of all the custom post types that should be exported.
* Should be all the custom post types that are not built in to WordPress and not part of Elementor.
*
* @return array
*/
private function get_default_settings_custom_post_types() {
return Utils::get_registered_cpt_names();
}
/**
* Init the zip archive.
*/
private function init_zip_archive() {
if ( ! class_exists( '\ZipArchive' ) ) {
throw new \Error( static::ZIP_ARCHIVE_MODULE_MISSING );
}
$zip = new \ZipArchive();
$temp_dir = Plugin::$instance->uploads_manager->create_unique_dir();
$zip_file_name = $temp_dir . sanitize_title( $this->settings_kit_info['title'] ) . '.zip';
$zip->open( $zip_file_name, \ZipArchive::CREATE | \ZipArchive::OVERWRITE );
$this->zip = $zip;
}
/**
* Init the manifest data and add some basic info to it.
*/
private function init_manifest_data() {
$kit_post = Plugin::$instance->kits_manager->get_active_kit()->get_post();
$manifest_data = [
'name' => sanitize_title( $this->settings_kit_info['title'] ),
'title' => $this->settings_kit_info['title'],
'description' => $this->settings_kit_info['description'],
'author' => get_the_author_meta( 'display_name', $kit_post->post_author ),
'version' => Module::FORMAT_VERSION,
'elementor_version' => ELEMENTOR_VERSION,
'created' => gmdate( 'Y-m-d H:i:s' ),
'thumbnail' => get_the_post_thumbnail_url( $kit_post ),
'site' => get_site_url(),
];
$this->manifest_data = $manifest_data;
}
/**
* Handle the export process output.
* Add the manifest data from the runner to the manifest.json file.
* Create files according to the files array that should be exported by the runner.
*
* @param array $export_result
*/
private function handle_export_result( $export_result ) {
foreach ( $export_result['manifest'] as $data ) {
$this->manifest_data += $data;
}
if ( isset( $export_result['files']['path'] ) ) {
$export_result['files'] = [ $export_result['files'] ];
}
foreach ( $export_result['files'] as $file ) {
$file_extension = pathinfo( $file['path'], PATHINFO_EXTENSION );
if ( empty( $file_extension ) ) {
$this->add_json_file(
$file['path'],
$file['data']
);
} else {
$this->add_file(
$file['path'],
$file['data']
);
}
}
}
/**
* Add json file to the zip archive.
*
* @param string $path The relative path to the file.
* @param array $content The content of the file.
* @param int $json_flags
*/
private function add_json_file( $path, array $content, $json_flags = 0 ) {
if ( ! Str::ends_with( $path, '.json' ) ) {
$path .= '.json';
}
$this->add_file( $path, wp_json_encode( $content, $json_flags ) );
}
/**
* Add file to the zip archive.
*
* @param string $file
* @param string $content The content of the file.
*/
private function add_file( $file, $content ) {
$this->zip->addFromString( $file, $content );
}
}

View File

@@ -0,0 +1,807 @@
<?php
namespace Elementor\App\Modules\ImportExport\Processes;
use Elementor\App\Modules\ImportExport\Compatibility\Base_Adapter;
use Elementor\App\Modules\ImportExport\Compatibility\Envato;
use Elementor\App\Modules\ImportExport\Compatibility\Kit_Library;
use Elementor\App\Modules\ImportExport\Utils;
use Elementor\Core\Base\Document;
use Elementor\Core\Kits\Documents\Kit;
use Elementor\Plugin;
use Elementor\App\Modules\ImportExport\Runners\Import\Elementor_Content;
use Elementor\App\Modules\ImportExport\Runners\Import\Import_Runner_Base;
use Elementor\App\Modules\ImportExport\Runners\Import\Plugins;
use Elementor\App\Modules\ImportExport\Runners\Import\Site_Settings;
use Elementor\App\Modules\ImportExport\Runners\Import\Taxonomies;
use Elementor\App\Modules\ImportExport\Runners\Import\Templates;
use Elementor\App\Modules\ImportExport\Runners\Import\Wp_Content;
use Elementor\App\Modules\ImportExport\Module;
use Elementor\App\Modules\KitLibrary\Connect\Kit_Library as Kit_Library_Api;
class Import {
const MANIFEST_ERROR_KEY = 'manifest-error';
const ZIP_FILE_ERROR_KEY = 'invalid-zip-file';
const ZIP_ARCHIVE_ERROR_KEY = 'zip-archive-module-missing';
/**
* @var Import_Runner_Base[]
*/
protected $runners = [];
/**
* The session ID of the import process.
* This ID is uniquely generated for each import process (by the temp folder which contains the extracted kit files).
*
* @var string
*/
private $session_id;
/**
* The Kit ID.
*
* @var string
*/
private $kit_id;
/**
* Adapter for the kit compatibility.
*
* @var Base_Adapter[]
*/
private $adapters;
/**
* Document's data (elements and settings) that was imported during the process.
*
* @var array { [document_id] => { "elements": array , "settings": array } }
*/
private $documents_data = [];
/**
* Path to the extracted kit files.
*
* @var string
*/
private $extracted_directory_path;
/**
* Imported kit manifest.
*
* @var array
*/
private $manifest;
/**
* Imported kit site settings. (e.g: custom_colors, custom_typography, etc.)
*
* @var array
*/
private $site_settings;
/**
* Selected content types to import.
*
* @var array
*/
private $settings_include;
/**
* Referer of the import. (e.g: kit-library, local, etc.)
*
* @var string
*/
private $settings_referrer;
/**
* All the conflict between the exited templates and the kit templates.
*
* @var array
*/
private $settings_conflicts;
/**
* Selected elementor templates conditions to override.
*
* @var array
*/
private $settings_selected_override_conditions;
/**
* Selected custom post types to import.
*
* @var array
*/
private $settings_selected_custom_post_types;
/**
* Selected plugins to import.
*
* @var array
*/
private $settings_selected_plugins;
/**
* The imported data output.
*
* @var array
*/
private $imported_data = [];
/**
* The metadata output of the import runners.
* Will be saved in the import_session and will be used to revert the import process.
*
* @var array
*/
private $runners_import_metadata = [];
/**
* @param string $path session_id | zip_file_path
* @param array $settings Use to determine which content to import.
* (e.g: include, selected_plugins, selected_cpt, selected_override_conditions, etc.)
* @param array|null $old_instance An array of old instance parameters that will be used for creating new instance.
* We are using it for quick creation of the instance when the import process is being split into chunks.
* @throws \Exception
*/
public function __construct( string $path, array $settings = [], array $old_instance = null ) {
if ( ! empty( $old_instance ) ) {
$this->set_import_object( $old_instance );
} else {
if ( is_file( $path ) ) {
$this->extracted_directory_path = $this->extract_zip( $path );
} else {
$elementor_tmp_directory = Plugin::$instance->uploads_manager->get_temp_dir();
$path = $elementor_tmp_directory . basename( $path );
if ( ! is_dir( $path ) ) {
throw new \Exception( 'Couldnt execute the import process because the import session does not exist.' );
}
$this->extracted_directory_path = $path . '/';
}
$this->session_id = basename( $this->extracted_directory_path );
$this->kit_id = $settings['id'] ?? '';
$this->settings_referrer = ! empty( $settings['referrer'] ) ? $settings['referrer'] : 'local';
$this->settings_include = ! empty( $settings['include'] ) ? $settings['include'] : null;
// Using isset and not empty is important since empty array is valid option.
$this->settings_selected_override_conditions = $settings['overrideConditions'] ?? null;
$this->settings_selected_custom_post_types = $settings['selectedCustomPostTypes'] ?? null;
$this->settings_selected_plugins = $settings['plugins'] ?? null;
$this->manifest = $this->read_manifest_json();
$this->site_settings = $this->read_site_settings_json();
$this->set_default_settings();
}
add_filter( 'wp_php_error_args', function ( $args, $error ) {
return $this->filter_php_error_args( $args, $error );
}, 10, 2 );
}
/**
* Set the import object parameters.
*
* @param array $instance
* @return void
*/
private function set_import_object( array $instance ) {
$this->session_id = $instance['session_id'];
$instance_data = $instance['instance_data'];
$this->extracted_directory_path = $instance_data['extracted_directory_path'];
$this->runners = $instance_data['runners'];
$this->adapters = $instance_data['adapters'];
$this->manifest = $instance_data['manifest'];
$this->site_settings = $instance_data['site_settings'];
$this->settings_include = $instance_data['settings_include'];
$this->settings_referrer = $instance_data['settings_referrer'];
$this->settings_conflicts = $instance_data['settings_conflicts'];
$this->settings_selected_override_conditions = $instance_data['settings_selected_override_conditions'];
$this->settings_selected_custom_post_types = $instance_data['settings_selected_custom_post_types'];
$this->settings_selected_plugins = $instance_data['settings_selected_plugins'];
$this->documents_data = $instance_data['documents_data'];
$this->imported_data = $instance_data['imported_data'];
$this->runners_import_metadata = $instance_data['runners_import_metadata'];
}
/**
* Creating a new instance of the import process by the id of the old import session.
*
* @param string $session_id
*
* @return Import
* @throws \Exception
*/
public static function from_session( string $session_id ): Import {
$import_sessions = Utils::get_import_sessions();
if ( ! $import_sessions || ! isset( $import_sessions[ $session_id ] ) ) {
throw new \Exception( 'Couldnt execute the import process because the import session does not exist.' );
}
$import_session = $import_sessions[ $session_id ];
return new self( $session_id, [], $import_session );
}
/**
* Register a runner.
* Be aware that the runner will be executed in the order of registration, the order is crucial for the import process.
*
* @param Import_Runner_Base $runner_instance
*/
public function register( Import_Runner_Base $runner_instance ) {
$this->runners[ $runner_instance::get_name() ] = $runner_instance;
}
public function register_default_runners() {
$this->register( new Site_Settings() );
$this->register( new Plugins() );
$this->register( new Templates() );
$this->register( new Taxonomies() );
$this->register( new Elementor_Content() );
$this->register( new Wp_Content() );
}
/**
* Set default settings for the import.
*/
private function set_default_settings() {
if ( ! is_array( $this->get_settings_include() ) ) {
$this->settings_include( $this->get_default_settings_include() );
}
if ( ! is_array( $this->get_settings_conflicts() ) ) {
$this->settings_conflicts( $this->get_default_settings_conflicts() );
}
if ( ! is_array( $this->get_settings_selected_override_conditions() ) ) {
$this->settings_selected_override_conditions( $this->get_default_settings_override_conditions() );
}
if ( ! is_array( $this->get_settings_selected_custom_post_types() ) ) {
$this->settings_selected_custom_post_types( $this->get_default_settings_custom_post_types() );
}
if ( ! is_array( $this->get_settings_selected_plugins() ) ) {
$this->settings_selected_plugins( $this->get_default_settings_plugins() );
}
}
/**
* Execute the import process.
*
* @return array The imported data output.
*
* @throws \Exception If no import runners have been specified.
*/
public function run() {
if ( empty( $this->runners ) ) {
throw new \Exception( 'Couldnt execute the import process because no import runners have been specified. Try again by specifying import runners.' );
}
$data = [
'session_id' => $this->session_id,
'include' => $this->settings_include,
'manifest' => $this->manifest,
'site_settings' => $this->site_settings,
'selected_plugins' => $this->settings_selected_plugins,
'extracted_directory_path' => $this->extracted_directory_path,
'selected_custom_post_types' => $this->settings_selected_custom_post_types,
];
$this->init_import_session();
remove_filter( 'elementor/document/save/data', [ Plugin::$instance->modules_manager->get_modules( 'content-sanitizer' ), 'sanitize_content' ] );
add_filter( 'elementor/document/save/data', [ $this, 'prevent_saving_elements_on_post_creation' ], 10, 2 );
// Set the Request's state as an Elementor upload request, in order to support unfiltered file uploads.
Plugin::$instance->uploads_manager->set_elementor_upload_state( true );
foreach ( $this->runners as $runner ) {
if ( $runner->should_import( $data ) ) {
$import = $runner->import( $data, $this->imported_data );
$this->imported_data = array_merge_recursive( $this->imported_data, $import );
$this->runners_import_metadata[ $runner::get_name() ] = $runner->get_import_session_metadata();
}
}
// After the upload complete, set the elementor upload state back to false.
Plugin::$instance->uploads_manager->set_elementor_upload_state( false );
remove_filter( 'elementor/document/save/data', [ $this, 'prevent_saving_elements_on_post_creation' ], 10 );
$this->finalize_import_session_option();
$this->save_elements_of_imported_posts();
Plugin::$instance->uploads_manager->remove_file_or_dir( $this->extracted_directory_path );
return $this->imported_data;
}
/**
* Run specific runner by runner_name
*
* @param string $runner_name
*
* @return array
*
* @throws \Exception If no export runners have been specified.
*/
public function run_runner( string $runner_name ): array {
if ( empty( $this->runners ) ) {
throw new \Exception( 'Couldnt execute the import process because no import runners have been specified. Try again by specifying import runners.' );
}
$data = [
'session_id' => $this->session_id,
'include' => $this->settings_include,
'manifest' => $this->manifest,
'site_settings' => $this->site_settings,
'selected_plugins' => $this->settings_selected_plugins,
'extracted_directory_path' => $this->extracted_directory_path,
'selected_custom_post_types' => $this->settings_selected_custom_post_types,
];
add_filter( 'elementor/document/save/data', [ $this, 'prevent_saving_elements_on_post_creation' ], 10, 2 );
// Set the Request's state as an Elementor upload request, in order to support unfiltered file uploads.
Plugin::$instance->uploads_manager->set_elementor_upload_state( true );
$runner = $this->runners[ $runner_name ];
if ( empty( $runner ) ) {
throw new \Exception( 'Couldnt execute the import process because the import runner was not found. Try again by specifying an import runner.' );
}
if ( $runner->should_import( $data ) ) {
$import = $runner->import( $data, $this->imported_data );
$this->imported_data = array_merge_recursive( $this->imported_data, $import );
$this->runners_import_metadata[ $runner::get_name() ] = $runner->get_import_session_metadata();
}
// After the upload complete, set the elementor upload state back to false.
Plugin::$instance->uploads_manager->set_elementor_upload_state( false );
remove_filter( 'elementor/document/save/data', [ $this, 'prevent_saving_elements_on_post_creation' ], 10 );
$is_last_runner = key( array_slice( $this->runners, -1, 1, true ) ) === $runner_name;
if ( $is_last_runner ) {
$this->finalize_import_session_option();
$this->save_elements_of_imported_posts();
} else {
$this->update_instance_data_in_import_session_option();
}
return [
'status' => 'success',
'runner' => $runner_name,
];
}
/**
* Create and save all the instance data to the import sessions option.
*
* @return void
*/
public function init_import_session( $save_instance_data = false ) {
$import_sessions = Utils::get_import_sessions( true );
$import_sessions[ $this->session_id ] = [
'session_id' => $this->session_id,
'kit_title' => $this->manifest['title'] ?? '',
'kit_name' => $this->manifest['name'] ?? '',
'kit_thumbnail' => $this->get_kit_thumbnail(),
'kit_source' => $this->settings_referrer,
'user_id' => get_current_user_id(),
'start_timestamp' => current_time( 'timestamp' ),
];
if ( $save_instance_data ) {
$import_sessions[ $this->session_id ]['instance_data'] = [
'extracted_directory_path' => $this->extracted_directory_path,
'runners' => $this->runners,
'adapters' => $this->adapters,
'manifest' => $this->manifest,
'site_settings' => $this->site_settings,
'settings_include' => $this->settings_include,
'settings_referrer' => $this->settings_referrer,
'settings_conflicts' => $this->settings_conflicts,
'settings_selected_override_conditions' => $this->settings_selected_override_conditions,
'settings_selected_custom_post_types' => $this->settings_selected_custom_post_types,
'settings_selected_plugins' => $this->settings_selected_plugins,
'documents_data' => $this->documents_data,
'imported_data' => $this->imported_data,
'runners_import_metadata' => $this->runners_import_metadata,
];
}
update_option( Module::OPTION_KEY_ELEMENTOR_IMPORT_SESSIONS, $import_sessions, false );
}
/**
* Get the Kit thumbnail, goes to the home page thumbnail if main doesn't exist
*
* @return string
*/
private function get_kit_thumbnail(): string {
if ( ! empty( $this->manifest['thumbnail'] ) ) {
return $this->manifest['thumbnail'];
}
if ( empty( $this->kit_id ) ) {
return '';
}
$api = new Kit_Library_Api();
$kit = $api->get_by_id( $this->kit_id );
if ( is_wp_error( $kit ) ) {
return '';
}
return $kit->thumbnail;
}
public function get_runners_name(): array {
return array_keys( $this->runners );
}
public function get_manifest() {
return $this->manifest;
}
public function get_extracted_directory_path() {
return $this->extracted_directory_path;
}
public function get_session_id() {
return $this->session_id;
}
public function get_adapters() {
return $this->adapters;
}
public function get_imported_data() {
return $this->imported_data;
}
/**
* Get settings by key.
* Used for backward compatibility.
*
* @param string $key The key of the setting.
*/
public function get_settings( $key ) {
switch ( $key ) {
case 'include':
return $this->get_settings_include();
case 'overrideConditions':
return $this->get_settings_selected_override_conditions();
case 'selectedCustomPostTypes':
return $this->get_settings_selected_custom_post_types();
case 'plugins':
return $this->get_settings_selected_plugins();
default:
return [];
}
}
public function settings_include( array $settings_include ) {
$this->settings_include = $settings_include;
return $this;
}
public function get_settings_include() {
return $this->settings_include;
}
public function settings_referrer( $settings_referrer ) {
$this->settings_referrer = $settings_referrer;
return $this;
}
public function get_settings_referrer() {
return $this->settings_referrer;
}
public function settings_conflicts( array $settings_conflicts ) {
$this->settings_conflicts = $settings_conflicts;
return $this;
}
public function get_settings_conflicts() {
return $this->settings_conflicts;
}
public function settings_selected_override_conditions( array $settings_selected_override_conditions ) {
$this->settings_selected_override_conditions = $settings_selected_override_conditions;
return $this;
}
public function get_settings_selected_override_conditions() {
return $this->settings_selected_override_conditions;
}
public function settings_selected_custom_post_types( array $settings_selected_custom_post_types ) {
$this->settings_selected_custom_post_types = $settings_selected_custom_post_types;
return $this;
}
public function get_settings_selected_custom_post_types() {
return $this->settings_selected_custom_post_types;
}
public function settings_selected_plugins( array $settings_selected_plugins ) {
$this->settings_selected_plugins = $settings_selected_plugins;
return $this;
}
public function get_settings_selected_plugins() {
return $this->settings_selected_plugins;
}
/**
* Prevent saving elements on elementor post creation.
*
* @param array $data
* @param Document $document
*
* @return array
*/
public function prevent_saving_elements_on_post_creation( array $data, Document $document ) {
if ( isset( $data['elements'] ) ) {
$this->documents_data[ $document->get_main_id() ] = [ 'elements' => $data['elements'] ];
$data['elements'] = [];
}
if ( isset( $data['settings'] ) ) {
$this->documents_data[ $document->get_main_id() ]['settings'] = $data['settings'];
}
return $data;
}
/**
* Extract the zip file.
*
* @param string $zip_path The path to the zip file.
* @return string The extracted directory path.
*/
private function extract_zip( $zip_path ) {
$extraction_result = Plugin::$instance->uploads_manager->extract_and_validate_zip( $zip_path, [ 'json', 'xml' ] );
if ( is_wp_error( $extraction_result ) ) {
if ( isset( $extraction_result->errors['zip_error'] ) ) {
throw new \Error( static::ZIP_ARCHIVE_ERROR_KEY );
}
throw new \Error( static::ZIP_FILE_ERROR_KEY );
}
return $extraction_result['extraction_directory'];
}
/**
* Get the manifest file from the extracted directory and adapt it if needed.
*
* @return string The manifest file content.
*/
private function read_manifest_json() {
$manifest = Utils::read_json_file( $this->extracted_directory_path . 'manifest' );
if ( ! $manifest ) {
Plugin::$instance->logger->get_logger()->error( static::MANIFEST_ERROR_KEY );
throw new \Error( static::ZIP_FILE_ERROR_KEY );
}
$this->init_adapters( $manifest );
foreach ( $this->adapters as $adapter ) {
$manifest = $adapter->adapt_manifest( $manifest );
}
return $manifest;
}
/**
* Init the adapters and determine which ones to use.
*
* @param array $manifest_data The manifest file content.
*/
private function init_adapters( array $manifest_data ) {
$this->adapters = [];
/** @var Base_Adapter[] $adapter_types */
$adapter_types = [ Envato::class, Kit_Library::class ];
foreach ( $adapter_types as $adapter_type ) {
if ( $adapter_type::is_compatibility_needed( $manifest_data, [ 'referrer' => $this->get_settings_referrer() ] ) ) {
$this->adapters[] = new $adapter_type( $this );
}
}
}
/**
* Get the site settings file from the extracted directory and adapt it if needed.
*
* @return string The site settings file content.
*/
private function read_site_settings_json() {
$site_settings = Utils::read_json_file( $this->extracted_directory_path . 'site-settings' );
foreach ( $this->adapters as $adapter ) {
$site_settings = $adapter->adapt_site_settings( $site_settings, $this->manifest, $this->extracted_directory_path );
}
return $site_settings;
}
/**
* Get all the custom post types in the kit.
*
* @return array Custom post types names.
*/
private function get_default_settings_custom_post_types() {
if ( empty( $this->manifest['custom-post-type-title'] ) ) {
return [];
}
$manifest_post_types = array_keys( $this->manifest['custom-post-type-title'] );
return array_diff( $manifest_post_types, Utils::get_builtin_wp_post_types() );
}
/**
* Get the default settings of elementor templates conditions to override.
*
* @return array
*/
private function get_default_settings_conflicts() {
if ( empty( $this->manifest['templates'] ) ) {
return [];
}
return apply_filters( 'elementor/import/get_default_settings_conflicts', [], $this->manifest['templates'] );
}
/**
* Get the default settings of elementor templates conditions to override.
*
* @return array
*/
private function get_default_settings_override_conditions() {
if ( empty( $this->settings_conflicts ) ) {
return [];
}
return array_keys( $this->settings_conflicts );
}
/**
* Get the default settings of the plugins that should be imported.
*
* @return array
*/
private function get_default_settings_plugins() {
return ! empty( $this->manifest['plugins'] ) ? $this->manifest['plugins'] : [];
}
/**
* Get the default settings of which content types should be imported.
*
* @return array
*/
private function get_default_settings_include() {
return [ 'templates', 'plugins', 'content', 'settings' ];
}
/**
* Get the data that requires updating/replacement when imported.
*
* @return array{post_ids: array, term_ids: array}
*/
private function get_imported_data_replacements() : array {
return [
'post_ids' => Utils::map_old_new_post_ids( $this->imported_data ),
'term_ids' => Utils::map_old_new_term_ids( $this->imported_data ),
];
}
/**
* Save the prevented elements on elementor post creation elements.
* Handle the replacement of all the dynamic content of the elements that probably have been changed during the import.
*/
private function save_elements_of_imported_posts() {
$imported_data_replacements = $this->get_imported_data_replacements();
foreach ( $this->documents_data as $new_id => $data ) {
$document = Plugin::$instance->documents->get( $new_id );
if ( isset( $data['elements'] ) ) {
$data['elements'] = $document->on_import_update_dynamic_content( $data['elements'], $imported_data_replacements );
}
if ( isset( $data['settings'] ) ) {
if ( $document instanceof Kit ) {
// Without post_status certain tabs in the Kit will not save properly.
$data['settings']['post_status'] = get_post_status( $new_id );
}
$data['settings'] = $document->on_import_update_settings( $data['settings'], $imported_data_replacements );
}
$document->save( $data );
}
}
private function update_instance_data_in_import_session_option() {
$import_sessions = Utils::get_import_sessions();
$import_sessions[ $this->session_id ]['instance_data']['documents_data'] = $this->documents_data;
$import_sessions[ $this->session_id ]['instance_data']['imported_data'] = $this->imported_data;
$import_sessions[ $this->session_id ]['instance_data']['runners_import_metadata'] = $this->runners_import_metadata;
update_option( Module::OPTION_KEY_ELEMENTOR_IMPORT_SESSIONS, $import_sessions, false );
}
public function finalize_import_session_option() {
$import_sessions = Utils::get_import_sessions();
if ( ! isset( $import_sessions[ $this->session_id ] ) ) {
return;
}
unset( $import_sessions[ $this->session_id ]['instance_data'] );
$import_sessions[ $this->session_id ]['end_timestamp'] = current_time( 'timestamp' );
$import_sessions[ $this->session_id ]['runners'] = $this->runners_import_metadata;
update_option( Module::OPTION_KEY_ELEMENTOR_IMPORT_SESSIONS, $import_sessions, false );
}
/**
* Filter the php error args and return 408 status code if the error is a timeout.
*
* @param array $args
* @param array $error
* @return array
*/
private function filter_php_error_args( $args, $error ) {
if ( strpos( $error['message'], 'Maximum execution time' ) !== false ) {
$args['response'] = 408;
}
return $args;
}
}

View File

@@ -0,0 +1,179 @@
<?php
namespace Elementor\App\Modules\ImportExport\Processes;
use Elementor\App\Modules\ImportExport\Module;
use Elementor\App\Modules\ImportExport\Runners\Revert\Elementor_Content;
use Elementor\App\Modules\ImportExport\Runners\Revert\Revert_Runner_Base;
use Elementor\App\Modules\ImportExport\Runners\Revert\Plugins;
use Elementor\App\Modules\ImportExport\Runners\Revert\Site_Settings;
use Elementor\App\Modules\ImportExport\Runners\Revert\Taxonomies;
use Elementor\App\Modules\ImportExport\Runners\Revert\Templates;
use Elementor\App\Modules\ImportExport\Runners\Revert\Wp_Content;
use Elementor\App\Modules\ImportExport\Utils;
class Revert {
/**
* @var Revert_Runner_Base[]
*/
protected $runners = [];
private $import_sessions;
private $revert_sessions;
/**
* @throws \Exception
*/
public function __construct() {
$this->import_sessions = self::get_import_sessions();
$this->revert_sessions = self::get_revert_sessions();
}
/**
* Register a runner.
*
* @param Revert_Runner_Base $runner_instance
*/
public function register( Revert_Runner_Base $runner_instance ) {
$this->runners[ $runner_instance::get_name() ] = $runner_instance;
}
public function register_default_runners() {
$this->register( new Site_Settings() );
$this->register( new Plugins() );
$this->register( new Templates() );
$this->register( new Taxonomies() );
$this->register( new Elementor_Content() );
$this->register( new Wp_Content() );
}
/**
* Execute the revert process.
*
* @throws \Exception If no revert runners have been specified.
*/
public function run() {
if ( empty( $this->runners ) ) {
throw new \Exception( 'Couldnt execute the revert process because no revert runners have been specified. Try again by specifying revert runners.' );
}
$import_session = $this->get_last_import_session();
if ( empty( $import_session ) ) {
throw new \Exception( 'Couldnt execute the revert process because there are no import sessions to revert.' );
}
// fallback if the import session failed and doesn't have the runners metadata
if ( ! isset( $import_session['runners'] ) && isset( $import_session['instance_data'] ) ) {
$import_session['runners'] = $import_session['instance_data']['runners_import_metadata'] ?? [];
}
foreach ( $this->runners as $runner ) {
if ( $runner->should_revert( $import_session ) ) {
$runner->revert( $import_session );
}
}
$this->revert_attachments( $import_session );
$this->delete_last_import_data();
}
public static function get_import_sessions() {
$import_sessions = Utils::get_import_sessions();
if ( ! $import_sessions ) {
return [];
}
usort( $import_sessions, function( $a, $b ) {
return strcmp( $a['start_timestamp'], $b['start_timestamp'] );
} );
return $import_sessions;
}
public static function get_revert_sessions() {
$revert_sessions = get_option( Module::OPTION_KEY_ELEMENTOR_REVERT_SESSIONS );
if ( ! $revert_sessions ) {
return [];
}
return $revert_sessions;
}
public function get_last_import_session() {
$import_sessions = $this->import_sessions;
if ( empty( $import_sessions ) ) {
return [];
}
return end( $import_sessions );
}
public function get_penultimate_import_session() {
$sessions_data = $this->import_sessions;
$penultimate_element_value = [];
if ( empty( $sessions_data ) ) {
return [];
}
end( $sessions_data );
prev( $sessions_data );
if ( ! is_null( key( $sessions_data ) ) ) {
$penultimate_element_value = current( $sessions_data );
}
return $penultimate_element_value;
}
private function delete_last_import_data() {
$import_sessions = $this->import_sessions;
$revert_sessions = $this->revert_sessions;
$reverted_session = array_pop( $import_sessions );
$revert_sessions[] = [
'session_id' => $reverted_session['session_id'],
'kit_title' => $reverted_session['kit_title'],
'kit_name' => $reverted_session['kit_name'],
'kit_thumbnail' => $reverted_session['kit_thumbnail'],
'source' => $reverted_session['kit_source'],
'user_id' => get_current_user_id(),
'import_timestamp' => $reverted_session['start_timestamp'],
'revert_timestamp' => current_time( 'timestamp' ),
];
update_option( Module::OPTION_KEY_ELEMENTOR_IMPORT_SESSIONS, $import_sessions, false );
update_option( Module::OPTION_KEY_ELEMENTOR_REVERT_SESSIONS, $revert_sessions, false );
$this->import_sessions = $import_sessions;
$this->revert_sessions = $revert_sessions;
}
private function revert_attachments( $data ) {
$query_args = [
'post_type' => 'attachment',
'post_status' => 'any',
'posts_per_page' => -1,
'meta_query' => [
[
'key' => Module::META_KEY_ELEMENTOR_IMPORT_SESSION_ID,
'value' => $data['session_id'],
],
],
];
$query = new \WP_Query( $query_args );
foreach ( $query->posts as $post ) {
wp_delete_attachment( $post->ID, true );
}
}
}

View File

@@ -0,0 +1,144 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Export;
use Elementor\App\Modules\ImportExport\Utils as ImportExportUtils;
use Elementor\Plugin;
class Elementor_Content extends Export_Runner_Base {
private $page_on_front_id;
public function __construct() {
$this->init_page_on_front_data();
}
public static function get_name() : string {
return 'elementor-content';
}
public function should_export( array $data ) {
return (
isset( $data['include'] ) &&
in_array( 'content', $data['include'], true )
);
}
public function export( array $data ) {
$elementor_post_types = ImportExportUtils::get_elementor_post_types();
$files = [];
$manifest = [];
foreach ( $elementor_post_types as $post_type ) {
$export = $this->export_elementor_post_type( $post_type );
$files = array_merge( $files, $export['files'] );
$manifest[ $post_type ] = $export['manifest_data'];
}
$manifest_data['content'] = $manifest;
return [
'files' => $files,
'manifest' => [
$manifest_data,
],
];
}
private function export_elementor_post_type( $post_type ) {
$query_args = [
'post_type' => $post_type,
'post_status' => 'publish',
'posts_per_page' => -1,
'meta_query' => [
[
'key' => static::META_KEY_ELEMENTOR_EDIT_MODE,
'compare' => 'EXISTS',
],
[
'key' => '_elementor_data',
'compare' => 'EXISTS',
],
[
'key' => '_elementor_data',
'compare' => '!=',
'value' => '[]',
],
],
];
$query = new \WP_Query( $query_args );
if ( empty( $query ) ) {
return [
'files' => [],
'manifest_data' => [],
];
}
$post_type_taxonomies = $this->get_post_type_taxonomies( $post_type );
$manifest_data = [];
$files = [];
foreach ( $query->posts as $post ) {
$document = Plugin::$instance->documents->get( $post->ID );
$terms = ! empty( $post_type_taxonomies ) ? $this->get_post_terms( $post->ID, $post_type_taxonomies ) : [];
$post_manifest_data = [
'title' => $post->post_title,
'excerpt' => $post->post_excerpt,
'doc_type' => $document->get_name(),
'thumbnail' => get_the_post_thumbnail_url( $post ),
'url' => get_permalink( $post ),
'terms' => $terms,
];
if ( $post->ID === $this->page_on_front_id ) {
$post_manifest_data['show_on_front'] = true;
}
$manifest_data[ $post->ID ] = $post_manifest_data;
$files[] = [
'path' => 'content/' . $post_type . '/' . $post->ID,
'data' => $document->get_export_data(),
];
}
return [
'files' => $files,
'manifest_data' => $manifest_data,
];
}
private function get_post_type_taxonomies( $post_type ) {
return get_object_taxonomies( $post_type );
}
private function get_post_terms( $post_id, array $taxonomies ) {
$terms = wp_get_object_terms( $post_id, $taxonomies );
$result = [];
foreach ( $terms as $term ) {
$result[] = [
'term_id' => $term->term_id,
'taxonomy' => $term->taxonomy,
'slug' => $term->slug,
];
}
return $result;
}
private function init_page_on_front_data() {
$show_page_on_front = 'page' === get_option( 'show_on_front' );
if ( $show_page_on_front ) {
$this->page_on_front_id = (int) get_option( 'page_on_front' );
}
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Export;
use Elementor\App\Modules\ImportExport\Runners\Runner_Interface;
abstract class Export_Runner_Base implements Runner_Interface {
/**
* By the passed data we should decide if we want to run the export function of the runner or not.
*
* @param array $data
*
* @return bool
*/
abstract public function should_export( array $data );
/**
* Main function of the runner export process.
*
* @param array $data Necessary data for the export process.
*
* @return array{files: array, manifest: array}
* The files that should be part of the kit and the relevant manifest data.
*/
abstract public function export( array $data );
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Export;
class Plugins extends Export_Runner_Base {
public static function get_name() : string {
return 'plugins';
}
public function should_export( array $data ) {
return (
isset( $data['include'] ) &&
in_array( 'plugins', $data['include'], true ) &&
is_array( $data['selected_plugins'] )
);
}
public function export( array $data ) {
$manifest_data['plugins'] = $data['selected_plugins'];
return [
'manifest' => [
$manifest_data,
],
'files' => [],
];
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Export;
use Elementor\Plugin;
class Site_Settings extends Export_Runner_Base {
public static function get_name() : string {
return 'site-settings';
}
public function should_export( array $data ) {
return (
isset( $data['include'] ) &&
in_array( 'settings', $data['include'], true )
);
}
public function export( array $data ) {
$kit = Plugin::$instance->kits_manager->get_active_kit();
$kit_data = $kit->get_export_data();
$kit_tabs = $kit->get_tabs();
$excluded_kit_settings_keys = [
'site_name',
'site_description',
'site_logo',
'site_favicon',
];
foreach ( $excluded_kit_settings_keys as $setting_key ) {
unset( $kit_data['settings'][ $setting_key ] );
}
unset( $kit_tabs['settings-site-identity'] );
$kit_tabs = array_keys( $kit_tabs );
$manifest_data['site-settings'] = $kit_tabs;
return [
'files' => [
'path' => 'site-settings',
'data' => $kit_data,
],
'manifest' => [
$manifest_data,
],
];
}
}

View File

@@ -0,0 +1,118 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Export;
use Elementor\App\Modules\ImportExport\Utils as ImportExportUtils;
class Taxonomies extends Export_Runner_Base {
public static function get_name() : string {
return 'taxonomies';
}
public function should_export( array $data ) {
return (
isset( $data['include'] ) &&
in_array( 'content', $data['include'], true )
);
}
public function export( array $data ) {
$wp_builtin_post_types = ImportExportUtils::get_builtin_wp_post_types();
$selected_custom_post_types = isset( $data['selected_custom_post_types'] ) ? $data['selected_custom_post_types'] : [];
$post_types = array_merge( $wp_builtin_post_types, $selected_custom_post_types );
$export = $this->export_taxonomies( $post_types );
$manifest_data['taxonomies'] = $export['manifest'];
return [
'files' => $export['files'],
'manifest' => [
$manifest_data,
],
];
}
private function export_taxonomies( array $post_types ) {
$files = [];
$manifest = [];
$taxonomies = get_taxonomies();
foreach ( $taxonomies as $taxonomy ) {
$taxonomy_post_types = get_taxonomy( $taxonomy )->object_type;
$intersected_post_types = array_intersect( $taxonomy_post_types, $post_types );
if ( empty( $intersected_post_types ) ) {
continue;
}
$data = $this->export_terms( $taxonomy );
if ( empty( $data ) ) {
continue;
}
foreach ( $intersected_post_types as $post_type ) {
$manifest[ $post_type ][] = $taxonomy;
}
$files[] = [
'path' => 'taxonomies/' . $taxonomy,
'data' => $data,
];
}
return [
'files' => $files,
'manifest' => $manifest,
];
}
private function export_terms( $taxonomy ) {
$terms = get_terms( [
'taxonomy' => (array) $taxonomy,
'hide_empty' => true,
'get' => 'all',
] );
$ordered_terms = $this->order_terms( $terms );
if ( empty( $ordered_terms ) ) {
return [];
}
$data = [];
foreach ( $ordered_terms as $term ) {
$data[] = [
'term_id' => $term->term_id,
'name' => $term->name,
'slug' => $term->slug,
'taxonomy' => $term->taxonomy,
'description' => $term->description,
'parent' => $term->parent,
];
}
return $data;
}
// Put terms in order with no child going before its parent.
private function order_terms( array $terms ) {
$ordered_terms = [];
while ( $term = array_shift( $terms ) ) {
$is_top_level = 0 === $term->parent;
$is_parent_exits = isset( $ordered_terms[ $term->parent ] );
if ( $is_top_level || $is_parent_exits ) {
$ordered_terms[ $term->term_id ] = $term;
} else {
$terms[] = $term;
}
}
return $ordered_terms;
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Export;
use Elementor\Core\Base\Document;
use Elementor\Plugin;
use Elementor\TemplateLibrary\Source_Local;
use Elementor\Utils;
class Templates extends Export_Runner_Base {
public static function get_name() : string {
return 'templates';
}
public function should_export( array $data ) {
return (
Utils::has_pro() &&
isset( $data['include'] ) &&
in_array( 'templates', $data['include'], true )
);
}
public function export( array $data ) {
$template_types = array_values( Source_Local::get_template_types() );
$query_args = [
'post_type' => Source_Local::CPT,
'post_status' => 'publish',
'posts_per_page' => -1,
'meta_query' => [
[
'key' => Document::TYPE_META_KEY,
'value' => $template_types,
],
],
];
$templates_query = new \WP_Query( $query_args );
$templates_manifest_data = [];
$files = [];
foreach ( $templates_query->posts as $template_post ) {
$template_id = $template_post->ID;
$template_document = Plugin::$instance->documents->get( $template_id );
$templates_manifest_data[ $template_id ] = $template_document->get_export_summary();
$files[] = [
'path' => 'templates/' . $template_id,
'data' => $template_document->get_export_data(),
];
}
$manifest_data['templates'] = $templates_manifest_data;
return [
'files' => $files,
'manifest' => [
$manifest_data,
],
];
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Export;
use Elementor\App\Modules\ImportExport\Utils as ImportExportUtils;
use Elementor\Core\Utils\ImportExport\WP_Exporter;
class Wp_Content extends Export_Runner_Base {
public static function get_name() : string {
return 'wp-content';
}
public function should_export( array $data ) {
return (
isset( $data['include'] ) &&
in_array( 'content', $data['include'], true )
);
}
public function export( array $data ) {
$post_types = ImportExportUtils::get_builtin_wp_post_types();
$custom_post_types = isset( $data['selected_custom_post_types'] ) ? $data['selected_custom_post_types'] : [];
$files = [];
$manifest_data = [];
foreach ( $post_types as $post_type ) {
$export = $this->export_wp_post_type( $post_type );
$files[] = $export['file'];
$manifest_data['wp-content'][ $post_type ] = $export['manifest_data'];
}
foreach ( $custom_post_types as $post_type ) {
$export = $this->export_wp_post_type( $post_type );
$files[] = $export['file'];
$manifest_data['wp-content'][ $post_type ] = $export['manifest_data'];
$post_type_object = get_post_type_object( $post_type );
$manifest_data['custom-post-type-title'][ $post_type ] = [
'name' => $post_type_object->name,
'label' => $post_type_object->label,
];
}
return [
'files' => $files,
'manifest' => [
$manifest_data,
],
];
}
private function export_wp_post_type( $post_type ) {
$wp_exporter = new WP_Exporter( [
'content' => $post_type,
'status' => 'publish',
'limit' => 20,
'meta_query' => [
[
'key' => static::META_KEY_ELEMENTOR_EDIT_MODE,
'compare' => 'NOT EXISTS',
],
],
'include_post_featured_image_as_attachment' => true,
] );
$export_result = $wp_exporter->run();
return [
'file' => [
'path' => 'wp-content/' . $post_type . '/' . $post_type . '.xml',
'data' => $export_result['xml'],
],
'manifest_data' => $export_result['ids'],
];
}
}

View File

@@ -0,0 +1,159 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Import;
use Elementor\App\Modules\ImportExport\Utils as ImportExportUtils;
use Elementor\Plugin;
class Elementor_Content extends Import_Runner_Base {
private $show_page_on_front;
private $page_on_front_id;
private $import_session_id;
public function __construct() {
$this->init_page_on_front_data();
}
public static function get_name() : string {
return 'elementor-content';
}
public function should_import( array $data ) {
return (
isset( $data['include'] ) &&
in_array( 'content', $data['include'], true ) &&
! empty( $data['manifest']['content'] ) &&
! empty( $data['extracted_directory_path'] )
);
}
public function import( array $data, array $imported_data ) {
$result['content'] = [];
$this->import_session_id = $data['session_id'];
$elementor_post_types = ImportExportUtils::get_elementor_post_types();
foreach ( $elementor_post_types as $post_type ) {
if ( empty( $data['manifest']['content'][ $post_type ] ) ) {
continue;
}
$posts_settings = $data['manifest']['content'][ $post_type ];
$path = $data['extracted_directory_path'] . 'content/' . $post_type . '/';
$imported_terms = ! empty( $imported_data['taxonomies'] )
? ImportExportUtils::map_old_new_term_ids( $imported_data )
: [];
$result['content'][ $post_type ] = $this->import_elementor_post_type( $posts_settings, $path, $post_type, $imported_terms );
}
return $result;
}
private function import_elementor_post_type( array $posts_settings, $path, $post_type, array $imported_terms ) {
$result = [
'succeed' => [],
'failed' => [],
];
foreach ( $posts_settings as $id => $post_settings ) {
try {
$post_data = ImportExportUtils::read_json_file( $path . $id );
$import = $this->import_post( $post_settings, $post_data, $post_type, $imported_terms );
if ( is_wp_error( $import ) ) {
$result['failed'][ $id ] = $import->get_error_message();
continue;
}
$result['succeed'][ $id ] = $import;
} catch ( \Exception $error ) {
$result['failed'][ $id ] = $error->getMessage();
}
}
return $result;
}
private function import_post( array $post_settings, array $post_data, $post_type, array $imported_terms ) {
$post_attributes = [
'post_title' => $post_settings['title'],
'post_type' => $post_type,
'post_status' => 'publish',
];
if ( ! empty( $post_settings['excerpt'] ) ) {
$post_attributes['post_excerpt'] = $post_settings['excerpt'];
}
$new_document = Plugin::$instance->documents->create(
$post_settings['doc_type'],
$post_attributes
);
if ( is_wp_error( $new_document ) ) {
throw new \Exception( $new_document->get_error_message() );
}
$post_data['import_settings'] = $post_settings;
$new_attachment_callback = function( $attachment_id ) {
$this->set_session_post_meta( $attachment_id, $this->import_session_id );
};
add_filter( 'elementor/template_library/import_images/new_attachment', $new_attachment_callback );
$new_document->import( $post_data );
remove_filter( 'elementor/template_library/import_images/new_attachment', $new_attachment_callback );
$new_post_id = $new_document->get_main_id();
if ( ! empty( $post_settings['terms'] ) ) {
$this->set_post_terms( $new_post_id, $post_settings['terms'], $imported_terms );
}
if ( ! empty( $post_settings['show_on_front'] ) ) {
$this->set_page_on_front( $new_post_id );
}
$this->set_session_post_meta( $new_post_id, $this->import_session_id );
return $new_post_id;
}
private function set_post_terms( $post_id, array $terms, array $imported_terms ) {
foreach ( $terms as $term ) {
if ( ! isset( $imported_terms[ $term['term_id'] ] ) ) {
continue;
}
wp_set_post_terms( $post_id, [ $imported_terms[ $term['term_id'] ] ], $term['taxonomy'], false );
}
}
private function init_page_on_front_data() {
$this->show_page_on_front = 'page' === get_option( 'show_on_front' );
if ( $this->show_page_on_front ) {
$this->page_on_front_id = (int) get_option( 'page_on_front' );
}
}
private function set_page_on_front( $page_id ) {
update_option( 'page_on_front', $page_id );
if ( ! $this->show_page_on_front ) {
update_option( 'show_on_front', 'page' );
}
}
public function get_import_session_metadata() : array {
return [
'page_on_front' => $this->page_on_front_id ?? 0,
];
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Import;
use Elementor\App\Modules\ImportExport\Runners\Runner_Interface;
abstract class Import_Runner_Base implements Runner_Interface {
/**
* By the passed data we should decide if we want to run the import function of the runner or not.
*
* @param array $data
*
* @return bool
*/
abstract public function should_import( array $data );
/**
* Main function of the runner import process.
*
* @param array $data Necessary data for the import process.
* @param array $imported_data Data that already imported by previously runners.
*
* @return array The result of the import process
*/
abstract public function import( array $data, array $imported_data );
public function get_import_session_metadata() : array {
return [];
}
public function set_session_post_meta( $post_id, $meta_value ) {
update_post_meta( $post_id, static::META_KEY_ELEMENTOR_IMPORT_SESSION_ID, $meta_value );
}
public function set_session_term_meta( $term_id, $meta_value ) {
update_term_meta( $term_id, static::META_KEY_ELEMENTOR_IMPORT_SESSION_ID, $meta_value );
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Import;
use Elementor\Core\Utils\Collection;
use Elementor\Core\Utils\Plugins_Manager;
use Elementor\Core\Utils\Str;
class Plugins extends Import_Runner_Base {
/**
* @var Plugins_Manager
*/
private $plugins_manager;
public function __construct( $plugins_manager = null ) {
if ( $plugins_manager ) {
$this->plugins_manager = $plugins_manager;
} else {
$this->plugins_manager = new Plugins_Manager();
}
}
public static function get_name() : string {
return 'plugins';
}
public function should_import( array $data ) {
return (
isset( $data['include'] ) &&
in_array( 'plugins', $data['include'], true ) &&
! empty( $data['manifest']['plugins'] ) &&
! empty( $data['selected_plugins'] )
);
}
public function import( array $data, array $imported_data ) {
$plugins = $data['selected_plugins'];
$plugins_collection = ( new Collection( $plugins ) )
->map( function ( $item ) {
if ( ! Str::ends_with( $item['plugin'], '.php' ) ) {
$item['plugin'] .= '.php';
}
return $item;
} );
$slugs = $plugins_collection
->map( function ( $item ) {
return $item['plugin'];
} )
->all();
$installed = $this->plugins_manager->install( $slugs );
$activated = $this->plugins_manager->activate( $installed['succeeded'] );
$ordered_activated_plugins = $plugins_collection
->filter( function ( $item ) use ( $activated ) {
return in_array( $item['plugin'], $activated['succeeded'], true );
} )
->map( function ( $item ) {
return $item['name'];
} )
->all();
$result['plugins'] = $ordered_activated_plugins;
return $result;
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Import;
use Elementor\Plugin;
use Elementor\Core\Settings\Page\Manager as PageManager;
use Elementor\App\Modules\ImportExport\Utils;
class Site_Settings extends Import_Runner_Base {
/**
* @var int
*/
private $previous_kit_id;
/**
* @var int
*/
private $active_kit_id;
/**
* @var int
*/
private $imported_kit_id;
public static function get_name() : string {
return 'site-settings';
}
public function should_import( array $data ) {
return (
isset( $data['include'] ) &&
in_array( 'settings', $data['include'], true ) &&
! empty( $data['site_settings']['settings'] )
);
}
public function import( array $data, array $imported_data ) {
$new_site_settings = $data['site_settings']['settings'];
$title = $data['manifest']['title'] ?? 'Imported Kit';
$active_kit = Plugin::$instance->kits_manager->get_active_kit();
$this->active_kit_id = (int) $active_kit->get_id();
$this->previous_kit_id = (int) Plugin::$instance->kits_manager->get_previous_id();
$result = [];
$old_settings = $active_kit->get_meta( PageManager::META_KEY );
if ( ! $old_settings ) {
$old_settings = [];
}
if ( ! empty( $old_settings['custom_colors'] ) ) {
$new_site_settings['custom_colors'] = array_merge( $old_settings['custom_colors'], $new_site_settings['custom_colors'] );
}
if ( ! empty( $old_settings['custom_typography'] ) ) {
$new_site_settings['custom_typography'] = array_merge( $old_settings['custom_typography'], $new_site_settings['custom_typography'] );
}
if ( ! empty( $new_site_settings['space_between_widgets'] ) ) {
$new_site_settings['space_between_widgets'] = Utils::update_space_between_widgets_values( $new_site_settings['space_between_widgets'] );
}
$new_site_settings = array_replace_recursive( $old_settings, $new_site_settings );
$new_kit = Plugin::$instance->kits_manager->create_new_kit( $title, $new_site_settings );
$this->imported_kit_id = (int) $new_kit;
$result['site-settings'] = (bool) $new_kit;
return $result;
}
public function get_import_session_metadata() : array {
return [
'previous_kit_id' => $this->previous_kit_id,
'active_kit_id' => $this->active_kit_id,
'imported_kit_id' => $this->imported_kit_id,
];
}
}

View File

@@ -0,0 +1,143 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Import;
use Elementor\App\Modules\ImportExport\Utils as ImportExportUtils;
class Taxonomies extends Import_Runner_Base {
private $import_session_id;
public static function get_name() : string {
return 'taxonomies';
}
public function should_import( array $data ) {
return (
isset( $data['include'] ) &&
in_array( 'content', $data['include'], true ) &&
! empty( $data['extracted_directory_path'] ) &&
! empty( $data['manifest']['taxonomies'] )
);
}
public function import( array $data, array $imported_data ) {
$path = $data['extracted_directory_path'] . 'taxonomies/';
$this->import_session_id = $data['session_id'];
$wp_builtin_post_types = ImportExportUtils::get_builtin_wp_post_types();
$selected_custom_post_types = isset( $data['selected_custom_post_types'] ) ? $data['selected_custom_post_types'] : [];
$post_types = array_merge( $wp_builtin_post_types, $selected_custom_post_types );
$result = [];
foreach ( $post_types as $post_type ) {
if ( empty( $data['manifest']['taxonomies'][ $post_type ] ) ) {
continue;
}
$result['taxonomies'][ $post_type ] = $this->import_taxonomies( $data['manifest']['taxonomies'][ $post_type ], $path );
}
return $result;
}
private function import_taxonomies( array $taxonomies, $path ) {
$result = [];
$imported_taxonomies = [];
foreach ( $taxonomies as $taxonomy ) {
if ( ! taxonomy_exists( $taxonomy ) ) {
continue;
}
if ( ! empty( $imported_taxonomies[ $taxonomy ] ) ) {
$result[ $taxonomy ] = $imported_taxonomies[ $taxonomy ];
continue;
}
$taxonomy_data = ImportExportUtils::read_json_file( $path . $taxonomy );
if ( empty( $taxonomy_data ) ) {
continue;
}
$import = $this->import_taxonomy( $taxonomy_data );
$result[ $taxonomy ] = $import;
$imported_taxonomies[ $taxonomy ] = $import;
}
return $result;
}
private function import_taxonomy( array $taxonomy_data ) {
$terms = [];
foreach ( $taxonomy_data as $term ) {
$old_slug = $term['slug'];
$existing_term = term_exists( $term['slug'], $term['taxonomy'] );
if ( $existing_term ) {
if ( 'nav_menu' === $term['taxonomy'] ) {
$term = $this->handle_duplicated_nav_menu_term( $term );
} else {
$terms[] = [
'old_id' => (int) $term['term_id'],
'new_id' => (int) $existing_term['term_id'],
'old_slug' => $old_slug,
'new_slug' => $term['slug'],
];
continue;
}
}
$parent = $this->get_term_parent( $term, $terms );
$args = [
'slug' => $term['slug'],
'description' => wp_slash( $term['description'] ),
'parent' => (int) $parent,
];
$new_term = wp_insert_term( wp_slash( $term['name'] ), $term['taxonomy'], $args );
if ( ! is_wp_error( $new_term ) ) {
$this->set_session_term_meta( (int) $new_term['term_id'], $this->import_session_id );
$terms[] = [
'old_id' => $term['term_id'],
'new_id' => (int) $new_term['term_id'],
'old_slug' => $old_slug,
'new_slug' => $term['slug'],
];
}
}
return $terms;
}
private function handle_duplicated_nav_menu_term( $term ) {
do {
$term['slug'] = $term['slug'] . '-duplicate';
$term['name'] = $term['name'] . ' duplicate';
} while ( term_exists( $term['slug'], 'nav_menu' ) );
return $term;
}
private function get_term_parent( $term, array $imported_terms ) {
$parent = $term['parent'];
if ( 0 !== $parent && ! empty( $imported_terms ) ) {
foreach ( $imported_terms as $imported_term ) {
if ( $parent === $imported_term['old_id'] ) {
$parent_term = term_exists( $imported_term['new_id'], $term['taxonomy'] );
break;
}
}
if ( isset( $parent_term['term_id'] ) ) {
return $parent_term['term_id'];
}
}
return 0;
}
}

View File

@@ -0,0 +1,87 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Import;
use Elementor\App\Modules\ImportExport\Utils as ImportExportUtils;
use Elementor\Plugin;
use Elementor\TemplateLibrary\Source_Local;
use Elementor\Utils;
class Templates extends Import_Runner_Base {
private $import_session_id;
public static function get_name() : string {
return 'templates';
}
public function should_import( array $data ) {
return (
Utils::has_pro() &&
isset( $data['include'] ) &&
in_array( 'templates', $data['include'], true ) &&
! empty( $data['extracted_directory_path'] ) &&
! empty( $data['manifest']['templates'] )
);
}
public function import( array $data, array $imported_data ) {
$this->import_session_id = $data['session_id'];
$path = $data['extracted_directory_path'] . 'templates/';
$templates = $data['manifest']['templates'];
$result['templates'] = [
'succeed' => [],
'failed' => [],
];
foreach ( $templates as $id => $template_settings ) {
try {
$template_data = ImportExportUtils::read_json_file( $path . $id );
$import = $this->import_template( $id, $template_settings, $template_data );
$result['templates']['succeed'][ $id ] = $import;
} catch ( \Exception $error ) {
$result['templates']['failed'][ $id ] = $error->getMessage();
}
}
return $result;
}
private function import_template( $id, array $template_settings, array $template_data ) {
$doc_type = $template_settings['doc_type'];
$new_document = Plugin::$instance->documents->create(
$doc_type,
[
'post_title' => $template_settings['title'],
'post_type' => Source_Local::CPT,
'post_status' => 'publish',
]
);
if ( is_wp_error( $new_document ) ) {
throw new \Exception( $new_document->get_error_message() );
}
$template_data['import_settings'] = $template_settings;
$template_data['id'] = $id;
$new_attachment_callback = function( $attachment_id ) {
$this->set_session_post_meta( $attachment_id, $this->import_session_id );
};
add_filter( 'elementor/template_library/import_images/new_attachment', $new_attachment_callback );
$new_document->import( $template_data );
remove_filter( 'elementor/template_library/import_images/new_attachment', $new_attachment_callback );
$document_id = $new_document->get_main_id();
$this->set_session_post_meta( $document_id, $this->import_session_id );
return $document_id;
}
}

View File

@@ -0,0 +1,124 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Import;
use Elementor\App\Modules\ImportExport\Utils as ImportExportUtils;
use Elementor\Core\Utils\ImportExport\WP_Import;
class Wp_Content extends Import_Runner_Base {
private $import_session_id;
/**
* @var array
*/
private $selected_custom_post_types = [];
public static function get_name() : string {
return 'wp-content';
}
public function should_import( array $data ) {
return (
isset( $data['include'] ) &&
in_array( 'content', $data['include'], true ) &&
! empty( $data['extracted_directory_path'] ) &&
! empty( $data['manifest']['wp-content'] )
);
}
public function import( array $data, array $imported_data ) {
$this->import_session_id = $data['session_id'];
$path = $data['extracted_directory_path'] . 'wp-content/';
$post_types = $this->filter_post_types( $data['selected_custom_post_types'] );
$taxonomies = $imported_data['taxonomies'] ?? [];
$imported_terms = ImportExportUtils::map_old_new_term_ids( $imported_data );
$result['wp-content'] = [];
foreach ( $post_types as $post_type ) {
$import = $this->import_wp_post_type(
$path,
$post_type,
$imported_data,
$taxonomies,
$imported_terms
);
if ( empty( $import ) ) {
continue;
}
$result['wp-content'][ $post_type ] = $import;
$imported_data = array_merge( $imported_data, $result );
}
return $result;
}
private function import_wp_post_type( $path, $post_type, array $imported_data, array $taxonomies, array $imported_terms ) {
$args = [
'fetch_attachments' => true,
'posts' => ImportExportUtils::map_old_new_post_ids( $imported_data ),
'terms' => $imported_terms,
'taxonomies' => ! empty( $taxonomies[ $post_type ] ) ? $taxonomies[ $post_type ] : [],
'posts_meta' => [
static::META_KEY_ELEMENTOR_IMPORT_SESSION_ID => $this->import_session_id,
],
'terms_meta' => [
static::META_KEY_ELEMENTOR_IMPORT_SESSION_ID => $this->import_session_id,
],
];
$file = $path . $post_type . '/' . $post_type . '.xml';
if ( ! file_exists( $file ) ) {
return [];
}
$wp_importer = new WP_Import( $file, $args );
$result = $wp_importer->run();
return $result['summary']['posts'];
}
private function filter_post_types( $selected_custom_post_types = [] ) {
$wp_builtin_post_types = ImportExportUtils::get_builtin_wp_post_types();
foreach ( $selected_custom_post_types as $custom_post_type ) {
if ( post_type_exists( $custom_post_type ) ) {
$this->selected_custom_post_types[] = $custom_post_type;
}
}
$post_types = array_merge( $wp_builtin_post_types, $this->selected_custom_post_types );
$post_types = $this->force_element_to_be_last_by_value( $post_types, 'nav_menu_item' );
return $post_types;
}
public function get_import_session_metadata() : array {
return [
'custom_post_types' => $this->selected_custom_post_types,
];
}
/**
* @param $array array The array we want to relocate his element.
* @param $element mixed The value of the element in the array we want to shift to end of the array.
* @return mixed
*/
private function force_element_to_be_last_by_value( array $array, $element ) {
$index = array_search( $element, $array, true );
if ( false !== $index ) {
unset( $array[ $index ] );
$array[] = $element;
}
return $array;
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Revert;
use Elementor\App\Modules\ImportExport\Utils as ImportExportUtils;
use Elementor\Plugin;
class Elementor_Content extends Revert_Runner_Base {
private $show_page_on_front;
private $page_on_front_id;
public function __construct() {
$this->init_page_on_front_data();
}
public static function get_name() : string {
return 'elementor-content';
}
public function should_revert( array $data ) : bool {
return (
isset( $data['runners'] ) &&
array_key_exists( static::get_name(), $data['runners'] )
);
}
public function revert( array $data ) {
$elementor_post_types = ImportExportUtils::get_elementor_post_types();
$query_args = [
'post_type' => $elementor_post_types,
'post_status' => 'any',
'posts_per_page' => -1,
'meta_query' => [
[
'key' => static::META_KEY_ELEMENTOR_EDIT_MODE,
'compare' => 'EXISTS',
],
[
'key' => static::META_KEY_ELEMENTOR_IMPORT_SESSION_ID,
'value' => $data['session_id'],
],
],
];
$query = new \WP_Query( $query_args );
foreach ( $query->posts as $post ) {
$post_type_document = Plugin::$instance->documents->get( $post->ID );
$post_type_document->delete();
// Deleting the post will reset the show_on_front option. We need to set it to false,
// so we can set it back to what it was.
if ( $post->ID === $this->page_on_front_id ) {
$this->show_page_on_front = false;
}
}
$this->restore_page_on_front( $data );
}
private function init_page_on_front_data() {
$this->show_page_on_front = 'page' === get_option( 'show_on_front' );
if ( $this->show_page_on_front ) {
$this->page_on_front_id = (int) get_option( 'page_on_front' );
}
}
private function restore_page_on_front( $data ) {
if ( empty( $data['runners'][ static::get_name() ]['page_on_front'] ) ) {
return;
}
$page_on_front = $data['runners'][ static::get_name() ]['page_on_front'];
$document = Plugin::$instance->documents->get( $page_on_front );
if ( ! $document ) {
return;
}
$this->set_page_on_front( $document->get_main_id() );
}
private function set_page_on_front( $page_id ) {
update_option( 'page_on_front', $page_id );
if ( ! $this->show_page_on_front ) {
update_option( 'show_on_front', 'page' );
}
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Revert;
class Plugins extends Revert_Runner_Base {
public static function get_name() : string {
return 'plugins';
}
public function should_revert( array $data ) : bool {
return false;
}
public function revert( array $data ) {}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Revert;
use Elementor\App\Modules\ImportExport\Runners\Runner_Interface;
abstract class Revert_Runner_Base implements Runner_Interface {
/**
* By the passed data we should decide if we want to run the revert function of the runner or not.
*
* @param array $data
*
* @return bool
*/
abstract public function should_revert( array $data ) : bool;
/**
* Main function of the runner revert process.
*
* @param array $data Necessary data for the revert process.
*/
abstract public function revert( array $data );
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Revert;
use Elementor\Plugin;
class Site_Settings extends Revert_Runner_Base {
public static function get_name() : string {
return 'site-settings';
}
public function should_revert( array $data ) : bool {
return (
isset( $data['runners'] ) &&
array_key_exists( static::get_name(), $data['runners'] )
);
}
public function revert( array $data ) {
Plugin::$instance->kits_manager->revert(
$data['runners'][ static::get_name() ]['imported_kit_id'],
$data['runners'][ static::get_name() ]['active_kit_id'],
$data['runners'][ static::get_name() ]['previous_kit_id']
);
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Revert;
class Taxonomies extends Revert_Runner_Base {
public static function get_name() : string {
return 'taxonomies';
}
public function should_revert( array $data ) : bool {
return (
isset( $data['runners'] ) &&
array_key_exists( static::get_name(), $data['runners'] )
);
}
public function revert( array $data ) {
$taxonomies = get_taxonomies();
$terms = get_terms( [
'taxonomy' => $taxonomies,
'hide_empty' => false,
'get' => 'all',
'meta_query' => [
[
'key' => static::META_KEY_ELEMENTOR_IMPORT_SESSION_ID,
'value' => $data['session_id'],
],
],
] );
foreach ( $terms as $term ) {
wp_delete_term( $term->term_id, $term->taxonomy );
}
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Revert;
class Templates extends Revert_Runner_Base {
/*
* The implement of this runner is part of the Pro plugin.
*/
public static function get_name() : string {
return 'templates';
}
public function should_revert( array $data ) : bool {
return false;
}
public function revert( array $data ) { }
}

View File

@@ -0,0 +1,73 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners\Revert;
use Elementor\App\Modules\ImportExport\Utils as ImportExportUtils;
class Wp_Content extends Revert_Runner_Base {
public static function get_name() : string {
return 'wp-content';
}
public function should_revert( array $data ) : bool {
return (
isset( $data['runners'] ) &&
array_key_exists( static::get_name(), $data['runners'] )
);
}
public function revert( array $data ) {
$builtin_post_types = ImportExportUtils::get_builtin_wp_post_types();
$custom_post_types = $data['runners']['wp-content']['custom_post_types'] ?? [];
$post_types = array_merge( $builtin_post_types, $custom_post_types );
$query_args = [
'post_type' => $post_types,
'post_status' => 'any',
'posts_per_page' => -1,
'meta_query' => [
[
'key' => static::META_KEY_ELEMENTOR_EDIT_MODE,
'compare' => 'NOT EXISTS',
],
[
'key' => static::META_KEY_ELEMENTOR_IMPORT_SESSION_ID,
'value' => $data['session_id'],
],
],
];
$query = new \WP_Query( $query_args );
foreach ( $query->posts as $post ) {
wp_delete_post( $post->ID, true );
}
/**
* Revert the nav menu terms.
* BC: The nav menu in new kits will be imported as part of the taxonomies, but old kits
* importing the nav menu terms as part from the wp-content import.
*/
$this->revert_nav_menus( $data );
}
private function revert_nav_menus( array $data ) {
$terms = get_terms( [
'taxonomy' => 'nav_menu',
'hide_empty' => false,
'get' => 'all',
'meta_query' => [
[
'key' => static::META_KEY_ELEMENTOR_IMPORT_SESSION_ID,
'value' => $data['session_id'],
],
],
] );
foreach ( $terms as $term ) {
wp_delete_term( $term->term_id, $term->taxonomy );
}
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace Elementor\App\Modules\ImportExport\Runners;
use Elementor\App\Modules\ImportExport\Module;
interface Runner_Interface {
const META_KEY_ELEMENTOR_IMPORT_SESSION_ID = Module::META_KEY_ELEMENTOR_IMPORT_SESSION_ID;
const META_KEY_ELEMENTOR_EDIT_MODE = Module::META_KEY_ELEMENTOR_EDIT_MODE;
/**
* Get the name of the runners, used to identify the runner.
* The name should be unique, unless you want to run over existing runner.
*
* @return string
*/
public static function get_name() : string;
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Elementor\App\Modules\ImportExport;
use Elementor\App\Modules\ImportExport\Processes\Revert;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class Usage {
/**
* Register hooks.
*
* @return void
*/
public function register() {
add_filter( 'elementor/tracker/send_tracking_data_params', function ( array $params ) {
$params['usages']['import_export']['revert'] = $this->get_revert_usage_data();
return $params;
} );
}
/**
* Get the Revert usage data.
*
* @return array
*/
private function get_revert_usage_data() {
$revert_sessions = ( new Revert() )->get_revert_sessions();
$data = [];
foreach ( $revert_sessions as $revert_session ) {
$data[] = [
'kit_name' => $revert_session['kit_name'],
'source' => $revert_session['source'],
'revert_timestamp' => (int) $revert_session['revert_timestamp'],
'total_time' => ( (int) $revert_session['revert_timestamp'] - (int) $revert_session['import_timestamp'] ),
];
}
return $data;
}
}

View File

@@ -0,0 +1,139 @@
<?php
namespace Elementor\App\Modules\ImportExport;
use Elementor\Core\Utils\Str;
use Elementor\Modules\LandingPages\Module as Landing_Pages_Module;
use Elementor\Modules\System_Info\Reporters\Server;
use Elementor\TemplateLibrary\Source_Local;
use Elementor\Utils as ElementorUtils;
class Utils {
public static function read_json_file( $path ) {
if ( ! Str::ends_with( $path, '.json' ) ) {
$path .= '.json';
}
$file_content = ElementorUtils::file_get_contents( $path, true );
return $file_content ? json_decode( $file_content, true ) : [];
}
public static function map_old_new_post_ids( array $imported_data ) {
$result = [];
$result += $imported_data['templates']['succeed'] ?? [];
if ( isset( $imported_data['content'] ) ) {
foreach ( $imported_data['content'] as $post_type ) {
$result += $post_type['succeed'] ?? [];
}
}
if ( isset( $imported_data['wp-content'] ) ) {
foreach ( $imported_data['wp-content'] as $post_type ) {
$result += $post_type['succeed'] ?? [];
}
}
return $result;
}
public static function map_old_new_term_ids( array $imported_data ) {
$result = [];
if ( ! isset( $imported_data['taxonomies'] ) ) {
return $result;
}
foreach ( $imported_data['taxonomies'] as $post_type_taxonomies ) {
foreach ( $post_type_taxonomies as $taxonomy ) {
foreach ( $taxonomy as $term ) {
$result[ $term['old_id'] ] = $term['new_id'];
}
}
}
return $result;
}
public static function get_elementor_post_types() {
$elementor_post_types = get_post_types_by_support( 'elementor' );
return array_filter( $elementor_post_types, function ( $value ) {
// Templates are handled in a separate process.
return 'elementor_library' !== $value;
} );
}
public static function get_builtin_wp_post_types() {
return [ 'post', 'page', 'nav_menu_item' ];
}
public static function get_registered_cpt_names() {
$post_types = get_post_types( [
'public' => true,
'can_export' => true,
'_builtin' => false,
] );
unset(
$post_types[ Landing_Pages_Module::CPT ],
$post_types[ Source_Local::CPT ]
);
return array_keys( $post_types );
}
/**
* Transform a string name to title format.
*
* @param $name
*
* @return string
*/
public static function transform_name_to_title( $name ): string {
if ( empty( $name ) ) {
return '';
}
$title = str_replace( [ '-', '_' ], ' ', $name );
return ucwords( $title );
}
public static function get_import_sessions( $should_run_cleanup = false ) {
$import_sessions = get_option( Module::OPTION_KEY_ELEMENTOR_IMPORT_SESSIONS, [] );
if ( $should_run_cleanup ) {
foreach ( $import_sessions as $session_id => $import_session ) {
if ( ! isset( $import_session['runners'] ) && isset( $import_session['instance_data'] ) ) {
$import_sessions[ $session_id ]['runners'] = $import_session['instance_data']['runners_import_metadata'] ?? [];
unset( $import_sessions[ $session_id ]['instance_data'] );
}
}
update_option( Module::OPTION_KEY_ELEMENTOR_IMPORT_SESSIONS, $import_sessions );
}
return $import_sessions;
}
public static function update_space_between_widgets_values( $space_between_widgets ) {
$setting_exist = isset( $space_between_widgets['size'] );
$already_processed = isset( $space_between_widgets['column'] );
if ( ! $setting_exist || $already_processed ) {
return $space_between_widgets;
}
$size = strval( $space_between_widgets['size'] );
$space_between_widgets['column'] = $size;
$space_between_widgets['row'] = $size;
$space_between_widgets['isLinked'] = true;
return $space_between_widgets;
}
}

View File

@@ -0,0 +1,281 @@
<?php
namespace Elementor\App\Modules\ImportExport;
use Elementor\Core\Utils\Collection;
use Elementor\Core\Utils\Plugins_Manager;
use Elementor\Plugin;
use Elementor\App\Modules\KitLibrary\Connect\Kit_Library;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class Wp_Cli extends \WP_CLI_Command {
const AVAILABLE_SETTINGS = [ 'include', 'overrideConditions', 'selectedCustomPostTypes', 'plugins' ];
/**
* Export a Kit
*
* [--include]
* Which type of content to include. Possible values are 'content', 'templates', 'site-settings'.
* if this parameter won't be specified, All data types will be included.
*
* ## EXAMPLES
*
* 1. wp elementor kit export path/to/export-file-name.zip
* - This will export all site data to the specified file name.
*
* 2. wp elementor kit export path/to/export-file-name.zip --include=kit-settings,content
* - This will export only site settings and content.
*
* @param array $args
* @param array $assoc_args
*/
public function export( $args, $assoc_args ) {
if ( empty( $args[0] ) ) {
\WP_CLI::error( 'Please specify a file name' );
}
\WP_CLI::line( 'Kit export started.' );
$export_settings = [];
foreach ( $assoc_args as $key => $value ) {
if ( ! in_array( $key, static::AVAILABLE_SETTINGS, true ) ) {
continue;
}
$export_settings[ $key ] = explode( ',', $value );
}
try {
/**
* Running the export process through the import-export module so the export property in the module will be available to use.
*
* @type Module $import_export_module
*/
$import_export_module = Plugin::$instance->app->get_component( 'import-export' );
$result = $import_export_module->export_kit( $export_settings );
rename( $result['file_name'], $args[0] );
} catch ( \Error $error ) {
\WP_CLI::error( $error->getMessage() );
}
\WP_CLI::success( 'Kit exported successfully.' );
}
/**
* Import a Kit
*
* [--include]
* Which type of content to include. Possible values are 'content', 'templates', 'site-settings'.
* if this parameter won't be specified, All data types will be included.
*
* [--overrideConditions]
* Templates ids to override conditions for.
*
* [--sourceType]
* Which source type is used in the current session. Available values are 'local', 'remote', 'library'.
* The default value is 'local'
*
* ## EXAMPLES
*
* 1. wp elementor kit import path/to/elementor-kit.zip
* - This will import the whole kit file content.
*
* 2. wp elementor kit import path/to/elementor-kit.zip --include=site-settings,content
* - This will import only site settings and content.
*
* 3. wp elementor kit import path/to/elementor-kit.zip --overrideConditions=3478,4520
* - This will import all content and will override conditions for the given template ids.
*
* 4. wp elementor kit import path/to/elementor-kit.zip --unfilteredFilesUpload=enable
* - This will allow the import process to import unfiltered files.
*
* @param array $args
* @param array $assoc_args
*/
public function import( array $args, array $assoc_args ) {
if ( ! current_user_can( 'administrator' ) ) {
\WP_CLI::error( 'You must run this command as an admin user' );
}
if ( empty( $args[0] ) ) {
\WP_CLI::error( 'Please specify a file to import' );
}
\WP_CLI::line( 'Kit import started' );
$assoc_args = wp_parse_args( $assoc_args, [
'sourceType' => 'local',
] );
$url = null;
$file_path = $args[0];
$import_settings = [];
$import_settings['referrer'] = Module::REFERRER_LOCAL;
switch ( $assoc_args['sourceType'] ) {
case 'library':
$url = $this->get_url_from_library( $file_path );
$zip_path = $this->create_temp_file_from_url( $url );
$import_settings['referrer'] = Module::REFERRER_KIT_LIBRARY;
break;
case 'remote':
$zip_path = $this->create_temp_file_from_url( $file_path );
break;
case 'local':
$zip_path = $file_path;
break;
default:
\WP_CLI::error( 'Unknown source type.' );
break;
}
if ( 'enable' === $assoc_args['unfilteredFilesUpload'] ) {
Plugin::$instance->uploads_manager->enable_unfiltered_files_upload();
}
foreach ( $assoc_args as $key => $value ) {
if ( ! in_array( $key, static::AVAILABLE_SETTINGS, true ) ) {
continue;
}
$import_settings[ $key ] = explode( ',', $value );
}
try {
\WP_CLI::line( 'Importing data...' );
/**
* Running the import process through the import-export module so the import property in the module will be available to use.
*
* @type Module $import_export_module
*/
$import_export_module = Plugin::$instance->app->get_component( 'import-export' );
if ( ! $import_export_module ) {
\WP_CLI::error( 'Import Export module is not available.' );
}
$import = $import_export_module->import_kit( $zip_path, $import_settings );
$manifest_data = $import_export_module->import->get_manifest();
/**
* Import Export Manifest Data
*
* Allows 3rd parties to read and edit the kit's manifest before it is used.
*
* @since 3.7.0
*
* @param array $manifest_data The Kit's Manifest data
*/
$manifest_data = apply_filters( 'elementor/import-export/wp-cli/manifest_data', $manifest_data );
\WP_CLI::line( 'Removing temp files...' );
// The file was created from remote or library request, it also should be removed.
if ( $url ) {
Plugin::$instance->uploads_manager->remove_file_or_dir( dirname( $zip_path ) );
}
\WP_CLI::success( 'Kit imported successfully' );
} catch ( \Error $error ) {
Plugin::$instance->logger->get_logger()->error( $error->getMessage(), [
'meta' => [
'trace' => $error->getTraceAsString(),
],
] );
if ( $url ) {
Plugin::$instance->uploads_manager->remove_file_or_dir( dirname( $zip_path ) );
}
\WP_CLI::error( $error->getMessage() );
}
}
/**
* Revert last imported kit.
*/
public function revert() {
\WP_CLI::line( 'Kit revert started.' );
try {
/**
* Running the revert process through the import-export module so the revert property in the module will be available to use.
*
* @type Module $import_export_module
*/
$import_export_module = Plugin::$instance->app->get_component( 'import-export' );
$import_export_module->revert_last_imported_kit();
} catch ( \Error $error ) {
\WP_CLI::error( $error->getMessage() );
}
\WP_CLI::success( 'Kit reverted successfully.' );
}
/**
* Helper to get kit url by the kit id
* TODO: Maybe extract it.
*
* @param $kit_id
*
* @return string
*/
private function get_url_from_library( $kit_id ) {
/** @var Kit_Library $app */
$app = Plugin::$instance->common->get_component( 'connect' )->get_app( 'kit-library' );
if ( ! $app ) {
\WP_CLI::error( 'Kit library app not found' );
}
$response = $app->download_link( $kit_id );
if ( is_wp_error( $response ) ) {
\WP_CLI::error( "Library Response: {$response->get_error_message()}" );
}
return $response->download_link;
}
/**
* Helper to get kit zip file path by the kit url
* TODO: Maybe extract it.
*
* @param $url
*
* @return string
*/
private function create_temp_file_from_url( $url ) {
\WP_CLI::line( 'Extracting zip archive...' );
$response = wp_remote_get( $url );
if ( is_wp_error( $response ) ) {
\WP_CLI::error( "Download file url: {$response->get_error_message()}" );
}
if ( 200 !== $response['response']['code'] ) {
\WP_CLI::error( "Download file url: {$response['response']['message']}" );
}
// Set the Request's state as an Elementor upload request, in order to support unfiltered file uploads.
Plugin::$instance->uploads_manager->set_elementor_upload_state( true );
$file = Plugin::$instance->uploads_manager->create_temp_file( $response['body'], 'kit.zip' );
// After the upload complete, set the elementor upload state back to false.
Plugin::$instance->uploads_manager->set_elementor_upload_state( false );
return $file;
}
}

View File

@@ -0,0 +1,76 @@
<?php
namespace Elementor\App\Modules\KitLibrary\Connect;
use Elementor\Core\Common\Modules\Connect\Apps\Base_App;
use Elementor\Core\Common\Modules\Connect\Apps\Library;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class Kit_Library extends Library {
const DEFAULT_BASE_ENDPOINT = 'https://my.elementor.com/api/v1/kits-library';
const FALLBACK_BASE_ENDPOINT = 'https://ms-8874.elementor.com/api/v1/kits-library';
public function get_title() {
return esc_html__( 'Kit Library', 'elementor' );
}
public function get_all( $args = [] ) {
return $this->http_request( 'GET', 'kits/plugin-version/' . ELEMENTOR_VERSION, $args );
}
public function get_by_id( $id ) {
return $this->http_request( 'GET', 'kits/' . $id );
}
public function get_taxonomies() {
return $this->http_request( 'GET', 'taxonomies' );
}
public function get_manifest( $id ) {
return $this->http_request( 'GET', "kits/{$id}/manifest" );
}
public function download_link( $id ) {
return $this->http_request( 'GET', "kits/{$id}/download-link" );
}
protected function get_api_url() {
return [
static::DEFAULT_BASE_ENDPOINT,
static::FALLBACK_BASE_ENDPOINT,
];
}
/**
* Get all the connect information
*
* @return array
*/
protected function get_connect_info() {
$connect_info = $this->get_base_connect_info();
$additional_info = [];
// BC Support.
$old_kit_library = new \Elementor\Core\App\Modules\KitLibrary\Connect\Kit_Library();
/**
* Additional connect info.
*
* Filters the connection information when connecting to Elementor servers.
* This hook can be used to add more information or add more data.
*
* @param array $additional_info Additional connecting information array.
* @param Base_App $this The base app instance.
*/
$additional_info = apply_filters( 'elementor/connect/additional-connect-info', $additional_info, $old_kit_library );
return array_merge( $connect_info, $additional_info );
}
protected function init() {
// Remove parent init actions.
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace Elementor\App\Modules\KitLibrary\Data;
use Elementor\Plugin;
use Elementor\Data\V2\Base\Controller;
use Elementor\Core\Utils\Collection;
use Elementor\Modules\Library\User_Favorites;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
abstract class Base_Controller extends Controller {
/**
* @var Repository
*/
private $repository;
/**
* @return Repository
*/
public function get_repository() {
if ( ! $this->repository ) {
/** @var \Elementor\Core\Common\Modules\Connect\Module $connect */
$connect = Plugin::$instance->common->get_component( 'connect' );
$subscription_plans = ( new Collection( $connect->get_subscription_plans() ) )
->map( function ( $value ) {
return $value['label'];
} );
$this->repository = new Repository(
$connect->get_app( 'kit-library' ),
new User_Favorites( get_current_user_id() ),
$subscription_plans
);
}
return $this->repository;
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace Elementor\App\Modules\KitLibrary\Data\Kits;
use Elementor\App\Modules\KitLibrary\Data\Base_Controller;
use Elementor\Data\V2\Base\Exceptions\Error_404;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
class Controller extends Base_Controller {
public function get_name() {
return 'kits';
}
public function get_items( $request ) {
$data = $this->get_repository()->get_all( $request->get_param( 'force' ) );
return [
'data' => $data->values(),
];
}
public function get_item( $request ) {
$data = $this->get_repository()->find( $request->get_param( 'id' ) );
if ( ! $data ) {
return new Error_404( esc_html__( 'Kit not exists.', 'elementor' ), 'kit_not_exists' );
}
return [
'data' => $data,
];
}
public function get_collection_params() {
return [
'force' => [
'description' => 'Force an API request and skip the cache.',
'required' => false,
'default' => false,
'type' => 'boolean',
],
];
}
public function register_endpoints() {
$this->index_endpoint->register_item_route( \WP_REST_Server::READABLE, [
'id' => [
'description' => 'Unique identifier for the object.',
'type' => 'string',
'required' => true,
],
'id_arg_type_regex' => '[\w]+',
] );
$this->register_endpoint( new Endpoints\Download_Link( $this ) );
$this->register_endpoint( new Endpoints\Favorites( $this ) );
}
public function get_permission_callback( $request ) {
return current_user_can( 'administrator' );
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Elementor\App\Modules\KitLibrary\Data\Kits\Endpoints;
use Elementor\Data\V2\Base\Endpoint;
use Elementor\App\Modules\KitLibrary\Data\Kits\Controller;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* @property Controller $controller
*/
class Download_Link extends Endpoint {
public function get_name() {
return 'download-link';
}
public function get_format() {
return 'kits/download-link/{id}';
}
protected function register() {
$this->register_item_route( \WP_REST_Server::READABLE, [
'id_arg_type_regex' => '[\w]+',
] );
}
public function get_item( $id, $request ) {
$repository = $this->controller->get_repository();
$data = $repository->get_download_link( $id );
return [
'data' => $data,
'meta' => [
'nonce' => wp_create_nonce( 'kit-library-import' ),
],
];
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Elementor\App\Modules\KitLibrary\Data\Kits\Endpoints;
use Elementor\App\Modules\KitLibrary\Data\Kits\Controller;
use Elementor\Data\V2\Base\Endpoint;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* @property Controller $controller
*/
class Favorites extends Endpoint {
public function get_name() {
return 'favorites';
}
public function get_format() {
return 'kits/favorites/{id}';
}
protected function register() {
$args = [
'id_arg_type_regex' => '[\w]+',
];
$this->register_item_route( \WP_REST_Server::CREATABLE, $args );
$this->register_item_route( \WP_REST_Server::DELETABLE, $args );
}
public function create_item( $id, $request ) {
$repository = $this->controller->get_repository();
$kit = $repository->add_to_favorites( $id );
return [
'data' => $kit,
];
}
public function delete_item( $id, $request ) {
$repository = $this->controller->get_repository();
$kit = $repository->remove_from_favorites( $id );
return [
'data' => $kit,
];
}
}

View File

@@ -0,0 +1,339 @@
<?php
namespace Elementor\App\Modules\KitLibrary\Data;
use Elementor\Core\Common\Modules\Connect\Module as ConnectModule;
use Elementor\Core\Utils\Collection;
use Elementor\Data\V2\Base\Exceptions\Error_404;
use Elementor\Data\V2\Base\Exceptions\WP_Error_Exception;
use Elementor\Modules\Library\User_Favorites;
use Elementor\App\Modules\KitLibrary\Connect\Kit_Library;
use Elementor\Plugin;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
class Repository {
/**
* There is no label for subscription plan with access_level=0 + it should not
* be translated.
*/
const SUBSCRIPTION_PLAN_FREE_TAG = 'Free';
const TAXONOMIES_KEYS = [ 'tags', 'categories', 'main_category', 'third_category', 'features', 'types' ];
const KITS_CACHE_KEY = 'elementor_remote_kits';
const KITS_TAXONOMIES_CACHE_KEY = 'elementor_remote_kits_taxonomies';
const KITS_CACHE_TTL_HOURS = 12;
const KITS_TAXONOMIES_CACHE_TTL_HOURS = 12;
/**
* @var Kit_Library
*/
protected $api;
/**
* @var User_Favorites
*/
protected $user_favorites;
/**
* @var Collection
*/
protected $subscription_plans;
/**
* Get all kits.
*
* @param false $force_api_request
*
* @return Collection
*/
public function get_all( $force_api_request = false ) {
return $this->get_kits_data( $force_api_request )
->map( function ( $kit ) {
return $this->transform_kit_api_response( $kit );
} );
}
/**
* Get specific kit.
*
* @param $id
* @param array $options
*
* @return array|null
*/
public function find( $id, $options = [] ) {
$options = wp_parse_args( $options, [
'manifest_included' => true,
] );
$item = $this->get_kits_data()
->find( function ( $kit ) use ( $id ) {
return $kit->_id === $id;
} );
if ( ! $item ) {
return null;
}
$manifest = null;
if ( $options['manifest_included'] ) {
$manifest = $this->api->get_manifest( $id );
if ( is_wp_error( $manifest ) ) {
throw new WP_Error_Exception( $manifest );
}
}
return $this->transform_kit_api_response( $item, $manifest );
}
/**
* @param false $force_api_request
*
* @return Collection
*/
public function get_taxonomies( $force_api_request = false ) {
return $this->get_taxonomies_data( $force_api_request )
->only( static::TAXONOMIES_KEYS )
->reduce( function ( Collection $carry, $taxonomies, $type ) {
return $carry->merge( array_map( function ( $taxonomy ) use ( $type ) {
return [
'text' => $taxonomy->name,
'type' => $type,
];
}, $taxonomies ) );
}, new Collection( [] ) )
->merge(
$this->subscription_plans->map( function ( $label ) {
return [
'text' => $label ? $label : self::SUBSCRIPTION_PLAN_FREE_TAG,
'type' => 'subscription_plans',
];
} )
)
->unique( [ 'text', 'type' ] );
}
/**
* @param $id
*
* @return array
*/
public function get_download_link( $id ) {
$response = $this->api->download_link( $id );
if ( is_wp_error( $response ) ) {
throw new WP_Error_Exception( $response );
}
return [ 'download_link' => $response->download_link ];
}
/**
* @param $id
*
* @return array
* @throws \Exception
*/
public function add_to_favorites( $id ) {
$kit = $this->find( $id, [ 'manifest_included' => false ] );
if ( ! $kit ) {
throw new Error_404( esc_html__( 'Kit not found', 'elementor' ), 'kit_not_found' );
}
$this->user_favorites->add( 'elementor', 'kits', $kit['id'] );
$kit['is_favorite'] = true;
return $kit;
}
/**
* @param $id
*
* @return array
* @throws \Exception
*/
public function remove_from_favorites( $id ) {
$kit = $this->find( $id, [ 'manifest_included' => false ] );
if ( ! $kit ) {
throw new Error_404( esc_html__( 'Kit not found', 'elementor' ), 'kit_not_found' );
}
$this->user_favorites->remove( 'elementor', 'kits', $kit['id'] );
$kit['is_favorite'] = false;
return $kit;
}
/**
* @param bool $force_api_request
*
* @return Collection
*/
private function get_kits_data( $force_api_request = false ) {
$data = get_transient( static::KITS_CACHE_KEY );
$experiments_manager = Plugin::$instance->experiments;
$kits_editor_layout_type = $experiments_manager->is_feature_active( 'container' ) ? 'container_flexbox' : '';
if ( ! $data || $force_api_request ) {
$args = [
'body' => [
'editor_layout_type' => $kits_editor_layout_type,
],
];
/**
* Filters arguments for the request to the Kits API.
*
* @since 3.11.0
*
* @param array[] $args Array of http arguments.
*/
$args = apply_filters( 'elementor/kit-library/get-kits-data/args', $args );
$data = $this->api->get_all( $args );
if ( is_wp_error( $data ) ) {
throw new WP_Error_Exception( $data );
}
set_transient( static::KITS_CACHE_KEY, $data, static::KITS_CACHE_TTL_HOURS * HOUR_IN_SECONDS );
}
return new Collection( $data );
}
/**
* @param bool $force_api_request
*
* @return Collection
*/
private function get_taxonomies_data( $force_api_request = false ) {
$data = get_transient( static::KITS_TAXONOMIES_CACHE_KEY );
if ( ! $data || $force_api_request ) {
$data = $this->api->get_taxonomies();
if ( is_wp_error( $data ) ) {
throw new WP_Error_Exception( $data );
}
set_transient( static::KITS_TAXONOMIES_CACHE_KEY, $data, static::KITS_TAXONOMIES_CACHE_TTL_HOURS * HOUR_IN_SECONDS );
}
return new Collection( (array) $data );
}
/**
* @param $kit
* @param null $manifest
*
* @return array
*/
private function transform_kit_api_response( $kit, $manifest = null ) {
// BC: Support legacy APIs that don't have access tiers.
if ( isset( $kit->access_tier ) ) {
$access_tier = $kit->access_tier;
} else {
$access_tier = 0 === $kit->access_level
? ConnectModule::ACCESS_TIER_FREE
: ConnectModule::ACCESS_TIER_ESSENTIAL;
}
$subscription_plan_tag = $this->subscription_plans->get( $access_tier );
$taxonomies = ( new Collection( ( (array) $kit )['taxonomies'] ) )
->filter( function ( $taxonomy ) {
return in_array( $taxonomy->type, self::TAXONOMIES_KEYS );
} )
->flatten()
->pluck( 'name' )
->push( $subscription_plan_tag ? $subscription_plan_tag : self::SUBSCRIPTION_PLAN_FREE_TAG );
return array_merge(
[
'id' => $kit->_id,
'title' => $kit->title,
'thumbnail_url' => $kit->thumbnail,
'access_level' => $kit->access_level,
'access_tier' => $access_tier,
'keywords' => $kit->keywords,
'taxonomies' => $taxonomies->values(),
'is_favorite' => $this->user_favorites->exists( 'elementor', 'kits', $kit->_id ),
// TODO: Remove all the isset when the API stable.
'trend_index' => isset( $kit->trend_index ) ? $kit->trend_index : 0,
'featured_index' => isset( $kit->featured_index ) ? $kit->featured_index : 0,
'popularity_index' => isset( $kit->popularity_index ) ? $kit->popularity_index : 0,
'created_at' => isset( $kit->created_at ) ? $kit->created_at : null,
'updated_at' => isset( $kit->updated_at ) ? $kit->updated_at : null,
//
],
$manifest ? $this->transform_manifest_api_response( $manifest ) : []
);
}
/**
* @param $manifest
*
* @return array
*/
private function transform_manifest_api_response( $manifest ) {
$manifest_content = ( new Collection( (array) $manifest->content ) )
->reduce( function ( $carry, $content, $type ) {
$mapped_documents = array_map( function ( $document ) use ( $type ) {
// TODO: Fix it!
// Hack to override a bug when a document with type of 'wp-page' is declared as 'wp-post'.
if ( 'page' === $type ) {
$document->doc_type = 'wp-page';
}
return $document;
}, (array) $content );
return $carry + $mapped_documents;
}, [] );
$content = ( new Collection( (array) $manifest->templates ) )
->union( $manifest_content )
->map( function ( $manifest_item, $key ) {
return [
'id' => isset( $manifest_item->id ) ? $manifest_item->id : $key,
'title' => $manifest_item->title,
'doc_type' => $manifest_item->doc_type,
'thumbnail_url' => $manifest_item->thumbnail,
'preview_url' => isset( $manifest_item->url ) ? $manifest_item->url : null,
];
} );
return [
'description' => $manifest->description,
'preview_url' => isset( $manifest->site ) ? $manifest->site : '',
'documents' => $content->values(),
];
}
/**
* @param Kit_Library $kit_library
* @param User_Favorites $user_favorites
* @param Collection $subscription_plans
*/
public function __construct( Kit_Library $kit_library, User_Favorites $user_favorites, Collection $subscription_plans ) {
$this->api = $kit_library;
$this->user_favorites = $user_favorites;
$this->subscription_plans = $subscription_plans;
}
public static function clear_cache() {
delete_transient( static::KITS_CACHE_KEY );
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Elementor\App\Modules\KitLibrary\Data\Taxonomies;
use Elementor\App\Modules\KitLibrary\Data\Base_Controller;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
class Controller extends Base_Controller {
public function get_name() {
return 'kit-taxonomies';
}
public function get_collection_params() {
return [
'force' => [
'description' => 'Force an API request and skip the cache.',
'required' => false,
'default' => false,
'type' => 'boolean',
],
];
}
public function get_items( $request ) {
$data = $this->get_repository()->get_taxonomies( $request->get_param( 'force' ) );
return [
'data' => $data->values(),
];
}
public function get_permission_callback( $request ) {
return current_user_can( 'administrator' );
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Elementor\App\Modules\KitLibrary;
use Elementor\Core\Admin\Menu\Interfaces\Admin_Menu_Item;
use Elementor\TemplateLibrary\Source_Local;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
class Kit_Library_Menu_Item implements Admin_Menu_Item {
public function is_visible() {
return true;
}
public function get_parent_slug() {
return Source_Local::ADMIN_MENU_SLUG;
}
public function get_label() {
return esc_html__( 'Kit Library', 'elementor' );
}
public function get_capability() {
return 'manage_options';
}
}

View File

@@ -0,0 +1,123 @@
<?php
namespace Elementor\App\Modules\KitLibrary;
use Elementor\App\Modules\KitLibrary\Data\Repository;
use Elementor\Core\Admin\Menu\Admin_Menu_Manager;
use Elementor\Core\Admin\Menu\Main as MainMenu;
use Elementor\Plugin;
use Elementor\TemplateLibrary\Source_Local;
use Elementor\Core\Base\Module as BaseModule;
use Elementor\App\Modules\KitLibrary\Connect\Kit_Library;
use Elementor\Core\Common\Modules\Connect\Module as ConnectModule;
use Elementor\App\Modules\KitLibrary\Data\Kits\Controller as Kits_Controller;
use Elementor\App\Modules\KitLibrary\Data\Taxonomies\Controller as Taxonomies_Controller;
use Elementor\Core\Utils\Promotions\Filtered_Promotions_Manager;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class Module extends BaseModule {
/**
* Get name.
*
* @access public
*
* @return string
*/
public function get_name() {
return 'kit-library';
}
private function register_admin_menu( MainMenu $menu ) {
$menu->add_submenu( [
'page_title' => esc_html__( 'Kit Library', 'elementor' ),
'menu_title' => '<span id="e-admin-menu__kit-library">' . esc_html__( 'Kit Library', 'elementor' ) . '</span>',
'menu_slug' => Plugin::$instance->app->get_base_url() . '#/kit-library',
'index' => 40,
] );
}
/**
* Register the admin menu the old way.
*/
private function register_admin_menu_legacy( Admin_Menu_Manager $admin_menu ) {
$admin_menu->register(
Plugin::$instance->app->get_base_url() . '#/kit-library',
new Kit_Library_Menu_Item()
);
}
private function set_kit_library_settings() {
if ( ! Plugin::$instance->common ) {
return;
}
/** @var ConnectModule $connect */
$connect = Plugin::$instance->common->get_component( 'connect' );
/** @var Kit_Library $kit_library */
$kit_library = $connect->get_app( 'kit-library' );
Plugin::$instance->app->set_settings( 'kit-library', [
'has_access_to_module' => current_user_can( 'administrator' ),
'subscription_plans' => $this->apply_filter_subscription_plans( $connect->get_subscription_plans( 'kit-library' ) ),
'is_pro' => false,
'is_library_connected' => $kit_library->is_connected(),
'library_connect_url' => $kit_library->get_admin_url( 'authorize', [
'utm_source' => 'kit-library',
'utm_medium' => 'wp-dash',
'utm_campaign' => 'library-connect',
'utm_term' => '%%page%%', // Will be replaced in the frontend.
] ),
'access_level' => ConnectModule::ACCESS_LEVEL_CORE,
'access_tier' => ConnectModule::ACCESS_TIER_FREE,
'app_url' => Plugin::$instance->app->get_base_url() . '#/' . $this->get_name(),
] );
}
private function apply_filter_subscription_plans( array $subscription_plans ): array {
foreach ( $subscription_plans as $key => $plan ) {
if ( null === $plan['promotion_url'] ) {
continue;
}
$subscription_plans[ $key ] = Filtered_Promotions_Manager::get_filtered_promotion_data(
$plan,
'elementor/kit_library/' . $key . '/promotion',
'promotion_url'
);
}
return $subscription_plans;
}
/**
* Module constructor.
*/
public function __construct() {
Plugin::$instance->data_manager_v2->register_controller( new Kits_Controller() );
Plugin::$instance->data_manager_v2->register_controller( new Taxonomies_Controller() );
// Assigning this action here since the repository is being loaded by demand.
add_action( 'elementor/experiments/feature-state-change/container', [ Repository::class, 'clear_cache' ], 10, 0 );
if ( Plugin::$instance->experiments->is_feature_active( 'admin_menu_rearrangement' ) ) {
add_action( 'elementor/admin/menu_registered/elementor', function( MainMenu $menu ) {
$this->register_admin_menu( $menu );
} );
} else {
add_action( 'elementor/admin/menu/register', function( Admin_Menu_Manager $admin_menu ) {
$this->register_admin_menu_legacy( $admin_menu );
}, Source_Local::ADMIN_MENU_PRIORITY + 30 );
}
add_action( 'elementor/connect/apps/register', function ( ConnectModule $connect_module ) {
$connect_module->register_app( 'kit-library', Kit_Library::get_class_name() );
} );
add_action( 'elementor/init', function () {
$this->set_kit_library_settings();
}, 12 /** after the initiation of the connect kit library */ );
}
}

View File

@@ -0,0 +1,485 @@
<?php
namespace Elementor\App\Modules\Onboarding;
use Automatic_Upgrader_Skin;
use Elementor\Core\Base\Module as BaseModule;
use Elementor\Core\Common\Modules\Ajax\Module as Ajax;
use Elementor\Core\Common\Modules\Connect\Apps\Library;
use Elementor\Core\Files\Uploads_Manager;
use Elementor\Plugin;
use Elementor\Tracker;
use Elementor\Utils;
use Plugin_Upgrader;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
/**
* Onboarding Module
*
* Responsible for initializing Elementor App functionality
*
* @since 3.6.0
*/
class Module extends BaseModule {
const VERSION = '1.0.0';
const ONBOARDING_OPTION = 'elementor_onboarded';
/**
* Get name.
*
* @since 3.6.0
* @access public
*
* @return string
*/
public function get_name() {
return 'onboarding';
}
/**
* Set Onboarding Settings
*
* Creates an array of module settings that is localized into the JS App config.
*
* @since 3.6.0
*/
private function set_onboarding_settings() {
if ( ! Plugin::$instance->common ) {
return;
}
// Get the published pages and posts
$pages_and_posts = new \WP_Query( [
'post_type' => [ 'page', 'post' ],
'post_status' => 'publish',
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'no_found_rows' => true,
] );
$custom_site_logo_id = get_theme_mod( 'custom_logo' );
$custom_logo_src = wp_get_attachment_image_src( $custom_site_logo_id, 'full' );
$site_name = get_option( 'blogname', '' );
$hello_theme = wp_get_theme( 'hello-elementor' );
$hello_theme_errors = is_object( $hello_theme->errors() ) ? $hello_theme->errors()->errors : [];
/** @var Library $library */
$library = Plugin::$instance->common->get_component( 'connect' )->get_app( 'library' );
Plugin::$instance->app->set_settings( 'onboarding', [
'eventPlacement' => 'Onboarding wizard',
'onboardingAlreadyRan' => get_option( self::ONBOARDING_OPTION ),
'onboardingVersion' => self::VERSION,
'isLibraryConnected' => $library->is_connected(),
// Used to check if the Hello Elementor theme is installed but not activated.
'helloInstalled' => empty( $hello_theme_errors['theme_not_found'] ),
'helloActivated' => 'hello-elementor' === get_option( 'template' ),
// The "Use Hello theme on my site" checkbox should be checked by default only if this condition is met.
'helloOptOut' => count( $pages_and_posts->posts ) < 5,
'siteName' => esc_html( $site_name ),
'isUnfilteredFilesEnabled' => Uploads_Manager::are_unfiltered_uploads_enabled(),
'urls' => [
'kitLibrary' => Plugin::$instance->app->get_base_url() . '#/kit-library?order[direction]=desc&order[by]=featuredIndex',
'createNewPage' => Plugin::$instance->documents->get_create_new_post_url(),
'connect' => $library->get_admin_url( 'authorize', [
'utm_source' => 'onboarding-wizard',
'utm_campaign' => 'connect-account',
'utm_medium' => 'wp-dash',
'utm_term' => self::VERSION,
'source' => 'generic',
] ),
'signUp' => $library->get_admin_url( 'authorize', [
'utm_source' => 'onboarding-wizard',
'utm_campaign' => 'connect-account',
'utm_medium' => 'wp-dash',
'utm_term' => self::VERSION,
'source' => 'generic',
'screen_hint' => 'signup',
] ),
'uploadPro' => Plugin::$instance->app->get_base_url() . '#/onboarding/uploadAndInstallPro?mode=popup',
],
'siteLogo' => [
'id' => $custom_site_logo_id,
'url' => $custom_logo_src ? $custom_logo_src[0] : '',
],
'utms' => [
'connectTopBar' => '&utm_content=top-bar',
'connectCta' => '&utm_content=cta-button',
'connectCtaLink' => '&utm_content=cta-link',
'downloadPro' => '?utm_source=onboarding-wizard&utm_campaign=my-account-subscriptions&utm_medium=wp-dash&utm_content=import-pro-plugin&utm_term=' . self::VERSION,
],
'nonce' => wp_create_nonce( 'onboarding' ),
] );
}
/**
* Get Permission Error Response
*
* Returns the response that is returned when the user's capabilities are not sufficient for performing an action.
*
* @since 3.6.4
*
* @return array
*/
private function get_permission_error_response() {
return [
'status' => 'error',
'payload' => [
'error_message' => esc_html__( 'You do not have permission to perform this action.', 'elementor' ),
],
];
}
/**
* Maybe Update Site Logo
*
* If a new name is provided, it will be updated as the Site Name.
*
* @since 3.6.0
*
* @return array
*/
private function maybe_update_site_name() {
$problem_error = [
'status' => 'error',
'payload' => [
'error_message' => esc_html__( 'There was a problem setting your site name.', 'elementor' ),
],
];
// phpcs:ignore WordPress.Security.NonceVerification.Missing
if ( empty( $_POST['data'] ) ) {
return $problem_error;
}
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$data = json_decode( Utils::get_super_global_value( $_POST, 'data' ), true );
if ( ! isset( $data['siteName'] ) ) {
return $problem_error;
}
/**
* Onboarding Site Name
*
* Filters the new site name passed by the user to update in Elementor's onboarding process.
* Elementor runs `esc_html()` on the Site Name passed by the user for security reasons. If a user wants to
* include special characters in their site name, they can use this filter to override it.
*
* @since 3.6.0
*
* @param string Escaped new site name
*/
$new_site_name = apply_filters( 'elementor/onboarding/site-name', $data['siteName'] );
// The site name is sanitized in `update_options()`
update_option( 'blogname', $new_site_name );
return [
'status' => 'success',
'payload' => [
'siteNameUpdated' => true,
],
];
}
/**
* Maybe Update Site Logo
*
* If an image attachment ID is provided, it will be updated as the Site Logo Theme Mod.
*
* @since 3.6.0
*
* @return array
*/
private function maybe_update_site_logo() {
if ( ! current_user_can( 'edit_theme_options' ) ) {
return $this->get_permission_error_response();
}
$data_error = [
'status' => 'error',
'payload' => [
'error_message' => esc_html__( 'There was a problem setting your site logo.', 'elementor' ),
],
];
// phpcs:ignore WordPress.Security.NonceVerification.Missing
if ( empty( $_POST['data'] ) ) {
return $data_error;
}
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$data = json_decode( Utils::get_super_global_value( $_POST, 'data' ), true );
// If there is no attachment ID passed or it is not a valid ID, exit here.
if ( empty( $data['attachmentId'] ) ) {
return $data_error;
}
$absint_attachment_id = absint( $data['attachmentId'] );
if ( 0 === $absint_attachment_id ) {
return $data_error;
}
$attachment_url = wp_get_attachment_url( $data['attachmentId'] );
// Check if the attachment exists. If it does not, exit here.
if ( ! $attachment_url ) {
return $data_error;
}
set_theme_mod( 'custom_logo', $absint_attachment_id );
return [
'status' => 'success',
'payload' => [
'siteLogoUpdated' => true,
],
];
}
/**
* Maybe Upload Logo Image
*
* If an image file upload is provided, and it passes validation, it will be uploaded to the site's Media Library.
*
* @since 3.6.0
*
* @return array
*/
private function maybe_upload_logo_image() {
$error_message = esc_html__( 'There was a problem uploading your file.', 'elementor' );
$file = Utils::get_super_global_value( $_FILES, 'fileToUpload' );
// phpcs:ignore WordPress.Security.NonceVerification.Missing
if ( ! is_array( $file ) || empty( $file['type'] ) ) {
return [
'status' => 'error',
'payload' => [
'error_message' => $error_message,
],
];
}
// If the user has allowed it, set the Request's state as an "Elementor Upload" request, in order to add
// support for non-standard file uploads.
if ( 'image/svg+xml' === $file['type'] ) {
if ( Uploads_Manager::are_unfiltered_uploads_enabled() ) {
Plugin::$instance->uploads_manager->set_elementor_upload_state( true );
} else {
wp_send_json_error( 'To upload SVG files, you must allow uploading unfiltered files.' );
}
}
// If the image is an SVG file, sanitation is performed during the import (upload) process.
$image_attachment = Plugin::$instance->templates_manager->get_import_images_instance()->import( $file );
if ( 'image/svg+xml' === $file['type'] && Uploads_Manager::are_unfiltered_uploads_enabled() ) {
// Reset Upload state.
Plugin::$instance->uploads_manager->set_elementor_upload_state( false );
}
if ( $image_attachment && ! is_wp_error( $image_attachment ) ) {
$result = [
'status' => 'success',
'payload' => [
'imageAttachment' => $image_attachment,
],
];
} else {
$result = [
'status' => 'error',
'payload' => [
'error_message' => $error_message,
],
];
}
return $result;
}
/**
* Activate Hello Theme
*
* @since 3.6.0
*
* @return array
*/
private function maybe_activate_hello_theme() {
if ( ! current_user_can( 'switch_themes' ) ) {
return $this->get_permission_error_response();
}
switch_theme( 'hello-elementor' );
return [
'status' => 'success',
'payload' => [
'helloThemeActivated' => true,
],
];
}
/**
* Upload and Install Elementor Pro
*
* @since 3.6.0
*
* @return array
*/
private function upload_and_install_pro() {
if ( ! current_user_can( 'install_plugins' ) || ! current_user_can( 'activate_plugins' ) ) {
return $this->get_permission_error_response();
}
$error_message = esc_html__( 'There was a problem uploading your file.', 'elementor' );
$file = Utils::get_super_global_value( $_FILES, 'fileToUpload' ) ?? [];
// phpcs:ignore WordPress.Security.NonceVerification.Missing
if ( ! is_array( $file ) || empty( $file['type'] ) ) {
return [
'status' => 'error',
'payload' => [
'error_message' => $error_message,
],
];
}
$result = [];
if ( ! class_exists( 'Automatic_Upgrader_Skin' ) ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
}
$skin = new Automatic_Upgrader_Skin();
$upgrader = new Plugin_Upgrader( $skin );
$upload_result = $upgrader->install( $file['tmp_name'], [ 'overwrite_package' => false ] );
if ( ! $upload_result || is_wp_error( $upload_result ) ) {
$result = [
'status' => 'error',
'payload' => [
'error_message' => $error_message,
],
];
} else {
$activated = activate_plugin( WP_PLUGIN_DIR . '/elementor-pro/elementor-pro.php', false, false, true );
if ( ! is_wp_error( $activated ) ) {
$result = [
'status' => 'success',
'payload' => [
'elementorProInstalled' => true,
],
];
} else {
$result = [
'status' => 'error',
'payload' => [
'error_message' => $error_message,
'elementorProInstalled' => false,
],
];
}
}
return $result;
}
private function maybe_update_onboarding_db_option() {
$db_option = get_option( self::ONBOARDING_OPTION );
if ( ! $db_option ) {
update_option( self::ONBOARDING_OPTION, true );
}
return [
'status' => 'success',
'payload' => 'onboarding DB',
];
}
/**
* Maybe Handle Ajax
*
* This method checks if there are any AJAX actions being
* @since 3.6.0
*
* @return array|null
*/
private function maybe_handle_ajax() {
$result = [];
// phpcs:ignore WordPress.Security.NonceVerification.Missing
switch ( Utils::get_super_global_value( $_POST, 'action' ) ) {
case 'elementor_update_site_name':
// If no value is passed for any reason, no need ot update the site name.
$result = $this->maybe_update_site_name();
break;
case 'elementor_update_site_logo':
$result = $this->maybe_update_site_logo();
break;
case 'elementor_upload_site_logo':
$result = $this->maybe_upload_logo_image();
break;
case 'elementor_activate_hello_theme':
$result = $this->maybe_activate_hello_theme();
break;
case 'elementor_upload_and_install_pro':
$result = $this->upload_and_install_pro();
break;
case 'elementor_update_onboarding_option':
$result = $this->maybe_update_onboarding_db_option();
}
if ( ! empty( $result ) ) {
if ( 'success' === $result['status'] ) {
wp_send_json_success( $result['payload'] );
} else {
wp_send_json_error( $result['payload'] );
}
}
}
public function __construct() {
add_action( 'elementor/init', function() {
// Only load when viewing the onboarding app.
if ( Plugin::$instance->app->is_current() ) {
$this->set_onboarding_settings();
// Needed for installing the Hello Elementor theme.
wp_enqueue_script( 'updates' );
// Needed for uploading Logo from WP Media Library.
wp_enqueue_media();
}
}, 12 );
// Needed for uploading Logo from WP Media Library. The 'admin_menu' hook is used because it runs before
// 'admin_init', and the App triggers printing footer scripts on 'admin_init' at priority 0.
add_action( 'admin_menu', function () {
add_action( 'wp_print_footer_scripts', function () {
if ( function_exists( 'wp_print_media_templates' ) ) {
wp_print_media_templates();
}
} );
} );
add_action( 'admin_init', function() {
if ( wp_doing_ajax() &&
isset( $_POST['action'] ) &&
isset( $_POST['_nonce'] ) &&
wp_verify_nonce( Utils::get_super_global_value( $_POST, '_nonce' ), Ajax::NONCE_KEY ) &&
current_user_can( 'manage_options' )
) {
$this->maybe_handle_ajax();
}
} );
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace Elementor\App\Modules\SiteEditor;
use Elementor\Core\Base\Module as BaseModule;
use Elementor\Plugin;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
/**
* Site Editor Module
*
* Responsible for initializing Elementor App functionality
*/
class Module extends BaseModule {
/**
* Get name.
*
* @access public
*
* @return string
*/
public function get_name() {
return 'site-editor';
}
public function add_menu_in_admin_bar( $admin_bar_config ) {
$admin_bar_config['elementor_edit_page']['children'][] = [
'id' => 'elementor_app_site_editor',
'title' => esc_html__( 'Theme Builder', 'elementor' ),
'sub_title' => esc_html__( 'Site', 'elementor' ),
'href' => Plugin::$instance->app->get_settings( 'menu_url' ),
'class' => 'elementor-app-link',
'parent_class' => 'elementor-second-section',
];
return $admin_bar_config;
}
public function __construct() {
add_filter( 'elementor/frontend/admin_bar/settings', [ $this, 'add_menu_in_admin_bar' ] ); // After kit (Site settings)
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace Elementor\App;
use Elementor\Utils;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* @var App $this
*/
$theme_class = 'dark' === $this->get_elementor_ui_theme_preference() ? 'eps-theme-dark' : '';
?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><?php echo esc_html__( 'Elementor', 'elementor' ) . ' ... '; ?></title>
<base target="_parent">
<?php wp_print_styles(); ?>
</head>
<body class="<?php Utils::print_unescaped_internal_string( $theme_class ); ?>">
<div id="e-app"></div>
<?php wp_print_footer_scripts(); ?>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,165 @@
/*! elementor - v3.21.0 - 25-04-2024 */
#e-dashboard-widget-admin-top-bar {
position: absolute;
opacity: 0;
pointer-events: none;
}
#e-admin-top-bar-root {
left: 0;
font-family: var(--e-a-font-family);
background: var(--e-a-bg-default);
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.03);
display: none;
position: absolute;
top: 0;
width: calc(100% - 160px);
z-index: 1;
}
body.folded #e-admin-top-bar-root {
width: calc(100% - 36px);
}
#e-admin-top-bar-root .e-admin-top-bar {
display: flex;
height: 50px;
justify-content: space-between;
padding: 0 16px;
}
#e-admin-top-bar-root .page-title-action {
font-size: 12px;
font-weight: 500;
line-height: 1.2;
text-transform: uppercase;
text-decoration: none;
padding: 8px 16px;
outline: none;
border: none;
border-radius: var(--e-a-border-radius);
background-color: var(--e-a-btn-bg);
color: var(--e-a-btn-color-invert);
transition: var(--e-a-transition-hover);
}
#e-admin-top-bar-root .page-title-action:hover {
background-color: var(--e-a-btn-bg-hover);
color: var(--e-a-btn-color-invert);
}
#e-admin-top-bar-root .e-admin-top-bar__heading {
display: inline-flex;
align-items: center;
justify-content: center;
margin-inline-end: 40px;
}
#e-admin-top-bar-root .e-admin-top-bar__main-area {
display: inline-flex;
align-items: center;
justify-content: center;
}
#e-admin-top-bar-root .e-admin-top-bar__main-area button {
margin: 0 4px;
}
#e-admin-top-bar-root .e-admin-top-bar__secondary-area {
display: inline-flex;
align-items: center;
justify-content: center;
}
#e-admin-top-bar-root .e-admin-top-bar__heading-title {
color: var(--e-a-color-txt);
font-size: 15px;
font-weight: 700;
padding: 0 8px;
line-height: normal;
}
#e-admin-top-bar-root .e-admin-top-bar__main-area-buttons {
display: inline-flex;
gap: 5px;
}
#e-admin-top-bar-root.e-admin-top-bar--active {
display: block;
}
#e-admin-top-bar-root.e-admin-top-bar--active ~ #wpbody #wpbody-content {
margin-block-start: 50px;
}
#e-admin-top-bar-root.e-admin-top-bar--active ~ #wpbody .wrap {
clear: both;
padding-block-start: 10px;
}
#e-admin-top-bar-root.e-admin-top-bar--active ~ #wpbody .wrap h1 {
display: none;
}
#e-admin-top-bar-root:not(.e-admin-top-bar--active) ~ #wpbody .wrap h1, #e-admin-top-bar-root:not(.e-admin-top-bar--active) ~ #wpbody .wrap .page-title-action {
display: inline-block;
}
#e-admin-top-bar-root .e-admin-top-bar__bar-button {
align-items: center;
cursor: pointer;
display: inline-flex;
justify-content: center;
margin: 0 10px;
text-decoration: none;
color: var(--e-a-color-txt);
}
#e-admin-top-bar-root .e-admin-top-bar__bar-button.accent {
color: var(--e-a-color-accent);
}
#e-admin-top-bar-root .e-admin-top-bar__bar-button.accent:hover .e-admin-top-bar__bar-button-title,
#e-admin-top-bar-root .e-admin-top-bar__bar-button.accent:hover .e-admin-top-bar__bar-button-icon {
color: var(--e-a-color-accent);
}
#e-admin-top-bar-root .e-admin-top-bar__bar-button .crown-icon {
font-size: 14px;
}
#e-admin-top-bar-root .e-admin-top-bar__bar-button .e-admin-top-bar__bar-button-icon {
margin: 0 4px;
}
#e-admin-top-bar-root .e-admin-top-bar__bar-button:hover .e-admin-top-bar__bar-button-title,
#e-admin-top-bar-root .e-admin-top-bar__bar-button:hover .e-admin-top-bar__bar-button-icon {
color: var(--e-a-color-txt-hover);
}
#e-admin-top-bar-root .e-admin-top-bar__bar-button-title {
font-size: 13px;
font-weight: 500;
margin: 0 4px;
line-height: normal;
}
#e-admin-top-bar-root ~ #wpbody .wrap h1, #e-admin-top-bar-root ~ #wpbody .wrap .page-title-action {
display: none;
}
@media screen and (max-width: 960px) {
#e-admin-top-bar-root {
width: calc(100% - 36px);
}
}
@media screen and (max-width: 782px) {
#e-admin-top-bar-root {
width: 100%;
}
}
@media screen and (max-width: 600px) {
#e-admin-top-bar-root {
top: 46px;
}
}
@media (max-width: 768px) {
#e-admin-top-bar-root {
display: inline-flex;
align-items: center;
justify-content: center;
}
#e-admin-top-bar-root .e-admin-top-bar__main-area-buttons {
position: absolute;
top: calc(100% + 10px);
}
#e-admin-top-bar-root .e-admin-top-bar__secondary-area .e-admin-top-bar__secondary-area-buttons {
display: none;
}
#e-admin-top-bar-root .e-admin-top-bar__secondary-area > .e-admin-top-bar__bar-button .e-admin-top-bar__bar-button-title {
display: none;
}
}
@media (min-width: 768px) {
#e-admin-top-bar-root .e-admin-top-bar__secondary-area .e-admin-top-bar__secondary-area-buttons {
display: flex;
}
}
/*# sourceMappingURL=admin-top-bar-rtl.css.map */

View File

@@ -0,0 +1,2 @@
/*! elementor - v3.21.0 - 25-04-2024 */
#e-dashboard-widget-admin-top-bar{position:absolute;opacity:0;pointer-events:none}#e-admin-top-bar-root{left:0;font-family:var(--e-a-font-family);background:var(--e-a-bg-default);box-shadow:0 4px 6px rgba(0,0,0,.03);display:none;position:absolute;top:0;width:calc(100% - 160px);z-index:1}body.folded #e-admin-top-bar-root{width:calc(100% - 36px)}#e-admin-top-bar-root .e-admin-top-bar{display:flex;height:50px;justify-content:space-between;padding:0 16px}#e-admin-top-bar-root .page-title-action{font-size:12px;font-weight:500;line-height:1.2;text-transform:uppercase;text-decoration:none;padding:8px 16px;outline:none;border:none;border-radius:var(--e-a-border-radius);background-color:var(--e-a-btn-bg);color:var(--e-a-btn-color-invert);transition:var(--e-a-transition-hover)}#e-admin-top-bar-root .page-title-action:hover{background-color:var(--e-a-btn-bg-hover);color:var(--e-a-btn-color-invert)}#e-admin-top-bar-root .e-admin-top-bar__heading{margin-inline-end:40px}#e-admin-top-bar-root .e-admin-top-bar__heading,#e-admin-top-bar-root .e-admin-top-bar__main-area{display:inline-flex;align-items:center;justify-content:center}#e-admin-top-bar-root .e-admin-top-bar__main-area button{margin:0 4px}#e-admin-top-bar-root .e-admin-top-bar__secondary-area{display:inline-flex;align-items:center;justify-content:center}#e-admin-top-bar-root .e-admin-top-bar__heading-title{color:var(--e-a-color-txt);font-size:15px;font-weight:700;padding:0 8px;line-height:normal}#e-admin-top-bar-root .e-admin-top-bar__main-area-buttons{display:inline-flex;gap:5px}#e-admin-top-bar-root.e-admin-top-bar--active{display:block}#e-admin-top-bar-root.e-admin-top-bar--active~#wpbody #wpbody-content{margin-block-start:50px}#e-admin-top-bar-root.e-admin-top-bar--active~#wpbody .wrap{clear:both;padding-block-start:10px}#e-admin-top-bar-root.e-admin-top-bar--active~#wpbody .wrap h1{display:none}#e-admin-top-bar-root:not(.e-admin-top-bar--active)~#wpbody .wrap .page-title-action,#e-admin-top-bar-root:not(.e-admin-top-bar--active)~#wpbody .wrap h1{display:inline-block}#e-admin-top-bar-root .e-admin-top-bar__bar-button{align-items:center;cursor:pointer;display:inline-flex;justify-content:center;margin:0 10px;text-decoration:none;color:var(--e-a-color-txt)}#e-admin-top-bar-root .e-admin-top-bar__bar-button.accent,#e-admin-top-bar-root .e-admin-top-bar__bar-button.accent:hover .e-admin-top-bar__bar-button-icon,#e-admin-top-bar-root .e-admin-top-bar__bar-button.accent:hover .e-admin-top-bar__bar-button-title{color:var(--e-a-color-accent)}#e-admin-top-bar-root .e-admin-top-bar__bar-button .crown-icon{font-size:14px}#e-admin-top-bar-root .e-admin-top-bar__bar-button .e-admin-top-bar__bar-button-icon{margin:0 4px}#e-admin-top-bar-root .e-admin-top-bar__bar-button:hover .e-admin-top-bar__bar-button-icon,#e-admin-top-bar-root .e-admin-top-bar__bar-button:hover .e-admin-top-bar__bar-button-title{color:var(--e-a-color-txt-hover)}#e-admin-top-bar-root .e-admin-top-bar__bar-button-title{font-size:13px;font-weight:500;margin:0 4px;line-height:normal}#e-admin-top-bar-root~#wpbody .wrap .page-title-action,#e-admin-top-bar-root~#wpbody .wrap h1{display:none}@media screen and (max-width:960px){#e-admin-top-bar-root{width:calc(100% - 36px)}}@media screen and (max-width:782px){#e-admin-top-bar-root{width:100%}}@media screen and (max-width:600px){#e-admin-top-bar-root{top:46px}}@media (max-width:768px){#e-admin-top-bar-root{display:inline-flex;align-items:center;justify-content:center}#e-admin-top-bar-root .e-admin-top-bar__main-area-buttons{position:absolute;top:calc(100% + 10px)}#e-admin-top-bar-root .e-admin-top-bar__secondary-area .e-admin-top-bar__secondary-area-buttons,#e-admin-top-bar-root .e-admin-top-bar__secondary-area>.e-admin-top-bar__bar-button .e-admin-top-bar__bar-button-title{display:none}}@media (min-width:768px){#e-admin-top-bar-root .e-admin-top-bar__secondary-area .e-admin-top-bar__secondary-area-buttons{display:flex}}

View File

@@ -0,0 +1,165 @@
/*! elementor - v3.21.0 - 25-04-2024 */
#e-dashboard-widget-admin-top-bar {
position: absolute;
opacity: 0;
pointer-events: none;
}
#e-admin-top-bar-root {
right: 0;
font-family: var(--e-a-font-family);
background: var(--e-a-bg-default);
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.03);
display: none;
position: absolute;
top: 0;
width: calc(100% - 160px);
z-index: 1;
}
body.folded #e-admin-top-bar-root {
width: calc(100% - 36px);
}
#e-admin-top-bar-root .e-admin-top-bar {
display: flex;
height: 50px;
justify-content: space-between;
padding: 0 16px;
}
#e-admin-top-bar-root .page-title-action {
font-size: 12px;
font-weight: 500;
line-height: 1.2;
text-transform: uppercase;
text-decoration: none;
padding: 8px 16px;
outline: none;
border: none;
border-radius: var(--e-a-border-radius);
background-color: var(--e-a-btn-bg);
color: var(--e-a-btn-color-invert);
transition: var(--e-a-transition-hover);
}
#e-admin-top-bar-root .page-title-action:hover {
background-color: var(--e-a-btn-bg-hover);
color: var(--e-a-btn-color-invert);
}
#e-admin-top-bar-root .e-admin-top-bar__heading {
display: inline-flex;
align-items: center;
justify-content: center;
margin-inline-end: 40px;
}
#e-admin-top-bar-root .e-admin-top-bar__main-area {
display: inline-flex;
align-items: center;
justify-content: center;
}
#e-admin-top-bar-root .e-admin-top-bar__main-area button {
margin: 0 4px;
}
#e-admin-top-bar-root .e-admin-top-bar__secondary-area {
display: inline-flex;
align-items: center;
justify-content: center;
}
#e-admin-top-bar-root .e-admin-top-bar__heading-title {
color: var(--e-a-color-txt);
font-size: 15px;
font-weight: 700;
padding: 0 8px;
line-height: normal;
}
#e-admin-top-bar-root .e-admin-top-bar__main-area-buttons {
display: inline-flex;
gap: 5px;
}
#e-admin-top-bar-root.e-admin-top-bar--active {
display: block;
}
#e-admin-top-bar-root.e-admin-top-bar--active ~ #wpbody #wpbody-content {
margin-block-start: 50px;
}
#e-admin-top-bar-root.e-admin-top-bar--active ~ #wpbody .wrap {
clear: both;
padding-block-start: 10px;
}
#e-admin-top-bar-root.e-admin-top-bar--active ~ #wpbody .wrap h1 {
display: none;
}
#e-admin-top-bar-root:not(.e-admin-top-bar--active) ~ #wpbody .wrap h1, #e-admin-top-bar-root:not(.e-admin-top-bar--active) ~ #wpbody .wrap .page-title-action {
display: inline-block;
}
#e-admin-top-bar-root .e-admin-top-bar__bar-button {
align-items: center;
cursor: pointer;
display: inline-flex;
justify-content: center;
margin: 0 10px;
text-decoration: none;
color: var(--e-a-color-txt);
}
#e-admin-top-bar-root .e-admin-top-bar__bar-button.accent {
color: var(--e-a-color-accent);
}
#e-admin-top-bar-root .e-admin-top-bar__bar-button.accent:hover .e-admin-top-bar__bar-button-title,
#e-admin-top-bar-root .e-admin-top-bar__bar-button.accent:hover .e-admin-top-bar__bar-button-icon {
color: var(--e-a-color-accent);
}
#e-admin-top-bar-root .e-admin-top-bar__bar-button .crown-icon {
font-size: 14px;
}
#e-admin-top-bar-root .e-admin-top-bar__bar-button .e-admin-top-bar__bar-button-icon {
margin: 0 4px;
}
#e-admin-top-bar-root .e-admin-top-bar__bar-button:hover .e-admin-top-bar__bar-button-title,
#e-admin-top-bar-root .e-admin-top-bar__bar-button:hover .e-admin-top-bar__bar-button-icon {
color: var(--e-a-color-txt-hover);
}
#e-admin-top-bar-root .e-admin-top-bar__bar-button-title {
font-size: 13px;
font-weight: 500;
margin: 0 4px;
line-height: normal;
}
#e-admin-top-bar-root ~ #wpbody .wrap h1, #e-admin-top-bar-root ~ #wpbody .wrap .page-title-action {
display: none;
}
@media screen and (max-width: 960px) {
#e-admin-top-bar-root {
width: calc(100% - 36px);
}
}
@media screen and (max-width: 782px) {
#e-admin-top-bar-root {
width: 100%;
}
}
@media screen and (max-width: 600px) {
#e-admin-top-bar-root {
top: 46px;
}
}
@media (max-width: 768px) {
#e-admin-top-bar-root {
display: inline-flex;
align-items: center;
justify-content: center;
}
#e-admin-top-bar-root .e-admin-top-bar__main-area-buttons {
position: absolute;
top: calc(100% + 10px);
}
#e-admin-top-bar-root .e-admin-top-bar__secondary-area .e-admin-top-bar__secondary-area-buttons {
display: none;
}
#e-admin-top-bar-root .e-admin-top-bar__secondary-area > .e-admin-top-bar__bar-button .e-admin-top-bar__bar-button-title {
display: none;
}
}
@media (min-width: 768px) {
#e-admin-top-bar-root .e-admin-top-bar__secondary-area .e-admin-top-bar__secondary-area-buttons {
display: flex;
}
}
/*# sourceMappingURL=admin-top-bar.css.map */

View File

@@ -0,0 +1,2 @@
/*! elementor - v3.21.0 - 25-04-2024 */
#e-dashboard-widget-admin-top-bar{position:absolute;opacity:0;pointer-events:none}#e-admin-top-bar-root{right:0;font-family:var(--e-a-font-family);background:var(--e-a-bg-default);box-shadow:0 4px 6px rgba(0,0,0,.03);display:none;position:absolute;top:0;width:calc(100% - 160px);z-index:1}body.folded #e-admin-top-bar-root{width:calc(100% - 36px)}#e-admin-top-bar-root .e-admin-top-bar{display:flex;height:50px;justify-content:space-between;padding:0 16px}#e-admin-top-bar-root .page-title-action{font-size:12px;font-weight:500;line-height:1.2;text-transform:uppercase;text-decoration:none;padding:8px 16px;outline:none;border:none;border-radius:var(--e-a-border-radius);background-color:var(--e-a-btn-bg);color:var(--e-a-btn-color-invert);transition:var(--e-a-transition-hover)}#e-admin-top-bar-root .page-title-action:hover{background-color:var(--e-a-btn-bg-hover);color:var(--e-a-btn-color-invert)}#e-admin-top-bar-root .e-admin-top-bar__heading{margin-inline-end:40px}#e-admin-top-bar-root .e-admin-top-bar__heading,#e-admin-top-bar-root .e-admin-top-bar__main-area{display:inline-flex;align-items:center;justify-content:center}#e-admin-top-bar-root .e-admin-top-bar__main-area button{margin:0 4px}#e-admin-top-bar-root .e-admin-top-bar__secondary-area{display:inline-flex;align-items:center;justify-content:center}#e-admin-top-bar-root .e-admin-top-bar__heading-title{color:var(--e-a-color-txt);font-size:15px;font-weight:700;padding:0 8px;line-height:normal}#e-admin-top-bar-root .e-admin-top-bar__main-area-buttons{display:inline-flex;gap:5px}#e-admin-top-bar-root.e-admin-top-bar--active{display:block}#e-admin-top-bar-root.e-admin-top-bar--active~#wpbody #wpbody-content{margin-block-start:50px}#e-admin-top-bar-root.e-admin-top-bar--active~#wpbody .wrap{clear:both;padding-block-start:10px}#e-admin-top-bar-root.e-admin-top-bar--active~#wpbody .wrap h1{display:none}#e-admin-top-bar-root:not(.e-admin-top-bar--active)~#wpbody .wrap .page-title-action,#e-admin-top-bar-root:not(.e-admin-top-bar--active)~#wpbody .wrap h1{display:inline-block}#e-admin-top-bar-root .e-admin-top-bar__bar-button{align-items:center;cursor:pointer;display:inline-flex;justify-content:center;margin:0 10px;text-decoration:none;color:var(--e-a-color-txt)}#e-admin-top-bar-root .e-admin-top-bar__bar-button.accent,#e-admin-top-bar-root .e-admin-top-bar__bar-button.accent:hover .e-admin-top-bar__bar-button-icon,#e-admin-top-bar-root .e-admin-top-bar__bar-button.accent:hover .e-admin-top-bar__bar-button-title{color:var(--e-a-color-accent)}#e-admin-top-bar-root .e-admin-top-bar__bar-button .crown-icon{font-size:14px}#e-admin-top-bar-root .e-admin-top-bar__bar-button .e-admin-top-bar__bar-button-icon{margin:0 4px}#e-admin-top-bar-root .e-admin-top-bar__bar-button:hover .e-admin-top-bar__bar-button-icon,#e-admin-top-bar-root .e-admin-top-bar__bar-button:hover .e-admin-top-bar__bar-button-title{color:var(--e-a-color-txt-hover)}#e-admin-top-bar-root .e-admin-top-bar__bar-button-title{font-size:13px;font-weight:500;margin:0 4px;line-height:normal}#e-admin-top-bar-root~#wpbody .wrap .page-title-action,#e-admin-top-bar-root~#wpbody .wrap h1{display:none}@media screen and (max-width:960px){#e-admin-top-bar-root{width:calc(100% - 36px)}}@media screen and (max-width:782px){#e-admin-top-bar-root{width:100%}}@media screen and (max-width:600px){#e-admin-top-bar-root{top:46px}}@media (max-width:768px){#e-admin-top-bar-root{display:inline-flex;align-items:center;justify-content:center}#e-admin-top-bar-root .e-admin-top-bar__main-area-buttons{position:absolute;top:calc(100% + 10px)}#e-admin-top-bar-root .e-admin-top-bar__secondary-area .e-admin-top-bar__secondary-area-buttons,#e-admin-top-bar-root .e-admin-top-bar__secondary-area>.e-admin-top-bar__bar-button .e-admin-top-bar__bar-button-title{display:none}}@media (min-width:768px){#e-admin-top-bar-root .e-admin-top-bar__secondary-area .e-admin-top-bar__secondary-area-buttons{display:flex}}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,107 @@
/*! elementor - v3.21.0 - 25-04-2024 */
:root {
--color-box-shadow-color: rgba(0, 0, 0, 0.05);
}
.eps-theme-dark {
--color-box-shadow-color: rgba(0, 0, 0, 0.1);
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
@media screen and (min-width: 480px) {
.text-start-sm {
text-align: start;
}
}
@media screen and (min-width: 480px) {
.text-center-sm {
text-align: center;
}
}
@media screen and (min-width: 480px) {
.text-end-sm {
text-align: end;
}
}
@media screen and (min-width: 768px) {
.text-start-md {
text-align: start;
}
}
@media screen and (min-width: 768px) {
.text-center-md {
text-align: center;
}
}
@media screen and (min-width: 768px) {
.text-end-md {
text-align: end;
}
}
@media screen and (min-width: 1025px) {
.text-start-lg {
text-align: start;
}
}
@media screen and (min-width: 1025px) {
.text-center-lg {
text-align: center;
}
}
@media screen and (min-width: 1025px) {
.text-end-lg {
text-align: end;
}
}
@media screen and (min-width: 1440px) {
.text-start-xl {
text-align: start;
}
}
@media screen and (min-width: 1440px) {
.text-center-xl {
text-align: center;
}
}
@media screen and (min-width: 1440px) {
.text-end-xl {
text-align: end;
}
}
@media screen and (min-width: 1600px) {
.text-start-xxl {
text-align: start;
}
}
@media screen and (min-width: 1600px) {
.text-center-xxl {
text-align: center;
}
}
@media screen and (min-width: 1600px) {
.text-end-xxl {
text-align: end;
}
}
@keyframes eps-animation-pop {
from {
transform: scale(0.75);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
/*# sourceMappingURL=app-base-rtl.css.map */

View File

@@ -0,0 +1,2 @@
/*! elementor - v3.21.0 - 25-04-2024 */
:root{--color-box-shadow-color:rgba(0,0,0,0.05)}.eps-theme-dark{--color-box-shadow-color:rgba(0,0,0,0.1)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media screen and (min-width:480px){.text-start-sm{text-align:start}}@media screen and (min-width:480px){.text-center-sm{text-align:center}}@media screen and (min-width:480px){.text-end-sm{text-align:end}}@media screen and (min-width:768px){.text-start-md{text-align:start}}@media screen and (min-width:768px){.text-center-md{text-align:center}}@media screen and (min-width:768px){.text-end-md{text-align:end}}@media screen and (min-width:1025px){.text-start-lg{text-align:start}}@media screen and (min-width:1025px){.text-center-lg{text-align:center}}@media screen and (min-width:1025px){.text-end-lg{text-align:end}}@media screen and (min-width:1440px){.text-start-xl{text-align:start}}@media screen and (min-width:1440px){.text-center-xl{text-align:center}}@media screen and (min-width:1440px){.text-end-xl{text-align:end}}@media screen and (min-width:1600px){.text-start-xxl{text-align:start}}@media screen and (min-width:1600px){.text-center-xxl{text-align:center}}@media screen and (min-width:1600px){.text-end-xxl{text-align:end}}@keyframes eps-animation-pop{0%{transform:scale(.75);opacity:0}to{transform:scale(1);opacity:1}}

View File

@@ -0,0 +1,107 @@
/*! elementor - v3.21.0 - 25-04-2024 */
:root {
--color-box-shadow-color: rgba(0, 0, 0, 0.05);
}
.eps-theme-dark {
--color-box-shadow-color: rgba(0, 0, 0, 0.1);
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
@media screen and (min-width: 480px) {
.text-start-sm {
text-align: start;
}
}
@media screen and (min-width: 480px) {
.text-center-sm {
text-align: center;
}
}
@media screen and (min-width: 480px) {
.text-end-sm {
text-align: end;
}
}
@media screen and (min-width: 768px) {
.text-start-md {
text-align: start;
}
}
@media screen and (min-width: 768px) {
.text-center-md {
text-align: center;
}
}
@media screen and (min-width: 768px) {
.text-end-md {
text-align: end;
}
}
@media screen and (min-width: 1025px) {
.text-start-lg {
text-align: start;
}
}
@media screen and (min-width: 1025px) {
.text-center-lg {
text-align: center;
}
}
@media screen and (min-width: 1025px) {
.text-end-lg {
text-align: end;
}
}
@media screen and (min-width: 1440px) {
.text-start-xl {
text-align: start;
}
}
@media screen and (min-width: 1440px) {
.text-center-xl {
text-align: center;
}
}
@media screen and (min-width: 1440px) {
.text-end-xl {
text-align: end;
}
}
@media screen and (min-width: 1600px) {
.text-start-xxl {
text-align: start;
}
}
@media screen and (min-width: 1600px) {
.text-center-xxl {
text-align: center;
}
}
@media screen and (min-width: 1600px) {
.text-end-xxl {
text-align: end;
}
}
@keyframes eps-animation-pop {
from {
transform: scale(0.75);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
/*# sourceMappingURL=app-base.css.map */

View File

@@ -0,0 +1,2 @@
/*! elementor - v3.21.0 - 25-04-2024 */
:root{--color-box-shadow-color:rgba(0,0,0,0.05)}.eps-theme-dark{--color-box-shadow-color:rgba(0,0,0,0.1)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media screen and (min-width:480px){.text-start-sm{text-align:start}}@media screen and (min-width:480px){.text-center-sm{text-align:center}}@media screen and (min-width:480px){.text-end-sm{text-align:end}}@media screen and (min-width:768px){.text-start-md{text-align:start}}@media screen and (min-width:768px){.text-center-md{text-align:center}}@media screen and (min-width:768px){.text-end-md{text-align:end}}@media screen and (min-width:1025px){.text-start-lg{text-align:start}}@media screen and (min-width:1025px){.text-center-lg{text-align:center}}@media screen and (min-width:1025px){.text-end-lg{text-align:end}}@media screen and (min-width:1440px){.text-start-xl{text-align:start}}@media screen and (min-width:1440px){.text-center-xl{text-align:center}}@media screen and (min-width:1440px){.text-end-xl{text-align:end}}@media screen and (min-width:1600px){.text-start-xxl{text-align:start}}@media screen and (min-width:1600px){.text-center-xxl{text-align:center}}@media screen and (min-width:1600px){.text-end-xxl{text-align:end}}@keyframes eps-animation-pop{0%{transform:scale(.75);opacity:0}to{transform:scale(1);opacity:1}}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,850 @@
/*! elementor - v3.21.0 - 25-04-2024 */
:root {
--e-a-color-white: #ffffff;
--e-a-color-black: #000000;
--e-a-color-logo: #ffffff;
--e-a-color-primary: #F3BAFD;
--e-a-color-primary-bold: #D004D4;
--e-a-color-secondary: #515962;
--e-a-color-success: #0A875A;
--e-a-color-danger: #DC2626;
--e-a-color-info: #2563EB;
--e-a-color-warning: #F59E0B;
--e-a-color-accent: #93003f;
--e-a-color-global: #1DDDBF;
--e-a-color-accent-promotion: #93003f;
--e-a-bg-default: #ffffff;
--e-a-bg-invert: #0C0D0E;
--e-a-bg-hover: #F1F2F3;
--e-a-bg-active: #E6E8EA;
--e-a-bg-active-bold: #D5D8DC;
--e-a-bg-loading: #F9FAFA;
--e-a-bg-logo: #000000;
--e-a-bg-primary: #FAE8FF;
--e-a-bg-secondary: #515962;
--e-a-bg-success: #F2FDF5;
--e-a-bg-info: #F0F7FF;
--e-a-bg-danger: #FEF1F4;
--e-a-bg-warning: #FFFBEB;
--e-a-color-txt: #515962;
--e-a-color-txt-muted: #818A96;
--e-a-color-txt-disabled: #BABFC5;
--e-a-color-txt-invert: #ffffff;
--e-a-color-txt-accent: #0C0D0E;
--e-a-color-txt-hover: #3f444b;
--e-a-color-txt-active: #0C0D0E;
--e-a-border-color: #E6E8EA;
--e-a-border-color-bold: #D5D8DC;
--e-a-border-color-focus: #BABFC5;
--e-a-border-color-accent: #0C0D0E;
--e-a-border: 1px solid var(--e-a-border-color);
--e-a-border-bold: 1px solid var(--e-a-border-color-bold);
--e-a-border-radius: 3px;
--e-a-btn-color: #0C0D0E;
--e-a-btn-color-invert: var(--e-a-color-txt-invert);
--e-a-btn-color-disabled: var(--e-a-color-txt-disabled);
--e-a-btn-bg: #515962;
--e-a-btn-bg-hover: #3a4046;
--e-a-btn-bg-active: #23262a;
--e-a-btn-bg-disabled: #D5D8DC;
--e-a-btn-bg-primary: #F3BAFD;
--e-a-btn-bg-primary-hover: #F5D0FE;
--e-a-btn-bg-primary-active:#F0ABFC;
--e-a-btn-bg-accent: #93003f;
--e-a-btn-bg-accent-hover: #8F1A4C;
--e-a-btn-bg-accent-active: #A93365;
--e-a-btn-bg-info: #2563EB;
--e-a-btn-bg-info-hover: #134cca;
--e-a-btn-bg-info-active: #0e3b9c;
--e-a-btn-bg-success: #0A875A;
--e-a-btn-bg-success-hover: #06583a;
--e-a-btn-bg-success-active:#03281b;
--e-a-btn-bg-warning: #F59E0B;
--e-a-btn-bg-warning-hover: #c57f08;
--e-a-btn-bg-warning-active:#945f06;
--e-a-btn-bg-danger: #DC2626;
--e-a-btn-bg-danger-hover: #b21d1d;
--e-a-btn-bg-danger-active: #861616;
--e-a-dark-bg: #0C0D0E;
--e-a-dark-color-txt: #9DA5AE;
--e-a-dark-color-txt-hover: #D5D8DC;
--e-a-font-family: Roboto, Arial, Helvetica, sans-serif;
--e-a-transition-hover: all .3s;
--e-a-popover-shadow: 0 2px 15px rgba(0, 0, 0, 0.3);
--e-a-dropdown-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
}
.dialog-widget-content {
background-color: var(--e-a-bg-default);
position: absolute;
border-radius: 3px;
box-shadow: 2px 8px 23px 3px rgba(0, 0, 0, 0.2);
overflow: hidden;
}
.dialog-message {
line-height: 1.5;
box-sizing: border-box;
}
.dialog-close-button {
cursor: pointer;
position: absolute;
margin-block-start: 15px;
left: 15px;
color: var(--e-a-color-txt);
font-size: 15px;
line-height: 1;
transition: var(--e-a-transition-hover);
}
.dialog-close-button:hover {
color: var(--e-a-color-txt-hover);
}
.dialog-prevent-scroll {
overflow: hidden;
max-height: 100vh;
}
.dialog-type-lightbox {
position: fixed;
height: 100%;
width: 100%;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.8);
z-index: 9999;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
.elementor-editor-active .elementor-popup-modal {
background-color: initial;
}
.dialog-type-confirm .dialog-widget-content,
.dialog-type-alert .dialog-widget-content {
margin: auto;
width: 400px;
padding: 20px;
}
.dialog-type-confirm .dialog-header,
.dialog-type-alert .dialog-header {
font-size: 15px;
font-weight: 500;
}
.dialog-type-confirm .dialog-header:after,
.dialog-type-alert .dialog-header:after {
content: "";
display: block;
border-block-end: var(--e-a-border);
padding-block-end: 10px;
margin-block-end: 10px;
margin-inline-start: -20px;
margin-inline-end: -20px;
}
.dialog-type-confirm .dialog-message,
.dialog-type-alert .dialog-message {
min-height: 50px;
}
.dialog-type-confirm .dialog-buttons-wrapper,
.dialog-type-alert .dialog-buttons-wrapper {
padding-block-start: 10px;
display: flex;
justify-content: flex-end;
gap: 15px;
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button {
font-size: 12px;
font-weight: 500;
line-height: 1.2;
padding: 8px 16px;
outline: none;
border: none;
border-radius: var(--e-a-border-radius);
background-color: var(--e-a-btn-bg);
color: var(--e-a-btn-color-invert);
transition: var(--e-a-transition-hover);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:hover {
border: none;
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:focus {
background-color: var(--e-a-btn-bg-hover);
color: var(--e-a-btn-color-invert);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button:active,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:active {
background-color: var(--e-a-btn-bg-active);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button:not([disabled]),
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:not([disabled]) {
cursor: pointer;
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button:disabled,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:disabled {
background-color: var(--e-a-btn-bg-disabled);
color: var(--e-a-btn-color-disabled);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button:not(.elementor-button-state) .elementor-state-icon,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:not(.elementor-button-state) .elementor-state-icon {
display: none;
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-cancel,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-cancel {
background: transparent;
color: var(--e-a-color-txt);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-cancel:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-cancel:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-cancel:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-cancel:focus {
background: var(--e-a-bg-hover);
color: var(--e-a-color-txt-hover);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt:disabled, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-cancel:disabled,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt:disabled,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-cancel:disabled {
background: transparent;
color: var(--e-a-color-txt-disabled);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt-border,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt-border {
border: 1px solid var(--e-a-color-txt-muted);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-success, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-success,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-success,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-success {
background-color: var(--e-a-btn-bg-success);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-success:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-success:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-success:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-success:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-success:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-success:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-success:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-success:focus {
background-color: var(--e-a-btn-bg-success-hover);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-take_over, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-ok,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-take_over,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-ok {
background-color: var(--e-a-btn-bg-primary);
color: var(--e-a-btn-color);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-take_over:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-ok:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-take_over:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-ok:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-take_over:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-ok:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-take_over:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-ok:focus {
background-color: var(--e-a-btn-bg-primary-hover);
color: var(--e-a-btn-color);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary.e-btn-txt, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-take_over, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary.dialog-cancel, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-cancel.dialog-take_over, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-ok, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-ok.dialog-cancel,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary.e-btn-txt,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-take_over,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary.dialog-cancel,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-cancel.dialog-take_over,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-ok,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-ok.dialog-cancel {
background: transparent;
color: var(--e-a-color-primary-bold);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary.e-btn-txt:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-take_over:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary.dialog-cancel:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-cancel.dialog-take_over:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-ok:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-ok.dialog-cancel:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary.e-btn-txt:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-take_over:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary.dialog-cancel:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-cancel.dialog-take_over:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-ok:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-ok.dialog-cancel:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary.e-btn-txt:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-take_over:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary.dialog-cancel:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-cancel.dialog-take_over:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-ok:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-ok.dialog-cancel:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary.e-btn-txt:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-take_over:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary.dialog-cancel:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-cancel.dialog-take_over:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-ok:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-ok.dialog-cancel:focus {
background: var(--e-a-bg-primary);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.go-pro, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-accent,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.go-pro,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-accent {
background-color: var(--e-a-btn-bg-accent);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.go-pro:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.go-pro:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-accent:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-accent:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.go-pro:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.go-pro:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-accent:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-accent:focus {
background-color: var(--e-a-btn-bg-accent-hover);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.go-pro:active, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-accent:active,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.go-pro:active,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-accent:active {
background-color: var(--e-a-btn-bg-accent-active);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-info, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-info,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-info,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-info {
background-color: var(--e-a-btn-bg-info);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-info:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-info:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-info:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-info:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-info:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-info:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-info:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-info:focus {
background-color: var(--e-a-btn-bg-info-hover);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-warning, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-warning,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-warning,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-warning {
background-color: var(--e-a-btn-bg-warning);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-warning:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-warning:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-warning:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-warning:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-warning:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-warning:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-warning:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-warning:focus {
background-color: var(--e-a-btn-bg-warning-hover);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-danger, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-danger,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-danger,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-danger {
background-color: var(--e-a-btn-bg-danger);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-danger:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-danger:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-danger:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-danger:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-danger:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-danger:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-danger:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-danger:focus {
background-color: var(--e-a-btn-bg-danger-hover);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button i,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button i {
margin-inline-end: 5px;
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button:visited,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:visited {
color: initial;
}
.flatpickr-calendar {
width: 280px;
}
.flatpickr-calendar .flatpickr-current-month span.cur-month {
font-weight: 300;
}
.flatpickr-calendar .dayContainer {
width: 280px;
min-width: 280px;
max-width: 280px;
}
.flatpickr-calendar .flatpickr-days {
width: 280px;
}
.flatpickr-calendar .flatpickr-day {
max-width: 37px;
height: 37px;
line-height: 37px;
}
.elementor-hidden {
display: none;
}
.elementor-screen-only,
.screen-reader-text,
.screen-reader-text span,
.ui-helper-hidden-accessible {
position: absolute;
top: -10000em;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
.elementor-clearfix:after {
content: "";
display: block;
clear: both;
width: 0;
height: 0;
}
.e-logo-wrapper {
background: var(--e-a-bg-logo);
display: inline-block;
padding: 0.75em;
border-radius: 50%;
line-height: 1;
}
.e-logo-wrapper i {
color: var(--e-a-color-logo);
font-size: 1em;
}
#elementor-change-exit-preference-dialog .dialog-message a {
cursor: pointer;
}
#elementor-change-exit-preference-dialog .dialog-message > div {
margin-block-end: 10px;
}
#e-experiments-messages-dialog .dialog-confirm-header {
font-weight: 600;
}
#e-kit-elements-defaults-create-dialog label {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
margin-block-start: 20px;
}
@media (min-width: 1024px) {
body.admin-bar .dialog-lightbox-widget {
height: calc(100vh - 32px);
}
}
@media (max-width: 1024px) {
body.admin-bar .dialog-type-lightbox {
position: sticky;
height: 100vh;
}
}
.elementor-templates-modal .dialog-widget-content {
font-family: Roboto, Arial, Helvetica, sans-serif;
background-color: var(--e-a-bg-default);
width: 100%;
}
@media (max-width: 1439px) {
.elementor-templates-modal .dialog-widget-content {
max-width: 990px;
}
}
@media (min-width: 1440px) {
.elementor-templates-modal .dialog-widget-content {
max-width: 1200px;
}
}
.elementor-templates-modal .dialog-header {
border-block-end: var(--e-a-border);
padding: 0;
z-index: 1;
}
.elementor-templates-modal .dialog-buttons-wrapper {
border-block-start: var(--e-a-border);
padding: 10px;
display: flex;
justify-content: flex-end;
gap: 15px;
}
.elementor-templates-modal .dialog-message {
height: 750px;
max-height: 85vh;
overflow-y: auto;
padding: 20px;
}
.elementor-templates-modal .dialog-content {
height: 100%;
text-align: center;
}
.elementor-templates-modal .dialog-loading {
display: none;
}
.elementor-templates-modal__header {
display: flex;
align-items: center;
justify-content: space-between;
height: 50px;
}
.elementor-templates-modal__header__logo {
line-height: 1;
text-transform: uppercase;
font-weight: bold;
cursor: pointer;
}
.elementor-templates-modal__header__logo-area {
text-align: start;
padding-inline-start: 15px;
}
.elementor-templates-modal__header__logo-area > * {
display: flex;
align-items: center;
}
.elementor-templates-modal__header__logo__icon-wrapper {
margin-inline-end: 10px;
font-size: 12px;
}
.elementor-templates-modal__header__logo__title {
color: var(--e-a-color-txt-active);
padding-block-start: 2px;
}
.elementor-templates-modal__header__items-area {
display: flex;
flex-direction: row-reverse;
}
.elementor-templates-modal__header__item {
position: relative;
display: flex;
align-items: center;
justify-content: center;
box-sizing: content-box;
}
.elementor-templates-modal__header__item > i {
font-size: 20px;
transition: var(--e-a-transition-hover);
cursor: pointer;
}
.elementor-templates-modal__header__item > i:hover {
color: var(--e-a-color-txt-hover);
}
.elementor-templates-modal__header__close--normal {
width: 47px;
border-inline-start: var(--e-a-border);
}
.elementor-templates-modal__header__close--normal i {
font-size: 18px;
}
.elementor-templates-modal__header__close--skip {
padding: 10px;
padding-inline-start: 20px;
margin-inline-end: 10px;
font-size: 11px;
font-weight: normal;
line-height: 1;
border-radius: var(--e-a-border-radius);
cursor: pointer;
}
.elementor-templates-modal__header__close--skip > i {
font-size: inherit;
padding-inline-start: 10px;
margin-inline-start: 15px;
border-inline-start: 1px solid;
}
.elementor-templates-modal__header__close--skip > i:not(:hover) {
color: var(--e-a-color-white);
}
.elementor-templates-modal__sidebar {
flex-shrink: 0;
width: 25%;
border-inline-end: var(--e-a-border);
}
.elementor-templates-modal__content {
flex-grow: 1;
}
#elementor-toast {
position: absolute;
width: 280px;
padding: 20px;
border-radius: 5px;
color: var(--e-a-dark-color-txt);
background-color: rgba(0, 0, 0, 0.8);
z-index: 10000;
}
#elementor-toast.dialog-position-window {
position: fixed;
}
#elementor-toast .dialog-message {
font-size: 13px;
}
#elementor-toast .dialog-buttons-wrapper {
display: flex;
justify-content: flex-end;
}
#elementor-toast .dialog-buttons-wrapper:not(:empty) {
margin-top: 15px;
}
#elementor-toast .dialog-button {
font-size: 12px;
font-weight: 500;
line-height: 1.2;
padding: 8px 16px;
margin-inline-end: 10px;
color: var(--e-a-dark-color-txt);
border-radius: var(--e-a-border-radius);
transition: var(--e-a-transition-hover);
cursor: pointer;
}
#elementor-toast .dialog-button:hover {
background: var(--e-a-bg-hover);
color: var(--e-a-color-txt-hover);
}
#elementor-toast .dialog-button:last-child {
margin-inline-end: 0;
}
/* Will select next element after last '.elementor-general-section' */
#wpadminbar #wp-admin-bar-elementor_edit_page .elementor-general-section + .elementor-second-section {
border-block-start: 1px solid #464b50;
margin-block-start: 6px;
}
.e-logo-wrapper {
background: var(--e-a-bg-logo);
display: inline-block;
padding: 0.75em;
border-radius: 50%;
line-height: 1;
}
.e-logo-wrapper i {
color: var(--e-a-color-logo);
font-size: 1em;
}
#elementor-finder__modal {
background: none;
z-index: 99999;
}
#elementor-finder__modal .dialog-widget-content {
width: 650px;
max-width: 98%;
top: 18vh;
left: calc(50% - 650px / 2);
}
#elementor-finder__modal .dialog-content {
text-align: start;
}
#elementor-finder__modal .dialog-message {
height: initial;
min-height: 0;
padding: 0;
text-align: start;
}
#elementor-finder__search {
padding: 15px;
display: flex;
}
#elementor-finder__search i {
font-size: 16px;
margin-inline-end: 15px;
}
#elementor-finder__search__input {
border: none;
background: none;
outline: none;
padding: 0;
margin: 0;
flex-grow: 1;
font-size: 14px;
box-shadow: none;
}
#elementor-finder__search__input::-moz-placeholder {
font-style: italic;
font-weight: 300;
}
#elementor-finder__search__input::placeholder {
font-style: italic;
font-weight: 300;
}
#elementor-finder__results {
max-height: 50vh;
overflow: auto;
}
#elementor-finder__no-results {
display: none;
padding: 20px;
}
#elementor-finder__lock-dialog {
z-index: 100000;
}
.elementor-finder__results__category {
position: relative;
}
.elementor-finder__results__category__title {
padding: 5px 25px;
font-size: 10px;
border-block-end: var(--e-a-border);
}
.elementor-finder__results__category--dynamic .elementor-finder__results__category__items {
min-height: 26px;
}
.elementor-finder__results__category .eicon-loading {
display: none;
position: absolute;
left: 10px;
top: 30px;
color: var(--e-a-color-info);
font-size: 14px;
}
.elementor-finder__results__item {
display: flex;
}
.elementor-finder__results__item a {
text-decoration: none;
color: inherit;
}
.elementor-finder__results__item.elementor-active {
background-color: var(--e-a-bg-hover);
}
.elementor-finder__results__item.elementor-active a {
color: inherit;
}
.elementor-finder__results__item:not(.elementor-active) .elementor-finder__results__item__actions {
display: none;
}
.elementor-finder__results__item__link {
display: flex;
align-items: center;
height: 35px;
flex-grow: 1;
}
.elementor-finder__results__item__icon {
width: 60px;
text-align: center;
font-size: 17px;
}
.elementor-finder__results__item__title {
font-size: 13px;
}
.elementor-finder__results__item__description {
margin-inline-start: 5px;
font-style: italic;
}
.elementor-finder__results__item__badge {
text-transform: uppercase;
position: absolute;
inset-inline-end: 16px;
font-size: 8px;
font-weight: 500;
display: flex;
align-items: center;
gap: 4px;
}
.elementor-finder__results__item__actions {
display: flex;
}
.elementor-finder__results__item__action {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 35px;
}
.elementor-finder__results__item__action:hover {
background-color: rgba(0, 0, 0, 0.07);
}
.tipsy {
font-size: 10px;
position: absolute;
padding: 5px;
z-index: 100000;
}
.tipsy-inner {
background-color: #000;
color: #FFF;
font-weight: 500;
max-width: 200px;
padding: 5px 12px;
text-align: center;
border-radius: 3px;
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.5);
}
.tipsy-arrow {
position: absolute;
width: 0;
height: 0;
line-height: 0;
border: 5px dashed #000;
}
.tipsy-arrow-n {
border-bottom-color: #000;
}
.tipsy-arrow-s {
border-top-color: #000;
}
.tipsy-arrow-e {
border-left-color: #000;
}
.tipsy-arrow-w {
border-right-color: #000;
}
.tipsy-n .tipsy-arrow, .tipsy-nw .tipsy-arrow {
border-left-color: transparent;
border-right-color: transparent;
top: 0;
border-bottom-style: solid;
border-top: none;
}
.tipsy-n .tipsy-arrow {
left: 50%;
margin-left: -5px;
}
.tipsy-nw .tipsy-arrow {
left: 10px;
}
.tipsy-ne .tipsy-arrow {
top: 0;
right: 10px;
border-bottom-style: solid;
border-top: none;
border-left-color: transparent;
border-right-color: transparent;
}
.tipsy-s .tipsy-arrow, .tipsy-se .tipsy-arrow, .tipsy-sw .tipsy-arrow {
bottom: 0;
border-top-style: solid;
border-bottom: none;
border-left-color: transparent;
border-right-color: transparent;
}
.tipsy-s .tipsy-arrow {
left: 50%;
margin-left: -5px;
}
.tipsy-sw .tipsy-arrow {
left: 10px;
}
.tipsy-se .tipsy-arrow {
right: 10px;
}
.tipsy-e .tipsy-arrow, .tipsy-w .tipsy-arrow {
top: 50%;
margin-top: -5px;
border-top-color: transparent;
border-bottom-color: transparent;
}
.tipsy-e .tipsy-arrow {
right: 0;
border-left-style: solid;
border-right: none;
}
.tipsy-w .tipsy-arrow {
left: 0;
border-right-style: solid;
border-left: none;
}
/*# sourceMappingURL=common-rtl.css.map */

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,775 @@
/*! elementor - v3.21.0 - 25-04-2024 */
.dialog-widget-content {
background-color: var(--e-a-bg-default);
position: absolute;
border-radius: 3px;
box-shadow: 2px 8px 23px 3px rgba(0, 0, 0, 0.2);
overflow: hidden;
}
.dialog-message {
line-height: 1.5;
box-sizing: border-box;
}
.dialog-close-button {
cursor: pointer;
position: absolute;
margin-block-start: 15px;
right: 15px;
color: var(--e-a-color-txt);
font-size: 15px;
line-height: 1;
transition: var(--e-a-transition-hover);
}
.dialog-close-button:hover {
color: var(--e-a-color-txt-hover);
}
.dialog-prevent-scroll {
overflow: hidden;
max-height: 100vh;
}
.dialog-type-lightbox {
position: fixed;
height: 100%;
width: 100%;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.8);
z-index: 9999;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
.elementor-editor-active .elementor-popup-modal {
background-color: initial;
}
.dialog-type-confirm .dialog-widget-content,
.dialog-type-alert .dialog-widget-content {
margin: auto;
width: 400px;
padding: 20px;
}
.dialog-type-confirm .dialog-header,
.dialog-type-alert .dialog-header {
font-size: 15px;
font-weight: 500;
}
.dialog-type-confirm .dialog-header:after,
.dialog-type-alert .dialog-header:after {
content: "";
display: block;
border-block-end: var(--e-a-border);
padding-block-end: 10px;
margin-block-end: 10px;
margin-inline-start: -20px;
margin-inline-end: -20px;
}
.dialog-type-confirm .dialog-message,
.dialog-type-alert .dialog-message {
min-height: 50px;
}
.dialog-type-confirm .dialog-buttons-wrapper,
.dialog-type-alert .dialog-buttons-wrapper {
padding-block-start: 10px;
display: flex;
justify-content: flex-end;
gap: 15px;
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button {
font-size: 12px;
font-weight: 500;
line-height: 1.2;
padding: 8px 16px;
outline: none;
border: none;
border-radius: var(--e-a-border-radius);
background-color: var(--e-a-btn-bg);
color: var(--e-a-btn-color-invert);
transition: var(--e-a-transition-hover);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:hover {
border: none;
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:focus {
background-color: var(--e-a-btn-bg-hover);
color: var(--e-a-btn-color-invert);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button:active,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:active {
background-color: var(--e-a-btn-bg-active);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button:not([disabled]),
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:not([disabled]) {
cursor: pointer;
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button:disabled,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:disabled {
background-color: var(--e-a-btn-bg-disabled);
color: var(--e-a-btn-color-disabled);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button:not(.elementor-button-state) .elementor-state-icon,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:not(.elementor-button-state) .elementor-state-icon {
display: none;
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-cancel,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-cancel {
background: transparent;
color: var(--e-a-color-txt);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-cancel:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-cancel:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-cancel:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-cancel:focus {
background: var(--e-a-bg-hover);
color: var(--e-a-color-txt-hover);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt:disabled, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-cancel:disabled,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt:disabled,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-cancel:disabled {
background: transparent;
color: var(--e-a-color-txt-disabled);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt-border,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt-border {
border: 1px solid var(--e-a-color-txt-muted);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-success, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-success,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-success,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-success {
background-color: var(--e-a-btn-bg-success);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-success:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-success:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-success:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-success:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-success:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-success:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-success:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-success:focus {
background-color: var(--e-a-btn-bg-success-hover);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-take_over, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-ok,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-take_over,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-ok {
background-color: var(--e-a-btn-bg-primary);
color: var(--e-a-btn-color);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-take_over:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-ok:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-take_over:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-ok:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-take_over:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-ok:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-take_over:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-ok:focus {
background-color: var(--e-a-btn-bg-primary-hover);
color: var(--e-a-btn-color);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary.e-btn-txt, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-take_over, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary.dialog-cancel, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-cancel.dialog-take_over, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-ok, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-ok.dialog-cancel,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary.e-btn-txt,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-take_over,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary.dialog-cancel,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-cancel.dialog-take_over,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-ok,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-ok.dialog-cancel {
background: transparent;
color: var(--e-a-color-primary-bold);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary.e-btn-txt:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-take_over:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary.dialog-cancel:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-cancel.dialog-take_over:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-ok:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-ok.dialog-cancel:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary.e-btn-txt:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-take_over:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-primary.dialog-cancel:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-cancel.dialog-take_over:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-ok:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.dialog-ok.dialog-cancel:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary.e-btn-txt:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-take_over:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary.dialog-cancel:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-cancel.dialog-take_over:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-ok:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-ok.dialog-cancel:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary.e-btn-txt:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-take_over:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-primary.dialog-cancel:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-cancel.dialog-take_over:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-btn-txt.dialog-ok:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.dialog-ok.dialog-cancel:focus {
background: var(--e-a-bg-primary);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.go-pro, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-accent,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.go-pro,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-accent {
background-color: var(--e-a-btn-bg-accent);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.go-pro:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.go-pro:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-accent:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-accent:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.go-pro:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.go-pro:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-accent:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-accent:focus {
background-color: var(--e-a-btn-bg-accent-hover);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.go-pro:active, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-accent:active,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.go-pro:active,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-accent:active {
background-color: var(--e-a-btn-bg-accent-active);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-info, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-info,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-info,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-info {
background-color: var(--e-a-btn-bg-info);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-info:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-info:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-info:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-info:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-info:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-info:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-info:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-info:focus {
background-color: var(--e-a-btn-bg-info-hover);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-warning, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-warning,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-warning,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-warning {
background-color: var(--e-a-btn-bg-warning);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-warning:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-warning:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-warning:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-warning:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-warning:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-warning:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-warning:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-warning:focus {
background-color: var(--e-a-btn-bg-warning-hover);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-danger, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-danger,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-danger,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-danger {
background-color: var(--e-a-btn-bg-danger);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-danger:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.elementor-button-danger:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-danger:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button.e-danger:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-danger:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.elementor-button-danger:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-danger:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button.e-danger:focus {
background-color: var(--e-a-btn-bg-danger-hover);
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button i,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button i {
margin-inline-end: 5px;
}
.dialog-type-confirm .dialog-buttons-wrapper .dialog-button:hover, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button:focus, .dialog-type-confirm .dialog-buttons-wrapper .dialog-button:visited,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:hover,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:focus,
.dialog-type-alert .dialog-buttons-wrapper .dialog-button:visited {
color: initial;
}
.flatpickr-calendar {
width: 280px;
}
.flatpickr-calendar .flatpickr-current-month span.cur-month {
font-weight: 300;
}
.flatpickr-calendar .dayContainer {
width: 280px;
min-width: 280px;
max-width: 280px;
}
.flatpickr-calendar .flatpickr-days {
width: 280px;
}
.flatpickr-calendar .flatpickr-day {
max-width: 37px;
height: 37px;
line-height: 37px;
}
.elementor-hidden {
display: none;
}
.elementor-screen-only,
.screen-reader-text,
.screen-reader-text span,
.ui-helper-hidden-accessible {
position: absolute;
top: -10000em;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
.elementor-clearfix:after {
content: "";
display: block;
clear: both;
width: 0;
height: 0;
}
.e-logo-wrapper {
background: var(--e-a-bg-logo);
display: inline-block;
padding: 0.75em;
border-radius: 50%;
line-height: 1;
}
.e-logo-wrapper i {
color: var(--e-a-color-logo);
font-size: 1em;
}
#elementor-change-exit-preference-dialog .dialog-message a {
cursor: pointer;
}
#elementor-change-exit-preference-dialog .dialog-message > div {
margin-block-end: 10px;
}
#e-experiments-messages-dialog .dialog-confirm-header {
font-weight: 600;
}
#e-kit-elements-defaults-create-dialog label {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
margin-block-start: 20px;
}
@media (min-width: 1024px) {
body.admin-bar .dialog-lightbox-widget {
height: calc(100vh - 32px);
}
}
@media (max-width: 1024px) {
body.admin-bar .dialog-type-lightbox {
position: sticky;
height: 100vh;
}
}
.elementor-templates-modal .dialog-widget-content {
font-family: Roboto, Arial, Helvetica, sans-serif;
background-color: var(--e-a-bg-default);
width: 100%;
}
@media (max-width: 1439px) {
.elementor-templates-modal .dialog-widget-content {
max-width: 990px;
}
}
@media (min-width: 1440px) {
.elementor-templates-modal .dialog-widget-content {
max-width: 1200px;
}
}
.elementor-templates-modal .dialog-header {
border-block-end: var(--e-a-border);
padding: 0;
z-index: 1;
}
.elementor-templates-modal .dialog-buttons-wrapper {
border-block-start: var(--e-a-border);
padding: 10px;
display: flex;
justify-content: flex-end;
gap: 15px;
}
.elementor-templates-modal .dialog-message {
height: 750px;
max-height: 85vh;
overflow-y: auto;
padding: 20px;
}
.elementor-templates-modal .dialog-content {
height: 100%;
text-align: center;
}
.elementor-templates-modal .dialog-loading {
display: none;
}
.elementor-templates-modal__header {
display: flex;
align-items: center;
justify-content: space-between;
height: 50px;
}
.elementor-templates-modal__header__logo {
line-height: 1;
text-transform: uppercase;
font-weight: bold;
cursor: pointer;
}
.elementor-templates-modal__header__logo-area {
text-align: start;
padding-inline-start: 15px;
}
.elementor-templates-modal__header__logo-area > * {
display: flex;
align-items: center;
}
.elementor-templates-modal__header__logo__icon-wrapper {
margin-inline-end: 10px;
font-size: 12px;
}
.elementor-templates-modal__header__logo__title {
color: var(--e-a-color-txt-active);
padding-block-start: 2px;
}
.elementor-templates-modal__header__items-area {
display: flex;
flex-direction: row-reverse;
}
.elementor-templates-modal__header__item {
position: relative;
display: flex;
align-items: center;
justify-content: center;
box-sizing: content-box;
}
.elementor-templates-modal__header__item > i {
font-size: 20px;
transition: var(--e-a-transition-hover);
cursor: pointer;
}
.elementor-templates-modal__header__item > i:hover {
color: var(--e-a-color-txt-hover);
}
.elementor-templates-modal__header__close--normal {
width: 47px;
border-inline-start: var(--e-a-border);
}
.elementor-templates-modal__header__close--normal i {
font-size: 18px;
}
.elementor-templates-modal__header__close--skip {
padding: 10px;
padding-inline-start: 20px;
margin-inline-end: 10px;
font-size: 11px;
font-weight: normal;
line-height: 1;
border-radius: var(--e-a-border-radius);
cursor: pointer;
}
.elementor-templates-modal__header__close--skip > i {
font-size: inherit;
padding-inline-start: 10px;
margin-inline-start: 15px;
border-inline-start: 1px solid;
}
.elementor-templates-modal__header__close--skip > i:not(:hover) {
color: var(--e-a-color-white);
}
.elementor-templates-modal__sidebar {
flex-shrink: 0;
width: 25%;
border-inline-end: var(--e-a-border);
}
.elementor-templates-modal__content {
flex-grow: 1;
}
#elementor-toast {
position: absolute;
width: 280px;
padding: 20px;
border-radius: 5px;
color: var(--e-a-dark-color-txt);
background-color: rgba(0, 0, 0, 0.8);
z-index: 10000;
}
#elementor-toast.dialog-position-window {
position: fixed;
}
#elementor-toast .dialog-message {
font-size: 13px;
}
#elementor-toast .dialog-buttons-wrapper {
display: flex;
justify-content: flex-end;
}
#elementor-toast .dialog-buttons-wrapper:not(:empty) {
margin-top: 15px;
}
#elementor-toast .dialog-button {
font-size: 12px;
font-weight: 500;
line-height: 1.2;
padding: 8px 16px;
margin-inline-end: 10px;
color: var(--e-a-dark-color-txt);
border-radius: var(--e-a-border-radius);
transition: var(--e-a-transition-hover);
cursor: pointer;
}
#elementor-toast .dialog-button:hover {
background: var(--e-a-bg-hover);
color: var(--e-a-color-txt-hover);
}
#elementor-toast .dialog-button:last-child {
margin-inline-end: 0;
}
/* Will select next element after last '.elementor-general-section' */
#wpadminbar #wp-admin-bar-elementor_edit_page .elementor-general-section + .elementor-second-section {
border-block-start: 1px solid #464b50;
margin-block-start: 6px;
}
.e-logo-wrapper {
background: var(--e-a-bg-logo);
display: inline-block;
padding: 0.75em;
border-radius: 50%;
line-height: 1;
}
.e-logo-wrapper i {
color: var(--e-a-color-logo);
font-size: 1em;
}
#elementor-finder__modal {
background: none;
z-index: 99999;
}
#elementor-finder__modal .dialog-widget-content {
width: 650px;
max-width: 98%;
top: 18vh;
left: calc(50% - 650px / 2);
}
#elementor-finder__modal .dialog-content {
text-align: start;
}
#elementor-finder__modal .dialog-message {
height: initial;
min-height: 0;
padding: 0;
text-align: start;
}
#elementor-finder__search {
padding: 15px;
display: flex;
}
#elementor-finder__search i {
font-size: 16px;
margin-inline-end: 15px;
}
#elementor-finder__search__input {
border: none;
background: none;
outline: none;
padding: 0;
margin: 0;
flex-grow: 1;
font-size: 14px;
box-shadow: none;
}
#elementor-finder__search__input::-moz-placeholder {
font-style: italic;
font-weight: 300;
}
#elementor-finder__search__input::placeholder {
font-style: italic;
font-weight: 300;
}
#elementor-finder__results {
max-height: 50vh;
overflow: auto;
}
#elementor-finder__no-results {
display: none;
padding: 20px;
}
#elementor-finder__lock-dialog {
z-index: 100000;
}
.elementor-finder__results__category {
position: relative;
}
.elementor-finder__results__category__title {
padding: 5px 25px;
font-size: 10px;
border-block-end: var(--e-a-border);
}
.elementor-finder__results__category--dynamic .elementor-finder__results__category__items {
min-height: 26px;
}
.elementor-finder__results__category .eicon-loading {
display: none;
position: absolute;
right: 10px;
top: 30px;
color: var(--e-a-color-info);
font-size: 14px;
}
.elementor-finder__results__item {
display: flex;
}
.elementor-finder__results__item a {
text-decoration: none;
color: inherit;
}
.elementor-finder__results__item.elementor-active {
background-color: var(--e-a-bg-hover);
}
.elementor-finder__results__item.elementor-active a {
color: inherit;
}
.elementor-finder__results__item:not(.elementor-active) .elementor-finder__results__item__actions {
display: none;
}
.elementor-finder__results__item__link {
display: flex;
align-items: center;
height: 35px;
flex-grow: 1;
}
.elementor-finder__results__item__icon {
width: 60px;
text-align: center;
font-size: 17px;
}
.elementor-finder__results__item__title {
font-size: 13px;
}
.elementor-finder__results__item__description {
margin-inline-start: 5px;
font-style: italic;
}
.elementor-finder__results__item__badge {
text-transform: uppercase;
position: absolute;
inset-inline-end: 16px;
font-size: 8px;
font-weight: 500;
display: flex;
align-items: center;
gap: 4px;
}
.elementor-finder__results__item__actions {
display: flex;
}
.elementor-finder__results__item__action {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 35px;
}
.elementor-finder__results__item__action:hover {
background-color: rgba(0, 0, 0, 0.07);
}
.tipsy {
font-size: 10px;
position: absolute;
padding: 5px;
z-index: 100000;
}
.tipsy-inner {
background-color: #000;
color: #FFF;
font-weight: 500;
max-width: 200px;
padding: 5px 12px;
text-align: center;
border-radius: 3px;
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.5);
}
.tipsy-arrow {
position: absolute;
width: 0;
height: 0;
line-height: 0;
border: 5px dashed #000;
}
.tipsy-arrow-n {
border-bottom-color: #000;
}
.tipsy-arrow-s {
border-top-color: #000;
}
.tipsy-arrow-e {
border-left-color: #000;
}
.tipsy-arrow-w {
border-right-color: #000;
}
.tipsy-n .tipsy-arrow, .tipsy-nw .tipsy-arrow {
border-left-color: transparent;
border-right-color: transparent;
top: 0;
border-bottom-style: solid;
border-top: none;
}
.tipsy-n .tipsy-arrow {
left: 50%;
margin-left: -5px;
}
.tipsy-nw .tipsy-arrow {
left: 10px;
}
.tipsy-ne .tipsy-arrow {
top: 0;
right: 10px;
border-bottom-style: solid;
border-top: none;
border-left-color: transparent;
border-right-color: transparent;
}
.tipsy-s .tipsy-arrow, .tipsy-se .tipsy-arrow, .tipsy-sw .tipsy-arrow {
bottom: 0;
border-top-style: solid;
border-bottom: none;
border-left-color: transparent;
border-right-color: transparent;
}
.tipsy-s .tipsy-arrow {
left: 50%;
margin-left: -5px;
}
.tipsy-sw .tipsy-arrow {
left: 10px;
}
.tipsy-se .tipsy-arrow {
right: 10px;
}
.tipsy-e .tipsy-arrow, .tipsy-w .tipsy-arrow {
top: 50%;
margin-top: -5px;
border-top-color: transparent;
border-bottom-color: transparent;
}
.tipsy-e .tipsy-arrow {
right: 0;
border-left-style: solid;
border-right: none;
}
.tipsy-w .tipsy-arrow {
left: 0;
border-right-style: solid;
border-left: none;
}
/*# sourceMappingURL=common.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,46 @@
/*! elementor - v3.21.0 - 25-04-2024 */
/**
* Here should be only styles that related to the Editor v1, and should be overridden when using the Editor v2.
*/
body {
--editor-v2-top-bar-height: 48px;
}
#elementor-editor-wrapper {
height: calc(100vh - var(--editor-v2-top-bar-height));
}
body.elementor-navigator-docked #elementor-navigator {
height: calc(100% - var(--editor-v2-top-bar-height));
top: var(--editor-v2-top-bar-height);
}
.elementor-panel #elementor-panel-header-menu-button,
.elementor-panel #elementor-panel-header-add-button,
.elementor-panel #elementor-panel-footer {
display: none;
}
.elementor-panel #elementor-panel-header {
font-weight: 700;
background-color: var(--e-a-bg-default);
color: var(--e-a-color-txt-accent);
border-block-end: var(--e-a-border);
height: 48px;
}
.elementor-control-type-wysiwyg .mce-fullscreen {
inset: var(--editor-v2-top-bar-height) 0 0 0;
}
.elementor-control-type-wysiwyg .mce-fullscreen > .mce-container-body {
display: flex;
flex-direction: column;
height: 100%;
}
.elementor-control-type-wysiwyg .mce-fullscreen > .mce-container-body > .mce-edit-area {
flex-grow: 1;
}
.elementor-control-type-wysiwyg .mce-fullscreen > .mce-container-body > .mce-edit-area > iframe {
height: 100% !important;
}
/*# sourceMappingURL=editor-v2-overrides.css.map */

View File

@@ -0,0 +1,2 @@
/*! elementor - v3.21.0 - 25-04-2024 */
body{--editor-v2-top-bar-height:48px}#elementor-editor-wrapper{height:calc(100vh - var(--editor-v2-top-bar-height))}body.elementor-navigator-docked #elementor-navigator{height:calc(100% - var(--editor-v2-top-bar-height));top:var(--editor-v2-top-bar-height)}.elementor-panel #elementor-panel-footer,.elementor-panel #elementor-panel-header-add-button,.elementor-panel #elementor-panel-header-menu-button{display:none}.elementor-panel #elementor-panel-header{font-weight:700;background-color:var(--e-a-bg-default);color:var(--e-a-color-txt-accent);border-block-end:var(--e-a-border);height:48px}.elementor-control-type-wysiwyg .mce-fullscreen{inset:var(--editor-v2-top-bar-height) 0 0 0}.elementor-control-type-wysiwyg .mce-fullscreen>.mce-container-body{display:flex;flex-direction:column;height:100%}.elementor-control-type-wysiwyg .mce-fullscreen>.mce-container-body>.mce-edit-area{flex-grow:1}.elementor-control-type-wysiwyg .mce-fullscreen>.mce-container-body>.mce-edit-area>iframe{height:100%!important}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,42 @@
.e-ai-button {
background: none;
border: none;
font-size: var(--control-title-size);
cursor: pointer;
transition: var(--e-a-transition-hover);
}
.e-ai-button:not(.e-active) {
color: var(--e-a-color-primary-bold);
}
.e-ai-button:hover {
color: #E73CF6;
}
.e-ai-promotion {
font-size: var(--control-title-size);
}
.e-ai-promotion i {
margin-inline-end: 5px;
}
.elementor-label-block .e-ai-promotion,
.elementor-label-block .e-ai-button {
margin-inline-start: auto;
}
.elementor-context-menu-list__item__ai-badge {
background-color: #524CFF;
border-radius: 25px;
display: flex;
justify-content: center;
padding: 4px;
}
.elementor-context-menu-list__item__ai-badge svg {
width: 12px;
height: 12px;
}
.elementor-context-menu-list__item__ai-badge svg path {
fill: #ffffff;
}
/*# sourceMappingURL=editor.css.map */

View File

@@ -0,0 +1 @@
.e-ai-button{background:none;border:none;font-size:var(--control-title-size);cursor:pointer;transition:var(--e-a-transition-hover)}.e-ai-button:not(.e-active){color:var(--e-a-color-primary-bold)}.e-ai-button:hover{color:#e73cf6}.e-ai-promotion{font-size:var(--control-title-size)}.e-ai-promotion i{margin-inline-end:5px}.elementor-label-block .e-ai-button,.elementor-label-block .e-ai-promotion{margin-inline-start:auto}.elementor-context-menu-list__item__ai-badge{background-color:#524cff;border-radius:25px;display:flex;justify-content:center;padding:4px}.elementor-context-menu-list__item__ai-badge svg{width:12px;height:12px}.elementor-context-menu-list__item__ai-badge svg path{fill:#fff}

View File

@@ -0,0 +1,131 @@
[data-id^=e-ai-preview-container] {
outline: 2px solid var(--e-p-border-con);
outline-offset: -2px;
}
[data-id^=e-ai-screenshot-container], [data-id^=e-ai-screenshot-container] * {
animation-duration: 0s !important;
animation-iteration-count: 1 !important;
transition-duration: 0s !important;
}
.e-ai-preview-container--idle {
height: 154px;
background-image: url("data:image/svg+xml,%3Csvg width='80' height='80' viewBox='0 0 80 80' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cg opacity='0.4'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M60.834 10.833C62.2147 10.833 63.334 11.9523 63.334 13.333C63.334 14.4381 63.773 15.4979 64.5544 16.2793C65.3358 17.0607 66.3956 17.4997 67.5007 17.4997C68.8814 17.4997 70.0007 18.619 70.0007 19.9997C70.0007 21.3804 68.8814 22.4997 67.5007 22.4997C66.3956 22.4997 65.3358 22.9387 64.5544 23.7201C63.773 24.5015 63.334 25.5613 63.334 26.6663C63.334 28.0471 62.2147 29.1663 60.834 29.1663C59.4533 29.1663 58.334 28.0471 58.334 26.6663C58.334 25.5613 57.895 24.5015 57.1136 23.7201C56.3322 22.9387 55.2724 22.4997 54.1673 22.4997C52.7866 22.4997 51.6673 21.3804 51.6673 19.9997C51.6673 18.619 52.7866 17.4997 54.1673 17.4997C55.2724 17.4997 56.3322 17.0607 57.1136 16.2793C57.895 15.4979 58.334 14.4381 58.334 13.333C58.334 11.9523 59.4533 10.833 60.834 10.833ZM60.834 19.6245C60.7734 19.6888 60.7118 19.7522 60.6491 19.8148C60.5865 19.8774 60.5231 19.9391 60.4588 19.9997C60.5231 20.0603 60.5865 20.1219 60.6491 20.1845C60.7118 20.2472 60.7734 20.3106 60.834 20.3748C60.8946 20.3106 60.9562 20.2472 61.0188 20.1845C61.0815 20.1219 61.1449 20.0603 61.2091 19.9997C61.1449 19.9391 61.0815 19.8774 61.0188 19.8148C60.9562 19.7522 60.8946 19.6888 60.834 19.6245ZM30.834 17.4997C32.2147 17.4997 33.334 18.619 33.334 19.9997C33.334 24.641 35.1777 29.0922 38.4596 32.374C41.7415 35.6559 46.1927 37.4997 50.834 37.4997C52.2147 37.4997 53.334 38.619 53.334 39.9997C53.334 41.3804 52.2147 42.4997 50.834 42.4997C46.1927 42.4997 41.7415 44.3434 38.4596 47.6253C35.1777 50.9072 33.334 55.3584 33.334 59.9997C33.334 61.3804 32.2147 62.4997 30.834 62.4997C29.4533 62.4997 28.334 61.3804 28.334 59.9997C28.334 55.3584 26.4902 50.9072 23.2084 47.6253C19.9265 44.3434 15.4753 42.4997 10.834 42.4997C9.45327 42.4997 8.33398 41.3804 8.33398 39.9997C8.33398 38.619 9.45327 37.4997 10.834 37.4997C15.4753 37.4997 19.9265 35.6559 23.2084 32.374C26.4902 29.0922 28.334 24.641 28.334 19.9997C28.334 18.619 29.4533 17.4997 30.834 17.4997ZM30.834 30.3075C29.778 32.3565 28.4041 34.2494 26.7439 35.9096C25.0837 37.5698 23.1908 38.9437 21.1418 39.9997C23.1908 41.0556 25.0837 42.4296 26.7439 44.0898C28.4041 45.75 29.778 47.6429 30.834 49.6919C31.8899 47.6429 33.2639 45.75 34.9241 44.0898C36.5843 42.4296 38.4772 41.0556 40.5262 39.9997C38.4772 38.9437 36.5843 37.5698 34.9241 35.9096C33.2639 34.2494 31.8899 32.3565 30.834 30.3075ZM60.834 50.833C62.2147 50.833 63.334 51.9523 63.334 53.333C63.334 54.4381 63.773 55.4979 64.5544 56.2793C65.3358 57.0607 66.3956 57.4997 67.5007 57.4997C68.8814 57.4997 70.0007 58.619 70.0007 59.9997C70.0007 61.3804 68.8814 62.4997 67.5007 62.4997C66.3956 62.4997 65.3358 62.9387 64.5544 63.7201C63.773 64.5015 63.334 65.5613 63.334 66.6663C63.334 68.0471 62.2147 69.1663 60.834 69.1663C59.4533 69.1663 58.334 68.0471 58.334 66.6663C58.334 65.5613 57.895 64.5015 57.1136 63.7201C56.3322 62.9387 55.2724 62.4997 54.1673 62.4997C52.7866 62.4997 51.6673 61.3804 51.6673 59.9997C51.6673 58.619 52.7866 57.4997 54.1673 57.4997C55.2724 57.4997 56.3322 57.0607 57.1136 56.2793C57.895 55.4979 58.334 54.4381 58.334 53.333C58.334 51.9523 59.4533 50.833 60.834 50.833ZM60.834 59.6245C60.7734 59.6888 60.7118 59.7522 60.6491 59.8148C60.5865 59.8774 60.5231 59.9391 60.4588 59.9997C60.5231 60.0603 60.5865 60.1219 60.6491 60.1845C60.7118 60.2472 60.7734 60.3106 60.834 60.3748C60.8946 60.3106 60.9562 60.2472 61.0188 60.1845C61.0815 60.1219 61.1449 60.0603 61.2091 59.9997C61.1449 59.9391 61.0815 59.8774 61.0188 59.8148C60.9562 59.7522 60.8946 59.6888 60.834 59.6245Z' fill='%23BABFC5'/%3E%3C/g%3E%3C/svg%3E");
background-position: center center;
background-repeat: no-repeat;
background-size: 80px auto;
}
.e-ai-preview-container--idle > * {
display: none !important;
}
.e-ai-preview-container--hidden {
display: none !important;
}
.e-ai-layout-button {
position: relative;
}
.e-ai-layout-button--sparkle {
--animation-duration: 1.5s;
--opacity: .2;
--size: 6px;
position: absolute;
z-index: 99999;
display: block;
height: var(--size);
aspect-ratio: 1;
background-image: url("data:image/svg+xml,%3Csvg width='6' height='6' viewBox='0 0 6 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M3 0.25C3.30335 0.25 3.57682 0.432732 3.69291 0.712987L4.15981 1.84019L5.28701 2.30709C5.56727 2.42318 5.75 2.69665 5.75 3C5.75 3.30335 5.56727 3.57682 5.28701 3.69291L4.15981 4.15981L3.69291 5.28701C3.57682 5.56727 3.30335 5.75 3 5.75C2.69665 5.75 2.42318 5.56727 2.30709 5.28701L1.84019 4.15981L0.712987 3.69291C0.432732 3.57682 0.25 3.30335 0.25 3C0.25 2.69665 0.432732 2.42318 0.712987 2.30709L1.84019 1.84019L2.30709 0.712987C2.42318 0.432732 2.69665 0.25 3 0.25Z' fill='%230c0d0e'/%3E%3C/svg%3E%0A");
background-size: cover;
opacity: 0;
}
.e-ai-layout-button--sparkle:nth-child(1), .e-ai-layout-button--sparkle:nth-child(2), .e-ai-layout-button--sparkle:nth-child(3) {
right: 12px;
top: 12px;
}
.e-ai-layout-button--sparkle:nth-child(4), .e-ai-layout-button--sparkle:nth-child(5), .e-ai-layout-button--sparkle:nth-child(6), .e-ai-layout-button--sparkle:nth-child(7) {
right: 12px;
top: 22px;
}
.e-ai-layout-button--sparkle:nth-child(1) {
--opacity: .3;
--size: 4px;
--animation-name: sparkle-1;
}
.e-ai-layout-button--sparkle:nth-child(2) {
--opacity: .3;
--size: 4px;
--animation-delay: .7s;
--animation-name: sparkle-2;
}
.e-ai-layout-button--sparkle:nth-child(3) {
--animation-delay: 3.5s;
--animation-name: sparkle-3;
}
.e-ai-layout-button--sparkle:nth-child(4) {
--animation-delay: .5s;
--animation-name: sparkle-4;
}
.e-ai-layout-button--sparkle:nth-child(5) {
--animation-delay: 1.5s;
--animation-name: sparkle-5;
}
.e-ai-layout-button--sparkle:nth-child(6) {
--animation-delay: 2.5s;
--animation-name: sparkle-6;
}
.e-ai-layout-button--sparkle:nth-child(7) {
--opacity: .3;
--animation-delay: .7s;
--animation-name: sparkle-7;
}
.e-ai-layout-button:hover .e-ai-layout-button--sparkle {
--timing: cubic-bezier( 0, 1.18, .96, .75 );
animation: var(--animation-name) var(--animation-duration) var(--animation-delay, 0s) var(--timing) infinite both, sparkle-opacity var(--animation-duration) var(--animation-delay, 0s) var(--timing) infinite both;
}
@keyframes sparkle-opacity {
50% {
opacity: var(--opacity);
}
100% {
opacity: 0;
}
}
@keyframes sparkle-1 {
100% {
transform: translate(16px, -12px);
}
}
@keyframes sparkle-2 {
100% {
transform: translate(16px, 12px);
}
}
@keyframes sparkle-3 {
100% {
transform: translate(12px, 8px);
}
}
@keyframes sparkle-4 {
100% {
transform: translate(16px, 16px);
}
}
@keyframes sparkle-5 {
100% {
transform: translate(12px, 16px);
}
}
@keyframes sparkle-6 {
100% {
transform: translate(-8px, -24px);
}
}
@keyframes sparkle-7 {
100% {
transform: translate(-20px, 16px);
}
}
/*# sourceMappingURL=layout-preview.css.map */

View File

@@ -0,0 +1 @@
[data-id^=e-ai-preview-container]{outline:2px solid var(--e-p-border-con);outline-offset:-2px}[data-id^=e-ai-screenshot-container],[data-id^=e-ai-screenshot-container] *{animation-duration:0s!important;animation-iteration-count:1!important;transition-duration:0s!important}.e-ai-preview-container--idle{height:154px;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='80' height='80' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M60.834 10.833a2.5 2.5 0 012.5 2.5 4.167 4.167 0 004.167 4.167 2.5 2.5 0 010 5 4.167 4.167 0 00-4.167 4.166 2.5 2.5 0 11-5 0 4.167 4.167 0 00-4.167-4.166 2.5 2.5 0 010-5 4.167 4.167 0 004.167-4.167 2.5 2.5 0 012.5-2.5zm0 8.792a8.722 8.722 0 01-.375.375 8.956 8.956 0 01.375.375 9.459 9.459 0 01.375-.375 9.464 9.464 0 01-.375-.375zm-30-2.125a2.5 2.5 0 012.5 2.5 17.5 17.5 0 0017.5 17.5 2.5 2.5 0 010 5 17.5 17.5 0 00-17.5 17.5 2.5 2.5 0 01-5 0 17.5 17.5 0 00-17.5-17.5 2.5 2.5 0 110-5 17.5 17.5 0 0017.5-17.5 2.5 2.5 0 012.5-2.5zm0 12.808A22.494 22.494 0 0121.142 40a22.491 22.491 0 019.692 9.692A22.491 22.491 0 0140.526 40a22.494 22.494 0 01-9.692-9.692zm30 20.525a2.5 2.5 0 012.5 2.5 4.167 4.167 0 004.167 4.167 2.5 2.5 0 010 5 4.167 4.167 0 00-4.167 4.166 2.5 2.5 0 11-5 0 4.167 4.167 0 00-4.167-4.166 2.5 2.5 0 010-5 4.167 4.167 0 004.167-4.167 2.5 2.5 0 012.5-2.5zm0 8.791a8.722 8.722 0 01-.375.376 8.956 8.956 0 01.375.375 9.459 9.459 0 01.375-.375 9.464 9.464 0 01-.375-.376z' fill='%23BABFC5' opacity='.4'/%3E%3C/svg%3E");background-position:50%;background-repeat:no-repeat;background-size:80px auto}.e-ai-preview-container--hidden,.e-ai-preview-container--idle>*{display:none!important}.e-ai-layout-button{position:relative}.e-ai-layout-button--sparkle{--animation-duration:1.5s;--opacity:.2;--size:6px;position:absolute;z-index:99999;display:block;height:var(--size);aspect-ratio:1;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='6' height='6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M3 .25a.75.75 0 01.693.463L4.16 1.84l1.127.467a.75.75 0 010 1.386L4.16 4.16l-.467 1.127a.75.75 0 01-1.386 0L1.84 4.16.713 3.693a.75.75 0 010-1.386L1.84 1.84 2.307.713A.75.75 0 013 .25z' fill='%230c0d0e'/%3E%3C/svg%3E");background-size:cover;opacity:0}.e-ai-layout-button--sparkle:first-child,.e-ai-layout-button--sparkle:nth-child(2),.e-ai-layout-button--sparkle:nth-child(3){right:12px;top:12px}.e-ai-layout-button--sparkle:nth-child(4),.e-ai-layout-button--sparkle:nth-child(5),.e-ai-layout-button--sparkle:nth-child(6),.e-ai-layout-button--sparkle:nth-child(7){right:12px;top:22px}.e-ai-layout-button--sparkle:first-child{--opacity:.3;--size:4px;--animation-name:sparkle-1}.e-ai-layout-button--sparkle:nth-child(2){--opacity:.3;--size:4px;--animation-delay:.7s;--animation-name:sparkle-2}.e-ai-layout-button--sparkle:nth-child(3){--animation-delay:3.5s;--animation-name:sparkle-3}.e-ai-layout-button--sparkle:nth-child(4){--animation-delay:.5s;--animation-name:sparkle-4}.e-ai-layout-button--sparkle:nth-child(5){--animation-delay:1.5s;--animation-name:sparkle-5}.e-ai-layout-button--sparkle:nth-child(6){--animation-delay:2.5s;--animation-name:sparkle-6}.e-ai-layout-button--sparkle:nth-child(7){--opacity:.3;--animation-delay:.7s;--animation-name:sparkle-7}.e-ai-layout-button:hover .e-ai-layout-button--sparkle{--timing:cubic-bezier(0,1.18,.96,.75);animation:var(--animation-name) var(--animation-duration) var(--animation-delay,0s) var(--timing) infinite both,sparkle-opacity var(--animation-duration) var(--animation-delay,0s) var(--timing) infinite both}@keyframes sparkle-opacity{50%{opacity:var(--opacity)}to{opacity:0}}@keyframes sparkle-1{to{transform:translate(16px,-12px)}}@keyframes sparkle-2{to{transform:translate(16px,12px)}}@keyframes sparkle-3{to{transform:translate(12px,8px)}}@keyframes sparkle-4{to{transform:translate(16px,16px)}}@keyframes sparkle-5{to{transform:translate(12px,16px)}}@keyframes sparkle-6{to{transform:translate(-8px,-24px)}}@keyframes sparkle-7{to{transform:translate(-20px,16px)}}

View File

@@ -0,0 +1,124 @@
#e-announcements-root {
position: fixed;
display: flex;
top: 0;
left: 0;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
color: var(--e-a-color-txt);
font-family: Roboto, Arial, Helvetica, sans-serif;
z-index: 9998;
}
#e-announcements-root .announcements-container {
width: 640px;
max-width: 100%;
background-color: var(--e-a-bg-default);
border-radius: var(--e-a-border-radius);
z-index: 9998;
}
#e-announcements-root .announcements-container .announcements-heading-container {
display: flex;
align-items: center;
padding: 16px 32px;
border-block-end: var(--e-a-border);
}
#e-announcements-root .announcements-container .announcements-heading-container .eicon-elementor {
color: var(--e-a-color-logo);
background-color: var(--e-a-bg-logo);
border-radius: 50%;
padding: 8px;
}
#e-announcements-root .announcements-container .announcements-heading-container .heading-title {
margin-inline-start: 12px;
text-transform: uppercase;
font-weight: 700;
color: var(--e-a-color-txt-active);
}
#e-announcements-root .announcements-container .announcements-heading-container .close-button {
margin-inline-start: auto;
background: none;
color: inherit;
border: none;
padding: 0;
font: inherit;
cursor: pointer;
outline: inherit;
}
#e-announcements-root .announcements-container .announcements-heading-container .close-button:hover {
color: var(--e-a-color-txt-hover);
}
#e-announcements-root .announcements-container .announcement-body-container .announcement-body-media img {
width: 100%;
max-height: 360px;
object-fit: contain;
}
#e-announcements-root .announcements-container .announcement-body-container .announcement-body-content {
padding: 30px;
}
#e-announcements-root .announcements-container .announcement-body-container .announcement-body-content .announcement-body-title {
font-size: 18px;
font-weight: 700;
color: var(--e-a-color-txt-accent);
padding-block-end: 15px;
}
#e-announcements-root .announcements-container .announcement-body-container .announcement-body-content .announcement-body-description {
font-size: 16px;
line-height: 24px;
font-weight: 400;
color: var(--e-a-color-txt);
}
#e-announcements-root .announcements-container .announcement-body-container .announcement-body-content p {
margin-block-end: 15px;
}
#e-announcements-root .announcements-container .announcement-body-container .announcement-body-content ul {
margin-inline-start: 20px;
margin-block-end: 15px;
}
#e-announcements-root .announcements-container .announcement-body-container .announcement-body-content li {
list-style: disc;
margin-block-end: 5px;
}
#e-announcements-root .announcements-container .announcement-footer-container {
display: flex;
flex-direction: row-reverse;
padding: 12px 32px 32px;
}
#e-announcements-root .announcements-container .announcement-footer-container .button-item {
margin-inline-start: 12px;
padding: 8px 16px;
outline: none;
border: none;
border-radius: var(--e-a-border-radius);
transition: var(--e-a-transition-hover);
background: transparent;
color: var(--e-a-color-txt);
cursor: pointer;
}
#e-announcements-root .announcements-container .announcement-footer-container .button-item:hover {
background: var(--e-a-bg-hover);
color: var(--e-a-color-txt-hover);
}
#e-announcements-root .announcements-container .announcement-footer-container .button-item:disabled {
background: transparent;
color: var(--e-a-color-txt-disabled);
}
#e-announcements-root .announcements-container .announcement-footer-container .button-item.primary {
background-color: var(--e-a-btn-bg-accent);
color: var(--e-a-btn-color-invert);
}
#e-announcements-root .announcements-container .announcement-footer-container .button-item.primary:hover {
background-color: var(--e-a-btn-bg-accent-hover);
}
#e-announcements-root .announcements-container .announcement-footer-container .button-item.primary:active {
background-color: var(--e-a-btn-bg-accent-active);
}
#e-announcements-root .announcements-screen-overlay {
position: fixed;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.6);
}
/*# sourceMappingURL=announcements.css.map */

View File

@@ -0,0 +1 @@
#e-announcements-root{position:fixed;display:flex;top:0;left:0;width:100%;height:100%;align-items:center;justify-content:center;color:var(--e-a-color-txt);font-family:Roboto,Arial,Helvetica,sans-serif;z-index:9998}#e-announcements-root .announcements-container{width:640px;max-width:100%;background-color:var(--e-a-bg-default);border-radius:var(--e-a-border-radius);z-index:9998}#e-announcements-root .announcements-container .announcements-heading-container{display:flex;align-items:center;padding:16px 32px;border-block-end:var(--e-a-border)}#e-announcements-root .announcements-container .announcements-heading-container .eicon-elementor{color:var(--e-a-color-logo);background-color:var(--e-a-bg-logo);border-radius:50%;padding:8px}#e-announcements-root .announcements-container .announcements-heading-container .heading-title{margin-inline-start:12px;text-transform:uppercase;font-weight:700;color:var(--e-a-color-txt-active)}#e-announcements-root .announcements-container .announcements-heading-container .close-button{margin-inline-start:auto;background:none;color:inherit;border:none;padding:0;font:inherit;cursor:pointer;outline:inherit}#e-announcements-root .announcements-container .announcements-heading-container .close-button:hover{color:var(--e-a-color-txt-hover)}#e-announcements-root .announcements-container .announcement-body-container .announcement-body-media img{width:100%;max-height:360px;-o-object-fit:contain;object-fit:contain}#e-announcements-root .announcements-container .announcement-body-container .announcement-body-content{padding:30px}#e-announcements-root .announcements-container .announcement-body-container .announcement-body-content .announcement-body-title{font-size:18px;font-weight:700;color:var(--e-a-color-txt-accent);padding-block-end:15px}#e-announcements-root .announcements-container .announcement-body-container .announcement-body-content .announcement-body-description{font-size:16px;line-height:24px;font-weight:400;color:var(--e-a-color-txt)}#e-announcements-root .announcements-container .announcement-body-container .announcement-body-content p{margin-block-end:15px}#e-announcements-root .announcements-container .announcement-body-container .announcement-body-content ul{margin-inline-start:20px;margin-block-end:15px}#e-announcements-root .announcements-container .announcement-body-container .announcement-body-content li{list-style:disc;margin-block-end:5px}#e-announcements-root .announcements-container .announcement-footer-container{display:flex;flex-direction:row-reverse;padding:12px 32px 32px}#e-announcements-root .announcements-container .announcement-footer-container .button-item{margin-inline-start:12px;padding:8px 16px;outline:none;border:none;border-radius:var(--e-a-border-radius);transition:var(--e-a-transition-hover);background:transparent;color:var(--e-a-color-txt);cursor:pointer}#e-announcements-root .announcements-container .announcement-footer-container .button-item:hover{background:var(--e-a-bg-hover);color:var(--e-a-color-txt-hover)}#e-announcements-root .announcements-container .announcement-footer-container .button-item:disabled{background:transparent;color:var(--e-a-color-txt-disabled)}#e-announcements-root .announcements-container .announcement-footer-container .button-item.primary{background-color:var(--e-a-btn-bg-accent);color:var(--e-a-btn-color-invert)}#e-announcements-root .announcements-container .announcement-footer-container .button-item.primary:hover{background-color:var(--e-a-btn-bg-accent-hover)}#e-announcements-root .announcements-container .announcement-footer-container .button-item.primary:active{background-color:var(--e-a-btn-bg-accent-active)}#e-announcements-root .announcements-screen-overlay{position:fixed;width:100%;height:100%;background-color:rgba(0,0,0,.6)}

View File

@@ -0,0 +1,101 @@
body.elementor-apps-page {
background: var(--e-a-color-white);
}
.e-a-apps .e-a-page-title {
margin: 30px auto 60px;
max-width: 770px;
text-align: center;
}
.e-a-apps .e-a-page-title h2 {
font-size: 28px;
margin: 0;
line-height: 1.6;
}
.e-a-apps .e-a-page-title p {
margin-block-start: 0;
font-size: 16px;
}
.e-a-apps .e-a-page-title p a {
color: inherit;
}
.e-a-apps .e-a-page-footer {
margin: 60px auto;
text-align: center;
}
.e-a-apps .e-a-page-footer p {
max-width: 1200px;
margin: auto;
}
.e-a-apps .e-a-list {
display: grid;
grid-gap: 30px;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
.e-a-apps .e-a-item {
border: var(--e-a-border);
border-radius: var(--e-a-border-radius);
display: flex;
padding: 20px 24px;
flex-direction: column;
align-items: flex-start;
transition: var(--e-a-transition-hover);
}
.e-a-apps .e-a-item:hover {
border-color: var(--e-a-border-color-bold);
}
.e-a-apps .e-a-heading {
display: flex;
justify-content: space-between;
align-items: flex-start;
width: 100%;
}
.e-a-apps .e-a-heading .e-a-img {
border-radius: var(--e-a-border-radius);
width: 70px;
display: flex;
margin-block-end: 20px;
}
.e-a-apps .e-a-heading .e-a-badge {
background: #ECFDF5;
color: #047857;
border-radius: 100px;
padding: 3px 8px;
}
.e-a-apps .e-a-title,
.e-a-apps .e-a-author {
margin: 0;
line-height: 1.6;
}
.e-a-apps .e-a-author {
font-size: 12px;
}
.e-a-apps .e-a-author a {
color: inherit;
}
.e-a-apps .e-a-desc {
flex-grow: 1;
}
.e-a-apps .e-a-offering {
font-size: 12px;
font-style: italic;
}
.e-a-apps .e-a-actions {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
margin-block-start: 20px;
}
.e-a-apps .e-a-actions a {
text-decoration: none;
}
.e-a-apps .e-a-actions .e-accent {
margin-inline-start: auto;
}
.e-a-apps .e-a-actions .e-a-learn-more {
color: #4338CA;
font-weight: 500;
}
/*# sourceMappingURL=admin.css.map */

View File

@@ -0,0 +1 @@
body.elementor-apps-page{background:var(--e-a-color-white)}.e-a-apps .e-a-page-title{margin:30px auto 60px;max-width:770px;text-align:center}.e-a-apps .e-a-page-title h2{font-size:28px;margin:0;line-height:1.6}.e-a-apps .e-a-page-title p{margin-block-start:0;font-size:16px}.e-a-apps .e-a-page-title p a{color:inherit}.e-a-apps .e-a-page-footer{margin:60px auto;text-align:center}.e-a-apps .e-a-page-footer p{max-width:1200px;margin:auto}.e-a-apps .e-a-list{display:grid;grid-gap:30px;grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}.e-a-apps .e-a-item{border:var(--e-a-border);border-radius:var(--e-a-border-radius);display:flex;padding:20px 24px;flex-direction:column;align-items:flex-start;transition:var(--e-a-transition-hover)}.e-a-apps .e-a-item:hover{border-color:var(--e-a-border-color-bold)}.e-a-apps .e-a-heading{display:flex;justify-content:space-between;align-items:flex-start;width:100%}.e-a-apps .e-a-heading .e-a-img{border-radius:var(--e-a-border-radius);width:70px;display:flex;margin-block-end:20px}.e-a-apps .e-a-heading .e-a-badge{background:#ecfdf5;color:#047857;border-radius:100px;padding:3px 8px}.e-a-apps .e-a-author,.e-a-apps .e-a-title{margin:0;line-height:1.6}.e-a-apps .e-a-author{font-size:12px}.e-a-apps .e-a-author a{color:inherit}.e-a-apps .e-a-desc{flex-grow:1}.e-a-apps .e-a-offering{font-size:12px;font-style:italic}.e-a-apps .e-a-actions{display:flex;justify-content:space-between;align-items:center;width:100%;margin-block-start:20px}.e-a-apps .e-a-actions a{text-decoration:none}.e-a-apps .e-a-actions .e-accent{margin-inline-start:auto}.e-a-apps .e-a-actions .e-a-learn-more{color:#4338ca;font-weight:500}

View File

@@ -0,0 +1,20 @@
.elementor-control-convert_to_container .elementor-button.e-loading {
font-size: 0;
width: 42px;
position: relative;
pointer-events: none;
}
.elementor-control-convert_to_container .elementor-button.e-loading::before {
content: "\e8fb";
font-family: "eicons";
font-size: 12px;
animation: eicon-spin 2s infinite linear;
display: inline-block;
position: absolute;
left: 50%;
top: 50%;
margin-inline-start: -6px;
margin-block-start: -6px;
}
/*# sourceMappingURL=editor.css.map */

View File

@@ -0,0 +1 @@
.elementor-control-convert_to_container .elementor-button.e-loading{font-size:0;width:42px;position:relative;pointer-events:none}.elementor-control-convert_to_container .elementor-button.e-loading:before{content:"\e8fb";font-family:eicons;font-size:12px;animation:eicon-spin 2s linear infinite;display:inline-block;position:absolute;left:50%;top:50%;margin-inline-start:-6px;margin-block-start:-6px}

View File

@@ -0,0 +1,6 @@
.elementor-panel-menu-item-notes .elementor-panel-menu-item-title-badge {
font-size: 16px;
color: var(--e-a-color-accent);
}
/*# sourceMappingURL=editor.css.map */

View File

@@ -0,0 +1 @@
.elementor-panel-menu-item-notes .elementor-panel-menu-item-title-badge{font-size:16px;color:var(--e-a-color-accent)}

View File

@@ -0,0 +1,37 @@
body.e-styleguide-shown {
overflow: hidden;
}
#e-styleguide-preview-dialog.dialog-styleguide-widget .dialog-styleguide-widget-content {
width: 100%;
height: 100%;
max-width: 100%;
max-height: 100%;
border-radius: 0;
top: 0 !important;
left: 0 !important;
overflow: scroll;
}
#e-styleguide-preview-dialog.dialog-styleguide-widget .dialog-styleguide-message {
min-height: 100vh;
padding: 0;
overflow-x: hidden;
text-align: initial;
font-family: Roboto, sans-serif;
}
#e-styleguide-preview-dialog.dialog-styleguide-widget .e-styleguide-loader {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
#e-styleguide-preview-dialog.dialog-styleguide-widget .e-styleguide-loader .eicon-loading {
font-size: 25px;
color: var(--e-a-color-txt-muted);
}
/*# sourceMappingURL=styleguide.css.map */

View File

@@ -0,0 +1 @@
body.e-styleguide-shown{overflow:hidden}#e-styleguide-preview-dialog.dialog-styleguide-widget .dialog-styleguide-widget-content{width:100%;height:100%;max-width:100%;max-height:100%;border-radius:0;top:0!important;left:0!important;overflow:scroll}#e-styleguide-preview-dialog.dialog-styleguide-widget .dialog-styleguide-message{min-height:100vh;padding:0;overflow-x:hidden;text-align:initial;font-family:Roboto,sans-serif}#e-styleguide-preview-dialog.dialog-styleguide-widget .e-styleguide-loader{position:absolute;top:0;left:0;height:100%;width:100%;display:flex;align-items:center;justify-content:center}#e-styleguide-preview-dialog.dialog-styleguide-widget .e-styleguide-loader .eicon-loading{font-size:25px;color:var(--e-a-color-txt-muted)}

View File

@@ -0,0 +1,194 @@
/*! elementor - v3.21.0 - 25-04-2024 */
:root {
--e-is-device-mode: 0;
}
.e-is-device-mode {
--e-is-device-mode: 1;
}
#elementor-responsive-bar {
position: sticky;
height: calc(40px * var(--e-is-device-mode));
align-self: stretch;
flex-shrink: 0;
transition: height 0.2s ease-in-out, opacity 0.1s;
left: 0;
top: 0;
z-index: 100;
opacity: var(--e-is-device-mode);
box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.33), 0 0 2px 1px rgba(0, 0, 0, 0.25), 0 0 6px -3px rgba(255, 255, 255, 0.5);
}
#elementor-responsive-bar:before {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: -1;
transform: scaleX(var(--e-preview-scale, 1));
}
.e-responsive-bar-switcher__option {
cursor: pointer;
text-align: center;
width: 22px;
height: 22px;
margin: 0 4px;
line-height: 22px;
border-radius: 3px;
font-size: 16px;
transition: var(--e-a-transition-hover);
}
.e-responsive-bar-switcher__option:hover {
color: var(--e-a-color-primary-bold);
background-color: #310132;
}
.e-responsive-bar-switcher__option[aria-selected=true] {
background-color: #3f444b;
color: #F9FAFA;
}
.e-responsive-bar-switcher__option input {
display: none;
}
.e-responsive-bar-switcher__option:not(:last-child) {
margin-inline-end: 6px;
}
.e-responsive-bar__button {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: none;
border: 0 none;
cursor: pointer;
color: inherit;
}
.e-responsive-bar__button:focus:not(:focus-visible) {
outline: none;
}
.e-responsive-bar__button:hover {
color: #F1F2F3;
background-color: #3f444b;
}
.e-responsive-bar--pipe {
position: relative;
}
.e-responsive-bar--pipe::before {
content: "";
display: block;
height: 20px;
width: 1px;
background-color: #BABFC5;
position: absolute;
inset-inline-end: -5px;
top: calc(50% - 10px);
}
.e-responsive-bar__input-size {
background-color: transparent;
color: #BABFC5;
border: 1px solid #BABFC5;
padding: 0 3px;
width: 60px;
font-size: 12px;
line-height: 16px;
height: 18px;
margin: auto 8px auto 4px;
text-align: center;
}
.e-responsive-bar__input-size-separator {
color: #BABFC5;
}
.e-responsive-bar__input-size[disabled] {
background-color: transparent;
color: #818A96;
cursor: default;
-moz-appearance: none;
appearance: none;
-webkit-appearance: none;
}
#e-responsive-bar {
width: 100%;
margin-block-start: calc(-40px + 40px * var(--e-is-device-mode));
z-index: 1;
transition: margin-block-start 0.2s ease-in-out;
display: grid;
grid-template-columns: auto 1fr;
align-items: center;
justify-content: space-between;
color: #BABFC5;
background-color: #1f2124;
}
#e-responsive-bar__center, #e-responsive-bar__end, #e-responsive-bar-scale, #e-responsive-bar-switcher {
display: flex;
justify-content: center;
align-items: center;
font-size: 13px;
background-color: #1f2124;
padding: 2px 0;
}
#e-responsive-bar__end {
justify-self: end;
}
@media (min-width: 1400px) {
#e-responsive-bar {
grid-template-columns: 1fr auto 1fr;
}
#e-responsive-bar::before {
content: "";
}
}
#e-responsive-bar__close-button, #e-responsive-bar__settings-button {
width: 22px;
height: 22px;
border-radius: 3px;
margin: 7px 5px;
font-size: 16px;
}
#e-responsive-bar__size-inputs-wrapper {
display: flex;
align-items: center;
margin-inline-end: 8px;
color: #BABFC5;
}
#e-responsive-bar-switcher {
padding: 0 20px;
}
#e-responsive-bar-scale {
padding: 0 20px;
}
#e-responsive-bar-scale__value-wrapper {
margin: 0 14px;
min-width: 32px;
text-align: center;
}
#e-responsive-bar-scale__plus, #e-responsive-bar-scale__minus, #e-responsive-bar-scale__reset {
cursor: pointer;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 3px;
transition: all 0.3s;
}
#e-responsive-bar-scale__plus:hover, #e-responsive-bar-scale__minus:hover, #e-responsive-bar-scale__reset:hover {
color: #F1F2F3;
background-color: #3f444b;
}
#e-responsive-bar-scale__minus:before {
content: "";
display: block;
width: 13px;
height: 2px;
background-color: #BABFC5;
border-radius: 3px;
}
#e-responsive-bar-scale__minus:hover:before {
background-color: #F1F2F3;
}
#e-responsive-bar-scale__reset {
margin: 0 8px;
}
/*# sourceMappingURL=responsive-bar.css.map */

View File

@@ -0,0 +1,2 @@
/*! elementor - v3.21.0 - 25-04-2024 */
:root{--e-is-device-mode:0}.e-is-device-mode{--e-is-device-mode:1}#elementor-responsive-bar{position:sticky;height:calc(40px * var(--e-is-device-mode));align-self:stretch;flex-shrink:0;transition:height .2s ease-in-out,opacity .1s;left:0;top:0;z-index:100;opacity:var(--e-is-device-mode);box-shadow:0 0 10px 2px rgba(0,0,0,.33),0 0 2px 1px rgba(0,0,0,.25),0 0 6px -3px hsla(0,0%,100%,.5)}#elementor-responsive-bar:before{content:"";position:absolute;left:0;top:0;width:100%;height:100%;z-index:-1;transform:scaleX(var(--e-preview-scale,1))}.e-responsive-bar-switcher__option{cursor:pointer;text-align:center;width:22px;height:22px;margin:0 4px;line-height:22px;border-radius:3px;font-size:16px;transition:var(--e-a-transition-hover)}.e-responsive-bar-switcher__option:hover{color:var(--e-a-color-primary-bold);background-color:#310132}.e-responsive-bar-switcher__option[aria-selected=true]{background-color:#3f444b;color:#f9fafa}.e-responsive-bar-switcher__option input{display:none}.e-responsive-bar-switcher__option:not(:last-child){margin-inline-end:6px}.e-responsive-bar__button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;cursor:pointer;color:inherit}.e-responsive-bar__button:focus:not(:focus-visible){outline:none}.e-responsive-bar__button:hover{color:#f1f2f3;background-color:#3f444b}.e-responsive-bar--pipe{position:relative}.e-responsive-bar--pipe:before{content:"";display:block;height:20px;width:1px;background-color:#babfc5;position:absolute;inset-inline-end:-5px;top:calc(50% - 10px)}.e-responsive-bar__input-size{background-color:transparent;color:#babfc5;border:1px solid #babfc5;padding:0 3px;width:60px;font-size:12px;line-height:16px;height:18px;margin:auto 8px auto 4px;text-align:center}.e-responsive-bar__input-size-separator{color:#babfc5}.e-responsive-bar__input-size[disabled]{background-color:transparent;color:#818a96;cursor:default;-moz-appearance:none;appearance:none;-webkit-appearance:none}#e-responsive-bar{width:100%;margin-block-start:calc(-40px + 40px * var(--e-is-device-mode));z-index:1;transition:margin-block-start .2s ease-in-out;display:grid;grid-template-columns:auto 1fr;align-items:center;justify-content:space-between;color:#babfc5;background-color:#1f2124}#e-responsive-bar-scale,#e-responsive-bar-switcher,#e-responsive-bar__center,#e-responsive-bar__end{display:flex;justify-content:center;align-items:center;font-size:13px;background-color:#1f2124;padding:2px 0}#e-responsive-bar__end{justify-self:end}@media (min-width:1400px){#e-responsive-bar{grid-template-columns:1fr auto 1fr}#e-responsive-bar:before{content:""}}#e-responsive-bar__close-button,#e-responsive-bar__settings-button{width:22px;height:22px;border-radius:3px;margin:7px 5px;font-size:16px}#e-responsive-bar__size-inputs-wrapper{display:flex;align-items:center;margin-inline-end:8px;color:#babfc5}#e-responsive-bar-scale,#e-responsive-bar-switcher{padding:0 20px}#e-responsive-bar-scale__value-wrapper{margin:0 14px;min-width:32px;text-align:center}#e-responsive-bar-scale__minus,#e-responsive-bar-scale__plus,#e-responsive-bar-scale__reset{cursor:pointer;width:20px;height:20px;display:flex;align-items:center;justify-content:center;border-radius:3px;transition:all .3s}#e-responsive-bar-scale__minus:hover,#e-responsive-bar-scale__plus:hover,#e-responsive-bar-scale__reset:hover{color:#f1f2f3;background-color:#3f444b}#e-responsive-bar-scale__minus:before{content:"";display:block;width:13px;height:2px;background-color:#babfc5;border-radius:3px}#e-responsive-bar-scale__minus:hover:before{background-color:#f1f2f3}#e-responsive-bar-scale__reset{margin:0 8px}

Some files were not shown because too many files have changed in this diff Show More