first commit
This commit is contained in:
143
wp-content/plugins/elementor/modules/admin-bar/module.php
Normal file
143
wp-content/plugins/elementor/modules/admin-bar/module.php
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\AdminBar;
|
||||
|
||||
use Elementor\Core\Base\Document;
|
||||
use Elementor\Core\Base\App as BaseApp;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Module extends BaseApp {
|
||||
/**
|
||||
* @var Document[]
|
||||
*/
|
||||
private $documents = [];
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_active() {
|
||||
return is_admin_bar_showing();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'admin-bar';
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the documents that was rendered in the current page.
|
||||
*
|
||||
* @param Document $document
|
||||
* @param $is_excerpt
|
||||
*/
|
||||
public function add_document_to_admin_bar( Document $document, $is_excerpt ) {
|
||||
if (
|
||||
$is_excerpt ||
|
||||
! $document::get_property( 'show_on_admin_bar' ) ||
|
||||
! $document->is_editable_by_current_user()
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->documents[ $document->get_main_id() ] = $document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scripts for module.
|
||||
*/
|
||||
public function enqueue_scripts() {
|
||||
if ( empty( $this->documents ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Should load 'elementor-admin-bar' before 'admin-bar'
|
||||
wp_dequeue_script( 'admin-bar' );
|
||||
|
||||
wp_enqueue_script(
|
||||
'elementor-admin-bar',
|
||||
$this->get_js_assets_url( 'elementor-admin-bar' ),
|
||||
[ 'elementor-frontend-modules' ],
|
||||
ELEMENTOR_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
// This is a core script of WordPress, it is not required to pass the 'ver' argument.
|
||||
wp_enqueue_script( // phpcs:ignore WordPress.WP.EnqueuedResourceParameters
|
||||
'admin-bar',
|
||||
null,
|
||||
[ 'elementor-admin-bar' ],
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
||||
$this->print_config( 'elementor-admin-bar' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates admin bar menu items config.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_init_settings() {
|
||||
$settings = [];
|
||||
|
||||
if ( ! empty( $this->documents ) ) {
|
||||
$settings['elementor_edit_page'] = $this->get_edit_button_config();
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin bar settings in the frontend.
|
||||
*
|
||||
* Register admin_bar config to parse later in the frontend and add to the admin bar with JS.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param array $settings the admin_bar config
|
||||
*/
|
||||
$settings = apply_filters( 'elementor/frontend/admin_bar/settings', $settings );
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the config for 'Edit with elementor' menu item.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_edit_button_config() {
|
||||
$queried_object_id = get_queried_object_id();
|
||||
$href = null;
|
||||
|
||||
if ( is_singular() && isset( $this->documents[ $queried_object_id ] ) ) {
|
||||
$href = $this->documents[ $queried_object_id ]->get_edit_url();
|
||||
|
||||
unset( $this->documents[ $queried_object_id ] );
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => 'elementor_edit_page',
|
||||
'title' => esc_html__( 'Edit with Elementor', 'elementor' ),
|
||||
'href' => $href,
|
||||
'children' => array_map( function ( $document ) {
|
||||
return [
|
||||
'id' => "elementor_edit_doc_{$document->get_main_id()}",
|
||||
'title' => $document->get_post()->post_title,
|
||||
'sub_title' => $document::get_title(),
|
||||
'href' => $document->get_edit_url(),
|
||||
];
|
||||
}, $this->documents ),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Module constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'elementor/frontend/before_get_builder_content', [ $this, 'add_document_to_admin_bar' ], 10, 2 );
|
||||
add_action( 'wp_footer', [ $this, 'enqueue_scripts' ], 11 /* after third party scripts */ );
|
||||
}
|
||||
}
|
||||
150
wp-content/plugins/elementor/modules/admin-top-bar/module.php
Normal file
150
wp-content/plugins/elementor/modules/admin-top-bar/module.php
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\AdminTopBar;
|
||||
|
||||
use Elementor\Core\Utils\Promotions\Filtered_Promotions_Manager;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Core\Base\App as BaseApp;
|
||||
use Elementor\Core\Experiments\Manager;
|
||||
use Elementor\Utils;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Module extends BaseApp {
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_active() {
|
||||
return is_admin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'admin-top-bar';
|
||||
}
|
||||
|
||||
private function render_admin_top_bar() {
|
||||
?>
|
||||
<div id="e-admin-top-bar-root">
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue admin scripts
|
||||
*/
|
||||
private function enqueue_scripts() {
|
||||
wp_enqueue_style( 'elementor-admin-top-bar-fonts', 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap', [], ELEMENTOR_VERSION );
|
||||
|
||||
wp_enqueue_style( 'elementor-admin-top-bar', $this->get_css_assets_url( 'admin-top-bar', null, 'default', true ), [], ELEMENTOR_VERSION );
|
||||
|
||||
/**
|
||||
* Before admin top bar enqueue scripts.
|
||||
*
|
||||
* Fires before Elementor admin top bar scripts are enqueued.
|
||||
*
|
||||
* @since 3.19.0
|
||||
*/
|
||||
do_action( 'elementor/admin_top_bar/before_enqueue_scripts', $this );
|
||||
|
||||
wp_enqueue_script( 'elementor-admin-top-bar', $this->get_js_assets_url( 'admin-top-bar' ), [
|
||||
'elementor-common',
|
||||
'react',
|
||||
'react-dom',
|
||||
'tipsy',
|
||||
], ELEMENTOR_VERSION, true );
|
||||
|
||||
wp_set_script_translations( 'elementor-admin-top-bar', 'elementor' );
|
||||
|
||||
$min_suffix = Utils::is_script_debug() ? '' : '.min';
|
||||
|
||||
wp_enqueue_script( 'tipsy', ELEMENTOR_ASSETS_URL . 'lib/tipsy/tipsy' . $min_suffix . '.js', [
|
||||
'jquery',
|
||||
], '1.0.0', true );
|
||||
|
||||
$this->print_config();
|
||||
}
|
||||
|
||||
private function add_frontend_settings() {
|
||||
$settings = [];
|
||||
$settings['is_administrator'] = current_user_can( 'manage_options' );
|
||||
|
||||
// TODO: Find a better way to add apps page url to the admin top bar.
|
||||
$settings['apps_url'] = admin_url( 'admin.php?page=elementor-apps' );
|
||||
$settings['promotion'] = [
|
||||
'text' => __( 'Upgrade Now', 'elementor' ),
|
||||
'url' => 'https://go.elementor.com/wp-dash-admin-top-bar-upgrade/',
|
||||
];
|
||||
|
||||
$settings['promotion'] = Filtered_Promotions_Manager::get_filtered_promotion_data(
|
||||
$settings['promotion'],
|
||||
'elementor/admin_top_bar/go_pro_promotion',
|
||||
'url'
|
||||
);
|
||||
|
||||
$current_screen = get_current_screen();
|
||||
|
||||
/** @var \Elementor\Core\Common\Modules\Connect\Apps\Library $library */
|
||||
$library = Plugin::$instance->common->get_component( 'connect' )->get_app( 'library' );
|
||||
if ( $library ) {
|
||||
$settings = array_merge( $settings, [
|
||||
'is_user_connected' => $library->is_connected(),
|
||||
'connect_url' => $library->get_admin_url( 'authorize', [
|
||||
'utm_source' => 'top-bar',
|
||||
'utm_medium' => 'wp-dash',
|
||||
'utm_campaign' => 'connect-account',
|
||||
'utm_content' => $current_screen->id,
|
||||
'source' => 'generic',
|
||||
] ),
|
||||
] );
|
||||
}
|
||||
|
||||
$this->set_settings( $settings );
|
||||
|
||||
do_action( 'elementor/admin-top-bar/init', $this );
|
||||
}
|
||||
|
||||
private function is_top_bar_active() {
|
||||
$current_screen = get_current_screen();
|
||||
|
||||
if ( ! $current_screen ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$is_elementor_page = strpos( $current_screen->id ?? '', 'elementor' ) !== false;
|
||||
$is_elementor_post_type_page = strpos( $current_screen->post_type ?? '', 'elementor' ) !== false;
|
||||
|
||||
return apply_filters(
|
||||
'elementor/admin-top-bar/is-active',
|
||||
$is_elementor_page || $is_elementor_post_type_page,
|
||||
$current_screen
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Module constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_action( 'current_screen', function () {
|
||||
if ( ! $this->is_top_bar_active() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->add_frontend_settings();
|
||||
|
||||
add_action( 'in_admin_header', function () {
|
||||
$this->render_admin_top_bar();
|
||||
} );
|
||||
|
||||
add_action( 'admin_enqueue_scripts', function () {
|
||||
$this->enqueue_scripts();
|
||||
} );
|
||||
} );
|
||||
}
|
||||
}
|
||||
732
wp-content/plugins/elementor/modules/ai/connect/ai.php
Normal file
732
wp-content/plugins/elementor/modules/ai/connect/ai.php
Normal file
@@ -0,0 +1,732 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Ai\Connect;
|
||||
|
||||
use Elementor\Core\Common\Modules\Connect\Apps\Library;
|
||||
use Elementor\Modules\Ai\Module;
|
||||
use Elementor\Utils as ElementorUtils;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Ai extends Library {
|
||||
const API_URL = 'https://my.elementor.com/api/v2/ai/';
|
||||
|
||||
const STYLE_PRESET = 'style_preset';
|
||||
const IMAGE_TYPE = 'image_type';
|
||||
const IMAGE_STRENGTH = 'image_strength';
|
||||
const ASPECT_RATIO = 'ratio';
|
||||
const IMAGE_RESOLUTION = 'image_resolution';
|
||||
|
||||
const PROMPT = 'prompt';
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'AI', 'elementor' );
|
||||
}
|
||||
|
||||
protected function get_api_url() {
|
||||
return static::API_URL . '/';
|
||||
}
|
||||
|
||||
public function get_usage() {
|
||||
return $this->ai_request(
|
||||
'POST',
|
||||
'status/check',
|
||||
[
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function get_cached_usage() {
|
||||
$cache_key = 'elementor_ai_usage';
|
||||
$cache_time = 24 * HOUR_IN_SECONDS;
|
||||
$usage = get_site_transient( $cache_key );
|
||||
|
||||
if ( ! $usage ) {
|
||||
$usage = $this->get_usage();
|
||||
set_site_transient( $cache_key, $usage, $cache_time );
|
||||
}
|
||||
|
||||
return $usage;
|
||||
}
|
||||
|
||||
public function get_remote_config() {
|
||||
return $this->ai_request(
|
||||
'GET',
|
||||
'remote-config/config',
|
||||
[
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_file_payload
|
||||
* @param $filename
|
||||
* @param $file_type
|
||||
* @param $file_path
|
||||
* @param $boundary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_file_payload( $filename, $file_type, $file_path, $boundary ) {
|
||||
$name = $filename ?? basename( $file_path );
|
||||
$mine_type = 'image' === $file_type ? image_type_to_mime_type( exif_imagetype( $file_path ) ) : $file_type;
|
||||
$payload = '';
|
||||
// Upload the file
|
||||
$payload .= '--' . $boundary;
|
||||
$payload .= "\r\n";
|
||||
$payload .= 'Content-Disposition: form-data; name="' . esc_attr( $name ) . '"; filename="' . esc_attr( $name ) . '"' . "\r\n";
|
||||
$payload .= 'Content-Type: ' . $mine_type . "\r\n";
|
||||
$payload .= "\r\n";
|
||||
$payload .= file_get_contents( $file_path );
|
||||
$payload .= "\r\n";
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
private function get_upload_request_body( $body, $file, $boundary, $file_name = '' ) {
|
||||
$payload = '';
|
||||
// add all body fields as standard POST fields:
|
||||
foreach ( $body as $name => $value ) {
|
||||
$payload .= '--' . $boundary;
|
||||
$payload .= "\r\n";
|
||||
$payload .= 'Content-Disposition: form-data; name="' . esc_attr( $name ) . '"' . "\r\n\r\n";
|
||||
$payload .= $value;
|
||||
$payload .= "\r\n";
|
||||
}
|
||||
|
||||
if ( is_array( $file ) ) {
|
||||
foreach ( $file as $key => $file_data ) {
|
||||
$payload .= $this->get_file_payload( $file_data['name'], $file_data['type'], $file_data['path'], $boundary );
|
||||
}
|
||||
} else {
|
||||
$image_mime = image_type_to_mime_type( exif_imagetype( $file ) );
|
||||
// @todo: add validation for supported image types
|
||||
|
||||
if ( empty( $file_name ) ) {
|
||||
$file_name = basename( $file );
|
||||
}
|
||||
$payload .= $this->get_file_payload( $file_name, $image_mime, $file, $boundary );
|
||||
}
|
||||
|
||||
$payload .= '--' . $boundary . '--';
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
private function ai_request( $method, $endpoint, $body, $file = false, $file_name = '', $format = 'default' ) {
|
||||
$headers = [
|
||||
'x-elementor-ai-version' => '2',
|
||||
];
|
||||
|
||||
if ( $file ) {
|
||||
$boundary = wp_generate_password( 24, false );
|
||||
$body = $this->get_upload_request_body( $body, $file, $boundary, $file_name );
|
||||
// add content type header
|
||||
$headers['Content-Type'] = 'multipart/form-data; boundary=' . $boundary;
|
||||
} elseif ( 'json' === $format ) {
|
||||
$headers['Content-Type'] = 'application/json';
|
||||
$body = wp_json_encode( $body );
|
||||
}
|
||||
|
||||
return $this->http_request(
|
||||
$method,
|
||||
$endpoint,
|
||||
[
|
||||
'timeout' => 100,
|
||||
'headers' => $headers,
|
||||
'body' => $body,
|
||||
|
||||
],
|
||||
[
|
||||
'return_type' => static::HTTP_RETURN_TYPE_ARRAY,
|
||||
'with_error_data' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function set_get_started() {
|
||||
return $this->ai_request(
|
||||
'POST',
|
||||
'status/get-started',
|
||||
[
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function set_status_feedback( $response_id ) {
|
||||
return $this->ai_request(
|
||||
'POST',
|
||||
'status/feedback/' . $response_id,
|
||||
[
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function set_used_gallery_image( $image_id ) {
|
||||
return $this->ai_request(
|
||||
'POST',
|
||||
'status/used-gallery-image/' . $image_id,
|
||||
[
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function get_completion_text( $prompt, $context, $request_ids ) {
|
||||
return $this->ai_request(
|
||||
'POST',
|
||||
'text/completion',
|
||||
[
|
||||
'prompt' => $prompt,
|
||||
'context' => wp_json_encode( $context ),
|
||||
'ids' => $request_ids,
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
],
|
||||
false,
|
||||
'',
|
||||
'json'
|
||||
);
|
||||
}
|
||||
|
||||
public function get_excerpt( $prompt, $context, $request_ids ) {
|
||||
$excerpt_length = apply_filters( 'excerpt_length', 55 );
|
||||
return $this->ai_request(
|
||||
'POST',
|
||||
'text/get-excerpt',
|
||||
[
|
||||
'content' => $prompt,
|
||||
'maxLength' => $excerpt_length,
|
||||
'context' => wp_json_encode( $context ),
|
||||
'ids' => $request_ids,
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
],
|
||||
false,
|
||||
'',
|
||||
'json'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_image_prompt_enhanced
|
||||
* @param $prompt
|
||||
*
|
||||
* @return mixed|\WP_Error
|
||||
*/
|
||||
public function get_image_prompt_enhanced( $prompt, $context, $request_ids ) {
|
||||
return $this->ai_request(
|
||||
'POST',
|
||||
'text/enhance-image-prompt',
|
||||
[
|
||||
'prompt' => $prompt,
|
||||
'context' => wp_json_encode( $context ),
|
||||
'ids' => $request_ids,
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function get_edit_text( $data, $context, $request_ids ) {
|
||||
return $this->ai_request(
|
||||
'POST',
|
||||
'text/edit',
|
||||
[
|
||||
'input' => $data['payload']['input'],
|
||||
'instruction' => $data['payload']['instruction'],
|
||||
'context' => wp_json_encode( $context ),
|
||||
'ids' => $request_ids,
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
],
|
||||
false,
|
||||
'',
|
||||
'json'
|
||||
);
|
||||
}
|
||||
|
||||
public function get_custom_code( $data, $context, $request_ids ) {
|
||||
return $this->ai_request(
|
||||
'POST',
|
||||
'text/custom-code',
|
||||
[
|
||||
'prompt' => $data['payload']['prompt'],
|
||||
'language' => $data['payload']['language'],
|
||||
'context' => wp_json_encode( $context ),
|
||||
'ids' => $request_ids,
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
],
|
||||
false,
|
||||
'',
|
||||
'json'
|
||||
);
|
||||
}
|
||||
|
||||
public function get_custom_css( $data, $context, $request_ids ) {
|
||||
return $this->ai_request(
|
||||
'POST',
|
||||
'text/custom-css',
|
||||
[
|
||||
'prompt' => $data['payload']['prompt'],
|
||||
'html_markup' => $data['payload']['html_markup'],
|
||||
'element_id' => $data['payload']['element_id'],
|
||||
'context' => wp_json_encode( $context ),
|
||||
'ids' => $request_ids,
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
],
|
||||
false,
|
||||
'',
|
||||
'json'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_text_to_image
|
||||
* @param $prompt
|
||||
* @param $prompt_settings
|
||||
*
|
||||
* @return mixed|\WP_Error
|
||||
*/
|
||||
public function get_text_to_image( $data, $context, $request_ids ) {
|
||||
return $this->ai_request(
|
||||
'POST',
|
||||
'image/text-to-image',
|
||||
[
|
||||
self::PROMPT => $data['payload']['prompt'],
|
||||
self::IMAGE_TYPE => $data['payload']['settings'][ self::IMAGE_TYPE ] . '/' . $data['payload']['settings'][ self::STYLE_PRESET ],
|
||||
self::ASPECT_RATIO => $data['payload']['settings'][ self::ASPECT_RATIO ],
|
||||
'context' => wp_json_encode( $context ),
|
||||
'ids' => $request_ids,
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
],
|
||||
false,
|
||||
'',
|
||||
'json'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_featured_image
|
||||
* @param $prompt
|
||||
* @param $prompt_settings
|
||||
*
|
||||
* @return mixed|\WP_Error
|
||||
*/
|
||||
public function get_featured_image( $data, $context, $request_ids ) {
|
||||
return $this->ai_request(
|
||||
'POST',
|
||||
'image/text-to-image/featured-image',
|
||||
[
|
||||
self::PROMPT => $data['payload']['prompt'],
|
||||
self::IMAGE_TYPE => $data['payload']['settings'][ self::IMAGE_TYPE ] . '/' . $data['payload']['settings'][ self::STYLE_PRESET ],
|
||||
self::ASPECT_RATIO => $data['payload']['settings'][ self::ASPECT_RATIO ],
|
||||
'context' => wp_json_encode( $context ),
|
||||
'ids' => $request_ids,
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
],
|
||||
false,
|
||||
'',
|
||||
'json'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_image_to_image
|
||||
* @param $image_data
|
||||
*
|
||||
* @return mixed|\WP_Error
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function get_image_to_image( $image_data, $context, $request_ids ) {
|
||||
$image_file = get_attached_file( $image_data['attachment_id'] );
|
||||
|
||||
if ( ! $image_file ) {
|
||||
throw new \Exception( 'Image file not found' );
|
||||
}
|
||||
|
||||
$result = $this->ai_request(
|
||||
'POST',
|
||||
'image/image-to-image',
|
||||
[
|
||||
self::PROMPT => $image_data[ self::PROMPT ],
|
||||
self::IMAGE_TYPE => $image_data['promptSettings'][ self::IMAGE_TYPE ] . '/' . $image_data['promptSettings'][ self::STYLE_PRESET ],
|
||||
self::IMAGE_STRENGTH => $image_data['promptSettings'][ self::IMAGE_STRENGTH ],
|
||||
self::ASPECT_RATIO => $image_data['promptSettings'][ self::ASPECT_RATIO ],
|
||||
'context' => wp_json_encode( $context ),
|
||||
'ids' => $request_ids,
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
],
|
||||
$image_file,
|
||||
'image'
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_image_to_image_upscale
|
||||
* @param $image_data
|
||||
*
|
||||
* @return mixed|\WP_Error
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function get_image_to_image_upscale( $image_data, $context, $request_ids ) {
|
||||
$image_file = get_attached_file( $image_data['attachment_id'] );
|
||||
|
||||
if ( ! $image_file ) {
|
||||
throw new \Exception( 'Image file not found' );
|
||||
}
|
||||
|
||||
$result = $this->ai_request(
|
||||
'POST',
|
||||
'image/image-to-image/upscale',
|
||||
[
|
||||
self::IMAGE_RESOLUTION => $image_data['promptSettings']['upscale_to'],
|
||||
'context' => wp_json_encode( $context ),
|
||||
'ids' => $request_ids,
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
],
|
||||
$image_file,
|
||||
'image'
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_image_to_image_remove_background
|
||||
* @param $image_data
|
||||
*
|
||||
* @return mixed|\WP_Error
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function get_image_to_image_remove_background( $image_data, $context, $request_ids ) {
|
||||
$image_file = get_attached_file( $image_data['attachment_id'] );
|
||||
|
||||
if ( ! $image_file ) {
|
||||
throw new \Exception( 'Image file not found' );
|
||||
}
|
||||
|
||||
$result = $this->ai_request(
|
||||
'POST',
|
||||
'image/image-to-image/remove-background',
|
||||
[
|
||||
'context' => wp_json_encode( $context ),
|
||||
'ids' => $request_ids,
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
],
|
||||
$image_file,
|
||||
'image'
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_image_to_image_remove_text
|
||||
* @param $image_data
|
||||
*
|
||||
* @return mixed|\WP_Error
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function get_image_to_image_replace_background( $image_data, $context, $request_ids ) {
|
||||
$image_file = get_attached_file( $image_data['attachment_id'] );
|
||||
|
||||
if ( ! $image_file ) {
|
||||
throw new \Exception( 'Image file not found' );
|
||||
}
|
||||
|
||||
$result = $this->ai_request(
|
||||
'POST',
|
||||
'image/image-to-image/replace-background',
|
||||
[
|
||||
self::PROMPT => $image_data[ self::PROMPT ],
|
||||
'context' => wp_json_encode( $context ),
|
||||
'ids' => $request_ids,
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
],
|
||||
$image_file,
|
||||
'image'
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* store_temp_file
|
||||
* used to store a temp file for the AI request and deletes it once the request is done
|
||||
* @param $file_content
|
||||
* @param $file_ext
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function store_temp_file( $file_content, $file_ext = '' ) {
|
||||
$temp_file = str_replace( '.tmp', '', wp_tempnam() . $file_ext );
|
||||
file_put_contents( $temp_file, $file_content );
|
||||
// make sure the temp file is deleted on shutdown
|
||||
register_shutdown_function( function () use ( $temp_file ) {
|
||||
if ( file_exists( $temp_file ) ) {
|
||||
unlink( $temp_file );
|
||||
}
|
||||
} );
|
||||
return $temp_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_image_to_image_out_painting
|
||||
* @param $image_data
|
||||
*
|
||||
* @return mixed|\WP_Error
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function get_image_to_image_out_painting( $image_data, $context, $request_ids ) {
|
||||
$img_content = str_replace( ' ', '+', $image_data['mask'] );
|
||||
$img_content = substr( $img_content, strpos( $img_content, ',' ) + 1 );
|
||||
$img_content = base64_decode( $img_content );
|
||||
$mask_file = $this->store_temp_file( $img_content, '.png' );
|
||||
|
||||
if ( ! $mask_file ) {
|
||||
throw new \Exception( 'Expended Image file not found' );
|
||||
}
|
||||
|
||||
$result = $this->ai_request(
|
||||
'POST',
|
||||
'image/image-to-image/outpainting',
|
||||
[
|
||||
'context' => wp_json_encode( $context ),
|
||||
'ids' => $request_ids,
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
'size' => wp_json_encode( $image_data['size'] ),
|
||||
'position' => wp_json_encode( $image_data['position'] ),
|
||||
'image_base64' => $image_data['image_base64'],
|
||||
$image_data['image'],
|
||||
],
|
||||
[
|
||||
[
|
||||
'name' => 'image',
|
||||
'type' => 'image',
|
||||
'path' => $mask_file,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_image_to_image_mask
|
||||
* @param $image_data
|
||||
*
|
||||
* @return mixed|\WP_Error
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function get_image_to_image_mask( $image_data, $context, $request_ids ) {
|
||||
$image_file = get_attached_file( $image_data['attachment_id'] );
|
||||
$mask_file = $this->store_temp_file( $image_data['mask'], '.svg' );
|
||||
|
||||
if ( ! $image_file ) {
|
||||
throw new \Exception( 'Image file not found' );
|
||||
}
|
||||
|
||||
if ( ! $mask_file ) {
|
||||
throw new \Exception( 'Mask file not found' );
|
||||
}
|
||||
|
||||
$result = $this->ai_request(
|
||||
'POST',
|
||||
'image/image-to-image/inpainting',
|
||||
[
|
||||
self::PROMPT => $image_data[ self::PROMPT ],
|
||||
'context' => wp_json_encode( $context ),
|
||||
'ids' => $request_ids,
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
'image_base64' => $image_data['image_base64'],
|
||||
],
|
||||
[
|
||||
[
|
||||
'name' => 'image',
|
||||
'type' => 'image',
|
||||
'path' => $image_file,
|
||||
],
|
||||
[
|
||||
'name' => 'mask_image',
|
||||
'type' => 'image/svg+xml',
|
||||
'path' => $mask_file,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function generate_layout( $data, $context ) {
|
||||
$endpoint = 'generate/layout';
|
||||
|
||||
$body = [
|
||||
'prompt' => $data['prompt'],
|
||||
'variationType' => (int) $data['variationType'],
|
||||
'ids' => $data['ids'],
|
||||
];
|
||||
|
||||
if ( ! empty( $data['prevGeneratedIds'] ) ) {
|
||||
$body['generatedBaseTemplatesIds'] = $data['prevGeneratedIds'];
|
||||
}
|
||||
|
||||
if ( ! empty( $data['attachments'] ) ) {
|
||||
$attachment = $data['attachments'][0];
|
||||
|
||||
switch ( $attachment['type'] ) {
|
||||
case 'json':
|
||||
$endpoint = 'generate/generate-json-variation';
|
||||
|
||||
$body['json'] = [
|
||||
'type' => 'elementor',
|
||||
'elements' => [ $attachment['content'] ],
|
||||
'label' => $attachment['label'],
|
||||
'source' => $attachment['source'],
|
||||
];
|
||||
break;
|
||||
case 'url':
|
||||
$endpoint = 'generate/html-to-elementor';
|
||||
|
||||
$html = wp_json_encode( $attachment['content'] );
|
||||
|
||||
$body['html'] = $html;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$context['currentContext'] = $data['currentContext'];
|
||||
$context['features'] = [
|
||||
'supportedFeatures' => [],
|
||||
];
|
||||
|
||||
if ( ElementorUtils::has_pro() ) {
|
||||
$context['features']['subscriptions'] = [ 'Pro' ];
|
||||
}
|
||||
|
||||
if ( Plugin::$instance->experiments->is_feature_active( 'container_grid' ) ) {
|
||||
$context['features']['supportedFeatures'][] = 'Grid';
|
||||
}
|
||||
|
||||
if ( Plugin::instance()->experiments->get_active_features()['nested-elements'] ) {
|
||||
$context['features']['supportedFeatures'][] = 'Nested';
|
||||
}
|
||||
|
||||
if ( Plugin::instance()->experiments->get_active_features()['taxonomy-filter'] ) {
|
||||
$context['features']['supportedFeatures'][] = 'Taxonomy';
|
||||
}
|
||||
|
||||
if ( Plugin::instance()->experiments->get_active_features()['mega-menu'] ) {
|
||||
$context['features']['supportedFeatures'][] = 'MegaMenu';
|
||||
}
|
||||
|
||||
$metadata = [
|
||||
'context' => $context,
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
'config' => [
|
||||
'generate' => [
|
||||
'all' => true,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$body = array_merge( $body, $metadata );
|
||||
|
||||
// Temp hack for platforms that filters the http_request_args, and it breaks JSON requests.
|
||||
remove_all_filters( 'http_request_args' );
|
||||
|
||||
return $this->ai_request(
|
||||
'POST',
|
||||
$endpoint,
|
||||
$body,
|
||||
false,
|
||||
'',
|
||||
'json'
|
||||
);
|
||||
}
|
||||
|
||||
public function get_layout_prompt_enhanced( $prompt, $enhance_type, $context ) {
|
||||
return $this->ai_request(
|
||||
'POST',
|
||||
'generate/enhance-prompt',
|
||||
[
|
||||
'prompt' => $prompt,
|
||||
'enhance_type' => $enhance_type,
|
||||
'context' => wp_json_encode( $context ),
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
],
|
||||
false,
|
||||
'',
|
||||
'json'
|
||||
);
|
||||
}
|
||||
|
||||
public function get_history_by_type( $type, $page, $limit, $context = [] ) {
|
||||
$endpoint = Module::HISTORY_TYPE_ALL === $type
|
||||
? 'history'
|
||||
: add_query_arg( [
|
||||
'page' => $page,
|
||||
'limit' => $limit,
|
||||
], "history/{$type}" );
|
||||
|
||||
return $this->ai_request(
|
||||
'POST',
|
||||
$endpoint,
|
||||
[
|
||||
'context' => wp_json_encode( $context ),
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function delete_history_item( $id, $context = [] ) {
|
||||
return $this->ai_request(
|
||||
'DELETE', 'history/' . $id,
|
||||
[
|
||||
'context' => wp_json_encode( $context ),
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function toggle_favorite_history_item( $id, $context = [] ) {
|
||||
return $this->ai_request(
|
||||
'POST', sprintf( 'history/%s/favorite', $id ),
|
||||
[
|
||||
'context' => wp_json_encode( $context ),
|
||||
'api_version' => ELEMENTOR_VERSION,
|
||||
'site_lang' => get_bloginfo( 'language' ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
protected function init() {}
|
||||
}
|
||||
1151
wp-content/plugins/elementor/modules/ai/module.php
Normal file
1151
wp-content/plugins/elementor/modules/ai/module.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\Announcements\Classes;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Announcement {
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $raw_data;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $triggers;
|
||||
|
||||
public function __construct( array $data ) {
|
||||
$this->raw_data = $data;
|
||||
$this->set_triggers();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function get_triggers(): array {
|
||||
return $this->triggers;
|
||||
}
|
||||
|
||||
protected function set_triggers() {
|
||||
$triggers = $this->raw_data['triggers'] ?? [];
|
||||
foreach ( $triggers as $trigger ) {
|
||||
$this->triggers[] = Utils::get_trigger_object( $trigger );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* is_active
|
||||
* @return bool
|
||||
*/
|
||||
public function is_active(): bool {
|
||||
$triggers = $this->get_triggers();
|
||||
|
||||
if ( empty( $triggers ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ( $triggers as $trigger ) {
|
||||
if ( ! $trigger->is_active() ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function after_triggered() {
|
||||
foreach ( $this->get_triggers() as $trigger ) {
|
||||
if ( $trigger->is_active() ) {
|
||||
$trigger->after_triggered();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_prepared_data(): array {
|
||||
$raw_data = $this->raw_data;
|
||||
unset( $raw_data['triggers'] );
|
||||
|
||||
return $raw_data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\Announcements\Classes;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
abstract class Trigger_Base {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'trigger-base';
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_name(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function is_active(): bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function after_triggered() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\Announcements\Classes;
|
||||
|
||||
use Elementor\Modules\Announcements\Triggers\{
|
||||
IsFlexContainerInactive, AiStarted
|
||||
};
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Utils {
|
||||
/**
|
||||
* get_trigger_object
|
||||
*
|
||||
* @param $trigger
|
||||
*
|
||||
* @return IsFlexContainerInactive|false
|
||||
*/
|
||||
public static function get_trigger_object( $trigger ) {
|
||||
$object_trigger = apply_filters( 'elementor/announcements/trigger_object', false, $trigger );
|
||||
|
||||
if ( false !== $object_trigger ) {
|
||||
return $object_trigger;
|
||||
}
|
||||
|
||||
//@TODO - replace with trigger manager
|
||||
switch ( $trigger['action'] ) {
|
||||
case 'isFlexContainerInactive':
|
||||
return new IsFlexContainerInactive();
|
||||
case 'aiStared':
|
||||
return new AiStarted();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
177
wp-content/plugins/elementor/modules/announcements/module.php
Normal file
177
wp-content/plugins/elementor/modules/announcements/module.php
Normal file
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\Announcements;
|
||||
|
||||
use Elementor\Core\Base\App as BaseApp;
|
||||
use Elementor\Modules\Announcements\Classes\Announcement;
|
||||
use Elementor\Settings as ElementorSettings;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Module extends BaseApp {
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_active(): bool {
|
||||
return is_admin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_name(): string {
|
||||
return 'announcements';
|
||||
}
|
||||
|
||||
/**
|
||||
* Render wrapper for the app to load.
|
||||
*/
|
||||
private function render_app_wrapper() {
|
||||
?>
|
||||
<div id="e-announcements-root"></div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue app scripts.
|
||||
*/
|
||||
private function enqueue_scripts() {
|
||||
wp_enqueue_script(
|
||||
'announcements-app',
|
||||
$this->get_js_assets_url( 'announcements-app' ),
|
||||
[
|
||||
'wp-i18n',
|
||||
],
|
||||
ELEMENTOR_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
wp_set_script_translations( 'announcements-app', 'elementor' );
|
||||
|
||||
$this->print_config( 'announcements-app' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get initialization settings to use in frontend.
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
protected function get_init_settings(): array {
|
||||
$active_announcements = $this->get_active_announcements();
|
||||
$additional_settings = [];
|
||||
|
||||
foreach ( $active_announcements as $announcement ) {
|
||||
$additional_settings[] = $announcement->get_prepared_data();
|
||||
//@TODO - replace with ajax request from the front after actually triggered
|
||||
$announcement->after_triggered();
|
||||
}
|
||||
|
||||
return [
|
||||
'announcements' => $additional_settings,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the module styles.
|
||||
*/
|
||||
public function enqueue_styles() {
|
||||
wp_enqueue_style(
|
||||
'announcements-app',
|
||||
$this->get_css_assets_url( 'modules/announcements/announcements' ),
|
||||
[],
|
||||
ELEMENTOR_VERSION
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all announcement in raw format ( array ).
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
private function get_raw_announcements(): array {
|
||||
$raw_announcements = [
|
||||
[
|
||||
'title' => __( 'Discover your new superpowers ', 'elementor' ),
|
||||
'description' => __( '<p>With AI for text, code, image generation and editing, you can bring your vision to life faster than ever. Start your free trial now - <b>no credit card required!</b></p>', 'elementor' ),
|
||||
'media' => [
|
||||
'type' => 'image',
|
||||
'src' => ELEMENTOR_ASSETS_URL . 'images/announcement.png?' . ELEMENTOR_VERSION,
|
||||
],
|
||||
'cta' => [
|
||||
[
|
||||
'label' => __( 'Let\'s do it', 'elementor' ),
|
||||
'variant' => 'primary',
|
||||
'target' => '_top',
|
||||
'url' => '#welcome-ai',
|
||||
],
|
||||
[
|
||||
'label' => __( 'Skip', 'elementor' ),
|
||||
'variant' => 'secondary',
|
||||
],
|
||||
],
|
||||
'triggers' => [
|
||||
[
|
||||
'action' => 'aiStared',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// DO NOT USE THIS FILTER
|
||||
return apply_filters( 'elementor/announcements/raw_announcements', $raw_announcements );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all announcement objects.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_announcements(): array {
|
||||
$announcements = [];
|
||||
foreach ( $this->get_raw_announcements() as $announcement_data ) {
|
||||
$announcements[] = new Announcement( $announcement_data );
|
||||
}
|
||||
|
||||
return $announcements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all active announcement objects.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_active_announcements(): array {
|
||||
$active_announcements = [];
|
||||
foreach ( $this->get_announcements() as $announcement ) {
|
||||
if ( $announcement->is_active() ) {
|
||||
$active_announcements[] = $announcement;
|
||||
}
|
||||
}
|
||||
|
||||
return $active_announcements;
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_action( 'elementor/init', [ $this, 'on_elementor_init' ] );
|
||||
}
|
||||
|
||||
public function on_elementor_init() {
|
||||
if ( empty( $this->get_active_announcements() ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action( 'elementor/editor/footer', function () {
|
||||
$this->render_app_wrapper();
|
||||
} );
|
||||
|
||||
add_action( 'elementor/editor/after_enqueue_scripts', function () {
|
||||
$this->enqueue_scripts();
|
||||
$this->enqueue_styles();
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\Announcements\Triggers;
|
||||
|
||||
use Elementor\Modules\Announcements\Classes\Trigger_Base;
|
||||
use Elementor\User;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class AiStarted extends Trigger_Base {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'ai-get-started-announcement';
|
||||
|
||||
public function after_triggered() {
|
||||
User::set_introduction_viewed( [ 'introductionKey' => $this->name ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function is_active(): bool {
|
||||
return ! User::get_introduction_meta( 'ai_get_started' ) && ! User::get_introduction_meta( $this->name );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\Announcements\Triggers;
|
||||
|
||||
use Elementor\Modules\Announcements\Classes\Trigger_Base;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class IsFlexContainerInactive extends Trigger_Base {
|
||||
|
||||
const USER_META_KEY = 'announcements_user_counter';
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'is-flex-container-inactive';
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function get_view_count(): int {
|
||||
$user_counter = $this->get_user_announcement_count();
|
||||
|
||||
return ! empty( $user_counter ) ? (int) $user_counter : 0;
|
||||
}
|
||||
|
||||
public function after_triggered() {
|
||||
$new_counter = $this->get_view_count() + 1;
|
||||
update_user_meta( get_current_user_id(), self::USER_META_KEY, $new_counter );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function is_active(): bool {
|
||||
$is_feature_active = Plugin::$instance->experiments->is_feature_active( 'container' );
|
||||
$counter = $this->get_user_announcement_count();
|
||||
|
||||
return ! $is_feature_active && (int) $counter < 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function get_user_announcement_count(): string {
|
||||
return get_user_meta( get_current_user_id(), self::USER_META_KEY, true );
|
||||
}
|
||||
}
|
||||
191
wp-content/plugins/elementor/modules/apps/admin-apps-page.php
Normal file
191
wp-content/plugins/elementor/modules/apps/admin-apps-page.php
Normal file
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Apps;
|
||||
|
||||
use Elementor\Core\Isolation\Wordpress_Adapter;
|
||||
use Elementor\Core\Isolation\Plugin_Status_Adapter;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Admin_Apps_Page {
|
||||
|
||||
const APPS_URL = 'https://assets.elementor.com/apps/v1/apps.json';
|
||||
|
||||
private static ?Wordpress_Adapter $wordpress_adapter = null;
|
||||
|
||||
private static ?Plugin_Status_Adapter $plugin_status_adapter = null;
|
||||
|
||||
public static function render() {
|
||||
?>
|
||||
<div class="wrap e-a-apps">
|
||||
|
||||
<div class="e-a-page-title">
|
||||
<h2><?php echo esc_html__( 'Popular Add-ons, New Possibilities.', 'elementor' ); ?></h2>
|
||||
<p><?php echo esc_html__( 'Boost your web-creation process with add-ons, plugins, and more tools specially selected to unleash your creativity, increase productivity, and enhance your Elementor-powered website.', 'elementor' ); ?>*<br>
|
||||
<a href="https://go.elementor.com/wp-dash-apps-about-apps-page/" target="_blank"><?php echo esc_html__( 'Learn more about this page.', 'elementor' ); ?></a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="e-a-list">
|
||||
<?php self::render_plugins_list(); ?>
|
||||
</div>
|
||||
<div class="e-a-page-footer">
|
||||
<p>*<?php echo esc_html__( 'Please note that certain tools and services on this page are developed by third-party companies and are not part of Elementor\'s suite of products or support. Before using them, we recommend independently evaluating them. Additionally, when clicking on their action buttons, you may be redirected to an external website.', 'elementor' ); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
private static function render_plugins_list() {
|
||||
$plugins = self::get_plugins();
|
||||
|
||||
foreach ( $plugins as $plugin ) {
|
||||
self::render_plugin_item( $plugin );
|
||||
}
|
||||
}
|
||||
|
||||
private static function get_plugins() : array {
|
||||
if ( ! self::$wordpress_adapter ) {
|
||||
self::$wordpress_adapter = new Wordpress_Adapter();
|
||||
}
|
||||
|
||||
if ( ! self::$plugin_status_adapter ) {
|
||||
self::$plugin_status_adapter = new Plugin_Status_Adapter( self::$wordpress_adapter );
|
||||
}
|
||||
|
||||
$apps = static::get_remote_apps();
|
||||
|
||||
return static::filter_apps( $apps );
|
||||
}
|
||||
|
||||
private static function get_remote_apps() {
|
||||
$apps = wp_remote_get( static::APPS_URL );
|
||||
|
||||
if ( is_wp_error( $apps ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$apps = json_decode( wp_remote_retrieve_body( $apps ), true );
|
||||
|
||||
if ( empty( $apps['apps'] ) || ! is_array( $apps['apps'] ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $apps['apps'];
|
||||
}
|
||||
|
||||
private static function filter_apps( $apps ) {
|
||||
$filtered_apps = [];
|
||||
|
||||
foreach ( $apps as $app ) {
|
||||
if ( static::is_wporg_app( $app ) ) {
|
||||
$app = static::filter_wporg_app( $app );
|
||||
}
|
||||
|
||||
if ( static::is_ecom_app( $app ) ) {
|
||||
$app = static::filter_ecom_app( $app );
|
||||
}
|
||||
|
||||
if ( empty( $app ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filtered_apps[] = $app;
|
||||
}
|
||||
|
||||
return $filtered_apps;
|
||||
}
|
||||
|
||||
private static function is_wporg_app( $app ) {
|
||||
return isset( $app['type'] ) && 'wporg' === $app['type'];
|
||||
}
|
||||
|
||||
private static function filter_wporg_app( $app ) {
|
||||
if ( self::$wordpress_adapter->is_plugin_active( $app['file_path'] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( self::$plugin_status_adapter->is_plugin_installed( $app['file_path'] ) ) {
|
||||
if ( current_user_can( 'activate_plugins' ) ) {
|
||||
$app['action_label'] = esc_html__( 'Activate', 'elementor' );
|
||||
$app['action_url'] = self::$plugin_status_adapter->get_activate_plugin_url( $app['file_path'] );
|
||||
} else {
|
||||
$app['action_label'] = esc_html__( 'Cannot Activate', 'elementor' );
|
||||
$app['action_url'] = '#';
|
||||
}
|
||||
} else {
|
||||
if ( current_user_can( 'install_plugins' ) ) {
|
||||
$app['action_label'] = esc_html__( 'Install', 'elementor' );
|
||||
$app['action_url'] = self::$plugin_status_adapter->get_install_plugin_url( $app['file_path'] );
|
||||
} else {
|
||||
$app['action_label'] = esc_html__( 'Cannot Install', 'elementor' );
|
||||
$app['action_url'] = '#';
|
||||
}
|
||||
}
|
||||
|
||||
return $app;
|
||||
}
|
||||
|
||||
private static function is_ecom_app( $app ) {
|
||||
return isset( $app['type'] ) && 'ecom' === $app['type'];
|
||||
}
|
||||
|
||||
private static function filter_ecom_app( $app ) {
|
||||
if ( self::$wordpress_adapter->is_plugin_active( $app['file_path'] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( ! self::$plugin_status_adapter->is_plugin_installed( $app['file_path'] ) ) {
|
||||
return $app;
|
||||
}
|
||||
|
||||
if ( current_user_can( 'activate_plugins' ) ) {
|
||||
$app['action_label'] = esc_html__( 'Activate', 'elementor' );
|
||||
$app['action_url'] = self::$plugin_status_adapter->get_activate_plugin_url( $app['file_path'] );
|
||||
} else {
|
||||
$app['action_label'] = esc_html__( 'Cannot Activate', 'elementor' );
|
||||
$app['action_url'] = '#';
|
||||
}
|
||||
|
||||
$app['target'] = '_self';
|
||||
|
||||
return $app;
|
||||
}
|
||||
|
||||
private static function get_images_url() {
|
||||
return ELEMENTOR_URL . 'modules/apps/images/';
|
||||
}
|
||||
|
||||
private static function is_elementor_pro_installed() {
|
||||
return defined( 'ELEMENTOR_PRO_VERSION' );
|
||||
}
|
||||
|
||||
private static function render_plugin_item( $plugin ) {
|
||||
?>
|
||||
<div class="e-a-item"<?php echo ! empty( $plugin['file_path'] ) ? ' data-plugin="' . esc_attr( $plugin['file_path'] ) . '"' : ''; ?>>
|
||||
<div class="e-a-heading">
|
||||
<img class="e-a-img" src="<?php echo esc_url( $plugin['image'] ); ?>" alt="<?php echo esc_attr( $plugin['name'] ); ?>">
|
||||
<?php if ( ! empty( $plugin['badge'] ) ) : ?>
|
||||
<span class="e-a-badge"><?php echo esc_html( $plugin['badge'] ); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<h3 class="e-a-title"><?php echo esc_html( $plugin['name'] ); ?></h3>
|
||||
<p class="e-a-author"><?php esc_html_e( 'By', 'elementor' ); ?> <a href="<?php echo esc_url( $plugin['author_url'] ); ?>" target="_blank"><?php echo esc_html( $plugin['author'] ); ?></a></p>
|
||||
<div class="e-a-desc">
|
||||
<p><?php echo esc_html( $plugin['description'] ); ?></p>
|
||||
<?php if ( ! empty( $plugin['offering'] ) ) : ?>
|
||||
<p class="e-a-offering"><?php echo esc_html( $plugin['offering'] ); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<p class="e-a-actions">
|
||||
<?php if ( ! empty( $plugin['learn_more_url'] ) ) : ?>
|
||||
<a class="e-a-learn-more" href="<?php echo esc_url( $plugin['learn_more_url'] ); ?>" target="_blank"><?php echo esc_html__( 'Learn More', 'elementor' ); ?></a>
|
||||
<?php endif; ?>
|
||||
<a href="<?php echo esc_url( $plugin['action_url'] ); ?>" class="e-btn e-accent" target="<?php echo isset( $plugin['target'] ) ? esc_attr( $plugin['target'] ) : '_blank'; ?>"><?php echo esc_html( $plugin['action_label'] ); ?></a>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Apps;
|
||||
|
||||
use Elementor\Core\Admin\Menu\Interfaces\Admin_Menu_Item_With_Page;
|
||||
use Elementor\Settings;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Admin_Menu_Apps implements Admin_Menu_Item_With_Page {
|
||||
|
||||
public function is_visible() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_parent_slug() {
|
||||
return Settings::PAGE_ID;
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Add-ons', 'elementor' );
|
||||
}
|
||||
|
||||
public function get_page_title() {
|
||||
return esc_html__( 'Add-ons', 'elementor' );
|
||||
}
|
||||
|
||||
public function get_capability() {
|
||||
return 'manage_options';
|
||||
}
|
||||
|
||||
public function render() {
|
||||
Admin_Apps_Page::render();
|
||||
}
|
||||
}
|
||||
67
wp-content/plugins/elementor/modules/apps/admin-pointer.php
Normal file
67
wp-content/plugins/elementor/modules/apps/admin-pointer.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Apps;
|
||||
|
||||
use Elementor\Core\Upgrade\Manager as Upgrade_Manager;
|
||||
use Elementor\User;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Admin_Pointer {
|
||||
|
||||
const RELEASE_VERSION = '3.15.0';
|
||||
|
||||
const CURRENT_POINTER_SLUG = 'e-apps';
|
||||
|
||||
public static function add_hooks() {
|
||||
add_action( 'admin_print_footer_scripts-index.php', [ __CLASS__, 'admin_print_script' ] );
|
||||
}
|
||||
|
||||
public static function admin_print_script() {
|
||||
if ( static::is_dismissed() || static::is_new_installation() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_script( 'wp-pointer' );
|
||||
wp_enqueue_style( 'wp-pointer' );
|
||||
|
||||
$pointer_content = '<h3>' . esc_html__( 'New! Popular Add-ons', 'elementor' ) . '</h3>';
|
||||
$pointer_content .= '<p>' . esc_html__( 'Discover our collection of plugins and add-ons carefully selected to enhance your Elementor website and unleash your creativity.', 'elementor' ) . '</p>';
|
||||
|
||||
$pointer_content .= sprintf(
|
||||
'<p><a class="button button-primary" href="%s">%s</a></p>',
|
||||
admin_url( 'admin.php?page=' . Module::PAGE_ID ),
|
||||
esc_html__( 'Explore Add-ons', 'elementor' )
|
||||
)
|
||||
|
||||
?>
|
||||
<script>
|
||||
jQuery( document ).ready( function( $ ) {
|
||||
$( '#toplevel_page_elementor' ).pointer( {
|
||||
content: '<?php echo $pointer_content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>',
|
||||
position: {
|
||||
edge: <?php echo is_rtl() ? "'right'" : "'left'"; ?>,
|
||||
align: 'center'
|
||||
},
|
||||
close: function() {
|
||||
elementorCommon.ajax.addRequest( 'introduction_viewed', {
|
||||
data: {
|
||||
introductionKey: '<?php echo esc_attr( static::CURRENT_POINTER_SLUG ); ?>',
|
||||
},
|
||||
} );
|
||||
}
|
||||
} ).pointer( 'open' );
|
||||
} );
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
private static function is_dismissed() {
|
||||
return User::get_introduction_meta( static::CURRENT_POINTER_SLUG );
|
||||
}
|
||||
|
||||
private static function is_new_installation() {
|
||||
return Upgrade_Manager::install_compare( static::RELEASE_VERSION, '>=' );
|
||||
}
|
||||
}
|
||||
109
wp-content/plugins/elementor/modules/apps/module.php
Normal file
109
wp-content/plugins/elementor/modules/apps/module.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Apps;
|
||||
|
||||
use Elementor\Core\Admin\Menu\Admin_Menu_Manager;
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Settings;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
const PAGE_ID = 'elementor-apps';
|
||||
|
||||
public function get_name() {
|
||||
return 'apps';
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
Admin_Pointer::add_hooks();
|
||||
|
||||
add_action( 'elementor/admin/menu/register', function( Admin_Menu_Manager $admin_menu ) {
|
||||
$admin_menu->register( static::PAGE_ID, new Admin_Menu_Apps() );
|
||||
}, 115 );
|
||||
|
||||
add_action( 'elementor/admin/menu/after_register', function ( Admin_Menu_Manager $admin_menu, array $hooks ) {
|
||||
if ( ! empty( $hooks[ static::PAGE_ID ] ) ) {
|
||||
add_action( "admin_print_scripts-{$hooks[ static::PAGE_ID ]}", [ $this, 'enqueue_assets' ] );
|
||||
}
|
||||
}, 10, 2 );
|
||||
|
||||
add_filter( 'elementor/finder/categories', function( array $categories ) {
|
||||
$categories['site']['items']['apps'] = [
|
||||
'title' => esc_html__( 'Add-ons', 'elementor' ),
|
||||
'url' => admin_url( 'admin.php?page=' . static::PAGE_ID ),
|
||||
'icon' => 'apps',
|
||||
'keywords' => [ 'apps', 'addon', 'plugin', 'extension', 'integration' ],
|
||||
];
|
||||
|
||||
return $categories;
|
||||
} );
|
||||
|
||||
// Add the Elementor Apps link to the plugin install action links.
|
||||
add_filter( 'install_plugins_tabs', [ $this, 'add_elementor_plugin_install_action_link' ] );
|
||||
add_action( 'install_plugins_pre_elementor', [ $this, 'maybe_open_elementor_tab' ] );
|
||||
add_action( 'admin_print_styles-plugin-install.php', [ $this, 'add_plugins_page_styles' ] );
|
||||
}
|
||||
|
||||
public function enqueue_assets() {
|
||||
add_filter( 'admin_body_class', [ $this, 'body_status_classes' ] );
|
||||
|
||||
wp_enqueue_style(
|
||||
'elementor-apps',
|
||||
$this->get_css_assets_url( 'modules/apps/admin' ),
|
||||
[],
|
||||
ELEMENTOR_VERSION
|
||||
);
|
||||
}
|
||||
|
||||
public function body_status_classes( $admin_body_classes ) {
|
||||
$admin_body_classes .= ' elementor-apps-page';
|
||||
|
||||
return $admin_body_classes;
|
||||
}
|
||||
|
||||
public function add_elementor_plugin_install_action_link( $tabs ) {
|
||||
$tabs['elementor'] = esc_html__( 'For Elementor', 'elementor' );
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
public function maybe_open_elementor_tab() {
|
||||
if ( ! isset( $_GET['tab'] ) || 'elementor' !== $_GET['tab'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$elementor_url = add_query_arg( [
|
||||
'page' => static::PAGE_ID,
|
||||
'tab' => 'elementor',
|
||||
'ref' => 'plugins',
|
||||
], admin_url( 'admin.php' ) );
|
||||
|
||||
wp_safe_redirect( $elementor_url );
|
||||
exit;
|
||||
}
|
||||
|
||||
public function add_plugins_page_styles() {
|
||||
?>
|
||||
<style>
|
||||
.plugin-install-elementor > a::after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8.33321 3H12.9999V7.66667H11.9999V4.70711L8.02009 8.68689L7.31299 7.97978L11.2928 4H8.33321V3Z' fill='%23646970'/%3E%3Cpath d='M6.33333 4.1665H4.33333C3.8731 4.1665 3.5 4.5396 3.5 4.99984V11.6665C3.5 12.1267 3.8731 12.4998 4.33333 12.4998H11C11.4602 12.4998 11.8333 12.1267 11.8333 11.6665V9.6665' stroke='%23646970'/%3E%3C/svg%3E%0A");
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-repeat: no-repeat;
|
||||
vertical-align: text-top;
|
||||
margin-left: 2px;
|
||||
}
|
||||
.plugin-install-elementor:hover > a::after {
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8.33321 3H12.9999V7.66667H11.9999V4.70711L8.02009 8.68689L7.31299 7.97978L11.2928 4H8.33321V3Z' fill='%23135E96'/%3E%3Cpath d='M6.33333 4.1665H4.33333C3.8731 4.1665 3.5 4.5396 3.5 4.99984V11.6665C3.5 12.1267 3.8731 12.4998 4.33333 12.4998H11C11.4602 12.4998 11.8333 12.1267 11.8333 11.6665V9.6665' stroke='%23135E96'/%3E%3C/svg%3E%0A");
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\CompatibilityTag;
|
||||
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Core\Utils\Version;
|
||||
use Elementor\Core\Utils\Collection;
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Modules\System_Info\Module as System_Info;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
abstract class Base_Module extends BaseModule {
|
||||
const MODULE_NAME = 'compatibility-tag';
|
||||
|
||||
/**
|
||||
* @var Compatibility_Tag
|
||||
*/
|
||||
private $compatibility_tag_service;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return static::MODULE_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Compatibility_Tag
|
||||
*/
|
||||
private function get_compatibility_tag_service() {
|
||||
if ( ! $this->compatibility_tag_service ) {
|
||||
$this->compatibility_tag_service = new Compatibility_Tag( $this->get_plugin_header() );
|
||||
}
|
||||
|
||||
return $this->compatibility_tag_service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add allowed headers to plugins.
|
||||
*
|
||||
* @param array $headers
|
||||
* @param $compatibility_tag_header
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function enable_elementor_headers( array $headers, $compatibility_tag_header ) {
|
||||
$headers[] = $compatibility_tag_header;
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
protected function get_plugins_to_check() {
|
||||
return $this->get_plugins_with_header();
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a compatibility message to the update plugin warning.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function on_plugin_update_message( array $args ) {
|
||||
$new_version = Version::create_from_string( $args['new_version'] );
|
||||
|
||||
if ( $new_version->compare( '=', $args['Version'], Version::PART_MAJOR_2 ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$plugins = $this->get_plugins_to_check();
|
||||
$plugins_compatibility = $this->get_compatibility_tag_service()->check( $new_version, $plugins->keys() );
|
||||
|
||||
$plugins = $plugins->filter( function ( $data, $plugin_name ) use ( $plugins_compatibility ) {
|
||||
return Compatibility_Tag::COMPATIBLE !== $plugins_compatibility[ $plugin_name ];
|
||||
} );
|
||||
|
||||
if ( $plugins->is_empty() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
include __DIR__ . '/views/plugin-update-message-compatibility.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all plugins with specific header.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private function get_plugins_with_header() {
|
||||
return Plugin::$instance->wp
|
||||
->get_plugins()
|
||||
->filter( function ( array $plugin ) {
|
||||
return ! empty( $plugin[ $this->get_plugin_header() ] );
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function get_plugin_header();
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function get_plugin_label();
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function get_plugin_name();
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function get_plugin_version();
|
||||
|
||||
/**
|
||||
* Base_Module constructor.
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct() {
|
||||
add_filter( 'extra_plugin_headers', function ( array $headers ) {
|
||||
return $this->enable_elementor_headers( $headers, $this->get_plugin_header() );
|
||||
} );
|
||||
|
||||
add_action( 'in_plugin_update_message-' . $this->get_plugin_name(), function ( array $args ) {
|
||||
$this->on_plugin_update_message( $args );
|
||||
}, 11 /* After the warning message for backup */ );
|
||||
|
||||
add_action( 'elementor/system_info/get_allowed_reports', function () {
|
||||
$plugin_short_name = basename( $this->get_plugin_name(), '.php' );
|
||||
|
||||
System_Info::add_report(
|
||||
"{$plugin_short_name}_compatibility",
|
||||
[
|
||||
'file_name' => __DIR__ . '/compatibility-tag-report.php',
|
||||
'class_name' => __NAMESPACE__ . '\Compatibility_Tag_Report',
|
||||
'fields' => [
|
||||
'compatibility_tag_service' => $this->get_compatibility_tag_service(),
|
||||
'plugin_label' => $this->get_plugin_label(),
|
||||
'plugin_version' => Version::create_from_string( $this->get_plugin_version() ),
|
||||
'plugins_to_check' => $this->get_plugins_to_check()
|
||||
->only( get_option( 'active_plugins' ) )
|
||||
->keys(),
|
||||
],
|
||||
]
|
||||
);
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\CompatibilityTag;
|
||||
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Core\Utils\Version;
|
||||
use Elementor\Core\Utils\Collection;
|
||||
use Elementor\Modules\System_Info\Reporters\Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Compatibility_Tag_Report extends Base {
|
||||
/**
|
||||
* @var Compatibility_Tag
|
||||
*/
|
||||
protected $compatibility_tag_service;
|
||||
|
||||
/**
|
||||
* @var Version
|
||||
*/
|
||||
protected $plugin_version;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $plugin_label;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $plugins_to_check;
|
||||
|
||||
/**
|
||||
* Compatibility_Tag_Report constructor.
|
||||
*
|
||||
* @param $properties
|
||||
*/
|
||||
public function __construct( $properties ) {
|
||||
parent::__construct( $properties );
|
||||
|
||||
$this->compatibility_tag_service = $this->_properties['fields']['compatibility_tag_service'];
|
||||
$this->plugin_label = $this->_properties['fields']['plugin_label'];
|
||||
$this->plugin_version = $this->_properties['fields']['plugin_version'];
|
||||
$this->plugins_to_check = $this->_properties['fields']['plugins_to_check'];
|
||||
}
|
||||
|
||||
/**
|
||||
* The title of the report
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_title() {
|
||||
return $this->plugin_label . ' - Compatibility Tag';
|
||||
}
|
||||
|
||||
/**
|
||||
* Report fields
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_fields() {
|
||||
return [
|
||||
'report_data' => '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Report data.
|
||||
*
|
||||
* @return string[]
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function get_report_data() {
|
||||
$compatibility_status = $this->compatibility_tag_service->check(
|
||||
$this->plugin_version,
|
||||
$this->plugins_to_check
|
||||
);
|
||||
|
||||
return [
|
||||
'value' => $compatibility_status,
|
||||
];
|
||||
}
|
||||
|
||||
public function get_html_report_data() {
|
||||
$compatibility_status = $this->compatibility_tag_service->check(
|
||||
$this->plugin_version,
|
||||
$this->plugins_to_check
|
||||
);
|
||||
|
||||
$compatibility_status = $this->get_html_from_compatibility_status( $compatibility_status );
|
||||
|
||||
return [
|
||||
'value' => $compatibility_status,
|
||||
];
|
||||
}
|
||||
|
||||
public function get_raw_report_data() {
|
||||
$compatibility_status = $this->compatibility_tag_service->check(
|
||||
$this->plugin_version,
|
||||
$this->plugins_to_check
|
||||
);
|
||||
|
||||
$compatibility_status = $this->get_raw_from_compatibility_status( $compatibility_status );
|
||||
|
||||
return [
|
||||
'value' => $compatibility_status,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge compatibility status with the plugins data.
|
||||
*
|
||||
* @param array $compatibility_status
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private function merge_compatibility_status_with_plugins( array $compatibility_status ) {
|
||||
$labels = $this->get_report_labels();
|
||||
|
||||
$compatibility_status = ( new Collection( $compatibility_status ) )
|
||||
->map( function ( $value ) use ( $labels ) {
|
||||
$status = isset( $labels[ $value ] ) ? $labels[ $value ] : esc_html__( 'Unknown', 'elementor' );
|
||||
|
||||
return [ 'compatibility_status' => $status ];
|
||||
} );
|
||||
|
||||
return Plugin::$instance->wp
|
||||
->get_plugins()
|
||||
->only( $compatibility_status->keys() )
|
||||
->merge_recursive( $compatibility_status );
|
||||
}
|
||||
|
||||
/**
|
||||
* Format compatibility status into HTML.
|
||||
*
|
||||
* @param array $compatibility_status
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_html_from_compatibility_status( array $compatibility_status ) {
|
||||
return $this->merge_compatibility_status_with_plugins( $compatibility_status )
|
||||
->map( function ( array $plugin ) {
|
||||
return "<tr><td> {$plugin['Name']} </td><td> {$plugin['compatibility_status']} </td></tr>";
|
||||
} )
|
||||
->implode( '' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Format compatibility status into raw string.
|
||||
*
|
||||
* @param array $compatibility_status
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_raw_from_compatibility_status( array $compatibility_status ) {
|
||||
return PHP_EOL . $this->merge_compatibility_status_with_plugins( $compatibility_status )
|
||||
->map( function ( array $plugin ) {
|
||||
return "\t{$plugin['Name']}: {$plugin['compatibility_status']}";
|
||||
} )
|
||||
->implode( PHP_EOL );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function get_report_labels() {
|
||||
return [
|
||||
Compatibility_Tag::COMPATIBLE => esc_html__( 'Compatible', 'elementor' ),
|
||||
Compatibility_Tag::INCOMPATIBLE => esc_html__( 'Incompatible', 'elementor' ),
|
||||
Compatibility_Tag::HEADER_NOT_EXISTS => esc_html__( 'Compatibility not specified', 'elementor' ),
|
||||
Compatibility_Tag::INVALID_VERSION => esc_html__( 'Compatibility unknown', 'elementor' ),
|
||||
Compatibility_Tag::PLUGIN_NOT_EXISTS => esc_html__( 'Error', 'elementor' ),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\CompatibilityTag;
|
||||
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Core\Utils\Version;
|
||||
use Elementor\Core\Base\Base_Object;
|
||||
use Elementor\Core\Utils\Collection;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Compatibility_Tag extends Base_Object {
|
||||
const PLUGIN_NOT_EXISTS = 'plugin_not_exists';
|
||||
const HEADER_NOT_EXISTS = 'header_not_exists';
|
||||
const INVALID_VERSION = 'invalid_version';
|
||||
const INCOMPATIBLE = 'incompatible';
|
||||
const COMPATIBLE = 'compatible';
|
||||
|
||||
/**
|
||||
* @var string Holds the header that should be checked.
|
||||
*/
|
||||
private $header;
|
||||
|
||||
/**
|
||||
* Compatibility_Tag constructor.
|
||||
*
|
||||
* @param string $header
|
||||
*/
|
||||
public function __construct( $header ) {
|
||||
$this->header = $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if plugins is compatible or not.
|
||||
*
|
||||
* @param Version $version
|
||||
* @param array $plugins_names
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function check( Version $version, array $plugins_names ) {
|
||||
return ( new Collection( $plugins_names ) )
|
||||
->map_with_keys( function ( $plugin_name ) use ( $version ) {
|
||||
return [ $plugin_name => $this->is_compatible( $version, $plugin_name ) ];
|
||||
} )
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check single plugin if is compatible or not.
|
||||
*
|
||||
* @param Version $version
|
||||
* @param $plugin_name
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function is_compatible( Version $version, $plugin_name ) {
|
||||
$plugins = Plugin::$instance->wp->get_plugins();
|
||||
|
||||
if ( ! isset( $plugins[ $plugin_name ] ) ) {
|
||||
return self::PLUGIN_NOT_EXISTS;
|
||||
}
|
||||
|
||||
$requested_plugin = $plugins[ $plugin_name ];
|
||||
|
||||
if ( empty( $requested_plugin[ $this->header ] ) ) {
|
||||
return self::HEADER_NOT_EXISTS;
|
||||
}
|
||||
|
||||
if ( ! Version::is_valid_version( $requested_plugin[ $this->header ] ) ) {
|
||||
return self::INVALID_VERSION;
|
||||
}
|
||||
|
||||
if ( $version->compare( '>', $requested_plugin[ $this->header ], Version::PART_MAJOR_2 ) ) {
|
||||
return self::INCOMPATIBLE;
|
||||
}
|
||||
|
||||
return self::COMPATIBLE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\CompatibilityTag;
|
||||
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Core\Utils\Version;
|
||||
use Elementor\Core\Utils\Collection;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspired By WooCommerce.
|
||||
*
|
||||
* @link https://github.com/woocommerce/woocommerce/blob/master/includes/admin/plugin-updates/class-wc-plugin-updates.php
|
||||
*/
|
||||
class Module extends Base_Module {
|
||||
/**
|
||||
* This is the header used by extensions to show testing.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PLUGIN_VERSION_TESTED_HEADER = 'Elementor tested up to';
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function get_plugin_header() {
|
||||
return static::PLUGIN_VERSION_TESTED_HEADER;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function get_plugin_label() {
|
||||
return esc_html__( 'Elementor', 'elementor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function get_plugin_name() {
|
||||
return ELEMENTOR_PLUGIN_BASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function get_plugin_version() {
|
||||
return ELEMENTOR_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
protected function get_plugins_to_check() {
|
||||
return parent::get_plugins_to_check()
|
||||
->merge( $this->get_plugins_with_plugin_title_in_their_name() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the plugins that has the name of the current plugin in their name.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private function get_plugins_with_plugin_title_in_their_name() {
|
||||
return Plugin::$instance->wp
|
||||
->get_plugins()
|
||||
->except( [
|
||||
'elementor/elementor.php',
|
||||
'elementor-beta/elementor-beta.php',
|
||||
'block-builder/block-builder.php',
|
||||
] )
|
||||
->filter( function ( array $data ) {
|
||||
return false !== strpos( strtolower( $data['Name'] ), 'elementor' );
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
use Elementor\Core\Utils\Version;
|
||||
use Elementor\Core\Utils\Collection;
|
||||
use Elementor\Modules\CompatibilityTag\Base_Module;
|
||||
use Elementor\Modules\CompatibilityTag\Compatibility_Tag;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Those variables were declared in 'in_plugin_update_message' method that included the current view file.
|
||||
*
|
||||
* @var Base_Module $this
|
||||
* @var Version $new_version
|
||||
* @var Collection $plugins
|
||||
* @var array $plugins_compatibility
|
||||
*/
|
||||
?>
|
||||
<hr class="e-major-update-warning__separator" />
|
||||
<div class="e-major-update-warning">
|
||||
<div class="e-major-update-warning__icon">
|
||||
<i class="eicon-info-circle"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="e-major-update-warning__message">
|
||||
<strong>
|
||||
<?php echo esc_html__( 'Compatibility Alert', 'elementor' ); ?>
|
||||
</strong> -
|
||||
<?php
|
||||
echo sprintf(
|
||||
/* translators: 1: Plugin name, 2: Plugin version. */
|
||||
esc_html__( 'Some of the plugins you’re using have not been tested with the latest version of %1$s (%2$s). To avoid issues, make sure they are all up to date and compatible before updating %1$s.', 'elementor' ),
|
||||
esc_html( $this->get_plugin_label() ),
|
||||
$new_version->__toString() // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<br />
|
||||
<table class="e-compatibility-update-table">
|
||||
<tr>
|
||||
<th><?php echo esc_html__( 'Plugin', 'elementor' ); ?></th>
|
||||
<th><?php
|
||||
/* translators: %s: Elementor plugin name. */
|
||||
echo sprintf( esc_html__( 'Tested up to %s version', 'elementor' ), esc_html( $this->get_plugin_label() ) );
|
||||
?></th>
|
||||
</tr>
|
||||
<?php foreach ( $plugins as $plugin_name => $plugin_data ) : ?>
|
||||
<?php
|
||||
if (
|
||||
in_array( $plugins_compatibility[ $plugin_name ], [
|
||||
Compatibility_Tag::PLUGIN_NOT_EXISTS,
|
||||
Compatibility_Tag::HEADER_NOT_EXISTS,
|
||||
Compatibility_Tag::INVALID_VERSION,
|
||||
], true )
|
||||
) {
|
||||
$plugin_data[ $this->get_plugin_header() ] = esc_html__( 'Unknown', 'elementor' );
|
||||
}
|
||||
?>
|
||||
|
||||
<tr>
|
||||
<td><?php echo esc_html( $plugin_data['Name'] ); ?></td>
|
||||
<td><?php echo esc_html( $plugin_data[ $this->get_plugin_header() ] ); ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\ContainerConverter;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use Elementor\Controls_Stack;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends \Elementor\Core\Base\Module {
|
||||
|
||||
// Event name dispatched by the buttons.
|
||||
const EVENT_NAME = 'elementorContainerConverter:convert';
|
||||
|
||||
/**
|
||||
* Retrieve the module name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'container-converter';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the module is active.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_active() {
|
||||
return Plugin::$instance->experiments->is_feature_active( 'container' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the module scripts.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_scripts() {
|
||||
wp_enqueue_script(
|
||||
'container-converter',
|
||||
$this->get_js_assets_url( 'container-converter' ),
|
||||
[ 'elementor-editor' ],
|
||||
ELEMENTOR_VERSION,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the module styles.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_styles() {
|
||||
wp_enqueue_style(
|
||||
'container-converter',
|
||||
$this->get_css_assets_url( 'modules/container-converter/editor' ),
|
||||
[],
|
||||
ELEMENTOR_VERSION
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a convert button to sections.
|
||||
*
|
||||
* @param \Elementor\Controls_Stack $controls_stack
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function add_section_convert_button( Controls_Stack $controls_stack ) {
|
||||
if ( ! Plugin::$instance->editor->is_edit_mode() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$controls_stack->start_injection( [
|
||||
'of' => '_title',
|
||||
] );
|
||||
|
||||
$controls_stack->add_control(
|
||||
'convert_to_container',
|
||||
[
|
||||
'type' => Controls_Manager::BUTTON,
|
||||
'label' => esc_html__( 'Convert to container', 'elementor' ),
|
||||
'text' => esc_html__( 'Convert', 'elementor' ),
|
||||
'button_type' => 'default',
|
||||
'description' => esc_html__( 'Copies all of the selected sections and columns and pastes them in a container beneath the original.', 'elementor' ),
|
||||
'separator' => 'after',
|
||||
'event' => static::EVENT_NAME,
|
||||
]
|
||||
);
|
||||
|
||||
$controls_stack->end_injection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a convert button to page settings.
|
||||
*
|
||||
* @param \Elementor\Controls_Stack $controls_stack
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function add_page_convert_button( Controls_Stack $controls_stack ) {
|
||||
if ( ! Plugin::$instance->editor->is_edit_mode() || ! $this->page_contains_sections( $controls_stack ) || ! Plugin::$instance->role_manager->user_can( 'design' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$controls_stack->start_injection( [
|
||||
'of' => 'post_title',
|
||||
'at' => 'before',
|
||||
] );
|
||||
|
||||
$controls_stack->add_control(
|
||||
'convert_to_container',
|
||||
[
|
||||
'type' => Controls_Manager::BUTTON,
|
||||
'label' => esc_html__( 'Convert to container', 'elementor' ),
|
||||
'text' => esc_html__( 'Convert', 'elementor' ),
|
||||
'button_type' => 'default',
|
||||
'description' => esc_html__( 'Copies all of the selected sections and columns and pastes them in a container beneath the original.', 'elementor' ),
|
||||
'separator' => 'after',
|
||||
'event' => static::EVENT_NAME,
|
||||
]
|
||||
);
|
||||
|
||||
$controls_stack->end_injection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if document has any Section elements.
|
||||
*
|
||||
* @param \Elementor\Controls_Stack $controls_stack
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function page_contains_sections( $controls_stack ) {
|
||||
$data = $controls_stack->get_elements_data();
|
||||
|
||||
if ( ! is_array( $data ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ( $data as $element ) {
|
||||
if ( isset( $element['elType'] ) && 'section' === $element['elType'] ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Container-Converter module.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'elementor/editor/after_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
|
||||
add_action( 'elementor/editor/after_enqueue_styles', [ $this, 'enqueue_styles' ] );
|
||||
|
||||
add_action( 'elementor/element/section/section_layout/after_section_end', function ( Controls_Stack $controls_stack ) {
|
||||
$this->add_section_convert_button( $controls_stack );
|
||||
} );
|
||||
|
||||
add_action( 'elementor/documents/register_controls', function ( Controls_Stack $controls_stack ) {
|
||||
$this->add_page_convert_button( $controls_stack );
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\ContentSanitizer\Interfaces;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
interface Sanitizable {
|
||||
public function sanitize( $content );
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\ContentSanitizer;
|
||||
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
const WIDGET_TO_SANITIZE = 'heading';
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_filter( 'elementor/document/save/data', [ $this, 'sanitize_content' ], 10, 2 );
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'content-sanitizer';
|
||||
}
|
||||
|
||||
public function sanitize_content( $data, $document ) : array {
|
||||
if ( current_user_can( 'manage_options' ) || empty( $data['elements'] ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
if ( ! $this->is_widget_present( $data ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
return Plugin::$instance->db->iterate_data( $data, function ( $element ) {
|
||||
if ( $this->is_target_widget( $element ) ) {
|
||||
$element['settings']['title'] = Plugin::$instance->widgets_manager->get_widget_types( self::WIDGET_TO_SANITIZE )->sanitize( $element['settings']['title'] );
|
||||
}
|
||||
|
||||
return $element;
|
||||
});
|
||||
}
|
||||
|
||||
private function is_target_widget( $element ) {
|
||||
return self::WIDGET_TO_SANITIZE === $element['widgetType'];
|
||||
}
|
||||
|
||||
private function is_widget_present( array $elements ): bool {
|
||||
$json = wp_json_encode( $elements );
|
||||
|
||||
return false !== strpos( $json, '"widgetType":"' . self::WIDGET_TO_SANITIZE . '"' );
|
||||
}
|
||||
}
|
||||
369
wp-content/plugins/elementor/modules/dev-tools/deprecation.php
Normal file
369
wp-content/plugins/elementor/modules/dev-tools/deprecation.php
Normal file
@@ -0,0 +1,369 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\DevTools;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Deprecation {
|
||||
const SOFT_VERSIONS_COUNT = 4;
|
||||
const HARD_VERSIONS_COUNT = 8;
|
||||
|
||||
private $current_version = null;
|
||||
private $soft_deprecated_notices = [];
|
||||
|
||||
public function __construct( $current_version ) {
|
||||
$this->current_version = $current_version;
|
||||
}
|
||||
|
||||
public function get_settings() {
|
||||
return [
|
||||
'soft_notices' => $this->soft_deprecated_notices,
|
||||
'soft_version_count' => self::SOFT_VERSIONS_COUNT,
|
||||
'hard_version_count' => self::HARD_VERSIONS_COUNT,
|
||||
'current_version' => ELEMENTOR_VERSION,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total of major.
|
||||
*
|
||||
* Since `get_total_major` cannot determine how much really versions between 2.9.0 and 3.3.0 if there is 2.10.0 version for example,
|
||||
* versions with major2 more then 9 will be added to total.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param array $parsed_version
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_total_major( $parsed_version ) {
|
||||
$major1 = $parsed_version['major1'];
|
||||
$major2 = $parsed_version['major2'];
|
||||
$major2 = $major2 > 9 ? 9 : $major2;
|
||||
$minor = 0;
|
||||
|
||||
$total = intval( "{$major1}{$major2}{$minor}" );
|
||||
|
||||
if ( $total > 99 ) {
|
||||
$total = $total / 10;
|
||||
} else {
|
||||
$total = intval( $total / 10 );
|
||||
}
|
||||
|
||||
if ( $parsed_version['major2'] > 9 ) {
|
||||
$total += $parsed_version['major2'] - 9;
|
||||
}
|
||||
|
||||
return $total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get next version.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param string $version
|
||||
* @param int $count
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function get_next_version( $version, $count = 1 ) {
|
||||
$version = $this->parse_version( $version );
|
||||
|
||||
if ( ! $version ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$version['total'] = $this->get_total_major( $version ) + $count;
|
||||
|
||||
$total = $version['total'];
|
||||
|
||||
if ( $total > 9 ) {
|
||||
$version['major1'] = intval( $total / 10 );
|
||||
$version['major2'] = $total % 10;
|
||||
} else {
|
||||
$version['major1'] = 0;
|
||||
$version['major2'] = $total;
|
||||
}
|
||||
|
||||
$version['minor'] = 0;
|
||||
|
||||
return $this->implode_version( $version );
|
||||
}
|
||||
|
||||
/**
|
||||
* Implode parsed version to string version.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param array $parsed_version
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function implode_version( $parsed_version ) {
|
||||
$major1 = $parsed_version['major1'];
|
||||
$major2 = $parsed_version['major2'];
|
||||
$minor = $parsed_version['minor'];
|
||||
|
||||
return "{$major1}.{$major2}.{$minor}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse to an informative array.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param string $version
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public function parse_version( $version ) {
|
||||
$version_explode = explode( '.', $version );
|
||||
$version_explode_count = count( $version_explode );
|
||||
|
||||
if ( $version_explode_count < 3 || $version_explode_count > 4 ) {
|
||||
trigger_error( 'Invalid Semantic Version string provided' );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
list( $major1, $major2, $minor ) = $version_explode;
|
||||
|
||||
$result = [
|
||||
'major1' => intval( $major1 ),
|
||||
'major2' => intval( $major2 ),
|
||||
'minor' => intval( $minor ),
|
||||
];
|
||||
|
||||
if ( $version_explode_count > 3 ) {
|
||||
$result['build'] = $version_explode[3];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two versions, result is equal to diff of major versions.
|
||||
* Notice: If you want to compare between 2.9.0 and 3.3.0, and there is also a 2.10.0 version, you cannot get the right comparison
|
||||
* Since $this->deprecation->get_total_major cannot determine how much really versions between 2.9.0 and 3.3.0.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param {string} $version1
|
||||
* @param {string} $version2
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public function compare_version( $version1, $version2 ) {
|
||||
$version1 = self::parse_version( $version1 );
|
||||
$version2 = self::parse_version( $version2 );
|
||||
|
||||
if ( $version1 && $version2 ) {
|
||||
$versions = [ &$version1, &$version2 ];
|
||||
|
||||
foreach ( $versions as &$version ) {
|
||||
$version['total'] = self::get_total_major( $version );
|
||||
}
|
||||
|
||||
return $version1['total'] - $version2['total'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Deprecation
|
||||
*
|
||||
* Checks whether the given entity is valid. If valid, this method checks whether the deprecation
|
||||
* should be soft (browser console notice) or hard (use WordPress' native deprecation methods).
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param string $entity - The Deprecated entity (the function/hook itself)
|
||||
* @param string $version
|
||||
* @param string $replacement Optional
|
||||
* @param string $base_version Optional. Default is `null`
|
||||
*
|
||||
* @return bool|void
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function check_deprecation( $entity, $version, $replacement, $base_version = null ) {
|
||||
if ( null === $base_version ) {
|
||||
$base_version = $this->current_version;
|
||||
}
|
||||
|
||||
$diff = $this->compare_version( $base_version, $version );
|
||||
|
||||
if ( false === $diff ) {
|
||||
throw new \Exception( 'Invalid deprecation diff.' );
|
||||
}
|
||||
|
||||
$print_deprecated = false;
|
||||
|
||||
if ( defined( 'WP_DEBUG' ) && WP_DEBUG && $diff <= self::SOFT_VERSIONS_COUNT ) {
|
||||
// Soft deprecated.
|
||||
if ( ! isset( $this->soft_deprecated_notices[ $entity ] ) ) {
|
||||
$this->soft_deprecated_notices[ $entity ] = [
|
||||
$version,
|
||||
$replacement,
|
||||
];
|
||||
}
|
||||
|
||||
if ( defined( 'ELEMENTOR_DEBUG' ) && ELEMENTOR_DEBUG ) {
|
||||
$print_deprecated = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $print_deprecated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated Function
|
||||
*
|
||||
* Handles the deprecation process for functions.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param string $function
|
||||
* @param string $version
|
||||
* @param string $replacement Optional. Default is ''
|
||||
* @param string $base_version Optional. Default is `null`
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function deprecated_function( $function, $version, $replacement = '', $base_version = null ) {
|
||||
$print_deprecated = $this->check_deprecation( $function, $version, $replacement, $base_version );
|
||||
|
||||
if ( $print_deprecated ) {
|
||||
// PHPCS - We need to echo special characters because they can exist in function calls.
|
||||
_deprecated_function( $function, esc_html( $version ), $replacement ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated Hook
|
||||
*
|
||||
* Handles the deprecation process for hooks.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param string $hook
|
||||
* @param string $version
|
||||
* @param string $replacement Optional. Default is ''
|
||||
* @param string $base_version Optional. Default is `null`
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function deprecated_hook( $hook, $version, $replacement = '', $base_version = null ) {
|
||||
$print_deprecated = $this->check_deprecation( $hook, $version, $replacement, $base_version );
|
||||
|
||||
if ( $print_deprecated ) {
|
||||
_deprecated_hook( esc_html( $hook ), esc_html( $version ), esc_html( $replacement ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated Argument
|
||||
*
|
||||
* Handles the deprecation process for function arguments.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param string $argument
|
||||
* @param string $version
|
||||
* @param string $replacement
|
||||
* @param string $message
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function deprecated_argument( $argument, $version, $replacement = '', $message = '' ) {
|
||||
$print_deprecated = $this->check_deprecation( $argument, $version, $replacement );
|
||||
|
||||
if ( $print_deprecated ) {
|
||||
$message = empty( $message ) ? '' : ' ' . $message;
|
||||
// These arguments are escaped because they are printed later, and are not escaped when printed.
|
||||
$error_message_args = [ esc_html( $argument ), esc_html( $version ) ];
|
||||
|
||||
if ( $replacement ) {
|
||||
/* translators: 1: Function argument, 2: Elementor version number, 3: Replacement argument name. */
|
||||
$translation_string = esc_html__( 'The %1$s argument is deprecated since version %2$s! Use %3$s instead.', 'elementor' );
|
||||
$error_message_args[] = $replacement;
|
||||
} else {
|
||||
/* translators: 1: Function argument, 2: Elementor version number. */
|
||||
$translation_string = esc_html__( 'The %1$s argument is deprecated since version %2$s!', 'elementor' );
|
||||
}
|
||||
|
||||
trigger_error(
|
||||
vsprintf(
|
||||
// PHPCS - $translation_string is already escaped above.
|
||||
$translation_string, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
// PHPCS - $error_message_args is an array.
|
||||
$error_message_args // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
) . esc_html( $message ),
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do Deprecated Action
|
||||
*
|
||||
* A method used to run deprecated actions through Elementor's deprecation process.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param string $hook
|
||||
* @param array $args
|
||||
* @param string $version
|
||||
* @param string $replacement
|
||||
* @param null|string $base_version
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function do_deprecated_action( $hook, $args, $version, $replacement = '', $base_version = null ) {
|
||||
if ( ! has_action( $hook ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->deprecated_hook( $hook, $version, $replacement, $base_version );
|
||||
|
||||
do_action_ref_array( $hook, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply Deprecated Filter
|
||||
*
|
||||
* A method used to run deprecated filters through Elementor's deprecation process.
|
||||
*
|
||||
* @since 3.2.0
|
||||
*
|
||||
* @param string $hook
|
||||
* @param array $args
|
||||
* @param string $version
|
||||
* @param string $replacement
|
||||
* @param null|string $base_version
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function apply_deprecated_filter( $hook, $args, $version, $replacement = '', $base_version = null ) {
|
||||
if ( ! has_action( $hook ) ) {
|
||||
// `$args` should be an array, but in order to keep BC, we need to support non-array values.
|
||||
if ( is_array( $args ) ) {
|
||||
return $args[0] ?? null;
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
// BC - See the comment above.
|
||||
if ( ! is_array( $args ) ) {
|
||||
$args = [ $args ];
|
||||
}
|
||||
|
||||
// Avoid associative arrays.
|
||||
$args = array_values( $args );
|
||||
|
||||
$this->deprecated_hook( $hook, $version, $replacement, $base_version );
|
||||
|
||||
return apply_filters_ref_array( $hook, $args );
|
||||
}
|
||||
}
|
||||
56
wp-content/plugins/elementor/modules/dev-tools/module.php
Normal file
56
wp-content/plugins/elementor/modules/dev-tools/module.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\DevTools;
|
||||
|
||||
use Elementor\Core\Base\App;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix issue with 'Potentially polymorphic call. The code may be inoperable depending on the actual class instance passed as the argument.'.
|
||||
* Its tells to the editor that instance() return right module. instead of base module.
|
||||
* @method Module instance()
|
||||
*/
|
||||
class Module extends App {
|
||||
/**
|
||||
* @var Deprecation
|
||||
*/
|
||||
public $deprecation;
|
||||
|
||||
public function __construct() {
|
||||
$this->deprecation = new Deprecation( ELEMENTOR_VERSION );
|
||||
|
||||
add_action( 'elementor/editor/before_enqueue_scripts', [ $this, 'register_scripts' ] );
|
||||
add_action( 'admin_enqueue_scripts', [ $this, 'register_scripts' ] );
|
||||
add_action( 'wp_enqueue_scripts', [ $this, 'register_scripts' ] );
|
||||
add_action( 'elementor/frontend/after_register_scripts', [ $this, 'register_scripts' ] );
|
||||
add_action( 'elementor/common/after_register_scripts', [ $this, 'register_scripts' ] );
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'dev-tools';
|
||||
}
|
||||
|
||||
public function register_scripts() {
|
||||
wp_register_script(
|
||||
'elementor-dev-tools',
|
||||
$this->get_js_assets_url( 'dev-tools' ),
|
||||
[],
|
||||
ELEMENTOR_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
$this->print_config( 'elementor-dev-tools' );
|
||||
}
|
||||
|
||||
protected function get_init_settings() {
|
||||
return [
|
||||
'isDebug' => ( defined( 'WP_DEBUG' ) && WP_DEBUG ),
|
||||
'urls' => [
|
||||
'assets' => ELEMENTOR_ASSETS_URL,
|
||||
],
|
||||
'deprecation' => $this->deprecation->get_settings(),
|
||||
];
|
||||
}
|
||||
}
|
||||
165
wp-content/plugins/elementor/modules/dynamic-tags/module.php
Normal file
165
wp-content/plugins/elementor/modules/dynamic-tags/module.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\DynamicTags;
|
||||
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Core\DynamicTags\Base_Tag;
|
||||
use Elementor\Core\DynamicTags\Manager;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor dynamic tags module.
|
||||
*
|
||||
* Elementor dynamic tags module handler class is responsible for registering
|
||||
* and managing Elementor dynamic tags modules.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class Module extends BaseModule {
|
||||
|
||||
/**
|
||||
* Base dynamic tag group.
|
||||
*/
|
||||
const BASE_GROUP = 'base';
|
||||
|
||||
/**
|
||||
* Dynamic tags text category.
|
||||
*/
|
||||
const TEXT_CATEGORY = 'text';
|
||||
|
||||
/**
|
||||
* Dynamic tags URL category.
|
||||
*/
|
||||
const URL_CATEGORY = 'url';
|
||||
|
||||
/**
|
||||
* Dynamic tags image category.
|
||||
*/
|
||||
const IMAGE_CATEGORY = 'image';
|
||||
|
||||
/**
|
||||
* Dynamic tags media category.
|
||||
*/
|
||||
const MEDIA_CATEGORY = 'media';
|
||||
|
||||
/**
|
||||
* Dynamic tags post meta category.
|
||||
*/
|
||||
const POST_META_CATEGORY = 'post_meta';
|
||||
|
||||
/**
|
||||
* Dynamic tags gallery category.
|
||||
*/
|
||||
const GALLERY_CATEGORY = 'gallery';
|
||||
|
||||
/**
|
||||
* Dynamic tags number category.
|
||||
*/
|
||||
const NUMBER_CATEGORY = 'number';
|
||||
|
||||
/**
|
||||
* Dynamic tags number category.
|
||||
*/
|
||||
const COLOR_CATEGORY = 'color';
|
||||
|
||||
/**
|
||||
* Dynamic tags datetime category.
|
||||
*/
|
||||
const DATETIME_CATEGORY = 'datetime';
|
||||
|
||||
/**
|
||||
* Dynamic tags module constructor.
|
||||
*
|
||||
* Initializing Elementor dynamic tags module.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->register_groups();
|
||||
|
||||
add_action( 'elementor/dynamic_tags/register', [ $this, 'register_tags' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get module name.
|
||||
*
|
||||
* Retrieve the dynamic tags module name.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*
|
||||
* @return string Module name.
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'dynamic_tags';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get classes names.
|
||||
*
|
||||
* Retrieve the dynamic tag classes names.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*
|
||||
* @return array Tag dynamic tag classes names.
|
||||
*/
|
||||
public function get_tag_classes_names() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get groups.
|
||||
*
|
||||
* Retrieve the dynamic tag groups.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*
|
||||
* @return array Tag dynamic tag groups.
|
||||
*/
|
||||
public function get_groups() {
|
||||
return [
|
||||
self::BASE_GROUP => [
|
||||
'title' => 'Base Tags',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register groups.
|
||||
*
|
||||
* Add all the available tag groups.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access private
|
||||
*/
|
||||
private function register_groups() {
|
||||
foreach ( $this->get_groups() as $group_name => $group_settings ) {
|
||||
Plugin::$instance->dynamic_tags->register_group( $group_name, $group_settings );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register tags.
|
||||
*
|
||||
* Add all the available dynamic tags.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*
|
||||
* @param Manager $dynamic_tags
|
||||
*/
|
||||
public function register_tags( $dynamic_tags ) {
|
||||
foreach ( $this->get_tag_classes_names() as $tag_class ) {
|
||||
/** @var Base_Tag $class_name */
|
||||
$class_name = $this->get_reflection()->getNamespaceName() . '\Tags\\' . $tag_class;
|
||||
|
||||
$dynamic_tags->register( new $class_name() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\EditorEvents;
|
||||
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Core\Common\Modules\Connect\Apps\Base_App;
|
||||
use Elementor\Core\Experiments\Manager as Experiments_Manager;
|
||||
use Elementor\Utils;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Tracker;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
const EXPERIMENT_NAME = 'editor_events';
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->register_experiment();
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'editor-events';
|
||||
}
|
||||
|
||||
public static function get_editor_events_config() {
|
||||
$can_send_events = defined( 'ELEMENTOR_EDITOR_EVENTS_MIXPANEL_TOKEN' ) &&
|
||||
Tracker::is_allow_track() &&
|
||||
Plugin::$instance->experiments->is_feature_active( self::EXPERIMENT_NAME );
|
||||
|
||||
$settings = [
|
||||
'can_send_events' => $can_send_events,
|
||||
'elementor_version' => ELEMENTOR_VERSION,
|
||||
'site_url' => hash( 'sha256', get_site_url() ),
|
||||
'wp_version' => get_bloginfo( 'version' ),
|
||||
'user_agent' => esc_html( Utils::get_super_global_value( $_SERVER, 'HTTP_USER_AGENT' ) ),
|
||||
'site_language' => get_locale(),
|
||||
'site_key' => get_option( Base_App::OPTION_CONNECT_SITE_KEY ),
|
||||
'subscription_id' => null,
|
||||
'token' => defined( 'ELEMENTOR_EDITOR_EVENTS_MIXPANEL_TOKEN' ) ? ELEMENTOR_EDITOR_EVENTS_MIXPANEL_TOKEN : '',
|
||||
];
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
private function register_experiment() {
|
||||
Plugin::$instance->experiments->add_feature( [
|
||||
'name' => static::EXPERIMENT_NAME,
|
||||
'title' => esc_html__( 'Elementor Editor Events', 'elementor' ),
|
||||
'description' => esc_html__( 'Editor events processing', 'elementor' ),
|
||||
'hidden' => true,
|
||||
'default' => Experiments_Manager::STATE_INACTIVE,
|
||||
] );
|
||||
}
|
||||
}
|
||||
159
wp-content/plugins/elementor/modules/element-cache/module.php
Normal file
159
wp-content/plugins/elementor/modules/element-cache/module.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\ElementCache;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Core\Experiments\Manager as ExperimentsManager;
|
||||
use Elementor\Element_Base;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Settings;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
public function get_name() {
|
||||
return 'element-cache';
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->register_experiments();
|
||||
$this->register_shortcode();
|
||||
|
||||
if ( ! Plugin::$instance->experiments->is_feature_active( 'e_element_cache' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->add_advanced_tab_actions();
|
||||
|
||||
if ( is_admin() ) {
|
||||
add_action( 'elementor/admin/after_create_settings/' . Settings::PAGE_ID, [ $this, 'register_admin_fields' ], 100 );
|
||||
}
|
||||
|
||||
$this->clear_cache_on_site_changed();
|
||||
}
|
||||
|
||||
private function register_experiments() {
|
||||
Plugin::$instance->experiments->add_feature( [
|
||||
'name' => 'e_element_cache',
|
||||
'title' => esc_html__( 'Element Caching', 'elementor' ),
|
||||
'tag' => esc_html__( 'Performance', 'elementor' ),
|
||||
'description' => esc_html__( 'Elements caching reduces loading times by serving up a copy of an element instead of rendering it fresh every time the page is loaded. When active, Elementor will determine which elements can benefit from static loading - but you can override this.', 'elementor' ),
|
||||
'release_status' => ExperimentsManager::RELEASE_STATUS_BETA,
|
||||
'default' => ExperimentsManager::STATE_INACTIVE,
|
||||
'new_site' => [
|
||||
'default_active' => true,
|
||||
'minimum_installation_version' => '3.23.0',
|
||||
],
|
||||
'generator_tag' => true,
|
||||
] );
|
||||
}
|
||||
|
||||
private function register_shortcode() {
|
||||
add_shortcode( 'elementor-element', function ( $atts ) {
|
||||
if ( empty( $atts['data'] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$widget_data = json_decode( base64_decode( $atts['data'] ), true );
|
||||
|
||||
if ( empty( $widget_data ) || ! is_array( $widget_data ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
$element = Plugin::$instance->elements_manager->create_element_instance( $widget_data );
|
||||
|
||||
if ( $element ) {
|
||||
$element->print_element();
|
||||
}
|
||||
|
||||
return ob_get_clean();
|
||||
} );
|
||||
}
|
||||
|
||||
private function add_advanced_tab_actions() {
|
||||
$hooks = array(
|
||||
'elementor/element/common/_section_style/after_section_end' => '_css_classes', // Widgets
|
||||
);
|
||||
|
||||
foreach ( $hooks as $hook => $injection_position ) {
|
||||
add_action(
|
||||
$hook,
|
||||
function( $element, $args ) use ( $injection_position ) {
|
||||
$this->add_control_to_advanced_tab( $element, $args, $injection_position );
|
||||
},
|
||||
10,
|
||||
2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function add_control_to_advanced_tab( Element_Base $element, $args, $injection_position ) {
|
||||
$element->start_injection(
|
||||
[
|
||||
'of' => $injection_position,
|
||||
]
|
||||
);
|
||||
|
||||
$control_data = [
|
||||
'label' => esc_html__( 'Cache Settings', 'elementor' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => '',
|
||||
'options' => [
|
||||
'' => esc_html__( 'Default', 'elementor' ),
|
||||
'yes' => esc_html__( 'Inactive', 'elementor' ),
|
||||
'no' => esc_html__( 'Active', 'elementor' ),
|
||||
],
|
||||
];
|
||||
|
||||
$element->add_control( '_element_cache', $control_data );
|
||||
|
||||
$element->end_injection();
|
||||
}
|
||||
|
||||
public function register_admin_fields( Settings $settings ) {
|
||||
$settings->add_field(
|
||||
Settings::TAB_PERFORMANCE,
|
||||
Settings::TAB_PERFORMANCE,
|
||||
'element_cache_ttl',
|
||||
[
|
||||
'label' => esc_html__( 'Element Cache Expiration', 'elementor' ),
|
||||
'field_args' => [
|
||||
'class' => 'elementor-element-cache-ttl',
|
||||
'type' => 'select',
|
||||
'std' => '24',
|
||||
'options' => [
|
||||
'1' => esc_html__( '1 Hour', 'elementor' ),
|
||||
'6' => esc_html__( '6 Hours', 'elementor' ),
|
||||
'12' => esc_html__( '12 Hours', 'elementor' ),
|
||||
'24' => esc_html__( '1 Day', 'elementor' ),
|
||||
'72' => esc_html__( '3 Days', 'elementor' ),
|
||||
'168' => esc_html__( '1 Week', 'elementor' ),
|
||||
'336' => esc_html__( '2 Weeks', 'elementor' ),
|
||||
'720' => esc_html__( '1 Month', 'elementor' ),
|
||||
'8760' => esc_html__( '1 Year', 'elementor' ),
|
||||
],
|
||||
'desc' => esc_html__( 'Specify the duration for which data is stored in the cache. Elements caching speeds up loading by serving pre-rendered copies of elements, rather than rendering them fresh each time. This control ensures efficient performance and up-to-date content.', 'elementor' ),
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
private function clear_cache_on_site_changed() {
|
||||
add_action( 'activated_plugin', [ $this, 'clear_cache' ] );
|
||||
add_action( 'deactivated_plugin', [ $this, 'clear_cache' ] );
|
||||
add_action( 'switch_theme', [ $this, 'clear_cache' ] );
|
||||
add_action( 'upgrader_process_complete', [ $this, 'clear_cache' ] );
|
||||
}
|
||||
|
||||
public function clear_cache() {
|
||||
Plugin::$instance->files_manager->clear_cache();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\ElementManager;
|
||||
|
||||
use Elementor\Core\Admin\Menu\Interfaces\Admin_Menu_Item_With_Page;
|
||||
use Elementor\Settings;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Admin_Menu_App implements Admin_Menu_Item_With_Page {
|
||||
|
||||
public function is_visible() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_parent_slug() {
|
||||
return Settings::PAGE_ID;
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Element Manager', 'elementor' );
|
||||
}
|
||||
|
||||
public function get_page_title() {
|
||||
return esc_html__( 'Element Manager', 'elementor' );
|
||||
}
|
||||
|
||||
public function get_capability() {
|
||||
return 'manage_options';
|
||||
}
|
||||
|
||||
public function render() {
|
||||
echo '<div class="wrap">';
|
||||
echo '<h3 class="wp-heading-inline">' . esc_html__( 'Element Manager', 'elementor' ) . '</h3>';
|
||||
echo '<div id="elementor-element-manager-wrap"></div>';
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
183
wp-content/plugins/elementor/modules/element-manager/ajax.php
Normal file
183
wp-content/plugins/elementor/modules/element-manager/ajax.php
Normal file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\ElementManager;
|
||||
|
||||
use Elementor\Core\Utils\Promotions\Filtered_Promotions_Manager;
|
||||
use Elementor\Modules\Usage\Module as Usage_Module;
|
||||
use Elementor\Api;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\User;
|
||||
use Elementor\Utils;
|
||||
use Elementor\Core\Utils\Promotions\Validate_Promotion;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Ajax {
|
||||
|
||||
const ELEMENT_MANAGER_PROMOTION_URL = 'https://go.elementor.com/go-pro-element-manager/';
|
||||
|
||||
const FREE_TO_PRO_PERMISSIONS_PROMOTION_URL = 'https://go.elementor.com/go-pro-element-manager-permissions/';
|
||||
|
||||
const PRO_TO_ADVANCED_PERMISSIONS_PROMOTION_URL = 'https://go.elementor.com/go-pro-advanced-element-manager-permissions/';
|
||||
|
||||
public function register_endpoints() {
|
||||
add_action( 'wp_ajax_elementor_element_manager_get_admin_app_data', [ $this, 'ajax_get_admin_page_data' ] );
|
||||
add_action( 'wp_ajax_elementor_element_manager_save_disabled_elements', [ $this, 'ajax_save_disabled_elements' ] );
|
||||
add_action( 'wp_ajax_elementor_element_manager_get_widgets_usage', [ $this, 'ajax_get_widgets_usage' ] );
|
||||
}
|
||||
|
||||
public function ajax_get_admin_page_data() {
|
||||
$this->verify_permission();
|
||||
$this->force_enabled_all_elements();
|
||||
|
||||
$widgets = [];
|
||||
$plugins = [];
|
||||
|
||||
foreach ( Plugin::$instance->widgets_manager->get_widget_types() as $widget ) {
|
||||
$widget_title = sanitize_user( $widget->get_title() );
|
||||
if ( empty( $widget_title ) || ! $widget->show_in_panel() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$plugin_name = $this->get_plugin_name_from_widget_instance( $widget );
|
||||
|
||||
if ( ! in_array( $plugin_name, $plugins ) ) {
|
||||
$plugins[] = $plugin_name;
|
||||
}
|
||||
|
||||
$widgets[] = [
|
||||
'name' => $widget->get_name(),
|
||||
'plugin' => $plugin_name,
|
||||
'title' => $widget_title,
|
||||
'icon' => $widget->get_icon(),
|
||||
];
|
||||
}
|
||||
|
||||
$notice_id = 'e-element-manager-intro-1';
|
||||
|
||||
$data = [
|
||||
'disabled_elements' => Options::get_disabled_elements(),
|
||||
'promotion_widgets' => [],
|
||||
'widgets' => $widgets,
|
||||
'plugins' => $plugins,
|
||||
'notice_data' => [
|
||||
'notice_id' => $notice_id,
|
||||
'is_viewed' => User::is_user_notice_viewed( $notice_id ),
|
||||
],
|
||||
'promotion_data' => [
|
||||
'manager_permissions' => [
|
||||
'pro' => $this->get_element_manager_promotion(
|
||||
[
|
||||
'text' => esc_html__( 'Upgrade Now', 'elementor' ),
|
||||
'url' => self::FREE_TO_PRO_PERMISSIONS_PROMOTION_URL,
|
||||
],
|
||||
'pro_permissions'
|
||||
),
|
||||
'advanced' => $this->get_element_manager_promotion(
|
||||
[
|
||||
'text' => esc_html__( 'Upgrade Now', 'elementor' ),
|
||||
'url' => self::PRO_TO_ADVANCED_PERMISSIONS_PROMOTION_URL,
|
||||
],
|
||||
'advanced_permissions'
|
||||
),
|
||||
],
|
||||
'element_manager' => $this->get_element_manager_promotion(
|
||||
[
|
||||
'text' => esc_html__( 'Upgrade Now', 'elementor' ),
|
||||
'url' => self::ELEMENT_MANAGER_PROMOTION_URL,
|
||||
],
|
||||
'element_manager'
|
||||
),
|
||||
],
|
||||
];
|
||||
|
||||
if ( ! Utils::has_pro() ) {
|
||||
$data['promotion_widgets'] = Api::get_promotion_widgets();
|
||||
}
|
||||
|
||||
$data['additional_data'] = apply_filters( 'elementor/element_manager/admin_app_data/additional_data', [] );
|
||||
|
||||
wp_send_json_success( $data );
|
||||
}
|
||||
|
||||
private function get_element_manager_promotion( $promotion_data, $filter_id ): array {
|
||||
|
||||
return Filtered_Promotions_Manager::get_filtered_promotion_data( $promotion_data, 'elementor/element_manager/admin_app_data/promotion_data/' . $filter_id, 'url' );
|
||||
}
|
||||
|
||||
private function verify_permission() {
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error( esc_html__( 'You do not have permission to edit these settings.', 'elementor' ) );
|
||||
}
|
||||
|
||||
$nonce = Utils::get_super_global_value( $_POST, 'nonce' ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'e-element-manager-app' ) ) {
|
||||
wp_send_json_error( esc_html__( 'Invalid nonce.', 'elementor' ) );
|
||||
}
|
||||
}
|
||||
|
||||
private function force_enabled_all_elements() {
|
||||
remove_all_filters( 'elementor/widgets/is_widget_enabled' );
|
||||
}
|
||||
|
||||
private function get_plugin_name_from_widget_instance( $widget ) {
|
||||
if ( in_array( 'wordpress', $widget->get_categories() ) ) {
|
||||
return esc_html__( 'WordPress Widgets', 'elementor' );
|
||||
}
|
||||
|
||||
$class_reflection = new \ReflectionClass( $widget );
|
||||
|
||||
$plugin_basename = plugin_basename( $class_reflection->getFileName() );
|
||||
|
||||
$plugin_directory = strtok( $plugin_basename, '/' );
|
||||
|
||||
$plugins_data = get_plugins( '/' . $plugin_directory );
|
||||
$plugin_data = array_shift( $plugins_data );
|
||||
|
||||
return $plugin_data['Name'] ?? esc_html__( 'Unknown', 'elementor' );
|
||||
}
|
||||
|
||||
public function ajax_save_disabled_elements() {
|
||||
$this->verify_permission();
|
||||
|
||||
$elements = Utils::get_super_global_value( $_POST, 'widgets' ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
|
||||
if ( empty( $elements ) ) {
|
||||
wp_send_json_error( esc_html__( 'No elements to save.', 'elementor' ) );
|
||||
}
|
||||
|
||||
$disabled_elements = json_decode( $elements );
|
||||
|
||||
if ( ! is_array( $disabled_elements ) ) {
|
||||
wp_send_json_error( esc_html__( 'Unexpected elements data.', 'elementor' ) );
|
||||
}
|
||||
|
||||
Options::update_disabled_elements( $disabled_elements );
|
||||
|
||||
do_action( 'elementor/element_manager/save_disabled_elements' );
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
public function ajax_get_widgets_usage() {
|
||||
$this->verify_permission();
|
||||
|
||||
/** @var Usage_Module $usage_module */
|
||||
$usage_module = Usage_Module::instance();
|
||||
$usage_module->recalc_usage();
|
||||
|
||||
$widgets_usage = [];
|
||||
foreach ( $usage_module->get_formatted_usage( 'raw' ) as $data ) {
|
||||
foreach ( $data['elements'] as $element => $count ) {
|
||||
if ( ! isset( $widgets_usage[ $element ] ) ) {
|
||||
$widgets_usage[ $element ] = 0;
|
||||
}
|
||||
|
||||
$widgets_usage[ $element ] += $count;
|
||||
}
|
||||
}
|
||||
|
||||
wp_send_json_success( $widgets_usage );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\ElementManager;
|
||||
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Core\Admin\Menu\Admin_Menu_Manager;
|
||||
use Elementor\Widget_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
const PAGE_ID = 'elementor-element-manager';
|
||||
|
||||
public function get_name() {
|
||||
return 'element-manager';
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$ajax = new Ajax();
|
||||
$ajax->register_endpoints();
|
||||
|
||||
add_action( 'elementor/admin/menu/register', function( Admin_Menu_Manager $admin_menu ) {
|
||||
$admin_menu->register( static::PAGE_ID, new Admin_Menu_App() );
|
||||
}, 25 );
|
||||
|
||||
add_action( 'elementor/admin/menu/after_register', function ( Admin_Menu_Manager $admin_menu, array $hooks ) {
|
||||
if ( ! empty( $hooks[ static::PAGE_ID ] ) ) {
|
||||
add_action( "admin_print_scripts-{$hooks[ static::PAGE_ID ]}", [ $this, 'enqueue_assets' ] );
|
||||
add_action( "admin_footer-{$hooks[ static::PAGE_ID ]}", [ $this, 'print_styles' ], 1000 );
|
||||
}
|
||||
}, 10, 2 );
|
||||
|
||||
add_filter( 'elementor/widgets/is_widget_enabled', function( $should_register, Widget_Base $widget_instance ) {
|
||||
return ! Options::is_element_disabled( $widget_instance->get_name() );
|
||||
}, 10, 2 );
|
||||
|
||||
add_filter( 'elementor/system-info/usage/settings', function( $usage ) {
|
||||
$disabled_elements = Options::get_disabled_elements();
|
||||
|
||||
if ( ! empty( $disabled_elements ) ) {
|
||||
$usage['disabled_elements'] = implode( ', ', $disabled_elements );
|
||||
}
|
||||
|
||||
return $usage;
|
||||
} );
|
||||
|
||||
add_filter( 'elementor/tracker/send_tracking_data_params', function( $params ) {
|
||||
$disabled_elements = Options::get_disabled_elements();
|
||||
|
||||
if ( ! empty( $disabled_elements ) ) {
|
||||
$params['usages']['disabled_elements'] = $disabled_elements;
|
||||
}
|
||||
|
||||
return $params;
|
||||
} );
|
||||
}
|
||||
|
||||
public function enqueue_assets() {
|
||||
wp_enqueue_script(
|
||||
'e-element-manager-app',
|
||||
$this->get_js_assets_url( 'element-manager-admin' ),
|
||||
[
|
||||
'wp-element',
|
||||
'wp-components',
|
||||
'wp-dom-ready',
|
||||
'wp-i18n',
|
||||
],
|
||||
ELEMENTOR_VERSION
|
||||
);
|
||||
|
||||
wp_localize_script( 'e-element-manager-app', 'eElementManagerConfig', [
|
||||
'nonce' => wp_create_nonce( 'e-element-manager-app' ),
|
||||
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
||||
] );
|
||||
|
||||
wp_set_script_translations( 'e-element-manager-app', 'elementor' );
|
||||
|
||||
wp_enqueue_style( 'wp-components' );
|
||||
wp_enqueue_style( 'wp-format-library' );
|
||||
}
|
||||
|
||||
public function print_styles() {
|
||||
?>
|
||||
<style>
|
||||
.components-button.is-secondary:disabled {
|
||||
box-shadow: inset 0 0 0 1px #949494;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\ElementManager;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Options {
|
||||
|
||||
public static function get_disabled_elements() {
|
||||
return (array) get_option( 'elementor_disabled_elements', [] );
|
||||
}
|
||||
|
||||
public static function update_disabled_elements( $elements ) {
|
||||
update_option( 'elementor_disabled_elements', (array) $elements );
|
||||
}
|
||||
|
||||
public static function is_element_disabled( $element_name ) {
|
||||
return in_array( $element_name, self::get_disabled_elements() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\ElementsColorPicker;
|
||||
|
||||
use Elementor\Core\Experiments\Manager;
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Core\Experiments\Manager as Experiments_Manager;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
/**
|
||||
* Retrieve the module name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'elements-color-picker';
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the `Color-Thief` library to pick colors from images.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_scripts() {
|
||||
wp_enqueue_script(
|
||||
'color-thief',
|
||||
$this->get_js_assets_url( 'color-thief', 'assets/lib/color-thief/', true ),
|
||||
[ 'elementor-editor' ],
|
||||
ELEMENTOR_VERSION,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Module constructor - Initialize the Eye-Dropper module.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'elementor/editor/after_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\Favorites;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
use Elementor\Data\V2\Base\Controller as Controller_Base;
|
||||
use Elementor\Plugin;
|
||||
|
||||
class Controller extends Controller_Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'favorites';
|
||||
}
|
||||
|
||||
public function create_item( $request ) {
|
||||
$module = $this->get_module();
|
||||
$type = $request->get_param( 'id' );
|
||||
$favorite = $request->get_param( 'favorite' );
|
||||
|
||||
$module->update( $type, $favorite, $module::ACTION_MERGE );
|
||||
|
||||
return $module->get( $type );
|
||||
}
|
||||
|
||||
public function delete_item( $request ) {
|
||||
$module = $this->get_module();
|
||||
$type = $request->get_param( 'id' );
|
||||
$favorite = $request->get_param( 'favorite' );
|
||||
|
||||
$module->update( $type, $favorite, $module::ACTION_DELETE );
|
||||
|
||||
return $module->get( $type );
|
||||
}
|
||||
|
||||
public function create_item_permissions_check( $request ) {
|
||||
return current_user_can( 'edit_posts' );
|
||||
}
|
||||
|
||||
public function delete_item_permissions_check( $request ) {
|
||||
return $this->create_item_permissions_check( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the favorites module instance.
|
||||
*
|
||||
* @return Module
|
||||
*/
|
||||
protected function get_module() {
|
||||
return Plugin::instance()->modules_manager->get_modules( 'favorites' );
|
||||
}
|
||||
|
||||
public function register_endpoints() {
|
||||
$this->index_endpoint->register_item_route( \WP_REST_Server::CREATABLE, [
|
||||
'id_arg_type_regex' => '[\w]+',
|
||||
'id' => [
|
||||
'description' => 'Type of favorites.',
|
||||
'type' => 'string',
|
||||
'required' => true,
|
||||
],
|
||||
'favorite' => [
|
||||
'description' => 'The favorite slug to create.',
|
||||
'type' => 'string',
|
||||
'required' => true,
|
||||
],
|
||||
] );
|
||||
|
||||
$this->index_endpoint->register_item_route( \WP_REST_Server::DELETABLE, [
|
||||
'id_arg_type_regex' => '[\w]+',
|
||||
'id' => [
|
||||
'description' => 'Type of favorites.',
|
||||
'type' => 'string',
|
||||
'required' => true,
|
||||
],
|
||||
'favorite' => [
|
||||
'description' => 'The favorite slug to delete.',
|
||||
'type' => 'string',
|
||||
'required' => true,
|
||||
],
|
||||
] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Favorites;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
use Elementor\Core\Utils\Collection;
|
||||
use Elementor\Core\Utils\Static_Collection;
|
||||
|
||||
abstract class Favorites_Type extends Static_Collection {
|
||||
|
||||
public function __construct( array $items = [] ) {
|
||||
parent::__construct( $items, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the type.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function get_name();
|
||||
|
||||
/**
|
||||
* Prepare favorites before taking any action.
|
||||
*
|
||||
* @param Collection|array|string $favorites
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function prepare( $favorites ) {
|
||||
if ( $favorites instanceof Collection ) {
|
||||
$favorites = $favorites->values();
|
||||
}
|
||||
|
||||
if ( ! is_array( $favorites ) ) {
|
||||
return [ $favorites ];
|
||||
}
|
||||
|
||||
return $favorites;
|
||||
}
|
||||
}
|
||||
248
wp-content/plugins/elementor/modules/favorites/module.php
Normal file
248
wp-content/plugins/elementor/modules/favorites/module.php
Normal file
@@ -0,0 +1,248 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Favorites;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Core\Experiments\Manager;
|
||||
use Elementor\Modules\Favorites\Types\Widgets;
|
||||
use Elementor\Plugin;
|
||||
use http\Exception\InvalidArgumentException;
|
||||
use WP_Error;
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
/**
|
||||
* List of registered favorites type.
|
||||
*
|
||||
* @var Favorites_Type[]
|
||||
*/
|
||||
protected $types = [];
|
||||
|
||||
const OPTION_NAME = 'elementor_editor_user_favorites';
|
||||
|
||||
/**
|
||||
* The name of the merge action.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const ACTION_MERGE = 'merge';
|
||||
|
||||
/**
|
||||
* The name of the delete action.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const ACTION_DELETE = 'delete';
|
||||
|
||||
/**
|
||||
* Favorites module constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
// Register default types
|
||||
$this->register( Widgets::class );
|
||||
|
||||
$this->populate();
|
||||
|
||||
Plugin::instance()->data_manager_v2->register_controller( new Controller() );
|
||||
|
||||
add_filter( 'elementor/tracker/send_tracking_data_params', [ $this, 'add_tracking_data' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add usage data related to favorites.
|
||||
*
|
||||
* @param $params
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_tracking_data( $params ) {
|
||||
$params['usages']['favorites'] = $this->get();
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'favorites';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user favorites by type.
|
||||
*
|
||||
* @param string[]|string $type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get( $type = null ) {
|
||||
if ( null === $type ) {
|
||||
$type = array_keys( $this->types );
|
||||
}
|
||||
|
||||
if ( is_array( $type ) ) {
|
||||
return array_intersect_key(
|
||||
$this->combined(),
|
||||
array_flip( (array) $type )
|
||||
);
|
||||
}
|
||||
|
||||
return $this->type_instance( $type )
|
||||
->values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge new user favorites to a type.
|
||||
*
|
||||
* @param string $type
|
||||
* @param array|string $favorites
|
||||
* @param bool $store
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function merge( $type, $favorites, $store = true ) {
|
||||
return $this->update( $type, $favorites, static::ACTION_MERGE, $store );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete existing favorites from a type.
|
||||
*
|
||||
* @param string $type
|
||||
* @param array|string $favorites
|
||||
* @param bool $store
|
||||
*
|
||||
* @return array|int
|
||||
*/
|
||||
public function delete( $type, $favorites, $store = true ) {
|
||||
return $this->update( $type, $favorites, static::ACTION_DELETE, $store );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update favorites on a type by merging or deleting from it.
|
||||
*
|
||||
* @param $type
|
||||
* @param $favorites
|
||||
* @param $action
|
||||
* @param bool $store
|
||||
*
|
||||
* @return array|boolean
|
||||
*/
|
||||
public function update( $type, $favorites, $action, $store = true ) {
|
||||
$type_instance = $this->type_instance( $type );
|
||||
$favorites = $type_instance->prepare( $favorites );
|
||||
|
||||
switch ( $action ) {
|
||||
case static::ACTION_MERGE:
|
||||
$type_instance->merge( $favorites );
|
||||
break;
|
||||
case static::ACTION_DELETE:
|
||||
$type_instance->filter(
|
||||
function( $value ) use ( $favorites ) {
|
||||
return ! in_array( $value, $favorites, true );
|
||||
}
|
||||
);
|
||||
break;
|
||||
default:
|
||||
$this->action_doesnt_exists( $action );
|
||||
}
|
||||
|
||||
if ( $store && ! $this->store() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $type_instance->values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get registered favorites type instance.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return Favorites_Type
|
||||
*/
|
||||
public function type_instance( $type ) {
|
||||
return $this->types[ $type ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new type class.
|
||||
*
|
||||
* @param string $class
|
||||
*/
|
||||
public function register( $class ) {
|
||||
$type_instance = new $class();
|
||||
|
||||
$this->types[ $type_instance->get_name() ] = $type_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available types keys.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function available() {
|
||||
return array_keys( $this->types );
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine favorites from all types into a single array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function combined() {
|
||||
$all = [];
|
||||
|
||||
foreach ( $this->types as $type ) {
|
||||
$favorites = $type->values();
|
||||
|
||||
if ( ! empty( $favorites ) ) {
|
||||
$all[ $type->get_name() ] = $favorites;
|
||||
}
|
||||
}
|
||||
|
||||
return $all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate all type classes with the stored data.
|
||||
*/
|
||||
protected function populate() {
|
||||
$combined = $this->retrieve();
|
||||
|
||||
foreach ( $this->types as $key => $type ) {
|
||||
if ( isset( $combined[ $key ] ) ) {
|
||||
$type->merge( $combined[ $key ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve stored user favorites types.
|
||||
*
|
||||
* @return mixed|false
|
||||
*/
|
||||
protected function retrieve() {
|
||||
return get_user_option( static::OPTION_NAME );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all changes to user favorites type.
|
||||
*
|
||||
* @return int|bool
|
||||
*/
|
||||
protected function store() {
|
||||
return update_user_option( get_current_user_id(), static::OPTION_NAME, $this->combined() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw action doesn't exist exception.
|
||||
*
|
||||
* @param string $action
|
||||
*/
|
||||
public function action_doesnt_exists( $action ) {
|
||||
throw new \InvalidArgumentException( sprintf(
|
||||
"Action '%s' to apply on favorites doesn't exists",
|
||||
$action
|
||||
) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Favorites\Types;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
use Elementor\Modules\Favorites\Favorites_Type;
|
||||
use Elementor\Plugin;
|
||||
|
||||
class Widgets extends Favorites_Type {
|
||||
const CATEGORY_SLUG = 'favorites';
|
||||
|
||||
/**
|
||||
* Widgets favorites type constructor.
|
||||
*/
|
||||
public function __construct( array $items = [] ) {
|
||||
parent::__construct( $items );
|
||||
|
||||
add_action( 'elementor/document/before_get_config', [ $this, 'update_widget_categories' ], 10, 1 );
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'widgets';
|
||||
}
|
||||
|
||||
public function prepare( $favorites ) {
|
||||
return array_intersect( parent::prepare( $favorites ), $this->get_available() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available widgets.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_available() {
|
||||
return array_merge(
|
||||
array_keys(
|
||||
Plugin::instance()->widgets_manager->get_widget_types()
|
||||
),
|
||||
array_keys(
|
||||
Plugin::instance()->elements_manager->get_element_types()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the categories of a widget inside a filter.
|
||||
*
|
||||
* @param $document
|
||||
*/
|
||||
public function update_widget_categories( $document ) {
|
||||
foreach ( $this->values() as $favorite ) {
|
||||
$widget = Plugin::$instance->widgets_manager->get_widget_types( $favorite );
|
||||
|
||||
// If it's not a widget, maybe it's an element.
|
||||
if ( ! $widget ) {
|
||||
$widget = Plugin::$instance->elements_manager->get_element_types( $favorite );
|
||||
}
|
||||
|
||||
if ( $widget ) {
|
||||
$widget->set_config( 'categories', [ static::CATEGORY_SLUG ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\FloatingButtons\AdminMenuItems;
|
||||
|
||||
use Elementor\Core\Admin\Menu\Interfaces\Admin_Menu_Item_With_Page;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Floating_Buttons_Empty_View_Menu_Item extends Floating_Buttons_Menu_Item implements Admin_Menu_Item_With_Page {
|
||||
|
||||
private $render_callback;
|
||||
|
||||
public function __construct( callable $render_callback ) {
|
||||
$this->render_callback = $render_callback;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
( $this->render_callback )();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\FloatingButtons\AdminMenuItems;
|
||||
|
||||
use Elementor\Core\Admin\Menu\Interfaces\Admin_Menu_Item;
|
||||
use Elementor\TemplateLibrary\Source_Local;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Floating_Buttons_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__( 'Floating Buttons', 'elementor' );
|
||||
}
|
||||
|
||||
public function get_page_title() {
|
||||
return esc_html__( 'Floating Buttons', 'elementor' );
|
||||
}
|
||||
|
||||
public function get_capability() {
|
||||
return 'manage_options';
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\FloatingButtons\Classes\Render;
|
||||
|
||||
/**
|
||||
* Class Contact_Buttons_Core_Render.
|
||||
*
|
||||
* This class handles the rendering of the Contact Buttons widget for the core version.
|
||||
*
|
||||
* @since 3.23.0
|
||||
*/
|
||||
class Contact_Buttons_Core_Render extends Contact_Buttons_Render_Base {
|
||||
|
||||
public function render(): void {
|
||||
$this->build_layout_render_attribute();
|
||||
$this->add_content_wrapper_render_attribute();
|
||||
|
||||
$content_classnames = 'e-contact-buttons__content';
|
||||
$animation_duration = $this->settings['style_chat_box_animation_duration'];
|
||||
|
||||
if ( ! empty( $animation_duration ) ) {
|
||||
$content_classnames .= ' has-animation-duration-' . $animation_duration;
|
||||
}
|
||||
|
||||
$this->widget->add_render_attribute( 'content', [
|
||||
'class' => $content_classnames,
|
||||
] );
|
||||
?>
|
||||
<div <?php echo $this->widget->get_render_attribute_string( 'layout' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
||||
<div <?php echo $this->widget->get_render_attribute_string( 'content-wrapper' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
||||
<div <?php echo $this->widget->get_render_attribute_string( 'content' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
||||
<?php
|
||||
$this->render_top_bar();
|
||||
$this->render_message_bubble();
|
||||
$this->render_send_button();
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
$this->render_chat_button();
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function add_layout_render_attribute( $layout_classnames ) {
|
||||
$this->widget->add_render_attribute( 'layout', [
|
||||
'class' => $layout_classnames,
|
||||
'id' => $this->settings['advanced_custom_css_id'],
|
||||
'data-document-id' => get_the_ID(),
|
||||
] );
|
||||
}
|
||||
|
||||
protected function add_content_wrapper_render_attribute() {
|
||||
$this->widget->add_render_attribute( 'content-wrapper', [
|
||||
'aria-hidden' => 'true',
|
||||
'aria-label' => __( 'Links window', 'elementor' ),
|
||||
'class' => 'e-contact-buttons__content-wrapper hidden',
|
||||
'id' => 'e-contact-buttons__content-wrapper',
|
||||
] );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,461 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\FloatingButtons\Classes\Render;
|
||||
|
||||
use Elementor\Core\Base\Providers\Social_Network_Provider;
|
||||
use Elementor\Icons_Manager;
|
||||
use Elementor\Modules\FloatingButtons\Base\Widget_Contact_Button_Base;
|
||||
use Elementor\Utils;
|
||||
|
||||
/**
|
||||
* Class Contact_Buttons_Render_Base.
|
||||
*
|
||||
* This is the base class that will hold shared functionality that will be needed by all the various widget versions.
|
||||
*
|
||||
* @since 3.23.0
|
||||
*/
|
||||
abstract class Contact_Buttons_Render_Base {
|
||||
|
||||
protected Widget_Contact_Button_Base $widget;
|
||||
|
||||
protected array $settings;
|
||||
|
||||
|
||||
abstract public function render(): void;
|
||||
|
||||
public function __construct( Widget_Contact_Button_Base $widget ) {
|
||||
$this->widget = $widget;
|
||||
$this->settings = $widget->get_settings_for_display();
|
||||
}
|
||||
|
||||
protected function render_chat_button_icon(): void {
|
||||
$platform = $this->settings['chat_button_platform'] ?? '';
|
||||
|
||||
$mapping = Social_Network_Provider::get_icon_mapping( $platform );
|
||||
$icon_lib = explode( ' ', $mapping )[0];
|
||||
$library = 'fab' === $icon_lib ? 'fa-brands' : 'fa-solid';
|
||||
Icons_Manager::render_icon(
|
||||
[
|
||||
'library' => $library,
|
||||
'value' => $mapping,
|
||||
],
|
||||
[ 'aria-hidden' => 'true' ]
|
||||
);
|
||||
}
|
||||
|
||||
protected function render_chat_button(): void {
|
||||
$platform = $this->settings['chat_button_platform'] ?? '';
|
||||
$display_dot = $this->settings['chat_button_show_dot'] ?? '';
|
||||
$button_size = $this->settings['style_chat_button_size'];
|
||||
$hover_animation = $this->settings['style_button_color_hover_animation'];
|
||||
$entrance_animation = $this->settings['style_chat_button_animation'];
|
||||
$entrance_animation_duration = $this->settings['style_chat_button_animation_duration'];
|
||||
$entrance_animation_delay = $this->settings['style_chat_button_animation_delay'];
|
||||
|
||||
$button_classnames = 'e-contact-buttons__chat-button e-contact-buttons__chat-button-shadow';
|
||||
|
||||
if ( ! empty( $button_size ) ) {
|
||||
$button_classnames .= ' has-size-' . $button_size;
|
||||
}
|
||||
|
||||
if ( ! empty( $hover_animation ) ) {
|
||||
$button_classnames .= ' elementor-animation-' . $hover_animation;
|
||||
}
|
||||
|
||||
if ( ! empty( $entrance_animation ) && 'none' != $entrance_animation ) {
|
||||
$button_classnames .= ' has-entrance-animation';
|
||||
}
|
||||
|
||||
if ( ! empty( $entrance_animation_delay ) ) {
|
||||
$button_classnames .= ' has-entrance-animation-delay';
|
||||
}
|
||||
|
||||
if ( ! empty( $entrance_animation_duration ) ) {
|
||||
$button_classnames .= ' has-entrance-animation-duration-' . $entrance_animation_duration;
|
||||
}
|
||||
|
||||
if ( 'yes' === $display_dot ) {
|
||||
$button_classnames .= ' has-dot';
|
||||
}
|
||||
|
||||
$this->widget->add_render_attribute( 'button', [
|
||||
'class' => $button_classnames,
|
||||
'aria-controls' => 'e-contact-buttons__content-wrapper',
|
||||
] );
|
||||
|
||||
?>
|
||||
<div class="e-contact-buttons__chat-button-container">
|
||||
<button <?php echo $this->widget->get_render_attribute_string( 'button' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> type="button" aria-label="<?php echo esc_attr__( 'Toggle Links Popup', 'elementor' ); ?>">
|
||||
<?php
|
||||
$this->render_chat_button_icon();
|
||||
?>
|
||||
</button>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function render_close_button(): void {
|
||||
?>
|
||||
<button type="button" class="e-contact-buttons__close-button" aria-label="<?php echo esc_attr__( 'Close Links Popup', 'elementor' ); ?>" aria-controls="e-contact-buttons__content-wrapper">
|
||||
<i class="eicon-close"></i>
|
||||
</button>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function render_top_bar(): void {
|
||||
$profile_image_value = $this->settings['top_bar_image'] ?? [];
|
||||
$has_profile_image = ! empty( $profile_image_value ) && ( ! empty( $profile_image_value['url'] || ! empty( $profile_image_value['id'] ) ) );
|
||||
$profile_image_size = $this->settings['style_top_bar_image_size'];
|
||||
$display_profile_dot = $this->settings['top_bar_show_dot'];
|
||||
|
||||
$profile_image_classnames = 'e-contact-buttons__profile-image';
|
||||
|
||||
if ( ! empty( $profile_image_size ) ) {
|
||||
$profile_image_classnames .= ' has-size-' . $profile_image_size;
|
||||
}
|
||||
|
||||
if ( 'yes' === $display_profile_dot ) {
|
||||
$profile_image_classnames .= ' has-dot';
|
||||
}
|
||||
|
||||
$top_bar_title = $this->settings['top_bar_title'] ?? '';
|
||||
$top_bar_subtitle = $this->settings['top_bar_subtitle'] ?? '';
|
||||
|
||||
$has_top_bar_title = ! empty( $top_bar_title );
|
||||
$has_top_bar_subtitle = ! empty( $top_bar_subtitle );
|
||||
|
||||
$this->widget->add_render_attribute( 'profile-image', [
|
||||
'class' => $profile_image_classnames,
|
||||
] );
|
||||
?>
|
||||
<div class="e-contact-buttons__top-bar">
|
||||
<?php $this->render_close_button(); ?>
|
||||
<div <?php echo $this->widget->get_render_attribute_string( 'profile-image' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
||||
<?php if ( ! empty( $profile_image_value['id'] ) ) {
|
||||
echo wp_get_attachment_image( $profile_image_value['id'], 'medium', false, [
|
||||
'class' => 'e-contact-buttons__profile-image-el',
|
||||
] );
|
||||
} else {
|
||||
$this->widget->add_render_attribute( 'profile-image-src', [
|
||||
'alt' => '',
|
||||
'class' => 'e-contact-buttons__profile-image-el',
|
||||
'src' => esc_url( $profile_image_value['url'] ),
|
||||
] );
|
||||
?>
|
||||
<img <?php echo $this->widget->get_render_attribute_string( 'profile-image-src' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> />
|
||||
<?php }; ?>
|
||||
</div>
|
||||
|
||||
<div class="e-contact-buttons__top-bar-details">
|
||||
<?php if ( $has_top_bar_title ) { ?>
|
||||
<p class="e-contact-buttons__top-bar-title"><?php echo esc_html( $top_bar_title ); ?></p>
|
||||
<?php } ?>
|
||||
<?php if ( $has_top_bar_subtitle ) { ?>
|
||||
<p class="e-contact-buttons__top-bar-subtitle"><?php echo esc_html( $top_bar_subtitle ); ?></p>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function render_message_bubble_typing_animation(): void {
|
||||
$has_typing_animation = 'yes' === $this->settings['chat_button_show_animation'];
|
||||
?>
|
||||
<?php if ( $has_typing_animation ) { ?>
|
||||
<div class="e-contact-buttons__dots-container">
|
||||
<span class="e-contact-buttons__dot e-contact-buttons__dot-1"></span>
|
||||
<span class="e-contact-buttons__dot e-contact-buttons__dot-2"></span>
|
||||
<span class="e-contact-buttons__dot e-contact-buttons__dot-3"></span>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function render_message_bubble_container(): void {
|
||||
$message_bubble_name = $this->settings['message_bubble_name'] ?? '';
|
||||
$message_bubble_body = $this->settings['message_bubble_body'] ?? '';
|
||||
$has_message_bubble_name = ! empty( $message_bubble_name );
|
||||
$has_message_bubble_body = ! empty( $message_bubble_body );
|
||||
$time_format = $this->settings['chat_button_time_format'];
|
||||
?>
|
||||
<div class="e-contact-buttons__bubble-container">
|
||||
<div class="e-contact-buttons__bubble">
|
||||
<?php if ( $has_message_bubble_name ) { ?>
|
||||
<p class="e-contact-buttons__message-bubble-name"><?php echo esc_html( $message_bubble_name ); ?></p>
|
||||
<?php } ?>
|
||||
<?php if ( $has_message_bubble_body ) { ?>
|
||||
<p class="e-contact-buttons__message-bubble-body"><?php echo esc_html( $message_bubble_body ); ?></p>
|
||||
<?php } ?>
|
||||
<p class="e-contact-buttons__message-bubble-time" data-time-format="<?php echo esc_attr( $time_format ); ?>"></p>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function render_message_bubble_powered_by(): void {
|
||||
if ( Utils::has_pro() ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<div class="e-contact-buttons__powered-container">
|
||||
<p class="e-contact-buttons__powered-text">
|
||||
<?php echo esc_attr__( 'Powered by Elementor', 'elementor' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function render_message_bubble(): void {
|
||||
$message_bubble_classnames = 'e-contact-buttons__message-bubble';
|
||||
$show_animation = $this->settings['chat_button_show_animation'] ?? false;
|
||||
$has_typing_animation = $show_animation && 'yes' === $show_animation;
|
||||
|
||||
if ( $has_typing_animation ) {
|
||||
$message_bubble_classnames .= ' has-typing-animation';
|
||||
}
|
||||
|
||||
$this->widget->add_render_attribute( 'message-bubble', [
|
||||
'class' => $message_bubble_classnames,
|
||||
] );
|
||||
?>
|
||||
<div <?php echo $this->widget->get_render_attribute_string( 'message-bubble' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
||||
<?php
|
||||
$this->render_message_bubble_typing_animation();
|
||||
$this->render_message_bubble_container();
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function render_contact_text(): void {
|
||||
$contact_cta_text = $this->settings['contact_cta_text'] ?? '';
|
||||
?>
|
||||
<?php if ( ! empty( $contact_cta_text ) ) { ?>
|
||||
<p class="e-contact-buttons__contact-text"><?php echo esc_html( $contact_cta_text ); ?></p>
|
||||
<?php } ?>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function render_contact_links(): void {
|
||||
$contact_icons = $this->settings['contact_repeater'] ?? [];
|
||||
$icons_size = $this->settings['style_contact_button_size'] ?? 'small';
|
||||
$hover_animation = $this->settings['style_contact_button_hover_animation'];
|
||||
?>
|
||||
<div class="e-contact-buttons__contact-links">
|
||||
<?php
|
||||
foreach ( $contact_icons as $key => $icon ) {
|
||||
|
||||
$link = [
|
||||
'platform' => $icon['contact_icon_platform'],
|
||||
'number' => $icon['contact_icon_number'] ?? '',
|
||||
'username' => $icon['contact_icon_username'] ?? '',
|
||||
'email_data' => [
|
||||
'contact_icon_mail' => $icon['contact_icon_mail'] ?? '',
|
||||
'contact_icon_mail_subject' => $icon['contact_icon_mail_subject'] ?? '',
|
||||
'contact_icon_mail_body' => $icon['contact_icon_mail_body'] ?? '',
|
||||
],
|
||||
'viber_action' => $icon['contact_icon_viber_action'] ?? '',
|
||||
];
|
||||
|
||||
$formatted_link = $this->get_formatted_link( $link, 'contact_icon' );
|
||||
|
||||
$icon_classnames = 'e-contact-buttons__contact-icon-link has-size-' . $icons_size;
|
||||
|
||||
if ( ! empty( $hover_animation ) ) {
|
||||
$icon_classnames .= ' elementor-animation-' . $hover_animation;
|
||||
}
|
||||
|
||||
$this->widget->add_render_attribute( 'icon-link-' . $key, [
|
||||
'aria-label' => esc_attr( $icon['contact_icon_platform'] ),
|
||||
'class' => $icon_classnames,
|
||||
'href' => $formatted_link,
|
||||
'rel' => 'noopener noreferrer',
|
||||
'target' => '_blank',
|
||||
] );
|
||||
|
||||
?>
|
||||
|
||||
<a <?php echo $this->widget->get_render_attribute_string( 'icon-link-' . $key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
||||
<?php
|
||||
$mapping = Social_Network_Provider::get_icon_mapping( $icon['contact_icon_platform'] );
|
||||
$icon_lib = explode( ' ', $mapping )[0];
|
||||
$library = 'fab' === $icon_lib ? 'fa-brands' : 'fa-solid';
|
||||
Icons_Manager::render_icon(
|
||||
[
|
||||
'library' => $library,
|
||||
'value' => $mapping,
|
||||
],
|
||||
[ 'aria-hidden' => 'true' ]
|
||||
);
|
||||
?>
|
||||
</a>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function render_contact_section(): void {
|
||||
?>
|
||||
<div class="e-contact-buttons__contact">
|
||||
<?php
|
||||
$this->render_contact_text();
|
||||
$this->render_contact_links();
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function render_send_button(): void {
|
||||
$platform = $this->settings['chat_button_platform'] ?? '';
|
||||
$send_button_text = $this->settings['send_button_text'];
|
||||
$hover_animation = $this->settings['style_send_hover_animation'];
|
||||
$cta_classnames = 'e-contact-buttons__send-cta';
|
||||
|
||||
$link = [
|
||||
'platform' => $platform,
|
||||
'number' => $this->settings['chat_button_number'] ?? '',
|
||||
'username' => $this->settings['chat_button_username'] ?? '',
|
||||
'email_data' => [
|
||||
'chat_button_mail' => $this->settings['chat_button_mail'],
|
||||
'chat_button_mail_subject' => $this->settings['chat_button_mail_subject'] ?? '',
|
||||
'chat_button_mail_body' => $this->settings['chat_button_mail_body'] ?? '',
|
||||
],
|
||||
'viber_action' => $this->settings['chat_button_viber_action'],
|
||||
];
|
||||
|
||||
$formatted_link = $this->get_formatted_link( $link, 'chat_button' );
|
||||
|
||||
if ( ! empty( $hover_animation ) ) {
|
||||
$cta_classnames .= ' elementor-animation-' . $hover_animation;
|
||||
}
|
||||
|
||||
$this->widget->add_render_attribute( 'formatted-cta', [
|
||||
'class' => $cta_classnames,
|
||||
'href' => $formatted_link,
|
||||
'rel' => 'noopener noreferrer',
|
||||
'target' => '_blank',
|
||||
] );
|
||||
|
||||
?>
|
||||
<div class="e-contact-buttons__send-button">
|
||||
<?php $this->render_message_bubble_powered_by(); ?>
|
||||
<div class="e-contact-buttons__send-button-container">
|
||||
<?php if ( $send_button_text ) { ?>
|
||||
<a <?php echo $this->widget->get_render_attribute_string( 'formatted-cta' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
||||
<?php
|
||||
$mapping = Social_Network_Provider::get_icon_mapping( $platform );
|
||||
$icon_lib = explode( ' ', $mapping )[0];
|
||||
$library = 'fab' === $icon_lib ? 'fa-brands' : 'fa-solid';
|
||||
Icons_Manager::render_icon(
|
||||
[
|
||||
'library' => $library,
|
||||
'value' => $mapping,
|
||||
],
|
||||
[ 'aria-hidden' => 'true' ]
|
||||
);
|
||||
?>
|
||||
<?php echo esc_html( $send_button_text ); ?>
|
||||
</a>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function get_formatted_link( array $link, string $prefix ): string {
|
||||
|
||||
// Ensure we clear the default link value if the matching type value is empty
|
||||
switch ( $link['platform'] ) {
|
||||
case Social_Network_Provider::EMAIL:
|
||||
$formatted_link = Social_Network_Provider::build_email_link( $link['email_data'], $prefix );
|
||||
break;
|
||||
case Social_Network_Provider::SMS:
|
||||
$formatted_link = ! empty( $link['number'] ) ? 'sms:' . $link['number'] : '';
|
||||
break;
|
||||
case Social_Network_Provider::MESSENGER:
|
||||
$formatted_link = ! empty( $link['username'] ) ?
|
||||
Social_Network_Provider::build_messenger_link( $link['username'] ) :
|
||||
'';
|
||||
break;
|
||||
case Social_Network_Provider::WHATSAPP:
|
||||
$formatted_link = ! empty( $link['number'] ) ? 'https://wa.me/' . $link['number'] : '';
|
||||
break;
|
||||
case Social_Network_Provider::VIBER:
|
||||
$formatted_link = Social_Network_Provider::build_viber_link( $link['viber_action'], $link['number'] );
|
||||
break;
|
||||
case Social_Network_Provider::SKYPE:
|
||||
$formatted_link = ! empty( $link['username'] ) ? 'skype:' . $link['username'] . '?chat' : '';
|
||||
break;
|
||||
case Social_Network_Provider::TELEPHONE:
|
||||
$formatted_link = ! empty( $link['number'] ) ? 'tel:' . $link['number'] : '';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return esc_html( $formatted_link );
|
||||
}
|
||||
|
||||
protected function is_url_link( string $platform ): bool {
|
||||
return Social_Network_Provider::URL === $platform || Social_Network_Provider::WAZE === $platform;
|
||||
}
|
||||
|
||||
protected function render_link_attributes( array $link, string $key ) {
|
||||
switch ( $link['platform'] ) {
|
||||
case Social_Network_Provider::WAZE:
|
||||
if ( empty( $link['location']['url'] ) ) {
|
||||
$link['location']['url'] = '#';
|
||||
}
|
||||
|
||||
$this->widget->add_link_attributes( $key, $link['location'] );
|
||||
break;
|
||||
case Social_Network_Provider::URL:
|
||||
if ( empty( $link['url']['url'] ) ) {
|
||||
$link['url']['url'] = '#';
|
||||
}
|
||||
|
||||
$this->widget->add_link_attributes( $key, $link['url'] );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function build_layout_render_attribute(): void {
|
||||
$layout_classnames = 'e-contact-buttons e-' . $this->widget->get_name();
|
||||
$platform = $this->settings['chat_button_platform'] ?? '';
|
||||
$border_radius = $this->settings['style_chat_box_corners'];
|
||||
$alignment_position_horizontal = $this->settings['advanced_horizontal_position'];
|
||||
$alignment_position_vertical = $this->settings['advanced_vertical_position'];
|
||||
$has_animations = ! empty( $this->settings['style_chat_box_exit_animation'] ) || ! empty( $this->settings['style_chat_box_entrance_animation'] );
|
||||
$custom_classes = $this->settings['advanced_custom_css_classes'] ?? '';
|
||||
|
||||
$icon_name_mapping = Social_Network_Provider::get_name_mapping( $platform );
|
||||
|
||||
if ( ! empty( $platform ) ) {
|
||||
$layout_classnames .= ' has-platform-' . $icon_name_mapping;
|
||||
}
|
||||
|
||||
if ( ! empty( $border_radius ) ) {
|
||||
$layout_classnames .= ' has-corners-' . $border_radius;
|
||||
}
|
||||
|
||||
if ( ! empty( $alignment_position_horizontal ) ) {
|
||||
$layout_classnames .= ' has-h-alignment-' . $alignment_position_horizontal;
|
||||
}
|
||||
|
||||
if ( ! empty( $alignment_position_vertical ) ) {
|
||||
$layout_classnames .= ' has-v-alignment-' . $alignment_position_vertical;
|
||||
}
|
||||
|
||||
if ( $has_animations ) {
|
||||
$layout_classnames .= ' has-animations';
|
||||
}
|
||||
|
||||
if ( $custom_classes ) {
|
||||
$layout_classnames .= ' ' . $custom_classes;
|
||||
}
|
||||
|
||||
$this->add_layout_render_attribute( $layout_classnames );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\FloatingButtons\Control;
|
||||
|
||||
use Elementor\Control_Hover_Animation;
|
||||
|
||||
class Hover_Animation_Floating_Buttons extends Control_Hover_Animation {
|
||||
|
||||
const TYPE = 'hover_animation_contact_buttons';
|
||||
|
||||
public function get_type() {
|
||||
return static::TYPE;
|
||||
}
|
||||
|
||||
public static function get_animations() {
|
||||
return [
|
||||
'grow' => 'Grow',
|
||||
'pulse' => 'Pulse',
|
||||
'push' => 'Push',
|
||||
'float' => 'Float',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\FloatingButtons\Documents;
|
||||
|
||||
use Elementor\Core\DocumentTypes\PageBase;
|
||||
use Elementor\Modules\Library\Traits\Library as Library_Trait;
|
||||
use Elementor\Modules\FloatingButtons\Module as Floating_Buttons_Module;
|
||||
use Elementor\Modules\PageTemplates\Module as Page_Templates_Module;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Floating_Buttons extends PageBase {
|
||||
use Library_Trait;
|
||||
|
||||
public static function get_properties() {
|
||||
$properties = parent::get_properties();
|
||||
|
||||
$properties['support_kit'] = true;
|
||||
$properties['support_site_editor'] = false;
|
||||
$properties['cpt'] = [ Floating_Buttons_Module::CPT_FLOATING_BUTTONS ];
|
||||
$properties['show_navigator'] = false;
|
||||
$properties['allow_adding_widgets'] = false;
|
||||
$properties['support_page_layout'] = false;
|
||||
$properties['library_close_title'] = esc_html__( 'Go To Dashboard', 'elementor' );
|
||||
$properties['publish_button_title'] = esc_html__( 'After publishing this widget, you will be able to set it as visible on the entire site in the Admin Table.', 'elementor' );
|
||||
$properties['allow_closing_remote_library'] = false;
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
public function print_content() {
|
||||
$plugin = \Elementor\Plugin::$instance;
|
||||
|
||||
if ( $plugin->preview->is_preview_mode( $this->get_main_id() ) ) {
|
||||
// PHPCS - the method builder_wrapper is safe.
|
||||
echo $plugin->preview->builder_wrapper( '' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
} else {
|
||||
// PHPCS - the method get_content is safe.
|
||||
echo $this->get_content(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
|
||||
public function get_location() {
|
||||
return self::get_property( 'location' );
|
||||
}
|
||||
|
||||
public static function get_type() {
|
||||
return Floating_Buttons_Module::FLOATING_BUTTONS_DOCUMENT_TYPE;
|
||||
}
|
||||
|
||||
public static function register_post_fields_control( $document ) {}
|
||||
|
||||
public static function register_hide_title_control( $document ) {}
|
||||
|
||||
public function get_name() {
|
||||
return Floating_Buttons_Module::FLOATING_BUTTONS_DOCUMENT_TYPE;
|
||||
}
|
||||
|
||||
public function filter_admin_row_actions( $actions ) {
|
||||
unset( $actions['edit'] );
|
||||
unset( $actions['inline hide-if-no-js'] );
|
||||
$built_with_elementor = parent::filter_admin_row_actions( [] );
|
||||
|
||||
if ( isset( $actions['trash'] ) ) {
|
||||
$delete = $actions['trash'];
|
||||
unset( $actions['trash'] );
|
||||
$actions['trash'] = $delete;
|
||||
}
|
||||
|
||||
if ( 'publish' === $this->get_post()->post_status ) {
|
||||
$actions = $this->set_as_entire_site( $actions );
|
||||
}
|
||||
|
||||
return $built_with_elementor + $actions;
|
||||
}
|
||||
|
||||
public function set_as_entire_site( $actions ) {
|
||||
if ( get_post_meta( $this->get_post()->ID, '_elementor_conditions', true ) ) {
|
||||
$actions['set_as_entire_site'] = sprintf(
|
||||
'<a style="color:red;" href="?post=%s&action=remove_from_entire_site&_wpnonce=%s">%s</a>',
|
||||
$this->get_post()->ID,
|
||||
wp_create_nonce( 'remove_from_entire_site_' . $this->get_post()->ID ),
|
||||
esc_html__( 'Remove From Entire Site', 'elementor' )
|
||||
);
|
||||
} else {
|
||||
$actions['set_as_entire_site'] = sprintf(
|
||||
'<a href="?post=%s&action=set_as_entire_site&_wpnonce=%s">%s</a>',
|
||||
$this->get_post()->ID,
|
||||
wp_create_nonce( 'set_as_entire_site_' . $this->get_post()->ID ),
|
||||
esc_html__( 'Set as Entire Site', 'elementor' )
|
||||
);
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
public static function get_title() {
|
||||
return esc_html__( 'Floating Button', 'elementor' );
|
||||
}
|
||||
|
||||
public static function get_plural_title() {
|
||||
return esc_html__( 'Floating Buttons', 'elementor' );
|
||||
}
|
||||
|
||||
public static function get_create_url() {
|
||||
return parent::get_create_url() . '#library';
|
||||
}
|
||||
|
||||
public function save( $data ) {
|
||||
if ( empty( $data['settings']['template'] ) ) {
|
||||
$data['settings']['template'] = Page_Templates_Module::TEMPLATE_CANVAS;
|
||||
}
|
||||
|
||||
return parent::save( $data );
|
||||
}
|
||||
|
||||
public function admin_columns_content( $column_name ) {
|
||||
if ( 'elementor_library_type' === $column_name ) {
|
||||
$this->print_admin_column_type();
|
||||
}
|
||||
}
|
||||
|
||||
public function get_edit_url() {
|
||||
$url = parent::get_edit_url();
|
||||
|
||||
if ( ! $this->get_post()->post_content ) {
|
||||
$url .= '#library';
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
protected function get_remote_library_config() {
|
||||
$config = [
|
||||
'type' => 'floating_button',
|
||||
'default_route' => 'templates/floating-buttons',
|
||||
'autoImportSettings' => true,
|
||||
];
|
||||
|
||||
return array_replace_recursive( parent::get_remote_library_config(), $config );
|
||||
}
|
||||
}
|
||||
540
wp-content/plugins/elementor/modules/floating-buttons/module.php
Normal file
540
wp-content/plugins/elementor/modules/floating-buttons/module.php
Normal file
@@ -0,0 +1,540 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\FloatingButtons;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use Elementor\Core\Admin\Menu\Admin_Menu_Manager;
|
||||
use Elementor\Core\Base\Document;
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Core\Documents_Manager;
|
||||
use Elementor\Core\Experiments\Manager;
|
||||
use Elementor\Modules\FloatingButtons\AdminMenuItems\Floating_Buttons_Empty_View_Menu_Item;
|
||||
use Elementor\Modules\FloatingButtons\AdminMenuItems\Floating_Buttons_Menu_Item;
|
||||
use Elementor\Modules\FloatingButtons\Base\Widget_Contact_Button_Base;
|
||||
use Elementor\Modules\FloatingButtons\Control\Hover_Animation_Floating_Buttons;
|
||||
use Elementor\Modules\FloatingButtons\Documents\Floating_Buttons;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\TemplateLibrary\Source_Local;
|
||||
use Elementor\Utils as ElementorUtils;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
const EXPERIMENT_NAME = 'floating-buttons';
|
||||
|
||||
const ROUTER_VERSION = '1.0.0';
|
||||
const ROUTER_OPTION_KEY = 'elementor_floating_buttons_router_version';
|
||||
|
||||
const META_CLICK_TRACKING = '_elementor_click_tracking';
|
||||
|
||||
const CLICK_TRACKING_NONCE = 'elementor-conversion-center-click';
|
||||
|
||||
const FLOATING_BUTTONS_DOCUMENT_TYPE = 'floating-buttons';
|
||||
const CPT_FLOATING_BUTTONS = 'e-floating-buttons';
|
||||
const ADMIN_PAGE_SLUG_CONTACT = 'edit.php?post_type=e-floating-buttons';
|
||||
|
||||
private $has_contact_pages = null;
|
||||
private $trashed_contact_pages;
|
||||
|
||||
public static function is_active(): bool {
|
||||
return Plugin::$instance->experiments->is_feature_active( static::EXPERIMENT_NAME );
|
||||
}
|
||||
|
||||
public function get_name(): string {
|
||||
return static::EXPERIMENT_NAME;
|
||||
}
|
||||
|
||||
public function get_widgets(): array {
|
||||
return [
|
||||
'Contact_Buttons',
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_experimental_data(): array {
|
||||
return [
|
||||
'name' => static::EXPERIMENT_NAME,
|
||||
'title' => esc_html__( 'Floating Buttons', 'elementor' ),
|
||||
'description' => esc_html__( 'Boost visitor engagement with Floating Buttons. The Floating Button template library offers a variety of interactive one-click contact options, highlighted links, and calls to action to increase your website conversions.', 'elementor' ),
|
||||
'default' => Manager::STATE_INACTIVE,
|
||||
'release_status' => Manager::RELEASE_STATUS_BETA,
|
||||
'dependencies' => [
|
||||
'container',
|
||||
],
|
||||
'new_site' => [
|
||||
'default_active' => true,
|
||||
'minimum_installation_version' => '3.23.0',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function register_admin_menu_legacy( Admin_Menu_Manager $admin_menu ) {
|
||||
$menu_args = $this->get_contact_menu_args();
|
||||
$function = $menu_args['function'];
|
||||
if ( is_callable( $function ) ) {
|
||||
$admin_menu->register( $menu_args['menu_slug'], new Floating_Buttons_Empty_View_Menu_Item( $function ) );
|
||||
} else {
|
||||
$admin_menu->register( $menu_args['menu_slug'], new Floating_Buttons_Menu_Item() );
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
if ( $this->is_editing_existing_floating_buttons_page() || $this->is_creating_floating_buttons_page() ) {
|
||||
Controls_Manager::add_tab(
|
||||
Widget_Contact_Button_Base::TAB_ADVANCED,
|
||||
esc_html__( 'Advanced', 'elementor' )
|
||||
);
|
||||
}
|
||||
|
||||
$this->register_contact_pages_cpt();
|
||||
|
||||
if ( ! ElementorUtils::has_pro() ) {
|
||||
add_action( 'elementor/documents/register', function ( Documents_Manager $documents_manager ) {
|
||||
$documents_manager->register_document_type(
|
||||
static::FLOATING_BUTTONS_DOCUMENT_TYPE,
|
||||
Floating_Buttons::get_class_full_name()
|
||||
);
|
||||
} );
|
||||
}
|
||||
|
||||
add_action( 'save_post_' . static::CPT_FLOATING_BUTTONS, [ $this, 'flush_permalinks_on_save' ] );
|
||||
|
||||
add_action( 'wp_ajax_elementor_send_clicks', [ $this, 'handle_click_tracking' ] );
|
||||
add_action( 'wp_ajax_nopriv_elementor_send_clicks', [ $this, 'handle_click_tracking' ] );
|
||||
|
||||
add_action( 'elementor/controls/register', function ( Controls_Manager $controls_manager ) {
|
||||
$controls_manager->register( new Hover_Animation_Floating_Buttons() );
|
||||
});
|
||||
|
||||
add_filter( 'elementor/widget/common/register_css_attributes_control', function ( $common_controls ) {
|
||||
if ( $this->is_creating_floating_buttons_page() || $this->is_editing_existing_floating_buttons_page() ) {
|
||||
return false;
|
||||
}
|
||||
return $common_controls;
|
||||
} );
|
||||
|
||||
add_filter(
|
||||
'elementor/template_library/sources/local/is_valid_template_type',
|
||||
function ( $is_valid_template_type, $cpt ) {
|
||||
|
||||
if ( in_array( static::CPT_FLOATING_BUTTONS, $cpt, true ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $is_valid_template_type;
|
||||
},
|
||||
10,
|
||||
2
|
||||
);
|
||||
|
||||
if ( ! ElementorUtils::has_pro() ) {
|
||||
add_action( 'wp_footer', function () {
|
||||
$this->render_floating_buttons();
|
||||
} );
|
||||
}
|
||||
|
||||
add_action( 'elementor/admin-top-bar/is-active', function ( $is_top_bar_active, $current_screen ) {
|
||||
|
||||
if ( strpos( $current_screen->id ?? '', static::CPT_FLOATING_BUTTONS ) !== false ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $is_top_bar_active;
|
||||
}, 10, 2 );
|
||||
|
||||
add_action( 'elementor/admin/menu/register', function( Admin_Menu_Manager $admin_menu ) {
|
||||
$this->register_admin_menu_legacy( $admin_menu );
|
||||
}, Source_Local::ADMIN_MENU_PRIORITY + 20 );
|
||||
|
||||
add_action( 'elementor/admin/localize_settings', function ( array $settings ) {
|
||||
return $this->admin_localize_settings( $settings );
|
||||
} );
|
||||
|
||||
add_action( 'elementor/editor/localize_settings', function ( $data ) {
|
||||
return $this->editor_localize_settings( $data );
|
||||
} );
|
||||
|
||||
add_filter( 'elementor/template_library/sources/local/register_taxonomy_cpts', function ( array $cpts ) {
|
||||
$cpts[] = static::CPT_FLOATING_BUTTONS;
|
||||
|
||||
return $cpts;
|
||||
} );
|
||||
|
||||
add_action( 'admin_init', function () {
|
||||
$action = filter_input( INPUT_GET, 'action' );
|
||||
$menu_args = $this->get_contact_menu_args();
|
||||
|
||||
switch ( $action ) {
|
||||
case 'remove_from_entire_site':
|
||||
$post = filter_input( INPUT_GET, 'post', FILTER_VALIDATE_INT );
|
||||
check_admin_referer( 'remove_from_entire_site_' . $post );
|
||||
delete_post_meta( $post, '_elementor_conditions' );
|
||||
wp_redirect( $menu_args['menu_slug'] );
|
||||
exit;
|
||||
case 'set_as_entire_site':
|
||||
$post = filter_input( INPUT_GET, 'post', FILTER_VALIDATE_INT );
|
||||
check_admin_referer( 'set_as_entire_site_' . $post );
|
||||
|
||||
$posts = get_posts( [
|
||||
'post_type' => static::CPT_FLOATING_BUTTONS,
|
||||
'posts_per_page' => -1,
|
||||
'post_status' => 'publish',
|
||||
'fields' => 'ids',
|
||||
'meta_key' => '_elementor_conditions',
|
||||
'meta_compare' => 'EXISTS',
|
||||
] );
|
||||
|
||||
foreach ( $posts as $post_id ) {
|
||||
delete_post_meta( $post_id, '_elementor_conditions' );
|
||||
}
|
||||
|
||||
update_post_meta( $post, '_elementor_conditions', [ 'include/general' ] );
|
||||
|
||||
wp_redirect( $menu_args['menu_slug'] );
|
||||
exit;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} );
|
||||
|
||||
add_action( 'manage_' . static::CPT_FLOATING_BUTTONS . '_posts_columns', function( $posts_columns ) {
|
||||
$source_local = Plugin::$instance->templates_manager->get_source( 'local' );
|
||||
unset( $posts_columns['date'] );
|
||||
unset( $posts_columns['comments'] );
|
||||
$posts_columns['click_tracking'] = esc_html__( 'Click Tracking', 'elementor' );
|
||||
|
||||
if ( ! ElementorUtils::has_pro() ) {
|
||||
$posts_columns['instances'] = esc_html__( 'Instances', 'elementor' );
|
||||
}
|
||||
|
||||
return $source_local->admin_columns_headers( $posts_columns );
|
||||
} );
|
||||
|
||||
add_action(
|
||||
'manage_' . static::CPT_FLOATING_BUTTONS . '_posts_custom_column',
|
||||
[ $this, 'set_admin_columns_content' ],
|
||||
10,
|
||||
2
|
||||
);
|
||||
|
||||
add_action( 'admin_bar_menu', function ( $admin_bar ) {
|
||||
|
||||
$this->override_admin_bar_add_contact( $admin_bar );
|
||||
}, 100 );
|
||||
}
|
||||
|
||||
public function handle_click_tracking() {
|
||||
$data = filter_input_array( INPUT_POST, [
|
||||
'clicks' => [
|
||||
'filter' => FILTER_VALIDATE_INT,
|
||||
'flags' => FILTER_REQUIRE_ARRAY,
|
||||
],
|
||||
'_nonce' => FILTER_UNSAFE_RAW,
|
||||
] );
|
||||
|
||||
if ( ! wp_verify_nonce( $data['_nonce'], static::CLICK_TRACKING_NONCE ) ) {
|
||||
wp_send_json_error( [ 'message' => 'Invalid nonce' ] );
|
||||
}
|
||||
|
||||
if ( ! check_ajax_referer( static::CLICK_TRACKING_NONCE, '_nonce', false ) ) {
|
||||
wp_send_json_error( [ 'message' => 'Invalid referrer' ] );
|
||||
}
|
||||
|
||||
$posts_to_update = [];
|
||||
|
||||
foreach ( $data['clicks'] as $post_id ) {
|
||||
if ( ! isset( $posts_to_update[ $post_id ] ) ) {
|
||||
$starting_clicks = (int) get_post_meta( $post_id, static::META_CLICK_TRACKING, true );
|
||||
$posts_to_update[ $post_id ] = $starting_clicks ? $starting_clicks : 0;
|
||||
}
|
||||
$posts_to_update[ $post_id ] ++;
|
||||
}
|
||||
|
||||
foreach ( $posts_to_update as $post_id => $clicks ) {
|
||||
update_post_meta( $post_id, static::META_CLICK_TRACKING, $clicks );
|
||||
}
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
public function set_admin_columns_content( $column_name, $post_id ) {
|
||||
$document = Plugin::$instance->documents->get( $post_id );
|
||||
|
||||
if ( method_exists( $document, 'admin_columns_content' ) ) {
|
||||
$document->admin_columns_content( $column_name );
|
||||
}
|
||||
|
||||
switch ( $column_name ) {
|
||||
case 'click_tracking':
|
||||
$click_tracking = get_post_meta( $post_id, static::META_CLICK_TRACKING, true );
|
||||
echo esc_html( $click_tracking );
|
||||
break;
|
||||
case 'instances':
|
||||
if ( ElementorUtils::has_pro() ) {
|
||||
break;
|
||||
}
|
||||
$instances = get_post_meta( $post_id, '_elementor_conditions', true );
|
||||
if ( $instances ) {
|
||||
echo esc_html__( 'Entire Site', 'elementor' );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function flush_permalinks_on_save() {
|
||||
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( get_option( static::ROUTER_OPTION_KEY ) !== static::ROUTER_VERSION ) {
|
||||
flush_rewrite_rules();
|
||||
update_option( static::ROUTER_OPTION_KEY, static::ROUTER_VERSION );
|
||||
}
|
||||
}
|
||||
|
||||
private function get_trashed_contact_posts(): array {
|
||||
if ( $this->trashed_contact_pages ) {
|
||||
return $this->trashed_contact_pages;
|
||||
}
|
||||
|
||||
$this->trashed_contact_pages = $this->get_trashed_posts(
|
||||
static::CPT_FLOATING_BUTTONS,
|
||||
static::FLOATING_BUTTONS_DOCUMENT_TYPE
|
||||
);
|
||||
|
||||
return $this->trashed_contact_pages;
|
||||
}
|
||||
|
||||
private function get_trashed_posts( string $cpt, string $document_type ) {
|
||||
$query = new \WP_Query( [
|
||||
'no_found_rows' => true,
|
||||
'post_type' => $cpt,
|
||||
'post_status' => 'trash',
|
||||
'posts_per_page' => 1,
|
||||
'meta_key' => '_elementor_template_type',
|
||||
'meta_value' => $document_type,
|
||||
] );
|
||||
|
||||
return $query->posts;
|
||||
}
|
||||
|
||||
private function get_add_new_contact_page_url() {
|
||||
if ( ElementorUtils::has_pro() ) {
|
||||
return Plugin::$instance->documents->get_create_new_post_url(
|
||||
static::CPT_FLOATING_BUTTONS,
|
||||
static::FLOATING_BUTTONS_DOCUMENT_TYPE
|
||||
);
|
||||
}
|
||||
|
||||
return Plugin::$instance->documents->get_create_new_post_url(
|
||||
static::CPT_FLOATING_BUTTONS,
|
||||
static::FLOATING_BUTTONS_DOCUMENT_TYPE
|
||||
) . '#library';
|
||||
}
|
||||
|
||||
public function print_empty_contact_pages_page() {
|
||||
$template_sources = Plugin::$instance->templates_manager->get_registered_sources();
|
||||
$source_local = $template_sources['local'];
|
||||
$trashed_posts = $this->get_trashed_contact_posts();
|
||||
|
||||
?>
|
||||
<div class="e-landing-pages-empty">
|
||||
<?php
|
||||
/** @var Source_Local $source_local */
|
||||
$source_local->print_blank_state_template(
|
||||
esc_html__( 'Floating Button', 'elementor' ),
|
||||
$this->get_add_new_contact_page_url(),
|
||||
nl2br( esc_html__( 'Add a Floating button so your users can easily get in touch!', 'elementor' ) )
|
||||
);
|
||||
|
||||
if ( ! empty( $trashed_posts ) ) : ?>
|
||||
<div class="e-trashed-items">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %1$s Link open tag, %2$s: Link close tag. */
|
||||
esc_html__( 'Or view %1$sTrashed Items%1$s', 'elementor' ),
|
||||
'<a href="' . esc_url( admin_url( 'edit.php?post_status=trash&post_type=' . self::CPT_FLOATING_BUTTONS ) ) . '">',
|
||||
'</a>'
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
private function admin_localize_settings( $settings ) {
|
||||
$contact_menu_slug = $this->get_contact_menu_args()['menu_slug'];
|
||||
|
||||
if ( static::CPT_FLOATING_BUTTONS === $contact_menu_slug ) {
|
||||
$contact_menu_slug = 'admin.php?page=' . $contact_menu_slug;
|
||||
}
|
||||
|
||||
$additional_settings = [
|
||||
'urls' => [
|
||||
'addNewLinkUrlContact' => $this->get_add_new_contact_page_url(),
|
||||
'viewContactPageUrl' => $contact_menu_slug,
|
||||
],
|
||||
'contactPages' => [
|
||||
'hasPages' => $this->has_contact_pages(),
|
||||
],
|
||||
];
|
||||
|
||||
return array_replace_recursive( $settings, $additional_settings );
|
||||
}
|
||||
|
||||
private function register_contact_pages_cpt() {
|
||||
$this->register_post_type(
|
||||
Floating_Buttons::get_labels(),
|
||||
static::CPT_FLOATING_BUTTONS
|
||||
);
|
||||
}
|
||||
|
||||
private function is_editing_existing_floating_buttons_page() {
|
||||
$action = ElementorUtils::get_super_global_value( $_GET, 'action' );
|
||||
$post_id = ElementorUtils::get_super_global_value( $_GET, 'post' );
|
||||
|
||||
return 'elementor' === $action && $this->is_floating_buttons_type_meta_key( $post_id );
|
||||
}
|
||||
|
||||
private function is_creating_floating_buttons_page() {
|
||||
$action = ElementorUtils::get_super_global_value( $_POST, 'action' ); //phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
$post_id = ElementorUtils::get_super_global_value( $_POST, 'editor_post_id' ); //phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
|
||||
return 'elementor_ajax' === $action && $this->is_floating_buttons_type_meta_key( $post_id );
|
||||
}
|
||||
|
||||
private function is_floating_buttons_type_meta_key( $post_id ) {
|
||||
return static::FLOATING_BUTTONS_DOCUMENT_TYPE === get_post_meta( $post_id, Document::TYPE_META_KEY, true );
|
||||
}
|
||||
|
||||
private function register_post_type( array $labels, string $cpt ) {
|
||||
$args = [
|
||||
'labels' => $labels,
|
||||
'public' => true,
|
||||
'show_in_menu' => 'edit.php?post_type=elementor_library&tabs_group=library',
|
||||
'capability_type' => 'page',
|
||||
'taxonomies' => [ Source_Local::TAXONOMY_TYPE_SLUG ],
|
||||
'supports' => [
|
||||
'title',
|
||||
'editor',
|
||||
'comments',
|
||||
'revisions',
|
||||
'trackbacks',
|
||||
'author',
|
||||
'excerpt',
|
||||
'page-attributes',
|
||||
'thumbnail',
|
||||
'custom-fields',
|
||||
'post-formats',
|
||||
'elementor',
|
||||
],
|
||||
];
|
||||
|
||||
register_post_type( $cpt, $args );
|
||||
}
|
||||
|
||||
private function has_contact_pages(): bool {
|
||||
if ( null !== $this->has_contact_pages ) {
|
||||
return $this->has_contact_pages;
|
||||
}
|
||||
|
||||
$this->has_contact_pages = $this->has_pages(
|
||||
static::CPT_FLOATING_BUTTONS,
|
||||
static::FLOATING_BUTTONS_DOCUMENT_TYPE
|
||||
);
|
||||
|
||||
return $this->has_contact_pages;
|
||||
}
|
||||
|
||||
private function has_pages( string $cpt, string $document_type ): bool {
|
||||
$posts_query = new \WP_Query( [
|
||||
'no_found_rows' => true,
|
||||
'post_type' => $cpt,
|
||||
'post_status' => 'any',
|
||||
'posts_per_page' => 1,
|
||||
'meta_key' => '_elementor_template_type',
|
||||
'meta_value' => $document_type,
|
||||
] );
|
||||
|
||||
return $posts_query->post_count > 0;
|
||||
|
||||
}
|
||||
|
||||
private function get_contact_menu_args(): array {
|
||||
if ( $this->has_contact_pages() ) {
|
||||
$menu_slug = static::ADMIN_PAGE_SLUG_CONTACT;
|
||||
$function = null;
|
||||
} else {
|
||||
$menu_slug = static::CPT_FLOATING_BUTTONS;
|
||||
$function = [ $this, 'print_empty_contact_pages_page' ];
|
||||
}
|
||||
|
||||
return [
|
||||
'menu_slug' => $menu_slug,
|
||||
'function' => $function,
|
||||
];
|
||||
}
|
||||
|
||||
public function override_admin_bar_add_contact( $admin_bar ): void {
|
||||
$new_contact_page_node = $admin_bar->get_node( 'new-e-floating-buttons' );
|
||||
|
||||
if ( $new_contact_page_node ) {
|
||||
$new_contact_page_node->href = $this->get_add_new_contact_page_url();
|
||||
|
||||
$admin_bar->add_node( $new_contact_page_node );
|
||||
}
|
||||
}
|
||||
|
||||
private function editor_localize_settings( $data ) {
|
||||
$data['admin_floating_button_admin_url'] = admin_url( $this->get_contact_menu_args()['menu_slug'] );
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function render_floating_buttons(): void {
|
||||
if ( Plugin::$instance->preview->is_preview_mode() ) {
|
||||
$post_id = ElementorUtils::get_super_global_value( $_GET, 'elementor-preview' );
|
||||
$document = Plugin::$instance->documents->get( $post_id );
|
||||
|
||||
if (
|
||||
$document instanceof Document &&
|
||||
$document->get_name() === static::FLOATING_BUTTONS_DOCUMENT_TYPE
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$query = new \WP_Query( [
|
||||
'post_type' => static::CPT_FLOATING_BUTTONS,
|
||||
'posts_per_page' => - 1,
|
||||
'post_status' => 'publish',
|
||||
'fields' => 'ids',
|
||||
'meta_key' => '_elementor_conditions',
|
||||
'meta_compare' => 'EXISTS',
|
||||
] );
|
||||
|
||||
if ( ! $query->have_posts() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $query->posts as $post_id ) {
|
||||
$conditions = get_post_meta( $post_id, '_elementor_conditions', true );
|
||||
if ( ! $conditions ) {
|
||||
continue;
|
||||
}
|
||||
if ( in_array( 'include/general', $conditions ) ) {
|
||||
$document = Plugin::$instance->documents->get( $post_id );
|
||||
$document->print_content();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\FloatingButtons\Widgets;
|
||||
|
||||
use Elementor\Modules\FloatingButtons\Base\Widget_Contact_Button_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor Contact Buttons widget.
|
||||
*
|
||||
* Elementor widget that displays contact buttons and a chat-like prompt message.
|
||||
*
|
||||
* @since 3.23.0
|
||||
*/
|
||||
class Contact_Buttons extends Widget_Contact_Button_Base {
|
||||
|
||||
public function get_name(): string {
|
||||
return 'contact-buttons';
|
||||
}
|
||||
|
||||
public function get_title(): string {
|
||||
return esc_html__( 'Single Chat', 'elementor' );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\GeneratorTag;
|
||||
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Settings;
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
public function get_name() {
|
||||
return 'generator-tag';
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_action( 'wp_head', [ $this, 'render_generator_tag' ] );
|
||||
add_action( 'elementor/admin/after_create_settings/' . Settings::PAGE_ID, [ $this, 'register_admin_settings' ], 100 );
|
||||
}
|
||||
|
||||
public function render_generator_tag() {
|
||||
if ( '1' === get_option( 'elementor_meta_generator_tag' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$generator_content = $this->get_generator_content();
|
||||
|
||||
echo '<meta name="generator" content="' . esc_attr( $generator_content ) . '">' . PHP_EOL;
|
||||
}
|
||||
|
||||
private function get_generator_content(): string {
|
||||
$active_features = $this->get_active_features();
|
||||
$settings = $this->get_generator_tag_settings();
|
||||
|
||||
$tags = [
|
||||
'Elementor ' . ELEMENTOR_VERSION,
|
||||
];
|
||||
|
||||
if ( ! empty( $active_features ) ) {
|
||||
$tags[] = 'features: ' . implode( ', ', $active_features );
|
||||
}
|
||||
|
||||
if ( ! empty( $settings ) ) {
|
||||
$tags[] = 'settings: ' . implode( ', ', $settings );
|
||||
}
|
||||
|
||||
return implode( '; ', $tags );
|
||||
}
|
||||
|
||||
private function get_active_features(): array {
|
||||
$active_features = [];
|
||||
|
||||
foreach ( Plugin::$instance->experiments->get_active_features() as $feature_slug => $feature ) {
|
||||
if ( isset( $feature['generator_tag'] ) && $feature['generator_tag'] ) {
|
||||
$active_features[] = $feature_slug;
|
||||
}
|
||||
}
|
||||
|
||||
return $active_features;
|
||||
}
|
||||
|
||||
private function get_generator_tag_settings(): array {
|
||||
return apply_filters( 'elementor/generator_tag/settings', [] );
|
||||
}
|
||||
|
||||
public function register_admin_settings( Settings $settings ) {
|
||||
$settings->add_field(
|
||||
Settings::TAB_ADVANCED,
|
||||
Settings::TAB_ADVANCED,
|
||||
'meta_generator_tag',
|
||||
[
|
||||
'label' => esc_html__( 'Generator Tag', 'elementor' ),
|
||||
'field_args' => [
|
||||
'type' => 'select',
|
||||
'std' => '',
|
||||
'options' => [
|
||||
'' => esc_html__( 'Enable', 'elementor' ),
|
||||
'1' => esc_html__( 'Disable', 'elementor' ),
|
||||
],
|
||||
'desc' => esc_html__( 'A generator tag is a meta element that indicates the attributes used to create a webpage. It is used for analytical purposes.', 'elementor' ),
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
231
wp-content/plugins/elementor/modules/gutenberg/module.php
Normal file
231
wp-content/plugins/elementor/modules/gutenberg/module.php
Normal file
@@ -0,0 +1,231 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Gutenberg;
|
||||
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Core\Experiments\Manager as Experiments_Manager;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\User;
|
||||
use Elementor\Utils;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
protected $is_gutenberg_editor_active = false;
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'gutenberg';
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function is_active() {
|
||||
return function_exists( 'register_block_type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function register_elementor_rest_field() {
|
||||
register_rest_field( get_post_types( '', 'names' ),
|
||||
'gutenberg_elementor_mode', [
|
||||
'update_callback' => function( $request_value, $object ) {
|
||||
if ( ! User::is_current_user_can_edit( $object->ID ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$document = Plugin::$instance->documents->get( $object->ID );
|
||||
|
||||
if ( ! $document ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$document->set_is_built_with_elementor( false );
|
||||
|
||||
return true;
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function enqueue_assets() {
|
||||
$document = Plugin::$instance->documents->get( get_the_ID() );
|
||||
|
||||
if ( ! $document || ! $document->is_editable_by_current_user() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->is_gutenberg_editor_active = true;
|
||||
|
||||
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
|
||||
|
||||
wp_enqueue_script( 'elementor-gutenberg', ELEMENTOR_ASSETS_URL . 'js/gutenberg' . $suffix . '.js', [ 'jquery' ], ELEMENTOR_VERSION, true );
|
||||
|
||||
$elementor_settings = [
|
||||
'isElementorMode' => $document->is_built_with_elementor(),
|
||||
'editLink' => $document->get_edit_url(),
|
||||
];
|
||||
Utils::print_js_config( 'elementor-gutenberg', 'ElementorGutenbergSettings', $elementor_settings );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function print_admin_js_template() {
|
||||
if ( ! $this->is_gutenberg_editor_active ) {
|
||||
return;
|
||||
}
|
||||
|
||||
?>
|
||||
<script id="elementor-gutenberg-button-switch-mode" type="text/html">
|
||||
<div id="elementor-switch-mode">
|
||||
<button id="elementor-switch-mode-button" type="button" class="button button-primary button-large">
|
||||
<span class="elementor-switch-mode-on"><?php echo esc_html__( '← Back to WordPress Editor', 'elementor' ); ?></span>
|
||||
<span class="elementor-switch-mode-off">
|
||||
<i class="eicon-elementor-square" aria-hidden="true"></i>
|
||||
<?php echo esc_html__( 'Edit with Elementor', 'elementor' ); ?>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script id="elementor-gutenberg-panel" type="text/html">
|
||||
<div id="elementor-editor">
|
||||
<div id="elementor-go-to-edit-page-link">
|
||||
<button id="elementor-editor-button" class="button button-primary button-hero">
|
||||
<i class="eicon-elementor-square" aria-hidden="true"></i>
|
||||
<?php echo esc_html__( 'Edit with Elementor', 'elementor' ); ?>
|
||||
</button>
|
||||
<div class="elementor-loader-wrapper">
|
||||
<div class="elementor-loader">
|
||||
<div class="elementor-loader-boxes">
|
||||
<div class="elementor-loader-box"></div>
|
||||
<div class="elementor-loader-box"></div>
|
||||
<div class="elementor-loader-box"></div>
|
||||
<div class="elementor-loader-box"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="elementor-loading-title"><?php echo esc_html__( 'Loading', 'elementor' ); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script id="elementor-gutenberg-button-tmpl" type="text/html">
|
||||
<div id="elementor-edit-button-gutenberg">
|
||||
<button id="elementor-edit-mode-button" type="button" class="button button-primary button-large">
|
||||
<span class="elementor-edit-mode-gutenberg">
|
||||
<i class="eicon-elementor-square" aria-hidden="true"></i>
|
||||
<?php echo esc_html__( 'Edit with Elementor', 'elementor' ); ?>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'rest_api_init', [ $this, 'register_elementor_rest_field' ] );
|
||||
add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_assets' ] );
|
||||
add_action( 'admin_footer', [ $this, 'print_admin_js_template' ] );
|
||||
add_action( 'wp_enqueue_scripts', [ $this, 'dequeue_assets' ], 999 );
|
||||
}
|
||||
|
||||
public function dequeue_assets() {
|
||||
if ( ! static::is_optimized_gutenberg_loading_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! static::should_dequeue_gutenberg_assets() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_dequeue_style( 'wp-block-library' );
|
||||
wp_dequeue_style( 'wp-block-library-theme' );
|
||||
wp_dequeue_style( 'wc-block-style' );
|
||||
wp_dequeue_style( 'wc-blocks-style' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the "Optimized Gutenberg Loading" settings is enabled.
|
||||
*
|
||||
* The 'elementor_optimized_gutenberg_loading' option can be enabled/disabled from the Elementor settings.
|
||||
* For BC, when the option has not been saved in the database, the default '1' value is returned.
|
||||
*
|
||||
* @since 3.21.0
|
||||
* @access private
|
||||
*/
|
||||
private static function is_optimized_gutenberg_loading_enabled() : bool {
|
||||
return (bool) get_option( 'elementor_optimized_gutenberg_loading', '1' );
|
||||
}
|
||||
|
||||
private static function should_dequeue_gutenberg_assets() : bool {
|
||||
$post = get_post();
|
||||
|
||||
if ( empty( $post->ID ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! static::is_built_with_elementor( $post ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( static::is_gutenberg_in_post( $post ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function is_built_with_elementor( $post ) : bool {
|
||||
$document = Plugin::$instance->documents->get( $post->ID );
|
||||
|
||||
if ( ! $document || ! $document->is_built_with_elementor() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function is_gutenberg_in_post( $post ) : bool {
|
||||
if ( has_blocks( $post ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( static::current_theme_is_fse_theme() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function current_theme_is_fse_theme() : bool {
|
||||
if ( function_exists( 'wp_is_block_theme' ) ) {
|
||||
return (bool) wp_is_block_theme();
|
||||
}
|
||||
if ( function_exists( 'gutenberg_is_fse_theme' ) ) {
|
||||
return (bool) gutenberg_is_fse_theme();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
74
wp-content/plugins/elementor/modules/history/module.php
Normal file
74
wp-content/plugins/elementor/modules/history/module.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\History;
|
||||
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor history module.
|
||||
*
|
||||
* Elementor history module handler class is responsible for registering and
|
||||
* managing Elementor history modules.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*/
|
||||
class Module extends BaseModule {
|
||||
|
||||
/**
|
||||
* Get module name.
|
||||
*
|
||||
* Retrieve the history module name.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @access public
|
||||
*
|
||||
* @return string Module name.
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'history';
|
||||
}
|
||||
|
||||
/**
|
||||
* Localize settings.
|
||||
*
|
||||
* Add new localized settings for the history module.
|
||||
*
|
||||
* Fired by `elementor/editor/localize_settings` filter.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @deprecated 3.1.0
|
||||
* @access public
|
||||
*
|
||||
* @return array Localized settings.
|
||||
*/
|
||||
public function localize_settings() {
|
||||
Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.1.0' );
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.3.0
|
||||
* @access public
|
||||
*/
|
||||
public function add_templates() {
|
||||
Plugin::$instance->common->add_template( __DIR__ . '/views/history-panel-template.php' );
|
||||
Plugin::$instance->common->add_template( __DIR__ . '/views/revisions-panel-template.php' );
|
||||
}
|
||||
|
||||
/**
|
||||
* History module constructor.
|
||||
*
|
||||
* Initializing Elementor history module.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @access public
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'elementor/editor/init', [ $this, 'add_templates' ] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,416 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\History;
|
||||
|
||||
use Elementor\Core\Base\Document;
|
||||
use Elementor\Core\Common\Modules\Ajax\Module as Ajax;
|
||||
use Elementor\Core\Files\CSS\Post as Post_CSS;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Utils;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor history revisions manager.
|
||||
*
|
||||
* Elementor history revisions manager handler class is responsible for
|
||||
* registering and managing Elementor revisions manager.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*/
|
||||
class Revisions_Manager {
|
||||
|
||||
/**
|
||||
* Maximum number of revisions to display.
|
||||
*/
|
||||
const MAX_REVISIONS_TO_DISPLAY = 50;
|
||||
|
||||
/**
|
||||
* Authors list.
|
||||
*
|
||||
* Holds all the authors.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $authors = [];
|
||||
|
||||
/**
|
||||
* History revisions manager constructor.
|
||||
*
|
||||
* Initializing Elementor history revisions manager.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @access public
|
||||
*/
|
||||
public function __construct() {
|
||||
self::register_actions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.7.0
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function handle_revision() {
|
||||
add_filter( 'wp_save_post_revision_check_for_changes', '__return_false' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @param $post_content
|
||||
* @param $post_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function avoid_delete_auto_save( $post_content, $post_id ) {
|
||||
// Add a temporary string in order the $post will not be equal to the $autosave
|
||||
// in edit-form-advanced.php:210
|
||||
$document = Plugin::$instance->documents->get( $post_id );
|
||||
|
||||
if ( $document && $document->is_built_with_elementor() ) {
|
||||
$post_content .= '<!-- Created with Elementor -->';
|
||||
}
|
||||
|
||||
return $post_content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function remove_temp_post_content() {
|
||||
global $post;
|
||||
|
||||
$document = Plugin::$instance->documents->get( $post->ID );
|
||||
|
||||
if ( ! $document || ! $document->is_built_with_elementor() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$post->post_content = str_replace( '<!-- Created with Elementor -->', '', $post->post_content );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.7.0
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @param int $post_id
|
||||
* @param array $query_args
|
||||
* @param bool $parse_result
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_revisions( $post_id = 0, $query_args = [], $parse_result = true ) {
|
||||
$post = get_post( $post_id );
|
||||
|
||||
if ( ! $post || empty( $post->ID ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$revisions = [];
|
||||
|
||||
$default_query_args = [
|
||||
'posts_per_page' => self::MAX_REVISIONS_TO_DISPLAY,
|
||||
'meta_key' => '_elementor_data',
|
||||
];
|
||||
|
||||
$query_args = array_merge( $default_query_args, $query_args );
|
||||
|
||||
$posts = wp_get_post_revisions( $post->ID, $query_args );
|
||||
|
||||
if ( ! wp_revisions_enabled( $post ) ) {
|
||||
$autosave = Utils::get_post_autosave( $post->ID );
|
||||
if ( $autosave ) {
|
||||
if ( $parse_result ) {
|
||||
array_unshift( $posts, $autosave );
|
||||
} else {
|
||||
array_unshift( $posts, $autosave->ID );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $parse_result ) {
|
||||
array_unshift( $posts, $post );
|
||||
} else {
|
||||
array_unshift( $posts, $post->ID );
|
||||
return $posts;
|
||||
}
|
||||
|
||||
$current_time = current_time( 'timestamp' );
|
||||
|
||||
/** @var \WP_Post $revision */
|
||||
foreach ( $posts as $revision ) {
|
||||
$date = date_i18n( _x( 'M j @ H:i', 'revision date format', 'elementor' ), strtotime( $revision->post_modified ) );
|
||||
|
||||
$human_time = human_time_diff( strtotime( $revision->post_modified ), $current_time );
|
||||
|
||||
if ( $revision->ID === $post->ID ) {
|
||||
$type = 'current';
|
||||
$type_label = esc_html__( 'Current Version', 'elementor' );
|
||||
} elseif ( false !== strpos( $revision->post_name, 'autosave' ) ) {
|
||||
$type = 'autosave';
|
||||
$type_label = esc_html__( 'Autosave', 'elementor' );
|
||||
} else {
|
||||
$type = 'revision';
|
||||
$type_label = esc_html__( 'Revision', 'elementor' );
|
||||
}
|
||||
|
||||
if ( ! isset( self::$authors[ $revision->post_author ] ) ) {
|
||||
self::$authors[ $revision->post_author ] = [
|
||||
'avatar' => get_avatar( $revision->post_author, 22 ),
|
||||
'display_name' => get_the_author_meta( 'display_name', $revision->post_author ),
|
||||
];
|
||||
}
|
||||
|
||||
$revisions[] = [
|
||||
'id' => $revision->ID,
|
||||
'author' => self::$authors[ $revision->post_author ]['display_name'],
|
||||
'timestamp' => strtotime( $revision->post_modified ),
|
||||
'date' => sprintf(
|
||||
/* translators: 1: Human readable time difference, 2: Date. */
|
||||
esc_html__( '%1$s ago (%2$s)', 'elementor' ),
|
||||
'<time>' . $human_time . '</time>',
|
||||
'<time>' . $date . '</time>'
|
||||
),
|
||||
'type' => $type,
|
||||
'typeLabel' => $type_label,
|
||||
'gravatar' => self::$authors[ $revision->post_author ]['avatar'],
|
||||
];
|
||||
}
|
||||
|
||||
return $revisions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.9.2
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function update_autosave( $autosave_data ) {
|
||||
self::save_revision( $autosave_data['ID'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.7.0
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function save_revision( $revision_id ) {
|
||||
$parent_id = wp_is_post_revision( $revision_id );
|
||||
|
||||
if ( $parent_id ) {
|
||||
Plugin::$instance->db->safe_copy_elementor_meta( $parent_id, $revision_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.7.0
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function restore_revision( $parent_id, $revision_id ) {
|
||||
$parent = Plugin::$instance->documents->get( $parent_id );
|
||||
$revision = Plugin::$instance->documents->get( $revision_id );
|
||||
|
||||
if ( ! $parent || ! $revision ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$is_built_with_elementor = $revision->is_built_with_elementor();
|
||||
|
||||
$parent->set_is_built_with_elementor( $is_built_with_elementor );
|
||||
|
||||
if ( ! $is_built_with_elementor ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Plugin::$instance->db->copy_elementor_meta( $revision_id, $parent_id );
|
||||
|
||||
$post_css = Post_CSS::create( $parent_id );
|
||||
|
||||
$post_css->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.3.0
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @param $data
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function ajax_get_revision_data( array $data ) {
|
||||
if ( ! isset( $data['id'] ) ) {
|
||||
throw new \Exception( 'You must set the revision ID.' );
|
||||
}
|
||||
|
||||
$revision = Plugin::$instance->documents->get_with_permissions( $data['id'] );
|
||||
|
||||
return [
|
||||
'settings' => $revision->get_settings(),
|
||||
'elements' => $revision->get_elements_data(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.7.0
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function add_revision_support_for_all_post_types() {
|
||||
$post_types = get_post_types_by_support( 'elementor' );
|
||||
foreach ( $post_types as $post_type ) {
|
||||
add_post_type_support( $post_type, 'revisions' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
* @static
|
||||
* @param array $return_data
|
||||
* @param Document $document
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function on_ajax_save_builder_data( $return_data, $document ) {
|
||||
$post_id = $document->get_main_id();
|
||||
|
||||
$latest_revisions = self::get_revisions(
|
||||
$post_id, [
|
||||
'posts_per_page' => 1,
|
||||
]
|
||||
);
|
||||
|
||||
$all_revision_ids = self::get_revisions(
|
||||
$post_id, [
|
||||
'fields' => 'ids',
|
||||
], false
|
||||
);
|
||||
|
||||
// Send revisions data only if has revisions.
|
||||
if ( ! empty( $latest_revisions ) ) {
|
||||
$current_revision_id = self::current_revision_id( $post_id );
|
||||
|
||||
$return_data = array_replace_recursive( $return_data, [
|
||||
'config' => [
|
||||
'document' => [
|
||||
'revisions' => [
|
||||
'current_id' => $current_revision_id,
|
||||
],
|
||||
],
|
||||
],
|
||||
'latest_revisions' => $latest_revisions,
|
||||
'revisions_ids' => $all_revision_ids,
|
||||
] );
|
||||
}
|
||||
|
||||
return $return_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.7.0
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function db_before_save( $status, $has_changes ) {
|
||||
if ( $has_changes ) {
|
||||
self::handle_revision();
|
||||
}
|
||||
}
|
||||
|
||||
public static function document_config( $settings, $post_id ) {
|
||||
$settings['revisions'] = [
|
||||
'enabled' => ( $post_id && wp_revisions_enabled( get_post( $post_id ) ) ),
|
||||
'current_id' => self::current_revision_id( $post_id ),
|
||||
];
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Localize settings.
|
||||
*
|
||||
* Add new localized settings for the revisions manager.
|
||||
*
|
||||
* Fired by `elementor/editor/editor_settings` filter.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @deprecated 3.1.0
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function editor_settings() {
|
||||
Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.1.0' );
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function ajax_get_revisions( $data ) {
|
||||
Plugin::$instance->documents->check_permissions( $data['editor_post_id'] );
|
||||
|
||||
return self::get_revisions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.3.0
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function register_ajax_actions( Ajax $ajax ) {
|
||||
$ajax->register_ajax_action( 'get_revisions', [ __CLASS__, 'ajax_get_revisions' ] );
|
||||
$ajax->register_ajax_action( 'get_revision_data', [ __CLASS__, 'ajax_get_revision_data' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.7.0
|
||||
* @access private
|
||||
* @static
|
||||
*/
|
||||
private static function register_actions() {
|
||||
add_action( 'wp_restore_post_revision', [ __CLASS__, 'restore_revision' ], 10, 2 );
|
||||
add_action( 'init', [ __CLASS__, 'add_revision_support_for_all_post_types' ], 9999 );
|
||||
add_filter( 'elementor/document/config', [ __CLASS__, 'document_config' ], 10, 2 );
|
||||
add_action( 'elementor/db/before_save', [ __CLASS__, 'db_before_save' ], 10, 2 );
|
||||
add_action( '_wp_put_post_revision', [ __CLASS__, 'save_revision' ] );
|
||||
add_action( 'wp_creating_autosave', [ __CLASS__, 'update_autosave' ] );
|
||||
add_action( 'elementor/ajax/register_actions', [ __CLASS__, 'register_ajax_actions' ] );
|
||||
|
||||
// Hack to avoid delete the auto-save revision in WP editor.
|
||||
add_filter( 'edit_post_content', [ __CLASS__, 'avoid_delete_auto_save' ], 10, 2 );
|
||||
add_action( 'edit_form_after_title', [ __CLASS__, 'remove_temp_post_content' ] );
|
||||
|
||||
if ( wp_doing_ajax() ) {
|
||||
add_filter( 'elementor/documents/ajax_save/return_data', [ __CLASS__, 'on_ajax_save_builder_data' ], 10, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.9.0
|
||||
* @access private
|
||||
* @static
|
||||
*/
|
||||
private static function current_revision_id( $post_id ) {
|
||||
$current_revision_id = $post_id;
|
||||
$autosave = Utils::get_post_autosave( $post_id );
|
||||
|
||||
if ( is_object( $autosave ) ) {
|
||||
$current_revision_id = $autosave->ID;
|
||||
}
|
||||
|
||||
return $current_revision_id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
?>
|
||||
<script type="text/template" id="tmpl-elementor-panel-history-page">
|
||||
<div id="elementor-panel-elements-navigation" class="elementor-panel-navigation">
|
||||
<button class="elementor-component-tab elementor-panel-navigation-tab" data-tab="actions"><?php echo esc_html__( 'Actions', 'elementor' ); ?></button>
|
||||
<button class="elementor-component-tab elementor-panel-navigation-tab" data-tab="revisions"><?php echo esc_html__( 'Revisions', 'elementor' ); ?></button>
|
||||
</div>
|
||||
<div id="elementor-panel-history-content"></div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="tmpl-elementor-panel-history-tab">
|
||||
<div id="elementor-history-list"></div>
|
||||
<div class="elementor-history-revisions-message"><?php echo esc_html__( 'Switch to Revisions tab for older versions', 'elementor' ); ?></div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="tmpl-elementor-panel-history-no-items">
|
||||
<img class="elementor-nerd-box-icon" src="<?php
|
||||
// PHPCS - Safe Elementor SVG
|
||||
echo ELEMENTOR_ASSETS_URL . 'images/information.svg'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>" loading="lazy" alt="<?php echo esc_attr__( 'Elementor', 'elementor' ); ?>" />
|
||||
<div class="elementor-nerd-box-title"><?php echo esc_html__( 'No History Yet', 'elementor' ); ?></div>
|
||||
<div class="elementor-nerd-box-message"><?php echo esc_html__( 'Once you start working, you\'ll be able to redo / undo any action you make in the editor.', 'elementor' ); ?></div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="tmpl-elementor-panel-history-item">
|
||||
<div class="elementor-history-item__details">
|
||||
<span class="elementor-history-item__title">{{{ title }}}</span>
|
||||
<span class="elementor-history-item__subtitle">{{{ subTitle }}}</span>
|
||||
<span class="elementor-history-item__action">{{{ action }}}</span>
|
||||
</div>
|
||||
<div class="elementor-history-item__icon">
|
||||
<span class="eicon" aria-hidden="true"></span>
|
||||
</div>
|
||||
</script>
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
?>
|
||||
<script type="text/template" id="tmpl-elementor-panel-revisions">
|
||||
<div class="elementor-panel-box">
|
||||
<div class="elementor-panel-revisions-buttons">
|
||||
<button class="elementor-button e-btn-txt e-revision-discard" disabled>
|
||||
<?php echo esc_html__( 'Discard', 'elementor' ); ?>
|
||||
</button>
|
||||
<button class="elementor-button e-revision-save" disabled>
|
||||
<?php echo esc_html__( 'Apply', 'elementor' ); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="elementor-panel-box">
|
||||
<div id="elementor-revisions-list" class="elementor-panel-box-content"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="tmpl-elementor-panel-revisions-no-revisions">
|
||||
<#
|
||||
var no_revisions_1 = '<?php echo esc_html__( 'Revision history lets you save your previous versions of your work, and restore them any time.', 'elementor' ); ?>',
|
||||
no_revisions_2 = '<?php echo esc_html__( 'Start designing your page and you will be able to see the entire revision history here.', 'elementor' ); ?>',
|
||||
revisions_disabled_1 = '<?php echo esc_html__( 'It looks like the post revision feature is unavailable in your website.', 'elementor' ); ?>',
|
||||
revisions_disabled_2 = '<?php printf(
|
||||
/* translators: %1$s Link open tag, %2$s: Link close tag. */
|
||||
esc_html__( 'Learn more about %1$sWordPress revisions%2$s', 'elementor' ),
|
||||
'<a target="_blank" href="https://go.elementor.com/wordpress-revisions/">',
|
||||
'</a>'
|
||||
); ?>';
|
||||
#>
|
||||
<img class="elementor-nerd-box-icon" src="<?php
|
||||
// PHPCS - Safe Elementor SVG
|
||||
echo ELEMENTOR_ASSETS_URL . 'images/information.svg' // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>" loading="lazy" alt="<?php echo esc_attr__( 'Elementor', 'elementor' ); ?>" />
|
||||
<div class="elementor-nerd-box-title"><?php echo esc_html__( 'No Revisions Saved Yet', 'elementor' ); ?></div>
|
||||
<div class="elementor-nerd-box-message">{{{ elementor.config.document.revisions.enabled ? no_revisions_1 : revisions_disabled_1 }}}</div>
|
||||
<div class="elementor-nerd-box-message">{{{ elementor.config.document.revisions.enabled ? no_revisions_2 : revisions_disabled_2 }}}</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="tmpl-elementor-panel-revisions-loading">
|
||||
<i class="eicon-loading eicon-animation-spin" aria-hidden="true"></i>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="tmpl-elementor-panel-revisions-revision-item">
|
||||
<button class="elementor-revision-item__wrapper {{ type }}">
|
||||
<div class="elementor-revision-item__gravatar">{{{ gravatar }}}</div>
|
||||
<div class="elementor-revision-item__details">
|
||||
<div class="elementor-revision-date" title="{{{ new Date( timestamp * 1000 ) }}}">{{{ date }}}</div>
|
||||
<div class="elementor-revision-meta">
|
||||
<span>{{{ typeLabel }}}</span>
|
||||
<?php echo esc_html__( 'By', 'elementor' ); ?> {{{ author }}}
|
||||
<span>(#{{{ id }}})</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="elementor-revision-item__tools">
|
||||
<i class="elementor-revision-item__tools-spinner eicon-loading eicon-animation-spin" aria-hidden="true"></i>
|
||||
|
||||
<# if ( 'current' === type ) { #>
|
||||
<i class="elementor-revision-item__tools-current eicon-check" aria-hidden="true"></i>
|
||||
<span class="elementor-screen-only"><?php echo esc_html__( 'Published', 'elementor' ); ?></span>
|
||||
<# } #>
|
||||
|
||||
<!-- <# if ( 'revision' === type ) { #>-->
|
||||
<!-- <i class="eicon-undo" aria-hidden="true"></i>-->
|
||||
<!-- <span class="elementor-screen-only">--><?php //echo esc_html__( 'Restore', 'elementor' ); ?><!--</span>-->
|
||||
<!-- <# } #>-->
|
||||
|
||||
</div>
|
||||
</button>
|
||||
</script>
|
||||
65
wp-content/plugins/elementor/modules/home/api.php
Normal file
65
wp-content/plugins/elementor/modules/home/api.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Home;
|
||||
|
||||
use Elementor\Modules\Home\Classes\Transformations_Manager;
|
||||
|
||||
class API {
|
||||
|
||||
const HOME_SCREEN_DATA_URL = 'https://assets.elementor.com/home-screen/v1/home-screen.json';
|
||||
|
||||
public static function get_home_screen_items( $force_request = false ): array {
|
||||
$home_screen_data = self::get_transient( '_elementor_home_screen_data' );
|
||||
|
||||
if ( $force_request || false === $home_screen_data ) {
|
||||
$home_screen_data = static::fetch_data();
|
||||
static::set_transient( '_elementor_home_screen_data', $home_screen_data, '+1 hour' );
|
||||
}
|
||||
|
||||
return self::transform_home_screen_data( $home_screen_data );
|
||||
}
|
||||
|
||||
private static function transform_home_screen_data( $json_data ): array {
|
||||
$transformers = new Transformations_Manager( $json_data );
|
||||
|
||||
return $transformers->run_transformations();
|
||||
}
|
||||
|
||||
private static function fetch_data(): array {
|
||||
$response = wp_remote_get( self::HOME_SCREEN_DATA_URL );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$data = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||
|
||||
if ( empty( $data['home-screen'] ) || ! is_array( $data['home-screen'] ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $data['home-screen'];
|
||||
}
|
||||
|
||||
private static function get_transient( $cache_key ) {
|
||||
$cache = get_option( $cache_key );
|
||||
|
||||
if ( empty( $cache['timeout'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( current_time( 'timestamp' ) > $cache['timeout'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return json_decode( $cache['value'], true );
|
||||
}
|
||||
|
||||
private static function set_transient( $cache_key, $value, $expiration = '+12 hours' ): bool {
|
||||
$data = [
|
||||
'timeout' => strtotime( $expiration, current_time( 'timestamp' ) ),
|
||||
'value' => json_encode( $value ),
|
||||
];
|
||||
|
||||
return update_option( $cache_key, $data, false );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Home\Classes;
|
||||
|
||||
use Elementor\Core\Isolation\Wordpress_Adapter;
|
||||
use Elementor\Core\Isolation\Plugin_Status_Adapter;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Transformations_Manager {
|
||||
|
||||
private static $cached_data = [];
|
||||
|
||||
private const TRANSFORMATIONS = [
|
||||
'Create_New_Page_Url',
|
||||
'Filter_Plugins',
|
||||
'Filter_Get_Started_By_License',
|
||||
'Filter_Sidebar_Upgrade_By_License',
|
||||
'Filter_Condition_Introduction_Meta',
|
||||
'Create_Site_Settings_Url',
|
||||
'Filter_Top_Section_By_License',
|
||||
];
|
||||
|
||||
protected array $home_screen_data;
|
||||
|
||||
protected Wordpress_Adapter $wordpress_adapter;
|
||||
|
||||
protected Plugin_Status_Adapter $plugin_status_adapter;
|
||||
|
||||
protected array $transformation_classes = [];
|
||||
|
||||
public function __construct( $home_screen_data ) {
|
||||
$this->home_screen_data = $home_screen_data;
|
||||
$this->wordpress_adapter = new Wordpress_Adapter();
|
||||
$this->plugin_status_adapter = new Plugin_Status_Adapter( $this->wordpress_adapter );
|
||||
$this->transformation_classes = $this->get_transformation_classes();
|
||||
}
|
||||
|
||||
public function run_transformations(): array {
|
||||
if ( ! empty( self::$cached_data ) ) {
|
||||
return self::$cached_data;
|
||||
}
|
||||
|
||||
$transformations = self::TRANSFORMATIONS;
|
||||
|
||||
foreach ( $transformations as $transformation_id ) {
|
||||
$this->home_screen_data = $this->transformation_classes[ $transformation_id ]->transform( $this->home_screen_data );
|
||||
}
|
||||
|
||||
self::$cached_data = $this->home_screen_data;
|
||||
|
||||
return $this->home_screen_data;
|
||||
}
|
||||
|
||||
private function get_transformation_classes(): array {
|
||||
$classes = [];
|
||||
|
||||
$transformations = self::TRANSFORMATIONS;
|
||||
|
||||
$arguments = [
|
||||
'wordpress_adapter' => $this->wordpress_adapter,
|
||||
'plugin_status_adapter' => $this->plugin_status_adapter,
|
||||
];
|
||||
|
||||
foreach ( $transformations as $transformation_id ) {
|
||||
$class_name = '\\Elementor\\Modules\\Home\\Transformations\\' . $transformation_id;
|
||||
$classes[ $transformation_id ] = new $class_name( $arguments );
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
}
|
||||
107
wp-content/plugins/elementor/modules/home/module.php
Normal file
107
wp-content/plugins/elementor/modules/home/module.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Home;
|
||||
|
||||
use Elementor\Core\Admin\Menu\Admin_Menu_Manager;
|
||||
use Elementor\Core\Base\App as BaseApp;
|
||||
use Elementor\Core\Experiments\Manager as Experiments_Manager;
|
||||
use Elementor\Settings;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Utils;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Module extends BaseApp {
|
||||
|
||||
const PAGE_ID = 'home_screen';
|
||||
|
||||
public function get_name(): string {
|
||||
return 'home';
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->register_layout_experiment();
|
||||
|
||||
if ( ! $this->is_experiment_active() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action( 'elementor/admin/menu/after_register', function ( Admin_Menu_Manager $admin_menu, array $hooks ) {
|
||||
$hook_suffix = 'toplevel_page_elementor';
|
||||
add_action( "admin_print_scripts-{$hook_suffix}", [ $this, 'enqueue_home_screen_scripts' ] );
|
||||
}, 10, 2 );
|
||||
|
||||
add_filter( 'elementor/document/urls/edit', [ $this, 'add_active_document_to_edit_link' ] );
|
||||
}
|
||||
|
||||
public function enqueue_home_screen_scripts(): void {
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$min_suffix = Utils::is_script_debug() ? '' : '.min';
|
||||
|
||||
wp_enqueue_script(
|
||||
'e-home-screen',
|
||||
ELEMENTOR_ASSETS_URL . 'js/e-home-screen' . $min_suffix . '.js',
|
||||
[
|
||||
'react',
|
||||
'react-dom',
|
||||
'elementor-common',
|
||||
'elementor-v2-ui',
|
||||
],
|
||||
ELEMENTOR_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
wp_set_script_translations( 'e-home-screen', 'elementor' );
|
||||
|
||||
wp_localize_script(
|
||||
'e-home-screen',
|
||||
'elementorHomeScreenData',
|
||||
$this->get_app_js_config()
|
||||
);
|
||||
}
|
||||
|
||||
public function is_experiment_active(): bool {
|
||||
return Plugin::$instance->experiments->is_feature_active( self::PAGE_ID );
|
||||
}
|
||||
|
||||
public function add_active_document_to_edit_link( $edit_link ) {
|
||||
$active_document = Utils::get_super_global_value( $_GET, 'active-document' ) ?? null;
|
||||
$active_tab = Utils::get_super_global_value( $_GET, 'active-tab' ) ?? null;
|
||||
|
||||
if ( $active_document ) {
|
||||
$edit_link = add_query_arg( 'active-document', $active_document, $edit_link );
|
||||
}
|
||||
|
||||
if ( $active_tab ) {
|
||||
$edit_link = add_query_arg( 'active-tab', $active_tab, $edit_link );
|
||||
}
|
||||
|
||||
return $edit_link;
|
||||
}
|
||||
|
||||
private function register_layout_experiment(): void {
|
||||
Plugin::$instance->experiments->add_feature( [
|
||||
'name' => static::PAGE_ID,
|
||||
'title' => esc_html__( 'Elementor Home Screen', 'elementor' ),
|
||||
'description' => esc_html__( 'Default Elementor menu page.', 'elementor' ),
|
||||
'hidden' => true,
|
||||
'default' => Experiments_Manager::STATE_ACTIVE,
|
||||
] );
|
||||
}
|
||||
|
||||
private function get_app_js_config(): array {
|
||||
return API::get_home_screen_items();
|
||||
}
|
||||
|
||||
public static function get_elementor_settings_page_id(): string {
|
||||
return Plugin::$instance->experiments->is_feature_active( self::PAGE_ID )
|
||||
? 'elementor-settings'
|
||||
: Settings::PAGE_ID;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Home\Transformations\Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
abstract class Transformations_Abstract {
|
||||
|
||||
protected $wordpress_adapter;
|
||||
protected $plugin_status_adapter;
|
||||
|
||||
public function __construct( $args ) {
|
||||
$this->wordpress_adapter = $args['wordpress_adapter'] ?? null;
|
||||
$this->plugin_status_adapter = $args['plugin_status_adapter'] ?? null;
|
||||
}
|
||||
|
||||
abstract public function transform( array $home_screen_data ): array;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Home\Transformations;
|
||||
|
||||
use Elementor\Modules\Home\Transformations\Base\Transformations_Abstract;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Create_New_Page_Url extends Transformations_Abstract {
|
||||
|
||||
public function transform( array $home_screen_data ): array {
|
||||
$home_screen_data['create_new_page_url'] = Plugin::$instance->documents->get_create_new_post_url( 'page' );
|
||||
|
||||
return $home_screen_data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Home\Transformations;
|
||||
|
||||
use Elementor\Core\Base\Document;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Create_Site_Settings_Url extends Base\Transformations_Abstract {
|
||||
|
||||
const URL_TYPE = 'site_settings';
|
||||
|
||||
const SITE_SETTINGS_ITEMS = [ 'Site Settings', 'Site Logo', 'Global Colors', 'Global Fonts' ];
|
||||
|
||||
public function transform( array $home_screen_data ): array {
|
||||
if ( empty( $home_screen_data['get_started'] ) ) {
|
||||
return $home_screen_data;
|
||||
}
|
||||
|
||||
$site_settings_url_config = $this->get_site_settings_url_config();
|
||||
|
||||
$home_screen_data['get_started']['repeater'] = array_map( function( $repeater_item ) use ( $site_settings_url_config ) {
|
||||
if ( ! in_array( $repeater_item['title'], static::SITE_SETTINGS_ITEMS, true ) ) {
|
||||
return $repeater_item;
|
||||
}
|
||||
|
||||
if ( ! empty( $repeater_item['tab_id'] ) ) {
|
||||
$site_settings_url_config['url'] = add_query_arg( [ 'active-tab' => $repeater_item['tab_id'] ], $site_settings_url_config['url'] );
|
||||
}
|
||||
|
||||
return array_merge( $repeater_item, $site_settings_url_config );
|
||||
}, $home_screen_data['get_started']['repeater'] );
|
||||
|
||||
return $home_screen_data;
|
||||
}
|
||||
|
||||
private function get_site_settings_url_config(): array {
|
||||
$existing_elementor_page = $this->get_elementor_page();
|
||||
$site_settings_url = ! empty( $existing_elementor_page )
|
||||
? $this->get_elementor_edit_url( $existing_elementor_page->ID )
|
||||
: $this->get_elementor_create_new_page_url();
|
||||
|
||||
return [
|
||||
'new_page' => empty( $existing_elementor_page ),
|
||||
'url' => $site_settings_url,
|
||||
'type' => static::URL_TYPE,
|
||||
];
|
||||
}
|
||||
|
||||
private function get_elementor_create_new_page_url(): string {
|
||||
$active_kit_id = Plugin::$instance->kits_manager->get_active_id();
|
||||
|
||||
if ( empty( $active_kit_id ) ) {
|
||||
return Plugin::$instance->documents->get_create_new_post_url( 'page' );
|
||||
}
|
||||
|
||||
return add_query_arg( [ 'active-document' => $active_kit_id ], Plugin::$instance->documents->get_create_new_post_url( 'page' ) );
|
||||
}
|
||||
|
||||
private function get_elementor_edit_url( int $post_id ): string {
|
||||
$active_kit_id = Plugin::$instance->kits_manager->get_active_id();
|
||||
$document = Plugin::$instance->documents->get( $post_id );
|
||||
|
||||
if ( ! $document ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return add_query_arg( [ 'active-document' => $active_kit_id ], $document->get_edit_url() );
|
||||
}
|
||||
|
||||
private function get_elementor_page() {
|
||||
$args = [
|
||||
'meta_key' => Document::BUILT_WITH_ELEMENTOR_META_KEY,
|
||||
'sort_order' => 'asc',
|
||||
'sort_column' => 'post_date',
|
||||
];
|
||||
$pages = get_pages( $args );
|
||||
|
||||
if ( empty( $pages ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$show_page_on_front = 'page' === get_option( 'show_on_front' );
|
||||
|
||||
if ( ! $show_page_on_front ) {
|
||||
return $pages[0];
|
||||
}
|
||||
|
||||
$home_page_id = get_option( 'page_on_front' );
|
||||
|
||||
foreach ( $pages as $page ) {
|
||||
if ( (string) $page->ID === $home_page_id ) {
|
||||
return $page;
|
||||
}
|
||||
}
|
||||
|
||||
return $pages[0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Home\Transformations;
|
||||
|
||||
use Elementor\Modules\Home\Transformations\Base\Transformations_Abstract;
|
||||
use Elementor\User;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Filter_Condition_Introduction_Meta extends Transformations_Abstract {
|
||||
|
||||
public array $introduction_meta_data;
|
||||
|
||||
public function __construct( $args ) {
|
||||
parent::__construct( $args );
|
||||
|
||||
$this->introduction_meta_data = User::get_introduction_meta() ?? [];
|
||||
}
|
||||
|
||||
public function transform( array $home_screen_data ): array {
|
||||
$introduction_meta_conditions = $this->get_introduction_meta_conditions( $home_screen_data );
|
||||
$active_addons = $this->get_activated_addons( $introduction_meta_conditions );
|
||||
$home_screen_data['add_ons']['repeater'] = $this->get_inactive_addons( $home_screen_data, $active_addons );
|
||||
|
||||
return $home_screen_data;
|
||||
}
|
||||
|
||||
private function get_introduction_meta_conditions( $home_screen_data ): array {
|
||||
$add_ons = $home_screen_data['add_ons']['repeater'];
|
||||
|
||||
$conditions = [];
|
||||
|
||||
foreach ( $add_ons as $add_on ) {
|
||||
if ( array_key_exists( 'condition', $add_on ) && 'introduction_meta' === $add_on['condition']['key'] ) {
|
||||
$conditions[ $add_on['title'] ] = $add_on['condition']['value'];
|
||||
}
|
||||
}
|
||||
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
private function get_activated_addons( $conditions ): array {
|
||||
$active_addons = [];
|
||||
|
||||
foreach ( $conditions as $add_on_title => $introduction_meta_value ) {
|
||||
if ( ! empty( $this->introduction_meta_data[ $introduction_meta_value ] ) ) {
|
||||
$active_addons[] = $add_on_title;
|
||||
}
|
||||
}
|
||||
|
||||
return $active_addons;
|
||||
}
|
||||
|
||||
private function get_inactive_addons( $home_screen_data, $active_addons ): array {
|
||||
$add_ons = $home_screen_data['add_ons']['repeater'];
|
||||
$inactive_add_ons = [];
|
||||
|
||||
foreach ( $add_ons as $add_on ) {
|
||||
if ( ! in_array( $add_on['title'], $active_addons ) ) {
|
||||
$inactive_add_ons[] = $add_on;
|
||||
}
|
||||
}
|
||||
|
||||
return $inactive_add_ons;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Home\Transformations;
|
||||
|
||||
use Elementor\Modules\Home\Transformations\Base\Transformations_Abstract;
|
||||
use Elementor\Utils;
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Filter_Get_Started_By_License extends Transformations_Abstract {
|
||||
public bool $has_pro;
|
||||
|
||||
public function __construct( $args ) {
|
||||
parent::__construct( $args );
|
||||
|
||||
$this->has_pro = Utils::has_pro();
|
||||
}
|
||||
|
||||
private function is_valid_item( $item ) {
|
||||
$has_pro_json_not_free = $this->has_pro && 'pro' === $item['license'][0];
|
||||
$is_not_pro_json_not_pro = ! $this->has_pro && 'free' === $item['license'][0];
|
||||
|
||||
return $has_pro_json_not_free || $is_not_pro_json_not_pro;
|
||||
}
|
||||
|
||||
public function transform( array $home_screen_data ): array {
|
||||
$new_get_started = [];
|
||||
|
||||
foreach ( $home_screen_data['get_started'] as $index => $item ) {
|
||||
if ( $this->is_valid_item( $item ) ) {
|
||||
$new_get_started[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$home_screen_data['get_started'] = reset( $new_get_started );
|
||||
|
||||
return $home_screen_data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Home\Transformations;
|
||||
|
||||
use Elementor\Modules\Home\Transformations\Base\Transformations_Abstract;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Filter_Plugins extends Transformations_Abstract {
|
||||
|
||||
const PLUGIN_IS_NOT_INSTALLED_FROM_WPORG = 'not-installed-wporg';
|
||||
|
||||
const PLUGIN_IS_NOT_INSTALLED_NOT_FROM_WPORG = 'not-installed-not-wporg';
|
||||
|
||||
const PLUGIN_IS_INSTALLED_NOT_ACTIVATED = 'installed-not-activated';
|
||||
|
||||
const PLUGIN_IS_ACTIVATED = 'activated';
|
||||
|
||||
public function transform( array $home_screen_data ): array {
|
||||
$home_screen_data['add_ons']['repeater'] = $this->get_add_ons_installation_status( $home_screen_data['add_ons']['repeater'] );
|
||||
|
||||
return $home_screen_data;
|
||||
}
|
||||
|
||||
private function is_plugin( $add_on ): bool {
|
||||
return 'link' !== $add_on['type'];
|
||||
}
|
||||
|
||||
private function get_add_ons_installation_status( array $add_ons ): array {
|
||||
$transformed_add_ons = [];
|
||||
|
||||
foreach ( $add_ons as $add_on ) {
|
||||
|
||||
if ( $this->is_plugin( $add_on ) ) {
|
||||
$this->handle_plugin_add_on( $add_on, $transformed_add_ons );
|
||||
} else {
|
||||
$transformed_add_ons[] = $add_on;
|
||||
}
|
||||
}
|
||||
|
||||
return $transformed_add_ons;
|
||||
}
|
||||
|
||||
private function get_plugin_installation_status( $add_on ): string {
|
||||
$plugin_path = $add_on['file_path'];
|
||||
|
||||
if ( ! $this->plugin_status_adapter->is_plugin_installed( $plugin_path ) ) {
|
||||
|
||||
if ( 'wporg' === $add_on['type'] ) {
|
||||
return self::PLUGIN_IS_NOT_INSTALLED_FROM_WPORG;
|
||||
}
|
||||
|
||||
return self::PLUGIN_IS_NOT_INSTALLED_NOT_FROM_WPORG;
|
||||
}
|
||||
|
||||
if ( $this->wordpress_adapter->is_plugin_active( $plugin_path ) ) {
|
||||
return self::PLUGIN_IS_ACTIVATED;
|
||||
}
|
||||
|
||||
return self::PLUGIN_IS_INSTALLED_NOT_ACTIVATED;
|
||||
}
|
||||
|
||||
private function handle_plugin_add_on( array $add_on, array &$transformed_add_ons ): void {
|
||||
$installation_status = $this->get_plugin_installation_status( $add_on );
|
||||
|
||||
if ( self::PLUGIN_IS_ACTIVATED === $installation_status ) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( $this->get_plugin_installation_status( $add_on ) ) {
|
||||
case self::PLUGIN_IS_NOT_INSTALLED_NOT_FROM_WPORG:
|
||||
break;
|
||||
case self::PLUGIN_IS_NOT_INSTALLED_FROM_WPORG:
|
||||
$installation_url = $this->plugin_status_adapter->get_install_plugin_url( $add_on['file_path'] );
|
||||
$add_on['url'] = html_entity_decode( $installation_url );
|
||||
$add_on['target'] = '_self';
|
||||
break;
|
||||
case self::PLUGIN_IS_INSTALLED_NOT_ACTIVATED:
|
||||
$activation_url = $this->plugin_status_adapter->get_activate_plugin_url( $add_on['file_path'] );
|
||||
$add_on['url'] = html_entity_decode( $activation_url );
|
||||
$add_on['button_label'] = esc_html__( 'Activate', 'elementor' );
|
||||
$add_on['target'] = '_self';
|
||||
break;
|
||||
}
|
||||
|
||||
$transformed_add_ons[] = $add_on;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
namespace elementor\modules\home\transformations;
|
||||
|
||||
use Elementor\Modules\Home\Transformations\Base\Transformations_Abstract;
|
||||
use Elementor\Utils;
|
||||
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Filter_Sidebar_Upgrade_By_License extends Transformations_Abstract {
|
||||
public bool $has_pro;
|
||||
|
||||
public function __construct( $args ) {
|
||||
parent::__construct( $args );
|
||||
|
||||
$this->has_pro = Utils::has_pro();
|
||||
}
|
||||
|
||||
private function is_valid_item( $item ) {
|
||||
$has_pro_json_not_free = $this->has_pro && 'pro' === $item['license'][0];
|
||||
$is_not_pro_json_not_pro = ! $this->has_pro && 'free' === $item['license'][0];
|
||||
$should_show = ! isset( $item['show'] ) || 'true' === $item['show'];
|
||||
return $has_pro_json_not_free && $should_show || $is_not_pro_json_not_pro && $should_show;
|
||||
}
|
||||
|
||||
public function transform( array $home_screen_data ): array {
|
||||
$new_sidebar_upgrade = [];
|
||||
|
||||
foreach ( $home_screen_data['sidebar_upgrade'] as $index => $item ) {
|
||||
if ( $this->is_valid_item( $item ) ) {
|
||||
$new_sidebar_upgrade[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $new_sidebar_upgrade ) ) {
|
||||
unset( $home_screen_data['sidebar_upgrade'] );
|
||||
return $home_screen_data;
|
||||
}
|
||||
|
||||
$home_screen_data['sidebar_upgrade'] = reset( $new_sidebar_upgrade );
|
||||
|
||||
return $home_screen_data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
namespace elementor\modules\home\transformations;
|
||||
|
||||
use Elementor\Modules\Home\Transformations\Base\Transformations_Abstract;
|
||||
use Elementor\Utils;
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Filter_Top_Section_By_License extends Transformations_Abstract {
|
||||
public bool $has_pro;
|
||||
|
||||
public function __construct( $args ) {
|
||||
parent::__construct( $args );
|
||||
|
||||
$this->has_pro = Utils::has_pro();
|
||||
}
|
||||
|
||||
private function is_valid_item( $item ) {
|
||||
if ( isset( $item['license'] ) ) {
|
||||
$has_pro_json_not_free = $this->has_pro && 'pro' === $item['license'][0];
|
||||
$is_not_pro_json_not_pro = ! $this->has_pro && 'free' === $item['license'][0];
|
||||
|
||||
return $has_pro_json_not_free || $is_not_pro_json_not_pro;
|
||||
}
|
||||
}
|
||||
|
||||
public function transform( array $home_screen_data ): array {
|
||||
foreach ( $home_screen_data['top_with_licences'] as $index => $item ) {
|
||||
if ( $this->is_valid_item( $item ) ) {
|
||||
$new_top[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$home_screen_data['top_with_licences'] = reset( $new_top );
|
||||
unset( $home_screen_data['top'] );
|
||||
|
||||
return $home_screen_data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\ImageLoadingOptimization;
|
||||
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
/**
|
||||
* @var int Minimum square-pixels threshold.
|
||||
*/
|
||||
private $min_priority_img_pixels = 50000;
|
||||
|
||||
/**
|
||||
* @var int The number of content media elements to not lazy-load.
|
||||
*/
|
||||
private $omit_threshold = 3;
|
||||
|
||||
/**
|
||||
* @var array Keep a track of images for which loading optimization strategy were computed.
|
||||
*/
|
||||
private static $image_visited = [];
|
||||
|
||||
/**
|
||||
* Get Module name.
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'image-loading-optimization';
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( ! static::is_optimized_image_loading_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
parent::__construct();
|
||||
|
||||
// Stop wp core logic.
|
||||
add_action( 'init', [ $this, 'stop_core_fetchpriority_high_logic' ] );
|
||||
add_filter( 'wp_lazy_loading_enabled', '__return_false' );
|
||||
|
||||
// Run optimization logic on header.
|
||||
add_action( 'get_header', [ $this, 'set_buffer' ] );
|
||||
|
||||
// Ensure buffer is flushed (if any) before the content logic.
|
||||
add_filter( 'the_content', [ $this, 'flush_header_buffer' ], 0 );
|
||||
|
||||
// Run optimization logic on content.
|
||||
add_filter( 'wp_content_img_tag', [ $this, 'loading_optimization_image' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the "Optimized Image Loading" settings is enabled.
|
||||
*
|
||||
* The 'optimized_image_loading' option can be enabled/disabled from the Elementor settings.
|
||||
*
|
||||
* @since 3.21.0
|
||||
* @access private
|
||||
*/
|
||||
private static function is_optimized_image_loading_enabled(): bool {
|
||||
return '1' === get_option( 'elementor_optimized_image_loading', '1' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop WordPress core fetchpriority logic by setting the wp_high_priority_element_flag flag to false.
|
||||
*/
|
||||
public function stop_core_fetchpriority_high_logic() {
|
||||
// wp_high_priority_element_flag was only introduced in 6.3.0
|
||||
if ( function_exists( 'wp_high_priority_element_flag' ) ) {
|
||||
wp_high_priority_element_flag( false );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set buffer to handle header and footer content.
|
||||
*/
|
||||
public function set_buffer() {
|
||||
ob_start( [ $this, 'handle_buffer_content' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function ensure that buffer if any is flushed before the content is called.
|
||||
* This function behaves more like an action than a filter.
|
||||
*
|
||||
* @param string $content the content.
|
||||
* @return string We simply return the content from parameter.
|
||||
*/
|
||||
public function flush_header_buffer( $content ) {
|
||||
$buffer_status = ob_get_status();
|
||||
|
||||
if ( ! empty( $buffer_status ) &&
|
||||
1 === $buffer_status['type'] &&
|
||||
get_class( $this ) . '::handle_buffer_content' === $buffer_status['name'] ) {
|
||||
ob_end_flush();
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to handle image optimization logic on buffered content.
|
||||
*
|
||||
* @param string $buffer Buffered content.
|
||||
* @return string Content with optimized images.
|
||||
*/
|
||||
public function handle_buffer_content( $buffer ) {
|
||||
return $this->filter_images( $buffer );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for image in the content provided and apply optimization logic on them.
|
||||
*
|
||||
* @param string $content Content to be analyzed.
|
||||
* @return string Content with optimized images.
|
||||
*/
|
||||
private function filter_images( $content ) {
|
||||
return preg_replace_callback(
|
||||
'/<img\s[^>]+>/',
|
||||
function ( $matches ) {
|
||||
return $this->loading_optimization_image( $matches[0] );
|
||||
},
|
||||
$content
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply loading optimization logic on the image.
|
||||
*
|
||||
* @param mixed $image Original image tag.
|
||||
* @return string Optimized image.
|
||||
*/
|
||||
public function loading_optimization_image( $image ) {
|
||||
if ( isset( self::$image_visited[ $image ] ) ) {
|
||||
return self::$image_visited[ $image ];
|
||||
}
|
||||
|
||||
$optimized_image = $this->add_loading_optimization_attrs( $image );
|
||||
self::$image_visited[ $image ] = $optimized_image;
|
||||
|
||||
return $optimized_image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds optimization attributes to an `img` HTML tag.
|
||||
*
|
||||
* @param string $image The HTML `img` tag where the attribute should be added.
|
||||
* @return string Converted `img` tag with optimization attributes added.
|
||||
*/
|
||||
private function add_loading_optimization_attrs( $image ) {
|
||||
$width = preg_match( '/ width=["\']([0-9]+)["\']/', $image, $match_width ) ? (int) $match_width[1] : null;
|
||||
$height = preg_match( '/ height=["\']([0-9]+)["\']/', $image, $match_height ) ? (int) $match_height[1] : null;
|
||||
$loading_val = preg_match( '/ loading=["\']([A-Za-z]+)["\']/', $image, $match_loading ) ? $match_loading[1] : null;
|
||||
$fetchpriority_val = preg_match( '/ fetchpriority=["\']([A-Za-z]+)["\']/', $image, $match_fetchpriority ) ? $match_fetchpriority[1] : null;
|
||||
|
||||
// Images should have height and dimension width for the loading optimization attributes to be added.
|
||||
if ( ! str_contains( $image, ' width="' ) || ! str_contains( $image, ' height="' ) ) {
|
||||
return $image;
|
||||
}
|
||||
|
||||
$optimization_attrs = $this->get_loading_optimization_attributes(
|
||||
[
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
'loading' => $loading_val,
|
||||
'fetchpriority' => $fetchpriority_val,
|
||||
]
|
||||
);
|
||||
|
||||
if ( ! empty( $optimization_attrs['fetchpriority'] ) ) {
|
||||
$image = str_replace( '<img', '<img fetchpriority="' . esc_attr( $optimization_attrs['fetchpriority'] ) . '"', $image );
|
||||
}
|
||||
|
||||
if ( ! empty( $optimization_attrs['loading'] ) ) {
|
||||
$image = str_replace( '<img', '<img loading="' . esc_attr( $optimization_attrs['loading'] ) . '"', $image );
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return loading Loading optimization attributes for a image with give attribute.
|
||||
*
|
||||
* @param array $attr Existing image attributes.
|
||||
* @return array Loading optimization attributes.
|
||||
*/
|
||||
private function get_loading_optimization_attributes( $attr ) {
|
||||
$loading_attrs = [];
|
||||
|
||||
// For any resources, width and height must be provided, to avoid layout shifts.
|
||||
if ( ! isset( $attr['width'], $attr['height'] ) ) {
|
||||
return $loading_attrs;
|
||||
}
|
||||
|
||||
/*
|
||||
* The key function logic starts here.
|
||||
*/
|
||||
$maybe_in_viewport = null;
|
||||
$increase_count = false;
|
||||
$maybe_increase_count = false;
|
||||
|
||||
/*
|
||||
* Logic to handle a `loading` attribute that is already provided.
|
||||
*
|
||||
* Copied from `wp_get_loading_optimization_attributes()`.
|
||||
*/
|
||||
if ( isset( $attr['loading'] ) ) {
|
||||
/*
|
||||
* Interpret "lazy" as not in viewport. Any other value can be
|
||||
* interpreted as in viewport (realistically only "eager" or `false`
|
||||
* to force-omit the attribute are other potential values).
|
||||
*/
|
||||
if ( 'lazy' === $attr['loading'] ) {
|
||||
$maybe_in_viewport = false;
|
||||
} else {
|
||||
$maybe_in_viewport = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Logic to handle a `fetchpriority` attribute that is already provided.
|
||||
$has_fetchpriority_high_attr = ( isset( $attr['fetchpriority'] ) && 'high' === $attr['fetchpriority'] );
|
||||
|
||||
/*
|
||||
* Handle cases where a `fetchpriority="high"` has already been set.
|
||||
*
|
||||
* Copied from `wp_get_loading_optimization_attributes()`.
|
||||
*/
|
||||
if ( $has_fetchpriority_high_attr ) {
|
||||
/*
|
||||
* If the image was already determined to not be in the viewport (e.g.
|
||||
* from an already provided `loading` attribute), trigger a warning.
|
||||
* Otherwise, the value can be interpreted as in viewport, since only
|
||||
* the most important in-viewport image should have `fetchpriority` set
|
||||
* to "high".
|
||||
*/
|
||||
if ( false === $maybe_in_viewport ) {
|
||||
_doing_it_wrong(
|
||||
__FUNCTION__,
|
||||
esc_html__( 'An image should not be lazy-loaded and marked as high priority at the same time.', 'elementor' ),
|
||||
''
|
||||
);
|
||||
/*
|
||||
* Set `fetchpriority` here for backward-compatibility as we should
|
||||
* not override what a developer decided, even though it seems
|
||||
* incorrect.
|
||||
*/
|
||||
$loading_attrs['fetchpriority'] = 'high';
|
||||
} else {
|
||||
$maybe_in_viewport = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( null === $maybe_in_viewport && ! is_admin() ) {
|
||||
$content_media_count = $this->increase_content_media_count( 0 );
|
||||
$increase_count = true;
|
||||
if ( $content_media_count < $this->omit_threshold ) {
|
||||
$maybe_in_viewport = true;
|
||||
} else {
|
||||
$maybe_in_viewport = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $maybe_in_viewport ) {
|
||||
$loading_attrs = $this->maybe_add_fetchpriority_high_attr( $loading_attrs, $attr );
|
||||
} else {
|
||||
$loading_attrs['loading'] = 'lazy';
|
||||
}
|
||||
|
||||
if ( $increase_count ) {
|
||||
$this->increase_content_media_count();
|
||||
} elseif ( $maybe_increase_count ) {
|
||||
if ( $this->get_min_priority_img_pixels() <= $attr['width'] * $attr['height'] ) {
|
||||
$this->increase_content_media_count();
|
||||
}
|
||||
}
|
||||
|
||||
return $loading_attrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get the minimum threshold for number of pixels an image needs to have to be considered "priority".
|
||||
*
|
||||
* @return int The minimum number of pixels (width * height). Default is 50000.
|
||||
*/
|
||||
private function get_min_priority_img_pixels() {
|
||||
/**
|
||||
* Filter the minimum pixel threshold used to determine if an image should have fetchpriority="high" applied.
|
||||
*
|
||||
* @see https://developer.wordpress.org/reference/hooks/wp_min_priority_img_pixels/
|
||||
*
|
||||
* @param int $pixels The minimum number of pixels (with * height).
|
||||
* @return int The filtered value.
|
||||
*/
|
||||
return apply_filters( 'elementor/image-loading-optimization/min_priority_img_pixels', $this->min_priority_img_pixels );
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps a count of media image.
|
||||
*
|
||||
* @param int $amount Amount by which count must be increased.
|
||||
* @return int current image count.
|
||||
*/
|
||||
private function increase_content_media_count( $amount = 1 ) {
|
||||
static $content_media_count = 0;
|
||||
|
||||
$content_media_count += $amount;
|
||||
|
||||
return $content_media_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether to add `fetchpriority='high'` to loading attributes.
|
||||
*
|
||||
* @param array $loading_attrs Array of the loading optimization attributes for the element.
|
||||
* @param array $attr Array of the attributes for the element.
|
||||
* @return array Updated loading optimization attributes for the element.
|
||||
*/
|
||||
private function maybe_add_fetchpriority_high_attr( $loading_attrs, $attr ) {
|
||||
if ( isset( $attr['fetchpriority'] ) ) {
|
||||
if ( 'high' === $attr['fetchpriority'] ) {
|
||||
$loading_attrs['fetchpriority'] = 'high';
|
||||
$this->high_priority_element_flag( false );
|
||||
}
|
||||
|
||||
return $loading_attrs;
|
||||
}
|
||||
|
||||
// Lazy-loading and `fetchpriority="high"` are mutually exclusive.
|
||||
if ( isset( $loading_attrs['loading'] ) && 'lazy' === $loading_attrs['loading'] ) {
|
||||
return $loading_attrs;
|
||||
}
|
||||
|
||||
if ( ! $this->high_priority_element_flag() ) {
|
||||
return $loading_attrs;
|
||||
}
|
||||
|
||||
if ( $this->get_min_priority_img_pixels() <= $attr['width'] * $attr['height'] ) {
|
||||
$loading_attrs['fetchpriority'] = 'high';
|
||||
$this->high_priority_element_flag( false );
|
||||
}
|
||||
|
||||
return $loading_attrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accesses a flag that indicates if an element is a possible candidate for `fetchpriority='high'`.
|
||||
*
|
||||
* @param bool $value Optional. Used to change the static variable. Default null.
|
||||
* @return bool Returns true if high-priority element was marked already, otherwise false.
|
||||
*/
|
||||
private function high_priority_element_flag( $value = null ) {
|
||||
static $high_priority_element = true;
|
||||
|
||||
if ( is_bool( $value ) ) {
|
||||
$high_priority_element = $value;
|
||||
}
|
||||
|
||||
return $high_priority_element;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\KitElementsDefaults\Data;
|
||||
|
||||
use Elementor\Core\Frontend\Performance;
|
||||
use Elementor\Modules\KitElementsDefaults\Module;
|
||||
use Elementor\Modules\KitElementsDefaults\Utils\Settings_Sanitizer;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Data\V2\Base\Exceptions\Error_404;
|
||||
use Elementor\Data\V2\Base\Controller as Base_Controller;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Controller extends Base_Controller {
|
||||
|
||||
public function get_name() {
|
||||
return 'kit-elements-defaults';
|
||||
}
|
||||
|
||||
public function register_endpoints() {
|
||||
$this->index_endpoint->register_item_route(\WP_REST_Server::EDITABLE, [
|
||||
'id_arg_name' => 'type',
|
||||
'id_arg_type_regex' => '[\w\-\_]+',
|
||||
'type' => [
|
||||
'type' => 'string',
|
||||
'description' => 'The type of the element.',
|
||||
'required' => true,
|
||||
'validate_callback' => function( $type ) {
|
||||
return $this->validate_type( $type );
|
||||
},
|
||||
],
|
||||
'settings' => [
|
||||
'description' => 'All the default values for the requested type',
|
||||
'required' => true,
|
||||
'type' => 'object',
|
||||
'validate_callback' => function( $settings ) {
|
||||
return is_array( $settings );
|
||||
},
|
||||
'sanitize_callback' => function( $settings, \WP_REST_Request $request ) {
|
||||
Performance::set_use_style_controls( true );
|
||||
|
||||
$sanitizer = new Settings_Sanitizer(
|
||||
Plugin::$instance->elements_manager,
|
||||
array_keys( Plugin::$instance->widgets_manager->get_widget_types() )
|
||||
);
|
||||
|
||||
$sanitized_data = $sanitizer
|
||||
->for( $request->get_param( 'type' ) )
|
||||
->using( $settings )
|
||||
->remove_invalid_settings()
|
||||
->kses_deep()
|
||||
->get();
|
||||
|
||||
Performance::set_use_style_controls( false );
|
||||
|
||||
return $sanitized_data;
|
||||
},
|
||||
],
|
||||
] );
|
||||
|
||||
$this->index_endpoint->register_item_route(\WP_REST_Server::DELETABLE, [
|
||||
'id_arg_name' => 'type',
|
||||
'id_arg_type_regex' => '[\w\-\_]+',
|
||||
'type' => [
|
||||
'type' => 'string',
|
||||
'description' => 'The type of the element.',
|
||||
'required' => true,
|
||||
'validate_callback' => function( $type ) {
|
||||
return $this->validate_type( $type );
|
||||
},
|
||||
],
|
||||
] );
|
||||
}
|
||||
|
||||
public function get_collection_params() {
|
||||
return [];
|
||||
}
|
||||
|
||||
public function get_items( $request ) {
|
||||
$this->validate_kit();
|
||||
|
||||
$kit = Plugin::$instance->kits_manager->get_active_kit();
|
||||
|
||||
return (object) $kit->get_json_meta( Module::META_KEY );
|
||||
}
|
||||
|
||||
public function update_item( $request ) {
|
||||
$this->validate_kit();
|
||||
|
||||
$kit = Plugin::$instance->kits_manager->get_active_kit();
|
||||
|
||||
$data = $kit->get_json_meta( Module::META_KEY );
|
||||
|
||||
$data[ $request->get_param( 'type' ) ] = $request->get_param( 'settings' );
|
||||
|
||||
$kit->update_json_meta( Module::META_KEY, $data );
|
||||
|
||||
return (object) [];
|
||||
}
|
||||
|
||||
public function delete_item( $request ) {
|
||||
$this->validate_kit();
|
||||
|
||||
$kit = Plugin::$instance->kits_manager->get_active_kit();
|
||||
|
||||
$data = $kit->get_json_meta( Module::META_KEY );
|
||||
|
||||
unset( $data[ $request->get_param( 'type' ) ] );
|
||||
|
||||
$kit->update_json_meta( Module::META_KEY, $data );
|
||||
|
||||
return (object) [];
|
||||
}
|
||||
|
||||
private function validate_kit() {
|
||||
$kit = Plugin::$instance->kits_manager->get_active_kit();
|
||||
$is_valid_kit = $kit && $kit->get_main_id();
|
||||
|
||||
if ( ! $is_valid_kit ) {
|
||||
throw new Error_404( 'Kit doesn\'t exist.' );
|
||||
}
|
||||
}
|
||||
|
||||
private function validate_type( $param ) {
|
||||
$element_types = array_keys( Plugin::$instance->elements_manager->get_element_types() );
|
||||
$widget_types = array_keys( Plugin::$instance->widgets_manager->get_widget_types() );
|
||||
|
||||
return in_array(
|
||||
$param,
|
||||
array_merge( $element_types, $widget_types ),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
public function get_items_permissions_check( $request ) {
|
||||
return current_user_can( 'edit_posts' );
|
||||
}
|
||||
|
||||
// TODO: Should be removed once the infra will support it.
|
||||
public function get_item_permissions_check( $request ) {
|
||||
return $this->get_items_permissions_check( $request );
|
||||
}
|
||||
|
||||
public function update_item_permissions_check( $request ) {
|
||||
return current_user_can( 'manage_options' );
|
||||
}
|
||||
|
||||
public function delete_item_permissions_check( $request ) {
|
||||
return current_user_can( 'manage_options' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\KitElementsDefaults\ImportExport;
|
||||
|
||||
use Elementor\App\Modules\ImportExport\Processes\Export;
|
||||
use Elementor\App\Modules\ImportExport\Processes\Import;
|
||||
use Elementor\Modules\KitElementsDefaults\ImportExport\Runners\Export as Export_Runner;
|
||||
use Elementor\Modules\KitElementsDefaults\ImportExport\Runners\Import as Import_Runner;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Import_Export {
|
||||
const FILE_NAME = 'kit-elements-defaults';
|
||||
|
||||
public function register() {
|
||||
// Revert kit is working by default, using the site-settings runner.
|
||||
|
||||
add_action( 'elementor/import-export/export-kit', function ( Export $export ) {
|
||||
$export->register( new Export_Runner() );
|
||||
} );
|
||||
|
||||
add_action( 'elementor/import-export/import-kit', function ( Import $import ) {
|
||||
$import->register( new Import_Runner() );
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\KitElementsDefaults\ImportExport\Runners;
|
||||
|
||||
use Elementor\Modules\KitElementsDefaults\ImportExport\Import_Export;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Core\Utils\Collection;
|
||||
use Elementor\Modules\KitElementsDefaults\Module;
|
||||
use Elementor\Modules\KitElementsDefaults\Utils\Settings_Sanitizer;
|
||||
use Elementor\App\Modules\ImportExport\Runners\Export\Export_Runner_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Export extends Export_Runner_Base {
|
||||
public static function get_name() : string {
|
||||
return 'elements-default-values';
|
||||
}
|
||||
|
||||
public function should_export( array $data ) {
|
||||
// Together with site-settings.
|
||||
return (
|
||||
isset( $data['include'] ) &&
|
||||
in_array( 'settings', $data['include'], true )
|
||||
);
|
||||
}
|
||||
|
||||
public function export( array $data ) {
|
||||
$kit = Plugin::$instance->kits_manager->get_active_kit();
|
||||
|
||||
if ( ! $kit ) {
|
||||
return [
|
||||
'manifest' => [],
|
||||
'files' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$default_values = $kit->get_json_meta( Module::META_KEY );
|
||||
|
||||
if ( ! $default_values ) {
|
||||
return [
|
||||
'manifest' => [],
|
||||
'files' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$sanitizer = new Settings_Sanitizer(
|
||||
Plugin::$instance->elements_manager,
|
||||
array_keys( Plugin::$instance->widgets_manager->get_widget_types() )
|
||||
);
|
||||
|
||||
$default_values = ( new Collection( $default_values ) )
|
||||
->map( function ( $settings, $type ) use ( $sanitizer, $kit ) {
|
||||
return $sanitizer
|
||||
->for( $type )
|
||||
->using( $settings )
|
||||
->remove_invalid_settings()
|
||||
->kses_deep()
|
||||
->prepare_for_export( $kit )
|
||||
->get();
|
||||
} )
|
||||
->all();
|
||||
|
||||
return [
|
||||
'files' => [
|
||||
'path' => Import_Export::FILE_NAME,
|
||||
'data' => $default_values,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\KitElementsDefaults\ImportExport\Runners;
|
||||
|
||||
use Elementor\Modules\KitElementsDefaults\ImportExport\Import_Export;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Core\Utils\Collection;
|
||||
use Elementor\Modules\KitElementsDefaults\Module;
|
||||
use Elementor\App\Modules\ImportExport\Utils as ImportExportUtils;
|
||||
use Elementor\Modules\KitElementsDefaults\Utils\Settings_Sanitizer;
|
||||
use Elementor\App\Modules\ImportExport\Runners\Import\Import_Runner_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Import extends Import_Runner_Base {
|
||||
public static function get_name() : string {
|
||||
return 'elements-default-values';
|
||||
}
|
||||
|
||||
public function should_import( array $data ) {
|
||||
// Together with site-settings.
|
||||
return (
|
||||
isset( $data['include'] ) &&
|
||||
in_array( 'settings', $data['include'], true ) &&
|
||||
! empty( $data['site_settings']['settings'] ) &&
|
||||
! empty( $data['extracted_directory_path'] )
|
||||
);
|
||||
}
|
||||
|
||||
public function import( array $data, array $imported_data ) {
|
||||
$kit = Plugin::$instance->kits_manager->get_active_kit();
|
||||
$file_name = Import_Export::FILE_NAME;
|
||||
$default_values = ImportExportUtils::read_json_file( "{$data['extracted_directory_path']}/{$file_name}.json" );
|
||||
|
||||
if ( ! $kit || ! $default_values ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$element_types = array_keys( Plugin::$instance->elements_manager->get_element_types() );
|
||||
$widget_types = array_keys( Plugin::$instance->widgets_manager->get_widget_types() );
|
||||
|
||||
$types = array_merge( $element_types, $widget_types );
|
||||
|
||||
$sanitizer = new Settings_Sanitizer(
|
||||
Plugin::$instance->elements_manager,
|
||||
$widget_types
|
||||
);
|
||||
|
||||
$default_values = ( new Collection( $default_values ) )
|
||||
->filter( function ( $settings, $type ) use ( $types ) {
|
||||
return in_array( $type, $types, true );
|
||||
} )
|
||||
->map( function ( $settings, $type ) use ( $sanitizer, $kit ) {
|
||||
return $sanitizer
|
||||
->for( $type )
|
||||
->using( $settings )
|
||||
->remove_invalid_settings()
|
||||
->kses_deep()
|
||||
->prepare_for_import( $kit )
|
||||
->get();
|
||||
} )
|
||||
->all();
|
||||
|
||||
$kit->update_json_meta( Module::META_KEY, $default_values );
|
||||
|
||||
return $default_values;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\KitElementsDefaults;
|
||||
|
||||
use Elementor\Core\Experiments\Manager as Experiments_Manager;
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Modules\KitElementsDefaults\Data\Controller;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Modules\KitElementsDefaults\ImportExport\Import_Export;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
const META_KEY = '_elementor_elements_default_values';
|
||||
|
||||
public function get_name() {
|
||||
return 'kit-elements-defaults';
|
||||
}
|
||||
|
||||
private function enqueue_scripts() {
|
||||
wp_enqueue_script(
|
||||
'elementor-kit-elements-defaults-editor',
|
||||
$this->get_js_assets_url( 'kit-elements-defaults-editor' ),
|
||||
[
|
||||
'elementor-common',
|
||||
'elementor-editor-modules',
|
||||
'elementor-editor-document',
|
||||
'wp-i18n',
|
||||
],
|
||||
ELEMENTOR_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
wp_set_script_translations( 'elementor-kit-elements-defaults-editor', 'elementor' );
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_action( 'elementor/editor/before_enqueue_scripts', function () {
|
||||
$this->enqueue_scripts();
|
||||
} );
|
||||
|
||||
Plugin::$instance->data_manager_v2->register_controller( new Controller() );
|
||||
|
||||
( new Usage() )->register();
|
||||
|
||||
if ( is_admin() ) {
|
||||
( new Import_Export() )->register();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\KitElementsDefaults;
|
||||
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Usage {
|
||||
|
||||
public function register() {
|
||||
add_filter( 'elementor/tracker/send_tracking_data_params', function ( array $params ) {
|
||||
$params['usages']['kit']['defaults'] = $this->get_usage_data();
|
||||
|
||||
return $params;
|
||||
} );
|
||||
}
|
||||
|
||||
private function get_usage_data() {
|
||||
$elements_defaults = $this->get_elements_defaults() ?? [];
|
||||
|
||||
return [
|
||||
'count' => count( $elements_defaults ),
|
||||
'elements' => array_keys( $elements_defaults ),
|
||||
];
|
||||
}
|
||||
|
||||
private function get_elements_defaults() {
|
||||
$kit = Plugin::$instance->kits_manager->get_active_kit();
|
||||
|
||||
return $kit->get_json_meta( Module::META_KEY );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\KitElementsDefaults\Utils;
|
||||
|
||||
use Elementor\Core\Breakpoints\Manager as Breakpoints_Manager;
|
||||
use Elementor\Element_Base;
|
||||
use Elementor\Elements_Manager;
|
||||
use Elementor\Core\Base\Document;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Settings_Sanitizer {
|
||||
|
||||
const SPECIAL_SETTINGS = [
|
||||
'__dynamic__',
|
||||
'__globals__',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var Elements_Manager
|
||||
*/
|
||||
private $elements_manager;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $widget_types;
|
||||
|
||||
/**
|
||||
* @var Element_Base | null
|
||||
*/
|
||||
private $pending_element = null;
|
||||
|
||||
/**
|
||||
* @var array | null
|
||||
*/
|
||||
private $pending_settings = null;
|
||||
|
||||
/**
|
||||
* @param Elements_Manager $elements_manager
|
||||
* @param array $widget_types
|
||||
*/
|
||||
public function __construct( Elements_Manager $elements_manager, array $widget_types = [] ) {
|
||||
$this->elements_manager = $elements_manager;
|
||||
$this->widget_types = $widget_types;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function for( $type ) {
|
||||
$this->pending_element = $this->create_element( $type );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $settings
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function using( $settings ) {
|
||||
$this->pending_settings = $settings;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function reset() {
|
||||
$this->pending_element = null;
|
||||
$this->pending_settings = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function is_prepared() {
|
||||
return $this->pending_element && is_array( $this->pending_settings );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function remove_invalid_settings() {
|
||||
if ( ! $this->is_prepared() ) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$valid_settings_keys = $this->get_valid_settings_keys(
|
||||
$this->pending_element->get_controls()
|
||||
);
|
||||
|
||||
$this->pending_settings = $this->filter_invalid_settings(
|
||||
$this->pending_settings,
|
||||
array_merge( $valid_settings_keys, self::SPECIAL_SETTINGS )
|
||||
);
|
||||
|
||||
foreach ( self::SPECIAL_SETTINGS as $special_setting ) {
|
||||
if ( ! isset( $this->pending_settings[ $special_setting ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->pending_settings[ $special_setting ] = $this->filter_invalid_settings(
|
||||
$this->pending_settings[ $special_setting ],
|
||||
$valid_settings_keys
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function kses_deep() {
|
||||
if ( ! $this->is_prepared() ) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->pending_settings = map_deep( $this->pending_settings, function( $value ) {
|
||||
if ( ! is_string( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return wp_kses_post( $value );
|
||||
} );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function prepare_for_export( Document $document ) {
|
||||
return $this->run_import_export_sanitize_process( $document, 'on_export' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function prepare_for_import( Document $document ) {
|
||||
return $this->run_import_export_sanitize_process( $document, 'on_import' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get() {
|
||||
if ( ! $this->is_prepared() ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$settings = $this->pending_settings;
|
||||
|
||||
$this->reset();
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param array $settings
|
||||
*
|
||||
* @return Element_Base|null
|
||||
*/
|
||||
private function create_element( $type ) {
|
||||
$is_widget = in_array( $type, $this->widget_types, true );
|
||||
$is_inner_section = 'inner-section' === $type;
|
||||
|
||||
if ( $is_inner_section ) {
|
||||
return $this->elements_manager->create_element_instance( [
|
||||
'elType' => 'section',
|
||||
'isInner' => true,
|
||||
'id' => '0',
|
||||
] );
|
||||
}
|
||||
|
||||
if ( $is_widget ) {
|
||||
return $this->elements_manager->create_element_instance( [
|
||||
'elType' => 'widget',
|
||||
'widgetType' => $type,
|
||||
'id' => '0',
|
||||
] );
|
||||
}
|
||||
|
||||
return $this->elements_manager->create_element_instance( [
|
||||
'elType' => $type,
|
||||
'id' => '0',
|
||||
] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document
|
||||
* @param $process_type
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
private function run_import_export_sanitize_process( Document $document, $process_type ) {
|
||||
if ( ! $this->is_prepared() ) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$result = $document->process_element_import_export(
|
||||
$this->pending_element,
|
||||
$process_type,
|
||||
[ 'settings' => $this->pending_settings ]
|
||||
);
|
||||
|
||||
if ( empty( $result['settings'] ) ) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->pending_settings = $result['settings'];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the available settings of a specific element, including responsive settings.
|
||||
*
|
||||
* @param array $controls
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_valid_settings_keys( $controls ) {
|
||||
if ( ! $controls ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$control_keys = array_keys( $controls );
|
||||
|
||||
$optional_responsive_keys = [
|
||||
Breakpoints_Manager::BREAKPOINT_KEY_MOBILE,
|
||||
Breakpoints_Manager::BREAKPOINT_KEY_MOBILE_EXTRA,
|
||||
Breakpoints_Manager::BREAKPOINT_KEY_TABLET,
|
||||
Breakpoints_Manager::BREAKPOINT_KEY_TABLET_EXTRA,
|
||||
Breakpoints_Manager::BREAKPOINT_KEY_LAPTOP,
|
||||
Breakpoints_Manager::BREAKPOINT_KEY_WIDESCREEN,
|
||||
];
|
||||
|
||||
$settings = [];
|
||||
|
||||
foreach ( $control_keys as $control_key ) {
|
||||
// Add the responsive settings.
|
||||
foreach ( $optional_responsive_keys as $responsive_key ) {
|
||||
$settings[] = "{$control_key}_{$responsive_key}";
|
||||
}
|
||||
// Add the setting itself (not responsive).
|
||||
$settings[] = $control_key;
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove invalid settings.
|
||||
*
|
||||
* @param $settings
|
||||
* @param $valid_settings_keys
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function filter_invalid_settings( $settings, $valid_settings_keys ) {
|
||||
return array_filter(
|
||||
$settings,
|
||||
function ( $setting_key ) use ( $valid_settings_keys ) {
|
||||
return in_array( $setting_key, $valid_settings_keys, true );
|
||||
},
|
||||
ARRAY_FILTER_USE_KEY
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\LandingPages\AdminMenuItems;
|
||||
|
||||
use Elementor\Core\Admin\Menu\Interfaces\Admin_Menu_Item_With_Page;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Landing_Pages_Empty_View_Menu_Item extends Landing_Pages_Menu_Item implements Admin_Menu_Item_With_Page {
|
||||
|
||||
private $render_callback;
|
||||
|
||||
public function __construct( callable $render_callback ) {
|
||||
$this->render_callback = $render_callback;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
( $this->render_callback )();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\LandingPages\AdminMenuItems;
|
||||
|
||||
use Elementor\Core\Admin\Menu\Interfaces\Admin_Menu_Item;
|
||||
use Elementor\TemplateLibrary\Source_Local;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Landing_Pages_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__( 'Landing Pages', 'elementor' );
|
||||
}
|
||||
|
||||
public function get_page_title() {
|
||||
return esc_html__( 'Landing Pages', 'elementor' );
|
||||
}
|
||||
|
||||
public function get_capability() {
|
||||
return 'manage_options';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\LandingPages\Documents;
|
||||
|
||||
use Elementor\Core\DocumentTypes\PageBase;
|
||||
use Elementor\Modules\LandingPages\Module as Landing_Pages_Module;
|
||||
use Elementor\Modules\Library\Traits\Library;
|
||||
use Elementor\Modules\PageTemplates\Module as Page_Templates_Module;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\TemplateLibrary\Source_Local;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Landing_Page extends PageBase {
|
||||
|
||||
// Library Document Trait
|
||||
use Library;
|
||||
|
||||
public static function get_properties() {
|
||||
$properties = parent::get_properties();
|
||||
|
||||
$properties['support_kit'] = true;
|
||||
$properties['show_in_library'] = true;
|
||||
$properties['cpt'] = [ Landing_Pages_Module::CPT ];
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
public static function get_type() {
|
||||
return Landing_Pages_Module::DOCUMENT_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @access public
|
||||
*/
|
||||
public function get_name() {
|
||||
return Landing_Pages_Module::DOCUMENT_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function get_title() {
|
||||
return esc_html__( 'Landing Page', 'elementor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function get_plural_title() {
|
||||
return esc_html__( 'Landing Pages', 'elementor' );
|
||||
}
|
||||
|
||||
public static function get_create_url() {
|
||||
return parent::get_create_url() . '#library';
|
||||
}
|
||||
|
||||
/**
|
||||
* Save Document.
|
||||
*
|
||||
* Save an Elementor document.
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access public
|
||||
*
|
||||
* @param $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save( $data ) {
|
||||
// This is for the first time a Landing Page is created. It is done in order to load a new Landing Page with
|
||||
// 'Canvas' as the default page template.
|
||||
if ( empty( $data['settings']['template'] ) ) {
|
||||
$data['settings']['template'] = Page_Templates_Module::TEMPLATE_CANVAS;
|
||||
}
|
||||
|
||||
return parent::save( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin Columns Content
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param $column_name
|
||||
* @access public
|
||||
*/
|
||||
public function admin_columns_content( $column_name ) {
|
||||
if ( 'elementor_library_type' === $column_name ) {
|
||||
$this->print_admin_column_type();
|
||||
}
|
||||
}
|
||||
|
||||
protected function get_remote_library_config() {
|
||||
$config = [
|
||||
'type' => 'lp',
|
||||
'default_route' => 'templates/landing-pages',
|
||||
'autoImportSettings' => true,
|
||||
];
|
||||
|
||||
return array_replace_recursive( parent::get_remote_library_config(), $config );
|
||||
}
|
||||
}
|
||||
504
wp-content/plugins/elementor/modules/landing-pages/module.php
Normal file
504
wp-content/plugins/elementor/modules/landing-pages/module.php
Normal file
@@ -0,0 +1,504 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\LandingPages;
|
||||
|
||||
use Elementor\Core\Admin\Menu\Admin_Menu_Manager;
|
||||
use Elementor\Core\Admin\Menu\Main as MainMenu;
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Core\Documents_Manager;
|
||||
use Elementor\Core\Experiments\Manager as Experiments_Manager;
|
||||
use Elementor\Modules\LandingPages\Documents\Landing_Page;
|
||||
use Elementor\Modules\LandingPages\AdminMenuItems\Landing_Pages_Menu_Item;
|
||||
use Elementor\Modules\LandingPages\AdminMenuItems\Landing_Pages_Empty_View_Menu_Item;
|
||||
use Elementor\Modules\LandingPages\Module as Landing_Pages_Module;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\TemplateLibrary\Source_Local;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
const DOCUMENT_TYPE = 'landing-page';
|
||||
const CPT = 'e-landing-page';
|
||||
const ADMIN_PAGE_SLUG = 'edit.php?post_type=' . self::CPT;
|
||||
|
||||
private $has_pages = null;
|
||||
private $trashed_posts;
|
||||
private $new_lp_url;
|
||||
private $permalink_structure;
|
||||
|
||||
public function get_name() {
|
||||
return 'landing-pages';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Experimental Data
|
||||
*
|
||||
* Implementation of this method makes the module an experiment.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_experimental_data() {
|
||||
return [
|
||||
'name' => 'landing-pages',
|
||||
'title' => esc_html__( 'Landing Pages', 'elementor' ),
|
||||
'description' => esc_html__( 'Adds a new Elementor content type that allows creating beautiful landing pages instantly in a streamlined workflow.', 'elementor' ),
|
||||
'release_status' => Experiments_Manager::RELEASE_STATUS_BETA,
|
||||
'default' => Experiments_Manager::STATE_ACTIVE,
|
||||
'new_site' => [
|
||||
'default_inactive' => true,
|
||||
'minimum_installation_version' => '3.22.0',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Trashed Landing Pages Posts
|
||||
*
|
||||
* Returns the posts property of a WP_Query run for Landing Pages with post_status of 'trash'.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @return array trashed posts
|
||||
*/
|
||||
private function get_trashed_landing_page_posts() {
|
||||
if ( $this->trashed_posts ) {
|
||||
return $this->trashed_posts;
|
||||
}
|
||||
|
||||
// `'posts_per_page' => 1` is because this is only used as an indicator to whether there are any trashed landing pages.
|
||||
$trashed_posts_query = new \WP_Query( [
|
||||
'no_found_rows' => true,
|
||||
'post_type' => self::CPT,
|
||||
'post_status' => 'trash',
|
||||
'posts_per_page' => 1,
|
||||
'meta_key' => '_elementor_template_type',
|
||||
'meta_value' => self::DOCUMENT_TYPE,
|
||||
] );
|
||||
|
||||
$this->trashed_posts = $trashed_posts_query->posts;
|
||||
|
||||
return $this->trashed_posts;
|
||||
}
|
||||
|
||||
private function has_landing_pages() {
|
||||
if ( null !== $this->has_pages ) {
|
||||
return $this->has_pages;
|
||||
}
|
||||
|
||||
$posts_query = new \WP_Query( [
|
||||
'no_found_rows' => true,
|
||||
'post_type' => self::CPT,
|
||||
'post_status' => 'any',
|
||||
'posts_per_page' => 1,
|
||||
'meta_key' => '_elementor_template_type',
|
||||
'meta_value' => self::DOCUMENT_TYPE,
|
||||
] );
|
||||
|
||||
$this->has_pages = $posts_query->post_count > 0;
|
||||
|
||||
return $this->has_pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Elementor Landing Page.
|
||||
*
|
||||
* Check whether the post is an Elementor Landing Page.
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access public
|
||||
*
|
||||
* @param \WP_Post $post Post Object
|
||||
*
|
||||
* @return bool Whether the post was built with Elementor.
|
||||
*/
|
||||
public function is_elementor_landing_page( $post ) {
|
||||
return self::CPT === $post->post_type;
|
||||
}
|
||||
|
||||
private function get_menu_args() {
|
||||
if ( $this->has_landing_pages() ) {
|
||||
$menu_slug = self::ADMIN_PAGE_SLUG;
|
||||
$function = null;
|
||||
} else {
|
||||
$menu_slug = self::CPT;
|
||||
$function = [ $this, 'print_empty_landing_pages_page' ];
|
||||
}
|
||||
|
||||
return [
|
||||
'menu_slug' => $menu_slug,
|
||||
'function' => $function,
|
||||
];
|
||||
}
|
||||
|
||||
private function register_admin_menu( MainMenu $menu ) {
|
||||
$landing_pages_title = esc_html__( 'Landing Pages', 'elementor' );
|
||||
|
||||
$menu_args = array_merge( $this->get_menu_args(), [
|
||||
'page_title' => $landing_pages_title,
|
||||
'menu_title' => $landing_pages_title,
|
||||
'index' => 20,
|
||||
] );
|
||||
|
||||
$menu->add_submenu( $menu_args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Submenu Page
|
||||
*
|
||||
* Adds the 'Landing Pages' submenu item to the 'Templates' menu item.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*/
|
||||
private function register_admin_menu_legacy( Admin_Menu_Manager $admin_menu ) {
|
||||
$menu_args = $this->get_menu_args();
|
||||
|
||||
$slug = $menu_args['menu_slug'];
|
||||
$function = $menu_args['function'];
|
||||
|
||||
if ( is_callable( $function ) ) {
|
||||
$admin_menu->register( $slug, new Landing_Pages_Empty_View_Menu_Item( $function ) );
|
||||
} else {
|
||||
$admin_menu->register( $slug, new Landing_Pages_Menu_Item() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get 'Add New' Landing Page URL
|
||||
*
|
||||
* Retrieves the custom URL for the admin dashboard's 'Add New' button in the Landing Pages admin screen. This URL
|
||||
* creates a new Landing Pages and directly opens the Elementor Editor with the Template Library modal open on the
|
||||
* Landing Pages tab.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_add_new_landing_page_url() {
|
||||
if ( ! $this->new_lp_url ) {
|
||||
$this->new_lp_url = Plugin::$instance->documents->get_create_new_post_url( self::CPT, self::DOCUMENT_TYPE ) . '#library';
|
||||
}
|
||||
return $this->new_lp_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Empty Landing Pages Page
|
||||
*
|
||||
* Prints the HTML content of the page that is displayed when there are no existing landing pages in the DB.
|
||||
* Added as the callback to add_submenu_page.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public function print_empty_landing_pages_page() {
|
||||
$template_sources = Plugin::$instance->templates_manager->get_registered_sources();
|
||||
$source_local = $template_sources['local'];
|
||||
$trashed_posts = $this->get_trashed_landing_page_posts();
|
||||
|
||||
?>
|
||||
<div class="e-landing-pages-empty">
|
||||
<?php
|
||||
/** @var Source_Local $source_local */
|
||||
$source_local->print_blank_state_template( esc_html__( 'Landing Page', 'elementor' ), $this->get_add_new_landing_page_url(), esc_html__( 'Build Effective Landing Pages for your business\' marketing campaigns.', 'elementor' ) );
|
||||
|
||||
if ( ! empty( $trashed_posts ) ) : ?>
|
||||
<div class="e-trashed-items">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %1$s Link open tag, %2$s: Link close tag. */
|
||||
esc_html__( 'Or view %1$sTrashed Items%1$s', 'elementor' ),
|
||||
'<a href="' . esc_url( admin_url( 'edit.php?post_status=trash&post_type=' . self::CPT ) ) . '">',
|
||||
'</a>'
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Current Admin Page Edit LP
|
||||
*
|
||||
* Checks whether the current page is a native WordPress edit page for a landing page.
|
||||
*/
|
||||
private function is_landing_page_admin_edit() {
|
||||
$screen = get_current_screen();
|
||||
|
||||
if ( 'post' === $screen->base ) {
|
||||
return $this->is_elementor_landing_page( get_post() );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin Localize Settings
|
||||
*
|
||||
* Enables adding properties to the globally available elementorAdmin.config JS object in the Admin Dashboard.
|
||||
* Runs on the 'elementor/admin/localize_settings' filter.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param $settings
|
||||
* @return array|null
|
||||
*/
|
||||
private function admin_localize_settings( $settings ) {
|
||||
$additional_settings = [
|
||||
'urls' => [
|
||||
'addNewLandingPageUrl' => $this->get_add_new_landing_page_url(),
|
||||
],
|
||||
'landingPages' => [
|
||||
'landingPagesHasPages' => $this->has_landing_pages(),
|
||||
'isLandingPageAdminEdit' => $this->is_landing_page_admin_edit(),
|
||||
],
|
||||
];
|
||||
|
||||
return array_replace_recursive( $settings, $additional_settings );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Landing Pages CPT
|
||||
*
|
||||
* @since 3.1.0
|
||||
*/
|
||||
private function register_landing_page_cpt() {
|
||||
$labels = [
|
||||
'name' => esc_html__( 'Landing Pages', 'elementor' ),
|
||||
'singular_name' => esc_html__( 'Landing Page', 'elementor' ),
|
||||
'add_new' => esc_html__( 'Add New', 'elementor' ),
|
||||
'add_new_item' => esc_html__( 'Add New Landing Page', 'elementor' ),
|
||||
'edit_item' => esc_html__( 'Edit Landing Page', 'elementor' ),
|
||||
'new_item' => esc_html__( 'New Landing Page', 'elementor' ),
|
||||
'all_items' => esc_html__( 'All Landing Pages', 'elementor' ),
|
||||
'view_item' => esc_html__( 'View Landing Page', 'elementor' ),
|
||||
'search_items' => esc_html__( 'Search Landing Pages', 'elementor' ),
|
||||
'not_found' => esc_html__( 'No landing pages found', 'elementor' ),
|
||||
'not_found_in_trash' => esc_html__( 'No landing pages found in trash', 'elementor' ),
|
||||
'parent_item_colon' => '',
|
||||
'menu_name' => esc_html__( 'Landing Pages', 'elementor' ),
|
||||
];
|
||||
|
||||
$args = [
|
||||
'labels' => $labels,
|
||||
'public' => true,
|
||||
'show_in_menu' => 'edit.php?post_type=elementor_library&tabs_group=library',
|
||||
'capability_type' => 'page',
|
||||
'taxonomies' => [ Source_Local::TAXONOMY_TYPE_SLUG ],
|
||||
'supports' => [ 'title', 'editor', 'comments', 'revisions', 'trackbacks', 'author', 'excerpt', 'page-attributes', 'thumbnail', 'custom-fields', 'post-formats', 'elementor' ],
|
||||
];
|
||||
|
||||
register_post_type( self::CPT, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove Post Type Slug
|
||||
*
|
||||
* Landing Pages are supposed to act exactly like pages. This includes their URLs being directly under the site's
|
||||
* domain name. Since "Landing Pages" is a CPT, WordPress automatically adds the landing page slug as a prefix to
|
||||
* it's posts' permalinks. This method checks if the post's post type is Landing Pages, and if it is, it removes
|
||||
* the CPT slug from the requested post URL.
|
||||
*
|
||||
* Runs on the 'post_type_link' filter.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param $post_link
|
||||
* @param $post
|
||||
* @param $leavename
|
||||
* @return string|string[]
|
||||
*/
|
||||
private function remove_post_type_slug( $post_link, $post, $leavename ) {
|
||||
// Only try to modify the permalink if the post is a Landing Page.
|
||||
if ( self::CPT !== $post->post_type || 'publish' !== $post->post_status ) {
|
||||
return $post_link;
|
||||
}
|
||||
|
||||
// Any slug prefixes need to be removed from the post link.
|
||||
return get_home_url() . '/' . $post->post_name . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust Landing Page Query
|
||||
*
|
||||
* Since Landing Pages are a CPT but should act like pages, the WP_Query that is used to fetch the page from the
|
||||
* database needs to be adjusted. This method adds the Landing Pages CPT to the list of queried post types, to
|
||||
* make sure the database query finds the correct Landing Page to display.
|
||||
* Runs on the 'pre_get_posts' action.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param \WP_Query $query
|
||||
*/
|
||||
private function adjust_landing_page_query( \WP_Query $query ) {
|
||||
// Only handle actual pages.
|
||||
if (
|
||||
! $query->is_main_query()
|
||||
// If the query is not for a page.
|
||||
|| ! isset( $query->query['page'] )
|
||||
// If the query is for a static home/blog page.
|
||||
|| is_home()
|
||||
// If the post type comes already set, the main query is probably a custom one made by another plugin.
|
||||
// In this case we do not want to intervene in order to not cause a conflict.
|
||||
|| isset( $query->query['post_type'] )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the post types property as an array and include the landing pages CPT in it.
|
||||
$query_post_types = [ 'post', 'page', self::CPT ];
|
||||
|
||||
// Since WordPress determined this is supposed to be a page, we'll pre-set the post_type query arg to make sure
|
||||
// it includes the Landing Page CPT, so when the query is parsed, our CPT will be a legitimate match to the
|
||||
// Landing Page's permalink (that is directly under the domain, without a CPT slug prefix). In some cases,
|
||||
// The 'name' property will be set, and in others it is the 'pagename', so we have to cover both cases.
|
||||
if ( ! empty( $query->query['name'] ) ) {
|
||||
$query->set( 'post_type', $query_post_types );
|
||||
} elseif ( ! empty( $query->query['pagename'] ) && false === strpos( $query->query['pagename'], '/' ) ) {
|
||||
$query->set( 'post_type', $query_post_types );
|
||||
|
||||
// We also need to set the name query var since redirect_guess_404_permalink() relies on it.
|
||||
add_filter( 'pre_redirect_guess_404_permalink', function( $value ) use ( $query ) {
|
||||
set_query_var( 'name', $query->query['pagename'] );
|
||||
|
||||
return $value;
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle 404
|
||||
*
|
||||
* This method runs after a page is not found in the database, but before a page is returned as a 404.
|
||||
* These cases are handled in this filter callback, that runs on the 'pre_handle_404' filter.
|
||||
*
|
||||
* In some cases (such as when a site uses custom permalink structures), WordPress's WP_Query does not identify a
|
||||
* Landing Page's URL as a post belonging to the Landing Page CPT. Some cases are handled successfully by the
|
||||
* adjust_landing_page_query() method, but some are not and still trigger a 404 process. This method handles such
|
||||
* cases by overriding the $wp_query global to fetch the correct landing page post entry.
|
||||
*
|
||||
* For example, since Landing Pages slugs come directly after the site domain name, WP_Query might parse the post
|
||||
* as a category page. Since there is no category matching the slug, it triggers a 404 process. In this case, we
|
||||
* run a query for a Landing Page post with the passed slug ($query->query['category_name']. If a Landing Page
|
||||
* with the passed slug is found, we override the global $wp_query with the new, correct query.
|
||||
*
|
||||
* @param $current_value
|
||||
* @param $query
|
||||
* @return false
|
||||
*/
|
||||
private function handle_404( $current_value, $query ) {
|
||||
global $wp_query;
|
||||
|
||||
// If another plugin/theme already used this filter, exit here to avoid conflicts.
|
||||
if ( $current_value ) {
|
||||
return $current_value;
|
||||
}
|
||||
|
||||
if (
|
||||
// Make sure we only intervene in the main query.
|
||||
! $query->is_main_query()
|
||||
// If a post was found, this is not a 404 case, so do not intervene.
|
||||
|| ! empty( $query->posts )
|
||||
// This filter is only meant to deal with wrong queries where the only query var is 'category_name'.
|
||||
// If there is no 'category_name' query var, do not intervene.
|
||||
|| empty( $query->query['category_name'] )
|
||||
// If the query is for a real taxonomy (determined by it including a table to search in, such as the
|
||||
// wp_term_relationships table), do not intervene.
|
||||
|| ! empty( $query->tax_query->table_aliases )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Search for a Landing Page with the same name passed as the 'category name'.
|
||||
$possible_new_query = new \WP_Query( [
|
||||
'no_found_rows' => true,
|
||||
'post_type' => self::CPT,
|
||||
'name' => $query->query['category_name'],
|
||||
] );
|
||||
|
||||
// Only if such a Landing Page is found, override the query to fetch the correct page.
|
||||
if ( ! empty( $possible_new_query->posts ) ) {
|
||||
$wp_query = $possible_new_query; //phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
$this->permalink_structure = get_option( 'permalink_structure' );
|
||||
|
||||
$this->register_landing_page_cpt();
|
||||
|
||||
// If there is a permalink structure set to the site, run the hooks that modify the Landing Pages permalinks to
|
||||
// match WordPress' native 'Pages' post type.
|
||||
if ( '' !== $this->permalink_structure ) {
|
||||
// Landing Pages' post link needs to be modified to be identical to the pages permalink structure. This
|
||||
// needs to happen in both the admin and the front end, since post links are also used in the admin pages.
|
||||
add_filter( 'post_type_link', function( $post_link, $post, $leavename ) {
|
||||
return $this->remove_post_type_slug( $post_link, $post, $leavename );
|
||||
}, 10, 3 );
|
||||
|
||||
// The query itself only has to be manipulated when pages are viewed in the front end.
|
||||
if ( ! is_admin() || wp_doing_ajax() ) {
|
||||
add_action( 'pre_get_posts', function ( $query ) {
|
||||
$this->adjust_landing_page_query( $query );
|
||||
} );
|
||||
|
||||
// Handle cases where visiting a Landing Page's URL returns 404.
|
||||
add_filter( 'pre_handle_404', function ( $value, $query ) {
|
||||
return $this->handle_404( $value, $query );
|
||||
}, 10, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
add_action( 'elementor/documents/register', function( Documents_Manager $documents_manager ) {
|
||||
$documents_manager->register_document_type( self::DOCUMENT_TYPE, Landing_Page::get_class_full_name() );
|
||||
} );
|
||||
|
||||
add_action( 'elementor/admin/menu/register', function( Admin_Menu_Manager $admin_menu ) {
|
||||
$this->register_admin_menu_legacy( $admin_menu );
|
||||
}, Source_Local::ADMIN_MENU_PRIORITY + 20 );
|
||||
|
||||
// Add the custom 'Add New' link for Landing Pages into Elementor's admin config.
|
||||
add_action( 'elementor/admin/localize_settings', function( array $settings ) {
|
||||
return $this->admin_localize_settings( $settings );
|
||||
} );
|
||||
|
||||
add_filter( 'elementor/template_library/sources/local/register_taxonomy_cpts', function( array $cpts ) {
|
||||
$cpts[] = self::CPT;
|
||||
|
||||
return $cpts;
|
||||
} );
|
||||
|
||||
// In the Landing Pages Admin Table page - Overwrite Template type column header title.
|
||||
add_action( 'manage_' . Landing_Pages_Module::CPT . '_posts_columns', function( $posts_columns ) {
|
||||
/** @var Source_Local $source_local */
|
||||
$source_local = Plugin::$instance->templates_manager->get_source( 'local' );
|
||||
|
||||
return $source_local->admin_columns_headers( $posts_columns );
|
||||
} );
|
||||
|
||||
// In the Landing Pages Admin Table page - Overwrite Template type column row values.
|
||||
add_action( 'manage_' . Landing_Pages_Module::CPT . '_posts_custom_column', function( $column_name, $post_id ) {
|
||||
/** @var Landing_Page $document */
|
||||
$document = Plugin::$instance->documents->get( $post_id );
|
||||
|
||||
$document->admin_columns_content( $column_name );
|
||||
}, 10, 2 );
|
||||
|
||||
// Overwrite the Admin Bar's 'New +' Landing Page URL with the link that creates the new LP in Elementor
|
||||
// with the Template Library modal open.
|
||||
add_action( 'admin_bar_menu', function( $admin_bar ) {
|
||||
// Get the Landing Page menu node.
|
||||
$new_landing_page_node = $admin_bar->get_node( 'new-e-landing-page' );
|
||||
|
||||
if ( $new_landing_page_node ) {
|
||||
$new_landing_page_node->href = $this->get_add_new_landing_page_url();
|
||||
|
||||
$admin_bar->add_node( $new_landing_page_node );
|
||||
}
|
||||
}, 100 );
|
||||
}
|
||||
}
|
||||
103
wp-content/plugins/elementor/modules/lazyload/module.php
Normal file
103
wp-content/plugins/elementor/modules/lazyload/module.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\LazyLoad;
|
||||
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Core\Experiments\Manager as Experiments_Manager;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
const EXPERIMENT_NAME = 'e_lazyload';
|
||||
|
||||
public function get_name() {
|
||||
return 'lazyload';
|
||||
}
|
||||
|
||||
public static function get_experimental_data() {
|
||||
return [
|
||||
'name' => static::EXPERIMENT_NAME,
|
||||
'title' => esc_html__( 'Lazy Load Background Images', 'elementor' ),
|
||||
'tag' => esc_html__( 'Performance', 'elementor' ),
|
||||
'description' => esc_html__( 'Lazy loading images that are not in the viewport improves initial page load performance and user experience. By activating this experiment all background images except the first one on your page will be lazy loaded to improve your LCP score', 'elementor' ),
|
||||
'release_status' => Experiments_Manager::RELEASE_STATUS_STABLE,
|
||||
'default' => Experiments_Manager::STATE_ACTIVE,
|
||||
'generator_tag' => true,
|
||||
];
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_action( 'init', [ $this, 'init' ] );
|
||||
}
|
||||
|
||||
public function init() {
|
||||
add_action( 'wp_head', function() {
|
||||
if ( ! $this->should_lazyload() ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<style>
|
||||
.e-con.e-parent:nth-of-type(n+4):not(.e-lazyloaded):not(.e-no-lazyload),
|
||||
.e-con.e-parent:nth-of-type(n+4):not(.e-lazyloaded):not(.e-no-lazyload) * {
|
||||
background-image: none !important;
|
||||
}
|
||||
@media screen and (max-height: 1024px) {
|
||||
.e-con.e-parent:nth-of-type(n+3):not(.e-lazyloaded):not(.e-no-lazyload),
|
||||
.e-con.e-parent:nth-of-type(n+3):not(.e-lazyloaded):not(.e-no-lazyload) * {
|
||||
background-image: none !important;
|
||||
}
|
||||
}
|
||||
@media screen and (max-height: 640px) {
|
||||
.e-con.e-parent:nth-of-type(n+2):not(.e-lazyloaded):not(.e-no-lazyload),
|
||||
.e-con.e-parent:nth-of-type(n+2):not(.e-lazyloaded):not(.e-no-lazyload) * {
|
||||
background-image: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
} );
|
||||
|
||||
add_action( 'wp_footer', function() {
|
||||
if ( ! $this->should_lazyload() ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<script type='text/javascript'>
|
||||
const lazyloadRunObserver = () => {
|
||||
const lazyloadBackgrounds = document.querySelectorAll( `.e-con.e-parent:not(.e-lazyloaded)` );
|
||||
const lazyloadBackgroundObserver = new IntersectionObserver( ( entries ) => {
|
||||
entries.forEach( ( entry ) => {
|
||||
if ( entry.isIntersecting ) {
|
||||
let lazyloadBackground = entry.target;
|
||||
if( lazyloadBackground ) {
|
||||
lazyloadBackground.classList.add( 'e-lazyloaded' );
|
||||
}
|
||||
lazyloadBackgroundObserver.unobserve( entry.target );
|
||||
}
|
||||
});
|
||||
}, { rootMargin: '200px 0px 200px 0px' } );
|
||||
lazyloadBackgrounds.forEach( ( lazyloadBackground ) => {
|
||||
lazyloadBackgroundObserver.observe( lazyloadBackground );
|
||||
} );
|
||||
};
|
||||
const events = [
|
||||
'DOMContentLoaded',
|
||||
'elementor/lazyload/observe',
|
||||
];
|
||||
events.forEach( ( event ) => {
|
||||
document.addEventListener( event, lazyloadRunObserver );
|
||||
} );
|
||||
</script>
|
||||
<?php
|
||||
} );
|
||||
}
|
||||
|
||||
private function should_lazyload() {
|
||||
return ! is_admin() && ! Plugin::$instance->preview->is_preview_mode() && ! Plugin::$instance->editor->is_edit_mode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Library\Documents;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor container library document.
|
||||
*
|
||||
* Elementor container library document handler class is responsible for
|
||||
* handling a document of a container type.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class Container extends Library_Document {
|
||||
|
||||
public static function get_properties() {
|
||||
$properties = parent::get_properties();
|
||||
|
||||
$properties['support_kit'] = true;
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get document name.
|
||||
*
|
||||
* Retrieve the document name.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*
|
||||
* @return string Document name.
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'container';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get document title.
|
||||
*
|
||||
* Retrieve the document title.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @return string Document title.
|
||||
*/
|
||||
public static function get_title() {
|
||||
return esc_html__( 'Container', 'elementor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* Return the container document type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_type() {
|
||||
return 'container';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Library\Documents;
|
||||
|
||||
use Elementor\Core\Base\Document;
|
||||
use Elementor\Modules\Library\Traits\Library;
|
||||
use Elementor\TemplateLibrary\Source_Local;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor library document.
|
||||
*
|
||||
* Elementor library document handler class is responsible for handling
|
||||
* a document of the library type.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
abstract class Library_Document extends Document {
|
||||
|
||||
// Library Document Trait
|
||||
use Library;
|
||||
|
||||
/**
|
||||
* The taxonomy type slug for the library document.
|
||||
*/
|
||||
const TAXONOMY_TYPE_SLUG = 'elementor_library_type';
|
||||
|
||||
/**
|
||||
* Get document properties.
|
||||
*
|
||||
* Retrieve the document properties.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @return array Document properties.
|
||||
*/
|
||||
public static function get_properties() {
|
||||
$properties = parent::get_properties();
|
||||
|
||||
$properties['admin_tab_group'] = 'library';
|
||||
$properties['show_in_library'] = true;
|
||||
$properties['register_type'] = true;
|
||||
$properties['cpt'] = [ Source_Local::CPT ];
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get initial config.
|
||||
*
|
||||
* Retrieve the current element initial configuration.
|
||||
*
|
||||
* Adds more configuration on top of the controls list and the tabs assigned
|
||||
* to the control. This method also adds element name, type, icon and more.
|
||||
*
|
||||
* @since 2.9.0
|
||||
* @access protected
|
||||
*
|
||||
* @return array The initial config.
|
||||
*/
|
||||
public function get_initial_config() {
|
||||
$config = parent::get_initial_config();
|
||||
|
||||
$config['library'] = [
|
||||
'save_as_same_type' => true,
|
||||
];
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function get_content( $with_css = false ) {
|
||||
return do_shortcode( parent::get_content( $with_css ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Library\Documents;
|
||||
|
||||
use Elementor\TemplateLibrary\Source_Local;
|
||||
use Elementor\Utils;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor section library document.
|
||||
*
|
||||
* Elementor section library document handler class is responsible for
|
||||
* handling a document of a section type.
|
||||
*
|
||||
*/
|
||||
class Not_Supported extends Library_Document {
|
||||
|
||||
/**
|
||||
* Get document properties.
|
||||
*
|
||||
* Retrieve the document properties.
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @return array Document properties.
|
||||
*/
|
||||
public static function get_properties() {
|
||||
$properties = parent::get_properties();
|
||||
|
||||
$properties['admin_tab_group'] = '';
|
||||
$properties['register_type'] = false;
|
||||
$properties['is_editable'] = false;
|
||||
$properties['show_in_library'] = false;
|
||||
$properties['show_in_finder'] = false;
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
public static function get_type() {
|
||||
return 'not-supported';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get document title.
|
||||
*
|
||||
* Retrieve the document title.
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @return string Document title.
|
||||
*/
|
||||
public static function get_title() {
|
||||
return esc_html__( 'Not Supported', 'elementor' );
|
||||
}
|
||||
|
||||
public function save_template_type() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
public function print_admin_column_type() {
|
||||
Utils::print_unescaped_internal_string( self::get_title() );
|
||||
}
|
||||
|
||||
public function filter_admin_row_actions( $actions ) {
|
||||
unset( $actions['view'] );
|
||||
|
||||
return $actions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Library\Documents;
|
||||
|
||||
use Elementor\Core\DocumentTypes\Post;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor page library document.
|
||||
*
|
||||
* Elementor page library document handler class is responsible for
|
||||
* handling a document of a page type.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class Page extends Library_Document {
|
||||
|
||||
/**
|
||||
* Get document properties.
|
||||
*
|
||||
* Retrieve the document properties.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @return array Document properties.
|
||||
*/
|
||||
public static function get_properties() {
|
||||
$properties = parent::get_properties();
|
||||
|
||||
$properties['support_wp_page_templates'] = true;
|
||||
$properties['support_kit'] = true;
|
||||
$properties['show_in_finder'] = true;
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
public static function get_type() {
|
||||
return 'page';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get document title.
|
||||
*
|
||||
* Retrieve the document title.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @return string Document title.
|
||||
*/
|
||||
public static function get_title() {
|
||||
return esc_html__( 'Page', 'elementor' );
|
||||
}
|
||||
|
||||
public static function get_plural_title() {
|
||||
return esc_html__( 'Pages', 'elementor' );
|
||||
}
|
||||
|
||||
public static function get_add_new_title() {
|
||||
return esc_html__( 'Add New Page Template', 'elementor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.3
|
||||
* @access public
|
||||
*/
|
||||
public function get_css_wrapper_selector() {
|
||||
return 'body.elementor-page-' . $this->get_main_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*/
|
||||
protected function register_controls() {
|
||||
parent::register_controls();
|
||||
|
||||
Post::register_hide_title_control( $this );
|
||||
|
||||
Post::register_style_controls( $this );
|
||||
}
|
||||
|
||||
protected function get_remote_library_config() {
|
||||
$config = parent::get_remote_library_config();
|
||||
|
||||
$config['type'] = 'page';
|
||||
$config['default_route'] = 'templates/pages';
|
||||
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Library\Documents;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor section library document.
|
||||
*
|
||||
* Elementor section library document handler class is responsible for
|
||||
* handling a document of a section type.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class Section extends Library_Document {
|
||||
|
||||
public static function get_properties() {
|
||||
$properties = parent::get_properties();
|
||||
|
||||
$properties['support_kit'] = true;
|
||||
$properties['show_in_finder'] = true;
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
public static function get_type() {
|
||||
return 'section';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get document title.
|
||||
*
|
||||
* Retrieve the document title.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @return string Document title.
|
||||
*/
|
||||
public static function get_title() {
|
||||
return esc_html__( 'Section', 'elementor' );
|
||||
}
|
||||
|
||||
public static function get_plural_title() {
|
||||
return esc_html__( 'Sections', 'elementor' );
|
||||
}
|
||||
}
|
||||
58
wp-content/plugins/elementor/modules/library/module.php
Normal file
58
wp-content/plugins/elementor/modules/library/module.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Library;
|
||||
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Modules\Library\Documents;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor library module.
|
||||
*
|
||||
* Elementor library module handler class is responsible for registering and
|
||||
* managing Elementor library modules.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class Module extends BaseModule {
|
||||
|
||||
/**
|
||||
* Get module name.
|
||||
*
|
||||
* Retrieve the library module name.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*
|
||||
* @return string Module name.
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'library';
|
||||
}
|
||||
|
||||
/**
|
||||
* Library module constructor.
|
||||
*
|
||||
* Initializing Elementor library module.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*/
|
||||
public function __construct() {
|
||||
Plugin::$instance->documents
|
||||
->register_document_type( 'not-supported', Documents\Not_Supported::get_class_full_name() )
|
||||
->register_document_type( 'page', Documents\Page::get_class_full_name() )
|
||||
->register_document_type( 'section', Documents\Section::get_class_full_name() );
|
||||
|
||||
$experiments_manager = Plugin::$instance->experiments;
|
||||
|
||||
// Register `Container` document type only if the experiment is active.
|
||||
if ( $experiments_manager->is_feature_active( 'container' ) ) {
|
||||
Plugin::$instance->documents
|
||||
->register_document_type( 'container', Documents\Container::get_class_full_name() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Library\Traits;
|
||||
|
||||
use Elementor\TemplateLibrary\Source_Local;
|
||||
|
||||
/**
|
||||
* Elementor Library Trait
|
||||
*
|
||||
* This trait is used by all Library Documents and Landing Pages.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*/
|
||||
trait Library {
|
||||
/**
|
||||
* Print Admin Column Type
|
||||
*
|
||||
* Runs on WordPress' 'manage_{custom post type}_posts_custom_column' hook to modify each row's content.
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function print_admin_column_type() {
|
||||
$admin_filter_url = admin_url( Source_Local::ADMIN_MENU_SLUG . '&elementor_library_type=' . $this->get_name() );
|
||||
//PHPCS - Not a user input
|
||||
printf( '<a href="%s">%s</a>', $admin_filter_url, $this->get_title() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* Save document type.
|
||||
*
|
||||
* Set new/updated document type.
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function save_template_type() {
|
||||
parent::save_template_type();
|
||||
|
||||
wp_set_object_terms( $this->post->ID, $this->get_name(), Source_Local::TAXONOMY_TYPE_SLUG );
|
||||
}
|
||||
}
|
||||
145
wp-content/plugins/elementor/modules/library/user-favorites.php
Normal file
145
wp-content/plugins/elementor/modules/library/user-favorites.php
Normal file
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Library;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class User_Favorites {
|
||||
const USER_META_KEY = 'elementor_library_favorites';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $user_id;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* User_Favorites constructor.
|
||||
*
|
||||
* @param $user_id
|
||||
*/
|
||||
public function __construct( $user_id ) {
|
||||
$this->user_id = $user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $vendor
|
||||
* @param null $resource
|
||||
* @param false $ignore_cache
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get( $vendor = null, $resource = null, $ignore_cache = false ) {
|
||||
if ( $ignore_cache || empty( $this->cache ) ) {
|
||||
$this->cache = get_user_meta( $this->user_id, self::USER_META_KEY, true );
|
||||
}
|
||||
|
||||
if ( ! $this->cache || ! is_array( $this->cache ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ( $vendor && $resource ) {
|
||||
$key = $this->get_key( $vendor, $resource );
|
||||
|
||||
return isset( $this->cache[ $key ] ) ? $this->cache[ $key ] : [];
|
||||
}
|
||||
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $vendor
|
||||
* @param $resource
|
||||
* @param $id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists( $vendor, $resource, $id ) {
|
||||
return in_array( $id, $this->get( $vendor, $resource ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $vendor
|
||||
* @param $resource
|
||||
* @param array $value
|
||||
*
|
||||
* @return $this
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function save( $vendor, $resource, $value = [] ) {
|
||||
$all_favorites = $this->get();
|
||||
|
||||
$all_favorites[ $this->get_key( $vendor, $resource ) ] = $value;
|
||||
|
||||
$result = update_user_meta( $this->user_id, self::USER_META_KEY, $all_favorites );
|
||||
|
||||
if ( false === $result ) {
|
||||
throw new \Exception( 'Failed to save user favorites.' );
|
||||
}
|
||||
|
||||
$this->cache = $all_favorites;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $vendor
|
||||
* @param $resource
|
||||
* @param $id
|
||||
*
|
||||
* @return $this
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function add( $vendor, $resource, $id ) {
|
||||
$favorites = $this->get( $vendor, $resource );
|
||||
|
||||
if ( in_array( $id, $favorites, true ) ) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$favorites[] = $id;
|
||||
|
||||
$this->save( $vendor, $resource, $favorites );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $vendor
|
||||
* @param $resource
|
||||
* @param $id
|
||||
*
|
||||
* @return $this
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function remove( $vendor, $resource, $id ) {
|
||||
$favorites = $this->get( $vendor, $resource );
|
||||
|
||||
if ( ! in_array( $id, $favorites, true ) ) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$favorites = array_filter( $favorites, function ( $item ) use ( $id ) {
|
||||
return $item !== $id;
|
||||
} );
|
||||
|
||||
$this->save( $vendor, $resource, $favorites );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $vendor
|
||||
* @param $resource
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_key( $vendor, $resource ) {
|
||||
return "{$vendor}/{$resource}";
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\LinkInBio\Classes\Render;
|
||||
|
||||
/**
|
||||
* Class Core_Render.
|
||||
*
|
||||
* This class handles the rendering of the Link In Bio widget for the core version.
|
||||
*
|
||||
* @since 3.23.0
|
||||
*/
|
||||
class Core_Render extends Render_Base {
|
||||
|
||||
public function render(): void {
|
||||
$this->build_layout_render_attribute();
|
||||
?>
|
||||
<div <?php echo $this->widget->get_render_attribute_string( 'layout' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
||||
<div class="e-link-in-bio__content">
|
||||
|
||||
<?php
|
||||
$this->render_identity_image();
|
||||
|
||||
$this->render_bio();
|
||||
|
||||
$this->render_icons();
|
||||
|
||||
$this->render_image_links();
|
||||
|
||||
$this->render_ctas();
|
||||
|
||||
$this->render_footer_bio();
|
||||
?>
|
||||
|
||||
</div>
|
||||
<div class="e-link-in-bio__bg">
|
||||
<div class="e-link-in-bio__bg-overlay"></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,593 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\LinkInBio\Classes\Render;
|
||||
|
||||
use Elementor\Core\Base\Providers\Social_Network_Provider;
|
||||
use Elementor\Core\Base\Traits\Shared_Widget_Controls_Trait;
|
||||
use Elementor\Icons_Manager;
|
||||
use Elementor\Modules\LinkInBio\Base\Widget_Link_In_Bio_Base;
|
||||
use Elementor\Utils;
|
||||
|
||||
/**
|
||||
* Class Render_Base.
|
||||
*
|
||||
* This is the base class that will hold shared functionality that will be needed by all the various widget versions.
|
||||
*
|
||||
* @since 3.23.0
|
||||
*/
|
||||
abstract class Render_Base {
|
||||
|
||||
use Shared_Widget_Controls_Trait;
|
||||
|
||||
protected Widget_Link_In_Bio_Base $widget;
|
||||
|
||||
protected array $settings;
|
||||
|
||||
abstract public function render(): void;
|
||||
|
||||
public function __construct( Widget_Link_In_Bio_Base $widget ) {
|
||||
$this->widget = $widget;
|
||||
$this->settings = $widget->get_settings_for_display();
|
||||
}
|
||||
|
||||
protected function render_image_links(): void {
|
||||
$image_links_value_initial = $this->settings['image_links'] ?? [];
|
||||
$image_links_columns_value = $this->settings['image_links_per_row'] ?? 2;
|
||||
|
||||
/**
|
||||
* if empty returns a sub-array with all empty values
|
||||
* Check for this here to avoid rendering container when empty
|
||||
*/
|
||||
$image_links_value = $this->clean_array( $image_links_value_initial );
|
||||
$has_image_links = ! empty( $image_links_value );
|
||||
|
||||
if ( ! $has_image_links ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$image_links_classnames = 'e-link-in-bio__image-links';
|
||||
|
||||
if ( ! empty( $image_links_columns_value ) ) {
|
||||
$image_links_classnames .= ' has-' . $image_links_columns_value . '-columns';
|
||||
}
|
||||
|
||||
$this->widget->add_render_attribute( 'image-links', [
|
||||
'class' => $image_links_classnames,
|
||||
] );
|
||||
?>
|
||||
|
||||
<div <?php echo $this->widget->get_render_attribute_string( 'image-links' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
||||
<?php
|
||||
foreach ( $image_links_value as $key => $image_link ) {
|
||||
$formatted_link = $image_link['image_links_url']['url'] ?? '';
|
||||
$image_link_image = $image_link['image_links_image'] ?? [];
|
||||
|
||||
// Manage Link class variations
|
||||
|
||||
$image_link_classnames = 'e-link-in-bio__image-links-link';
|
||||
|
||||
// Manage Link attributes
|
||||
|
||||
$url_attrs = [
|
||||
'class' => $image_link_classnames,
|
||||
'href' => esc_url( $formatted_link ),
|
||||
];
|
||||
|
||||
$url_combined_attrs = $this->get_link_attributes(
|
||||
$image_link['image_links_url'],
|
||||
$url_attrs
|
||||
);
|
||||
|
||||
foreach ( $url_combined_attrs as $attr_key => $attr_value ) {
|
||||
$this->widget->add_render_attribute( 'image-links-link' . $key, [
|
||||
$attr_key => $attr_value,
|
||||
] );
|
||||
}
|
||||
?>
|
||||
<a <?php echo $this->widget->get_render_attribute_string( 'image-links-link' . $key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
||||
<?php if ( ! empty( $image_link_image['id'] ) ) {
|
||||
echo wp_get_attachment_image( $image_link_image['id'], 'thumbnail', false, [
|
||||
'class' => 'e-link-in-bio__image-links-img',
|
||||
] );
|
||||
} else {
|
||||
$this->widget->add_render_attribute( 'image-links-img-' . $key, [
|
||||
'alt' => '',
|
||||
'class' => 'e-link-in-bio__image-links-img',
|
||||
'src' => esc_url( $image_link_image['url'] ),
|
||||
] );
|
||||
?>
|
||||
<img <?php echo $this->widget->get_render_attribute_string( 'image-links-img-' . $key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> />
|
||||
<?php }; ?>
|
||||
</a>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function render_ctas(): void {
|
||||
$ctas_props_corners = $this->settings['cta_links_corners'] ?? 'rounded';
|
||||
$ctas_props_show_border = $this->settings['cta_links_show_border'] ?? false;
|
||||
$ctas_props_type = $this->settings['cta_links_type'] ?? 'button';
|
||||
$ctas_value_initial = $this->settings['cta_link'] ?? [];
|
||||
|
||||
/**
|
||||
* $this->settings['cta_link'] if empty returns a sub-array with all empty values
|
||||
* Check for this here to avoid rendering container when empty
|
||||
*/
|
||||
$ctas_value = $this->clean_array( $ctas_value_initial );
|
||||
$has_ctas = ! empty( $ctas_value );
|
||||
|
||||
if ( ! $has_ctas ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->widget->add_render_attribute( 'ctas', [
|
||||
'class' => 'e-link-in-bio__ctas has-type-' . $ctas_props_type,
|
||||
] );
|
||||
?>
|
||||
|
||||
<div <?php echo $this->widget->get_render_attribute_string( 'ctas' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
||||
<?php
|
||||
foreach ( $ctas_value as $key => $cta ) {
|
||||
$formatted_link = $this->get_formatted_link_based_on_type_for_cta( $cta );
|
||||
$cta_image = $cta['cta_link_image'] ?? [];
|
||||
$cta_has_image = ! empty( $cta_image ) &&
|
||||
( ! empty( $cta_image['url'] || ! empty( $cta_image['id'] ) ) ) &&
|
||||
'button' === $ctas_props_type;
|
||||
|
||||
// Manage Link class variations
|
||||
|
||||
$ctas_classnames = 'e-link-in-bio__cta is-type-' . $ctas_props_type;
|
||||
|
||||
if ( 'button' === $ctas_props_type && $ctas_props_show_border ) {
|
||||
$ctas_classnames .= ' has-border';
|
||||
}
|
||||
|
||||
if ( $cta_has_image ) {
|
||||
$ctas_classnames .= ' has-image';
|
||||
}
|
||||
|
||||
if ( 'button' === $ctas_props_type ) {
|
||||
$ctas_classnames .= ' has-corners-' . $ctas_props_corners;
|
||||
}
|
||||
|
||||
// Manage Link attributes
|
||||
|
||||
$url_attrs = [
|
||||
'class' => $ctas_classnames,
|
||||
'href' => esc_url( $formatted_link ),
|
||||
];
|
||||
|
||||
if (
|
||||
Social_Network_Provider::FILE_DOWNLOAD === $cta['cta_link_type'] ||
|
||||
Social_Network_Provider::VCF === $cta['cta_link_type']
|
||||
) {
|
||||
$url_attrs['download'] = 'download';
|
||||
}
|
||||
|
||||
$cta_url = $cta['cta_link_url'];
|
||||
|
||||
if ( Social_Network_Provider::WAZE == $cta['cta_link_type'] ) {
|
||||
$cta_url = $cta['cta_link_location'];
|
||||
}
|
||||
|
||||
$url_combined_attrs = $this->get_link_attributes(
|
||||
$cta_url,
|
||||
$url_attrs
|
||||
);
|
||||
|
||||
foreach ( $url_combined_attrs as $attr_key => $attr_value ) {
|
||||
$this->widget->add_render_attribute( 'cta-' . $key, [
|
||||
$attr_key => $attr_value,
|
||||
] );
|
||||
}
|
||||
?>
|
||||
<a <?php echo $this->widget->get_render_attribute_string( 'cta-' . $key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
||||
<?php if ( $cta_has_image ) : ?>
|
||||
<span class="e-link-in-bio__cta-image">
|
||||
<?php if ( ! empty( $cta_image['id'] ) ) {
|
||||
echo wp_get_attachment_image( $cta_image['id'], 'thumbnail', false, [
|
||||
'class' => 'e-link-in-bio__cta-image-element',
|
||||
] );
|
||||
} else {
|
||||
$this->widget->add_render_attribute( 'cta-link-image' . $key, [
|
||||
'alt' => '',
|
||||
'class' => 'e-link-in-bio__cta-image-element',
|
||||
'src' => esc_url( $cta_image['url'] ),
|
||||
] );
|
||||
?>
|
||||
<img <?php echo $this->widget->get_render_attribute_string( 'cta-link-image' . $key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> />
|
||||
<?php }; ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
<span class="e-link-in-bio__cta-text">
|
||||
<?php echo esc_html( $cta['cta_link_text'] ); ?>
|
||||
</span>
|
||||
</a>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function render_icons(): void {
|
||||
$icons_props_show_border = $this->settings['icons_border_show_border'] ?? false;
|
||||
$icons_props_size = $this->settings['icons_size'] ?? 'small';
|
||||
$icons_value = $this->settings['icon'] ?? [];
|
||||
|
||||
$has_icons = ! empty( $icons_value );
|
||||
if ( ! $has_icons ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->widget->add_render_attribute( 'icons', [
|
||||
'class' => 'e-link-in-bio__icons has-size-' . $icons_props_size,
|
||||
] );
|
||||
?>
|
||||
<div <?php echo $this->widget->get_render_attribute_string( 'icons' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
||||
<?php
|
||||
foreach ( $icons_value as $key => $icon ) {
|
||||
|
||||
$formatted_link = $this->get_formatted_link_for_icon( $icon );
|
||||
|
||||
$icon_class_names = 'e-link-in-bio__icon is-size-' . $icons_props_size;
|
||||
|
||||
if ( $icons_props_show_border ) {
|
||||
$icon_class_names .= ' has-border';
|
||||
}
|
||||
|
||||
$this->widget->add_render_attribute( 'icon-' . $key, [
|
||||
'class' => $icon_class_names,
|
||||
] );
|
||||
|
||||
// Manage Link attributes
|
||||
|
||||
$url_attrs = [
|
||||
'aria-label' => esc_attr( $icon['icon_platform'] ),
|
||||
'class' => 'e-link-in-bio__icon-link',
|
||||
'href' => esc_url( $formatted_link ),
|
||||
];
|
||||
|
||||
$icon_url = $icon['icon_url'];
|
||||
|
||||
if ( Social_Network_Provider::WAZE == $icon['icon_platform'] ) {
|
||||
$icon_url = $icon['icon_location'];
|
||||
}
|
||||
|
||||
$url_combined_attrs = $this->get_link_attributes(
|
||||
$icon_url,
|
||||
$url_attrs
|
||||
);
|
||||
|
||||
foreach ( $url_combined_attrs as $attr_key => $attr_value ) {
|
||||
$this->widget->add_render_attribute( 'icon-link-' . $key, [
|
||||
$attr_key => $attr_value,
|
||||
] );
|
||||
}
|
||||
?>
|
||||
<div <?php echo $this->widget->get_render_attribute_string( 'icon-' . $key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
||||
<a <?php echo $this->widget->get_render_attribute_string( 'icon-link-' . $key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
||||
<span class="e-link-in-bio__icon-svg">
|
||||
<?php
|
||||
$mapping = Social_Network_Provider::get_icon_mapping( $icon['icon_platform'] );
|
||||
$icon_lib = explode( ' ', $mapping )[0];
|
||||
$library = 'fab' === $icon_lib ? 'fa-brands' : 'fa-solid';
|
||||
Icons_Manager::render_icon(
|
||||
[
|
||||
'library' => $library,
|
||||
'value' => $mapping,
|
||||
],
|
||||
[ 'aria-hidden' => 'true' ]
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
<?php if ( ! empty( $icon['icon_text'] ) ) : ?>
|
||||
<span class="e-link-in-bio__icon-label">
|
||||
<?php echo esc_html( $icon['icon_text'] ); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function render_bio(): void {
|
||||
$bio_heading_props_tag = $this->settings['bio_heading_tag'] ?? 'h2';
|
||||
$bio_heading_value = $this->settings['bio_heading'] ?? '';
|
||||
|
||||
$bio_title_props_tag = $this->settings['bio_title_tag'] ?? 'h2';
|
||||
$bio_title_value = $this->settings['bio_title'] ?? '';
|
||||
|
||||
if ( 'top' === $this->widget->get_description_position() ) {
|
||||
$bio_about_heading_props_tag = $this->settings['bio_about_tag'] ?? 'h3';
|
||||
$bio_about_heading_value = $this->settings['bio_about'] ?? '';
|
||||
|
||||
$bio_description_value = $this->settings['bio_description'] ?? '';
|
||||
}
|
||||
|
||||
$has_bio_about_heading = ! empty( $bio_about_heading_value );
|
||||
$has_bio_description = ! empty( $bio_description_value );
|
||||
$has_bio_heading = ! empty( $bio_heading_value );
|
||||
$has_bio_title = ! empty( $bio_title_value );
|
||||
|
||||
if ( $has_bio_heading || $has_bio_title || $has_bio_about_heading || $has_bio_description ) {
|
||||
?>
|
||||
<div class="e-link-in-bio__bio">
|
||||
<?php if ( $has_bio_heading ) {
|
||||
$this->widget->add_render_attribute( 'heading', 'class', 'e-link-in-bio__heading' );
|
||||
$bio_heading_output = sprintf( '<%1$s %2$s>%3$s</%1$s>', Utils::validate_html_tag( $bio_heading_props_tag ), $this->widget->get_render_attribute_string( 'heading' ), esc_html( $bio_heading_value ) );
|
||||
// Escaped above
|
||||
Utils::print_unescaped_internal_string( $bio_heading_output );
|
||||
} ?>
|
||||
<?php if ( $has_bio_title ) {
|
||||
$this->widget->add_render_attribute( 'title', 'class', 'e-link-in-bio__title' );
|
||||
$bio_title_output = sprintf( '<%1$s %2$s>%3$s</%1$s>', Utils::validate_html_tag( $bio_title_props_tag ), $this->widget->get_render_attribute_string( 'title' ), esc_html( $bio_title_value ) );
|
||||
// Escaped above
|
||||
Utils::print_unescaped_internal_string( $bio_title_output );
|
||||
} ?>
|
||||
<?php if ( $has_bio_about_heading ) {
|
||||
$this->widget->add_render_attribute( 'about-heading', 'class', 'e-link-in-bio__about-heading' );
|
||||
$bio_about_heading_output = sprintf( '<%1$s %2$s>%3$s</%1$s>', Utils::validate_html_tag( $bio_about_heading_props_tag ), $this->widget->get_render_attribute_string( 'about-heading' ), esc_html( $bio_about_heading_value ) );
|
||||
// Escaped above
|
||||
Utils::print_unescaped_internal_string( $bio_about_heading_output );
|
||||
} ?>
|
||||
<?php if ( $has_bio_description ) {
|
||||
$this->widget->add_render_attribute( 'description', 'class', 'e-link-in-bio__description' );
|
||||
$bio_description_output = sprintf( '<p %1$s>%2$s</p>', $this->widget->get_render_attribute_string( 'description' ), esc_html( $bio_description_value ) );
|
||||
// Escaped above
|
||||
Utils::print_unescaped_internal_string( $bio_description_output );
|
||||
} ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
protected function render_footer_bio(): void {
|
||||
if ( 'bottom' !== $this->widget->get_description_position() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$bio_about_heading_props_tag = $this->settings['bio_about_tag'] ?? 'h3';
|
||||
$bio_about_heading_value = $this->settings['bio_about'] ?? '';
|
||||
|
||||
$bio_description_value = $this->settings['bio_description'] ?? '';
|
||||
|
||||
$has_bio_description = ! empty( $bio_description_value );
|
||||
$has_bio_about_heading = ! empty( $bio_about_heading_value );
|
||||
|
||||
if ( $has_bio_about_heading || $has_bio_description ) {
|
||||
?>
|
||||
<div class="e-link-in-bio__bio e-link-in-bio__bio--footer">
|
||||
<?php if ( $has_bio_about_heading ) {
|
||||
$this->widget->add_render_attribute( 'about-heading', 'class', 'e-link-in-bio__about-heading' );
|
||||
$bio_about_heading_output = sprintf( '<%1$s %2$s>%3$s</%1$s>', Utils::validate_html_tag( $bio_about_heading_props_tag ), $this->widget->get_render_attribute_string( 'about-heading' ), esc_html( $bio_about_heading_value ) );
|
||||
// Escaped above
|
||||
Utils::print_unescaped_internal_string( $bio_about_heading_output );
|
||||
} ?>
|
||||
<?php if ( $has_bio_description ) {
|
||||
$this->widget->add_render_attribute( 'description', 'class', 'e-link-in-bio__description' );
|
||||
$bio_description_output = sprintf( '<p %1$s>%2$s</p>', $this->widget->get_render_attribute_string( 'description' ), esc_html( $bio_description_value ) );
|
||||
// Escaped above
|
||||
Utils::print_unescaped_internal_string( $bio_description_output );
|
||||
} ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
protected function render_identity_image(): void {
|
||||
/**
|
||||
* Get base data for potential images
|
||||
* Note order is important - secondary must render before primary
|
||||
*/
|
||||
$output_images = [
|
||||
'secondary_image' => [
|
||||
'props' => [],
|
||||
'should_render' => false,
|
||||
'value' => $this->settings['identity_image_cover'] ?? [],
|
||||
],
|
||||
'primary_image' => [
|
||||
'props' => [],
|
||||
'should_render' => false,
|
||||
'value' => $this->settings['identity_image'] ?? [],
|
||||
],
|
||||
];
|
||||
|
||||
$output_images['primary_image']['should_render'] = ! empty( $output_images['primary_image']['value'] ) && ( ! empty( $output_images['primary_image']['value']['url'] || ! empty( $output_images['primary_image']['value']['id'] ) ) );
|
||||
$output_images['secondary_image']['should_render'] = ! empty( $output_images['secondary_image']['value'] ) && ( ! empty( $output_images['secondary_image']['value']['url'] || ! empty( $output_images['secondary_image']['value']['id'] ) ) );
|
||||
|
||||
if ( ! $output_images['primary_image']['should_render'] && ! $output_images['secondary_image']['should_render'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$output_images = $this->set_primary_image_properties( $output_images );
|
||||
|
||||
$output_images = $this->set_secondary_image_properties( $output_images );
|
||||
?>
|
||||
<div class="e-link-in-bio__identity">
|
||||
<?php
|
||||
foreach ( $output_images as $image_key => $image ) :
|
||||
if ( $image['should_render'] ) :
|
||||
$this->widget->add_render_attribute( 'identity_image_' . $image_key, [
|
||||
'class' => $this->get_image_classnames( $image ),
|
||||
] );
|
||||
?>
|
||||
<div <?php echo $this->widget->get_render_attribute_string( 'identity_image_' . $image_key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
||||
<?php if ( ! empty( $image['value']['id'] ) ) {
|
||||
echo wp_get_attachment_image( $image['value']['id'], 'medium', false, [
|
||||
'class' => 'e-link-in-bio__identity-image-element',
|
||||
] );
|
||||
} else {
|
||||
$this->widget->add_render_attribute( 'identity_image_src' . $image_key, [
|
||||
'alt' => '',
|
||||
'class' => 'e-link-in-bio__identity-image-element',
|
||||
'src' => esc_url( $image['value']['url'] ),
|
||||
] );
|
||||
?>
|
||||
<img <?php echo $this->widget->get_render_attribute_string( 'identity_image_src' . $image_key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> />
|
||||
|
||||
<?php }; ?>
|
||||
<?php
|
||||
if ( ! empty( $image['props']['has_shape_divider'] ) ) {
|
||||
$this->print_shape_divider();
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
endforeach;
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function get_image_classnames( array $image ): string {
|
||||
$image_classnames = 'e-link-in-bio__identity-image e-link-in-bio__identity-image-' . $image['props']['style'];
|
||||
if ( ! empty( $image['props']['show_border'] ) || ! empty( $image['props']['show_bottom_border'] ) ) {
|
||||
$image_classnames .= ' has-border';
|
||||
}
|
||||
if ( ! empty( $image['props']['shape'] ) && 'profile' === $image['props']['style'] ) {
|
||||
$image_classnames .= ' has-style-' . $image['props']['shape'];
|
||||
}
|
||||
if ( ! empty( $image['props']['has_shape_divider'] ) ) {
|
||||
$image_classnames .= ' has-shape-divider';
|
||||
}
|
||||
return $image_classnames;
|
||||
}
|
||||
|
||||
protected function get_formatted_link_based_on_type_for_cta( array $cta ): string {
|
||||
$formatted_link = $cta['cta_link_url']['url'] ?? '';
|
||||
|
||||
// Ensure we clear the default link value if the matching type value is empty
|
||||
switch ( $cta['cta_link_type'] ) {
|
||||
case Social_Network_Provider::EMAIL:
|
||||
$formatted_link = Social_Network_Provider::build_email_link( $cta, 'cta_link' );
|
||||
break;
|
||||
case Social_Network_Provider::TELEPHONE:
|
||||
$formatted_link = ! empty( $cta['cta_link_number'] ) ? 'tel:' . $cta['cta_link_number'] : '';
|
||||
break;
|
||||
case Social_Network_Provider::MESSENGER:
|
||||
$formatted_link = ! empty( $cta['cta_link_username'] ) ?
|
||||
Social_Network_Provider::build_messenger_link( $cta['cta_link_username'] ) :
|
||||
'';
|
||||
break;
|
||||
case Social_Network_Provider::WAZE:
|
||||
$formatted_link = ! empty( $cta['cta_link_location']['url'] ) ? $cta['cta_link_location']['url'] : '';
|
||||
break;
|
||||
case Social_Network_Provider::WHATSAPP:
|
||||
$formatted_link = ! empty( $cta['cta_link_number'] ) ? 'https://wa.me/' . $cta['cta_link_number'] : '';
|
||||
break;
|
||||
case Social_Network_Provider::FILE_DOWNLOAD:
|
||||
$formatted_link = ! empty( $cta['cta_link_file']['url'] ) ? $cta['cta_link_file']['url'] : '';
|
||||
break;
|
||||
case Social_Network_Provider::VCF:
|
||||
$formatted_link = ! empty( $cta['cta_link_file']['url'] ) ? $cta['cta_link_file']['url'] : '';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return $formatted_link;
|
||||
}
|
||||
|
||||
protected function get_formatted_link_for_icon( array $icon ): string {
|
||||
$formatted_link = $icon['icon_url']['url'] ?? '';
|
||||
|
||||
// Ensure we clear the default link value if the matching type value is empty
|
||||
switch ( $icon['icon_platform'] ) {
|
||||
case Social_Network_Provider::EMAIL:
|
||||
$formatted_link = Social_Network_Provider::build_email_link( $icon, 'icon' );
|
||||
break;
|
||||
case Social_Network_Provider::TELEPHONE:
|
||||
$formatted_link = ! empty( $icon['icon_number'] ) ? 'tel:' . $icon['icon_number'] : '';
|
||||
break;
|
||||
case Social_Network_Provider::MESSENGER:
|
||||
$formatted_link = ! empty( $icon['icon_username'] ) ?
|
||||
Social_Network_Provider::build_messenger_link( $icon['icon_username'] ) :
|
||||
'';
|
||||
break;
|
||||
case Social_Network_Provider::WAZE:
|
||||
$formatted_link = ! empty( $icon['icon_location']['url'] ) ? $icon['icon_location']['url'] : '';
|
||||
break;
|
||||
case Social_Network_Provider::WHATSAPP:
|
||||
$formatted_link = ! empty( $icon['icon_number'] ) ? 'https://wa.me/' . $icon['icon_number'] : '';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return $formatted_link;
|
||||
}
|
||||
|
||||
protected function build_layout_render_attribute(): void {
|
||||
$layout_props_full_height = $this->settings['advanced_layout_full_screen_height'] ?? '';
|
||||
$layout_props_full_height_controls = $this->settings['advanced_layout_full_screen_height_controls'] ?? '';
|
||||
$layout_props_full_width = $this->settings['advanced_layout_full_width_custom'] ?? '';
|
||||
$layout_props_show_border = $this->settings['background_show_border'] ?? '';
|
||||
$custom_classes = $this->settings['advanced_custom_css_classes'] ?? '';
|
||||
|
||||
$layout_classnames = 'e-link-in-bio e-' . $this->widget->get_name();
|
||||
|
||||
if ( 'yes' === $layout_props_show_border ) {
|
||||
$layout_classnames .= ' has-border';
|
||||
}
|
||||
|
||||
if ( 'yes' === $layout_props_full_width ) {
|
||||
$layout_classnames .= ' is-full-width';
|
||||
}
|
||||
|
||||
if ( 'yes' === $layout_props_full_height ) {
|
||||
$layout_classnames .= ' is-full-height';
|
||||
}
|
||||
|
||||
if ( ! empty( $layout_props_full_height_controls ) ) {
|
||||
foreach ( $layout_props_full_height_controls as $breakpoint ) {
|
||||
$layout_classnames .= ' is-full-height-' . $breakpoint;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $custom_classes ) {
|
||||
$layout_classnames .= ' ' . $custom_classes;
|
||||
}
|
||||
|
||||
$attrs = [
|
||||
'class' => $layout_classnames,
|
||||
];
|
||||
|
||||
if ( ! empty( $this->settings['advanced_custom_css_id'] ) ) {
|
||||
$attrs['id'] = $this->settings['advanced_custom_css_id'];
|
||||
}
|
||||
|
||||
$this->widget->add_render_attribute( 'layout', $attrs );
|
||||
}
|
||||
|
||||
private function set_primary_image_properties( array $output_images ): array {
|
||||
if ( $output_images['primary_image']['should_render'] ) {
|
||||
$output_images['primary_image']['props']['shape'] = $this->settings['identity_image_shape'] ?? 'circle';
|
||||
$output_images['primary_image']['props']['style'] = $this->settings['identity_image_style'] ?? 'profile';
|
||||
$output_images['primary_image']['props']['show_border'] = $this->settings['identity_image_show_border'] ?? false;
|
||||
$output_images['primary_image']['props']['show_bottom_border'] = $this->settings['identity_image_bottom_show_border'] ?? false;
|
||||
}
|
||||
|
||||
return $output_images;
|
||||
}
|
||||
|
||||
private function set_secondary_image_properties( array $output_images ): array {
|
||||
if ( $output_images['secondary_image']['should_render'] ) {
|
||||
$output_images['secondary_image']['props']['style'] = 'cover';
|
||||
$output_images['secondary_image']['props']['show_bottom_border'] = $this->settings['identity_image_bottom_show_border'] ?? false;
|
||||
|
||||
if ( ! empty( $this->settings['identity_section_style_cover_divider_bottom'] ) ) {
|
||||
$output_images['secondary_image']['props']['has_shape_divider'] = true;
|
||||
|
||||
// Remove border if a shaped divider is applied
|
||||
$output_images['secondary_image']['props']['show_bottom_border'] = false;
|
||||
}
|
||||
|
||||
$output_images['primary_image']['props']['style'] = 'profile';
|
||||
}
|
||||
|
||||
return $output_images;
|
||||
}
|
||||
}
|
||||
44
wp-content/plugins/elementor/modules/link-in-bio/module.php
Normal file
44
wp-content/plugins/elementor/modules/link-in-bio/module.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\LinkInBio;
|
||||
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Core\Experiments\Manager;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
const EXPERIMENT_NAME = 'link-in-bio';
|
||||
|
||||
public static function is_active(): bool {
|
||||
return Plugin::$instance->experiments->is_feature_active( static::EXPERIMENT_NAME );
|
||||
}
|
||||
|
||||
public function get_name(): string {
|
||||
return static::EXPERIMENT_NAME;
|
||||
}
|
||||
|
||||
public function get_widgets(): array {
|
||||
return [
|
||||
'Link_In_Bio',
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_experimental_data(): array {
|
||||
return [
|
||||
'name' => static::EXPERIMENT_NAME,
|
||||
'title' => esc_html__( 'Link In Bio', 'elementor' ),
|
||||
'description' => esc_html__( 'Create bio link landing pages and digital business cards that convert with Link in Bio widgets. Share your link in bio pages on your social media profiles. Create as many as you need for different audiences and goals.', 'elementor' ),
|
||||
'default' => Manager::STATE_INACTIVE,
|
||||
'release_status' => Manager::RELEASE_STATUS_BETA,
|
||||
'new_site' => [
|
||||
'default_active' => true,
|
||||
'minimum_installation_version' => '3.23.0',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\LinkInBio\Widgets;
|
||||
|
||||
use Elementor\Modules\LinkInBio\Base\Widget_Link_In_Bio_Base;
|
||||
use Elementor\Modules\LinkInBio\Classes\Render\Core_Render;
|
||||
use Elementor\Modules\LinkInBio\Module as ConversionCenterModule;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor Link in Bio widget.
|
||||
*
|
||||
* Elementor widget that displays an image, a bio, up to 4 CTA links and up to 5 icons.
|
||||
*
|
||||
* @since 3.23.0
|
||||
*/
|
||||
class Link_In_Bio extends Widget_Link_In_Bio_Base {
|
||||
|
||||
public function get_name(): string {
|
||||
return 'link-in-bio';
|
||||
}
|
||||
|
||||
public function get_title(): string {
|
||||
return esc_html__( 'Minimalist', 'elementor' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\NestedAccordion;
|
||||
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
public static function is_active() {
|
||||
return Plugin::$instance->experiments->is_feature_active( 'nested-elements' );
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'nested-accordion';
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_action( 'elementor/editor/before_enqueue_scripts', function () {
|
||||
wp_enqueue_script( $this->get_name(), $this->get_js_assets_url( $this->get_name() ), [
|
||||
'nested-elements',
|
||||
], ELEMENTOR_VERSION, true );
|
||||
} );
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\NestedElements\Base;
|
||||
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Widget_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to create a new widget that can be nested inside other widgets.
|
||||
*/
|
||||
abstract class Widget_Nested_Base extends Widget_Base {
|
||||
|
||||
/**
|
||||
* Get default children elements structure.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function get_default_children_elements();
|
||||
|
||||
/**
|
||||
* Get repeater title setting key name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function get_default_repeater_title_setting_key();
|
||||
|
||||
/**
|
||||
* Get default children title for the navigator, using `%d` as index in the format.
|
||||
*
|
||||
* @note The title in this method is used to set the default title for each created child in nested element.
|
||||
* for handling the children title for new created widget(s), use `get_default_children_elements()` method,
|
||||
* eg:
|
||||
* [
|
||||
* 'elType' => 'container',
|
||||
* 'settings' => [
|
||||
* '_title' => __( 'Tab #1', 'elementor' ),
|
||||
* ],
|
||||
* ],
|
||||
* @return string
|
||||
*/
|
||||
protected function get_default_children_title() {
|
||||
return esc_html__( 'Item #%d', 'elementor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default children placeholder selector, Empty string, means will be added at the end view.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_default_children_placeholder_selector() {
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function get_default_children_container_placeholder_selector() {
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function is_dynamic_content(): bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* To support nesting.
|
||||
*/
|
||||
protected function _get_default_child_type( array $element_data ) {
|
||||
return Plugin::$instance->elements_manager->get_element_types( $element_data['elType'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* Adding new 'defaults' config for handling children elements.
|
||||
*/
|
||||
protected function get_initial_config() {
|
||||
return array_merge( parent::get_initial_config(), [
|
||||
'defaults' => [
|
||||
'elements' => $this->get_default_children_elements(),
|
||||
'elements_title' => $this->get_default_children_title(),
|
||||
'elements_placeholder_selector' => $this->get_default_children_placeholder_selector(),
|
||||
'child_container_placeholder_selector' => $this->get_default_children_container_placeholder_selector(),
|
||||
'repeater_title_setting' => $this->get_default_repeater_title_setting_key(),
|
||||
],
|
||||
'support_nesting' => true,
|
||||
] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* Each element including its children elements.
|
||||
*/
|
||||
public function get_raw_data( $with_html_content = false ) {
|
||||
$elements = [];
|
||||
$data = $this->get_data();
|
||||
|
||||
$children = $this->get_children();
|
||||
|
||||
foreach ( $children as $child ) {
|
||||
$child_raw_data = $child->get_raw_data( $with_html_content );
|
||||
|
||||
$elements[] = $child_raw_data;
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $this->get_id(),
|
||||
'elType' => $data['elType'],
|
||||
'widgetType' => $data['widgetType'],
|
||||
'settings' => $data['settings'],
|
||||
'elements' => $elements,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Print child, helper method to print the child element.
|
||||
*
|
||||
* @param int $index
|
||||
*/
|
||||
public function print_child( $index ) {
|
||||
$children = $this->get_children();
|
||||
|
||||
if ( ! empty( $children[ $index ] ) ) {
|
||||
$children[ $index ]->print_element();
|
||||
}
|
||||
}
|
||||
|
||||
protected function content_template_single_repeater_item() {}
|
||||
|
||||
public function print_template() {
|
||||
parent::print_template();
|
||||
if ( $this->get_initial_config()['support_improved_repeaters'] ?? false ) {
|
||||
?>
|
||||
<script type="text/html" id="tmpl-elementor-<?php echo esc_attr( $this->get_name() ); ?>-content-single">
|
||||
<?php $this->content_template_single_repeater_item(); ?>
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\NestedElements\Controls;
|
||||
|
||||
use Elementor\Control_Repeater;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
/**
|
||||
* Changing the default repeater control behavior for custom item title defaults.
|
||||
* For custom management of nested repeater controls.
|
||||
*/
|
||||
class Control_Nested_Repeater extends Control_Repeater {
|
||||
|
||||
const CONTROL_TYPE = 'nested-elements-repeater';
|
||||
|
||||
public function get_type() {
|
||||
return static::CONTROL_TYPE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\NestedElements;
|
||||
|
||||
use Elementor\Core\Experiments\Manager as Experiments_Manager;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends \Elementor\Core\Base\Module {
|
||||
|
||||
const EXPERIMENT_NAME = 'nested-elements';
|
||||
|
||||
public static function get_experimental_data() {
|
||||
return [
|
||||
'name' => self::EXPERIMENT_NAME,
|
||||
'title' => esc_html__( 'Nested Elements', 'elementor' ),
|
||||
'description' => sprintf(
|
||||
'%1$s <a href="https://go.elementor.com/wp-dash-nested-elements/" target="_blank">%2$s</a>',
|
||||
esc_html__( 'Create a rich user experience by layering widgets together inside "Nested" Tabs, etc. When turned on, we’ll automatically enable new nested features. Your old widgets won’t be affected.', 'elementor' ),
|
||||
esc_html__( 'Learn more', 'elementor' )
|
||||
),
|
||||
'release_status' => Experiments_Manager::RELEASE_STATUS_BETA,
|
||||
'default' => Experiments_Manager::STATE_INACTIVE,
|
||||
'dependencies' => [
|
||||
'container',
|
||||
],
|
||||
'new_site' => [
|
||||
'default_active' => false,
|
||||
'minimum_installation_version' => '3.10.0',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'nested-elements';
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_action( 'elementor/controls/register', function ( $controls_manager ) {
|
||||
$controls_manager->register( new Controls\Control_Nested_Repeater() );
|
||||
} );
|
||||
|
||||
add_action( 'elementor/editor/before_enqueue_scripts', function () {
|
||||
wp_enqueue_script( $this->get_name(), $this->get_js_assets_url( $this->get_name() ), [
|
||||
'elementor-common',
|
||||
], ELEMENTOR_VERSION, true );
|
||||
} );
|
||||
}
|
||||
}
|
||||
30
wp-content/plugins/elementor/modules/nested-tabs/module.php
Normal file
30
wp-content/plugins/elementor/modules/nested-tabs/module.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\NestedTabs;
|
||||
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Modules\NestedElements\Module as NestedElementsModule;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends \Elementor\Core\Base\Module {
|
||||
|
||||
public static function is_active() {
|
||||
return Plugin::$instance->experiments->is_feature_active( NestedElementsModule::EXPERIMENT_NAME );
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'nested-tabs';
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_action( 'elementor/editor/before_enqueue_scripts', function () {
|
||||
wp_enqueue_script( $this->get_name(), $this->get_js_assets_url( $this->get_name() ), [
|
||||
'nested-elements',
|
||||
], ELEMENTOR_VERSION, true );
|
||||
} );
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
66
wp-content/plugins/elementor/modules/notes/module.php
Normal file
66
wp-content/plugins/elementor/modules/notes/module.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Notes;
|
||||
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Utils;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
public function get_name() {
|
||||
return 'notes';
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the module scripts.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_scripts() {
|
||||
wp_enqueue_script(
|
||||
'elementor-notes',
|
||||
$this->get_js_assets_url( 'notes' ),
|
||||
[ 'elementor-editor' ],
|
||||
ELEMENTOR_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
wp_set_script_translations( 'elementor-notes', 'elementor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the module styles.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_styles() {
|
||||
wp_enqueue_style(
|
||||
'elementor-notes',
|
||||
$this->get_css_assets_url( 'modules/notes/editor' ),
|
||||
[ 'elementor-editor' ],
|
||||
ELEMENTOR_VERSION
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_active() {
|
||||
return ! Utils::has_pro();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Notes module.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_action( 'elementor/editor/after_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
|
||||
add_action( 'elementor/editor/after_enqueue_styles', [ $this, 'enqueue_styles' ] );
|
||||
}
|
||||
}
|
||||
179
wp-content/plugins/elementor/modules/notifications/api.php
Normal file
179
wp-content/plugins/elementor/modules/notifications/api.php
Normal file
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Notifications;
|
||||
|
||||
use Elementor\User;
|
||||
|
||||
class API {
|
||||
|
||||
const NOTIFICATIONS_URL = 'https://assets.elementor.com/notifications/v1/notifications.json';
|
||||
|
||||
public static function get_notifications_by_conditions( $force_request = false ) {
|
||||
$notifications = static::get_notifications( $force_request );
|
||||
|
||||
$filtered_notifications = [];
|
||||
|
||||
foreach ( $notifications as $notification ) {
|
||||
if ( empty( $notification['conditions'] ) ) {
|
||||
$filtered_notifications = static::add_to_array( $filtered_notifications, $notification );
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! static::check_conditions( $notification['conditions'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filtered_notifications = static::add_to_array( $filtered_notifications, $notification );
|
||||
}
|
||||
|
||||
return $filtered_notifications;
|
||||
}
|
||||
|
||||
private static function get_notifications( $force_request = false ) {
|
||||
$notifications = self::get_transient( '_elementor_notifications_data' );
|
||||
|
||||
if ( $force_request || false === $notifications ) {
|
||||
$notifications = static::fetch_data();
|
||||
|
||||
static::set_transient( '_elementor_notifications_data', $notifications, '+1 hour' );
|
||||
}
|
||||
|
||||
return $notifications;
|
||||
}
|
||||
|
||||
private static function fetch_data() : array {
|
||||
$response = wp_remote_get( self::NOTIFICATIONS_URL );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$data = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||
|
||||
if ( empty( $data['notifications'] ) || ! is_array( $data['notifications'] ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $data['notifications'];
|
||||
}
|
||||
|
||||
private static function add_to_array( $filtered_notifications, $notification ) {
|
||||
foreach ( $filtered_notifications as $filtered_notification ) {
|
||||
if ( $filtered_notification['id'] === $notification['id'] ) {
|
||||
return $filtered_notifications;
|
||||
}
|
||||
}
|
||||
|
||||
$filtered_notifications[] = $notification;
|
||||
|
||||
return $filtered_notifications;
|
||||
}
|
||||
|
||||
private static function check_conditions( $groups ) {
|
||||
foreach ( $groups as $group ) {
|
||||
if ( static::check_group( $group ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function check_group( $group ) {
|
||||
$is_or_relation = ! empty( $group['relation'] ) && 'OR' === $group['relation'];
|
||||
unset( $group['relation'] );
|
||||
$result = false;
|
||||
|
||||
foreach ( $group as $condition ) {
|
||||
// Reset results for each condition.
|
||||
$result = false;
|
||||
switch ( $condition['type'] ) {
|
||||
case 'wordpress': // phpcs:ignore WordPress.WP.CapitalPDangit.Misspelled
|
||||
// include an unmodified $wp_version
|
||||
include ABSPATH . WPINC . '/version.php';
|
||||
$result = version_compare( $wp_version, $condition['version'], $condition['operator'] );
|
||||
break;
|
||||
case 'multisite':
|
||||
$result = is_multisite() === $condition['multisite'];
|
||||
break;
|
||||
case 'language':
|
||||
$in_array = in_array( get_locale(), $condition['languages'], true );
|
||||
$result = 'in' === $condition['operator'] ? $in_array : ! $in_array;
|
||||
break;
|
||||
case 'plugin':
|
||||
if ( ! function_exists( 'is_plugin_active' ) ) {
|
||||
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
||||
}
|
||||
|
||||
$is_plugin_active = is_plugin_active( $condition['plugin'] );
|
||||
|
||||
if ( empty( $condition['operator'] ) ) {
|
||||
$condition['operator'] = '==';
|
||||
}
|
||||
|
||||
$result = '==' === $condition['operator'] ? $is_plugin_active : ! $is_plugin_active;
|
||||
break;
|
||||
case 'theme':
|
||||
$theme = wp_get_theme();
|
||||
if ( wp_get_theme()->parent() ) {
|
||||
$theme = wp_get_theme()->parent();
|
||||
}
|
||||
|
||||
if ( $theme->get_template() === $condition['theme'] ) {
|
||||
$version = $theme->version;
|
||||
} else {
|
||||
$version = '';
|
||||
}
|
||||
|
||||
$result = version_compare( $version, $condition['version'], $condition['operator'] );
|
||||
break;
|
||||
case 'introduction_meta':
|
||||
$result = User::get_introduction_meta( $condition['meta'] );
|
||||
break;
|
||||
|
||||
default:
|
||||
/**
|
||||
* Filters the notification condition, whether to check the group or not.
|
||||
*
|
||||
* The dynamic portion of the hook name, `$condition['type']`, refers to the condition type.
|
||||
*
|
||||
* @since 3.19.0
|
||||
*
|
||||
* @param bool $result Whether to check the group.
|
||||
* @param array $condition Notification condition.
|
||||
*/
|
||||
$result = apply_filters( "elementor/notifications/condition/{$condition['type']}", $result, $condition );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ( $is_or_relation && $result ) || ( ! $is_or_relation && ! $result ) ) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function get_transient( $cache_key ) {
|
||||
$cache = get_option( $cache_key );
|
||||
|
||||
if ( empty( $cache['timeout'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( current_time( 'timestamp' ) > $cache['timeout'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return json_decode( $cache['value'], true );
|
||||
}
|
||||
|
||||
private static function set_transient( $cache_key, $value, $expiration = '+12 hours' ) {
|
||||
$data = [
|
||||
'timeout' => strtotime( $expiration, current_time( 'timestamp' ) ),
|
||||
'value' => json_encode( $value ),
|
||||
];
|
||||
|
||||
return update_option( $cache_key, $data, false );
|
||||
}
|
||||
}
|
||||
101
wp-content/plugins/elementor/modules/notifications/module.php
Normal file
101
wp-content/plugins/elementor/modules/notifications/module.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Notifications;
|
||||
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Module extends BaseModule {
|
||||
|
||||
public function get_name() {
|
||||
return 'notification-center';
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_action( 'elementor/admin_top_bar/before_enqueue_scripts', function() {
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_script(
|
||||
'e-admin-notifications',
|
||||
$this->get_js_assets_url( 'admin-notifications' ),
|
||||
[
|
||||
'elementor-v2-ui',
|
||||
'elementor-v2-icons',
|
||||
'elementor-v2-query',
|
||||
'wp-i18n',
|
||||
],
|
||||
ELEMENTOR_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
wp_localize_script(
|
||||
'e-admin-notifications',
|
||||
'elementorNotifications',
|
||||
$this->get_app_js_config()
|
||||
);
|
||||
|
||||
wp_set_script_translations( 'e-editor-notifications', 'elementor' );
|
||||
}, 5 /* Before Elementor's admin enqueue scripts */ );
|
||||
|
||||
add_action( 'elementor/editor/v2/scripts/enqueue', [ $this, 'enqueue_editor_scripts' ] );
|
||||
add_action( 'elementor/editor/after_enqueue_scripts', [ $this, 'enqueue_editor_scripts' ] );
|
||||
|
||||
add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_actions' ] );
|
||||
}
|
||||
|
||||
public function enqueue_editor_scripts() {
|
||||
$deps = [
|
||||
'elementor-editor',
|
||||
'elementor-v2-ui',
|
||||
'elementor-v2-icons',
|
||||
'elementor-v2-query',
|
||||
'wp-i18n',
|
||||
];
|
||||
|
||||
$is_editor_v2 = current_action() === 'elementor/editor/v2/scripts/enqueue';
|
||||
|
||||
if ( $is_editor_v2 ) {
|
||||
$deps[] = 'elementor-v2-editor-app-bar';
|
||||
}
|
||||
|
||||
wp_enqueue_script(
|
||||
'e-editor-notifications',
|
||||
$this->get_js_assets_url( 'editor-notifications' ),
|
||||
$deps,
|
||||
ELEMENTOR_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
wp_localize_script(
|
||||
'e-editor-notifications',
|
||||
'elementorNotifications',
|
||||
$this->get_app_js_config()
|
||||
);
|
||||
|
||||
wp_set_script_translations( 'e-editor-notifications', 'elementor' );
|
||||
}
|
||||
|
||||
private function get_app_js_config() : array {
|
||||
return [
|
||||
'is_unread' => Options::has_unread_notifications(),
|
||||
];
|
||||
}
|
||||
|
||||
public function register_ajax_actions( $ajax ) {
|
||||
$ajax->register_ajax_action( 'notifications_get', [ $this, 'ajax_get_notifications' ] );
|
||||
}
|
||||
|
||||
public function ajax_get_notifications() {
|
||||
$notifications = API::get_notifications_by_conditions( true );
|
||||
|
||||
Options::mark_notification_read( $notifications );
|
||||
|
||||
return $notifications;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\Notifications;
|
||||
|
||||
class Options {
|
||||
|
||||
public static function has_unread_notifications() : bool {
|
||||
$current_user = wp_get_current_user();
|
||||
|
||||
if ( ! $current_user ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$unread_notifications = get_transient( "elementor_unread_notifications_{$current_user->ID}" );
|
||||
|
||||
if ( false === $unread_notifications ) {
|
||||
$notifications = API::get_notifications_by_conditions();
|
||||
$notifications_ids = wp_list_pluck( $notifications, 'id' );
|
||||
|
||||
$unread_notifications = array_diff( $notifications_ids, static::get_notifications_dismissed() );
|
||||
|
||||
set_transient( "elementor_unread_notifications_{$current_user->ID}", $unread_notifications, HOUR_IN_SECONDS );
|
||||
}
|
||||
|
||||
return ! empty( $unread_notifications );
|
||||
}
|
||||
|
||||
public static function get_notifications_dismissed() {
|
||||
$current_user = wp_get_current_user();
|
||||
|
||||
if ( ! $current_user ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$notifications_dismissed = get_user_meta( $current_user->ID, '_e_notifications_dismissed', true );
|
||||
|
||||
if ( ! is_array( $notifications_dismissed ) ) {
|
||||
$notifications_dismissed = [];
|
||||
}
|
||||
|
||||
return $notifications_dismissed;
|
||||
}
|
||||
|
||||
public static function mark_notification_read( $notifications ) : bool {
|
||||
$current_user = wp_get_current_user();
|
||||
|
||||
if ( ! $current_user ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$notifications_dismissed = static::get_notifications_dismissed();
|
||||
|
||||
foreach ( $notifications as $notification ) {
|
||||
if ( ! in_array( $notification['id'], $notifications_dismissed, true ) ) {
|
||||
$notifications_dismissed[] = $notification['id'];
|
||||
}
|
||||
}
|
||||
|
||||
$notifications_dismissed = array_unique( $notifications_dismissed );
|
||||
|
||||
update_user_meta( $current_user->ID, '_e_notifications_dismissed', $notifications_dismissed );
|
||||
|
||||
delete_transient( "elementor_unread_notifications_{$current_user->ID}" );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
435
wp-content/plugins/elementor/modules/page-templates/module.php
Normal file
435
wp-content/plugins/elementor/modules/page-templates/module.php
Normal file
@@ -0,0 +1,435 @@
|
||||
<?php
|
||||
namespace Elementor\Modules\PageTemplates;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use Elementor\Core\Base\Document;
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Core\Kits\Documents\Kit;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Utils;
|
||||
use Elementor\Core\DocumentTypes\PageBase as PageBase;
|
||||
use Elementor\Modules\Library\Documents\Page as LibraryPageDocument;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor page templates module.
|
||||
*
|
||||
* Elementor page templates module handler class is responsible for registering
|
||||
* and managing Elementor page templates modules.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class Module extends BaseModule {
|
||||
|
||||
/**
|
||||
* The of the theme.
|
||||
*/
|
||||
const TEMPLATE_THEME = 'elementor_theme';
|
||||
|
||||
/**
|
||||
* Elementor Canvas template name.
|
||||
*/
|
||||
const TEMPLATE_CANVAS = 'elementor_canvas';
|
||||
|
||||
/**
|
||||
* Elementor Header & Footer template name.
|
||||
*/
|
||||
const TEMPLATE_HEADER_FOOTER = 'elementor_header_footer';
|
||||
|
||||
/**
|
||||
* Print callback.
|
||||
*
|
||||
* Holds the page template callback content.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access protected
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
protected $print_callback;
|
||||
|
||||
/**
|
||||
* Get module name.
|
||||
*
|
||||
* Retrieve the page templates module name.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*
|
||||
* @return string Module name.
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'page-templates';
|
||||
}
|
||||
|
||||
/**
|
||||
* Template include.
|
||||
*
|
||||
* Update the path for the Elementor Canvas template.
|
||||
*
|
||||
* Fired by `template_include` filter.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*
|
||||
* @param string $template The path of the template to include.
|
||||
*
|
||||
* @return string The path of the template to include.
|
||||
*/
|
||||
public function template_include( $template ) {
|
||||
if ( is_singular() ) {
|
||||
$document = Plugin::$instance->documents->get_doc_for_frontend( get_the_ID() );
|
||||
|
||||
if ( $document && $document::get_property( 'support_wp_page_templates' ) ) {
|
||||
$page_template = $document->get_meta( '_wp_page_template' );
|
||||
|
||||
$template_path = $this->get_template_path( $page_template );
|
||||
|
||||
if ( self::TEMPLATE_THEME !== $page_template && ! $template_path && $document->is_built_with_elementor() ) {
|
||||
$kit_default_template = Plugin::$instance->kits_manager->get_current_settings( 'default_page_template' );
|
||||
$template_path = $this->get_template_path( $kit_default_template );
|
||||
}
|
||||
|
||||
if ( $template_path ) {
|
||||
$template = $template_path;
|
||||
|
||||
Plugin::$instance->inspector->add_log( 'Page Template', Plugin::$instance->inspector->parse_template_path( $template ), $document->get_edit_url() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add WordPress templates.
|
||||
*
|
||||
* Adds Elementor templates to all the post types that support
|
||||
* Elementor.
|
||||
*
|
||||
* Fired by `init` action.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*/
|
||||
public function add_wp_templates_support() {
|
||||
$post_types = get_post_types_by_support( 'elementor' );
|
||||
|
||||
foreach ( $post_types as $post_type ) {
|
||||
add_filter( "theme_{$post_type}_templates", [ $this, 'add_page_templates' ], 10, 4 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add page templates.
|
||||
*
|
||||
* Add the Elementor page templates to the theme templates.
|
||||
*
|
||||
* Fired by `theme_{$post_type}_templates` filter.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @param array $page_templates Array of page templates. Keys are filenames,
|
||||
* checks are translated names.
|
||||
*
|
||||
* @param \WP_Theme $wp_theme
|
||||
* @param \WP_Post $post
|
||||
*
|
||||
* @return array Page templates.
|
||||
*/
|
||||
public function add_page_templates( $page_templates, $wp_theme, $post ) {
|
||||
if ( $post ) {
|
||||
// FIX ME: Gutenberg not send $post as WP_Post object, just the post ID.
|
||||
$post_id = ! empty( $post->ID ) ? $post->ID : $post;
|
||||
|
||||
$document = Plugin::$instance->documents->get( $post_id );
|
||||
if ( $document && ! $document::get_property( 'support_wp_page_templates' ) ) {
|
||||
return $page_templates;
|
||||
}
|
||||
}
|
||||
|
||||
$page_templates = [
|
||||
self::TEMPLATE_CANVAS => esc_html__( 'Elementor Canvas', 'elementor' ),
|
||||
self::TEMPLATE_HEADER_FOOTER => esc_html__( 'Elementor Full Width', 'elementor' ),
|
||||
self::TEMPLATE_THEME => esc_html__( 'Theme', 'elementor' ),
|
||||
] + $page_templates;
|
||||
|
||||
return $page_templates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set print callback.
|
||||
*
|
||||
* Set the page template callback.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function set_print_callback( $callback ) {
|
||||
$this->print_callback = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print callback.
|
||||
*
|
||||
* Prints the page template content using WordPress loop.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*/
|
||||
public function print_callback() {
|
||||
while ( have_posts() ) :
|
||||
the_post();
|
||||
the_content();
|
||||
endwhile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print content.
|
||||
*
|
||||
* Prints the page template content.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*/
|
||||
public function print_content() {
|
||||
if ( ! $this->print_callback ) {
|
||||
$this->print_callback = [ $this, 'print_callback' ];
|
||||
}
|
||||
|
||||
call_user_func( $this->print_callback );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get page template path.
|
||||
*
|
||||
* Retrieve the path for any given page template.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*
|
||||
* @param string $page_template The page template name.
|
||||
*
|
||||
* @return string Page template path.
|
||||
*/
|
||||
public function get_template_path( $page_template ) {
|
||||
$template_path = '';
|
||||
switch ( $page_template ) {
|
||||
case self::TEMPLATE_CANVAS:
|
||||
$template_path = __DIR__ . '/templates/canvas.php';
|
||||
break;
|
||||
case self::TEMPLATE_HEADER_FOOTER:
|
||||
$template_path = __DIR__ . '/templates/header-footer.php';
|
||||
break;
|
||||
}
|
||||
|
||||
return $template_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register template control.
|
||||
*
|
||||
* Adds custom controls to any given document.
|
||||
*
|
||||
* Fired by `update_post_metadata` action.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*
|
||||
* @param Document $document The document instance.
|
||||
*/
|
||||
public function action_register_template_control( $document ) {
|
||||
if (
|
||||
( $document instanceof PageBase || $document instanceof LibraryPageDocument ) &&
|
||||
$document::get_property( 'support_page_layout' )
|
||||
) {
|
||||
$this->register_template_control( $document );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register template control.
|
||||
*
|
||||
* Adds custom controls to any given document.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*
|
||||
* @param Document $document The document instance.
|
||||
* @param string $control_id Optional. The control ID. Default is `template`.
|
||||
*/
|
||||
public function register_template_control( $document, $control_id = 'template' ) {
|
||||
if ( ! Utils::is_cpt_custom_templates_supported() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
require_once ABSPATH . '/wp-admin/includes/template.php';
|
||||
|
||||
$document->start_injection( [
|
||||
'of' => 'post_status',
|
||||
'fallback' => [
|
||||
'of' => 'post_title',
|
||||
],
|
||||
] );
|
||||
|
||||
$control_options = [
|
||||
'options' => array_flip( get_page_templates( null, $document->get_main_post()->post_type ) ),
|
||||
];
|
||||
|
||||
$this->add_template_controls( $document, $control_id, $control_options );
|
||||
|
||||
$document->end_injection();
|
||||
}
|
||||
|
||||
// The $options variable is an array of $control_options to overwrite the default
|
||||
public function add_template_controls( Document $document, $control_id, $control_options ) {
|
||||
// Default Control Options
|
||||
$default_control_options = [
|
||||
'label' => esc_html__( 'Page Layout', 'elementor' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => 'default',
|
||||
'options' => [
|
||||
'default' => esc_html__( 'Default', 'elementor' ),
|
||||
],
|
||||
];
|
||||
|
||||
$control_options = array_replace_recursive( $default_control_options, $control_options );
|
||||
|
||||
$document->add_control(
|
||||
$control_id,
|
||||
$control_options
|
||||
);
|
||||
|
||||
$document->add_control(
|
||||
$control_id . '_default_description',
|
||||
[
|
||||
'type' => Controls_Manager::RAW_HTML,
|
||||
'raw' => '<b>' . esc_html__( 'The default page template as defined in Elementor Panel → Hamburger Menu → Site Settings.', 'elementor' ) . '</b>',
|
||||
'content_classes' => 'elementor-descriptor',
|
||||
'condition' => [
|
||||
$control_id => 'default',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$document->add_control(
|
||||
$control_id . '_theme_description',
|
||||
[
|
||||
'type' => Controls_Manager::RAW_HTML,
|
||||
'raw' => '<b>' . esc_html__( 'Default Page Template from your theme.', 'elementor' ) . '</b>',
|
||||
'content_classes' => 'elementor-descriptor',
|
||||
'condition' => [
|
||||
$control_id => self::TEMPLATE_THEME,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$document->add_control(
|
||||
$control_id . '_canvas_description',
|
||||
[
|
||||
'type' => Controls_Manager::RAW_HTML,
|
||||
'raw' => '<b>' . esc_html__( 'No header, no footer, just Elementor', 'elementor' ) . '</b>',
|
||||
'content_classes' => 'elementor-descriptor',
|
||||
'condition' => [
|
||||
$control_id => self::TEMPLATE_CANVAS,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$document->add_control(
|
||||
$control_id . '_header_footer_description',
|
||||
[
|
||||
'type' => Controls_Manager::RAW_HTML,
|
||||
'raw' => '<b>' . esc_html__( 'This template includes the header, full-width content and footer', 'elementor' ) . '</b>',
|
||||
'content_classes' => 'elementor-descriptor',
|
||||
'condition' => [
|
||||
$control_id => self::TEMPLATE_HEADER_FOOTER,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
if ( $document instanceof Kit ) {
|
||||
$document->add_control(
|
||||
'reload_preview_description',
|
||||
[
|
||||
'type' => Controls_Manager::RAW_HTML,
|
||||
'raw' => esc_html__( 'Changes will be reflected in the preview only after the page reloads.', 'elementor' ),
|
||||
'content_classes' => 'elementor-descriptor',
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter metadata update.
|
||||
*
|
||||
* Filters whether to update metadata of a specific type.
|
||||
*
|
||||
* Elementor don't allow WordPress to update the parent page template
|
||||
* during `wp_update_post`.
|
||||
*
|
||||
* Fired by `update_{$meta_type}_metadata` filter.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*
|
||||
* @param bool $check Whether to allow updating metadata for the given type.
|
||||
* @param int $object_id Object ID.
|
||||
* @param string $meta_key Meta key.
|
||||
*
|
||||
* @return bool Whether to allow updating metadata of a specific type.
|
||||
*/
|
||||
public function filter_update_meta( $check, $object_id, $meta_key ) {
|
||||
if ( '_wp_page_template' === $meta_key && Plugin::$instance->common ) {
|
||||
/** @var \Elementor\Core\Common\Modules\Ajax\Module $ajax */
|
||||
$ajax = Plugin::$instance->common->get_component( 'ajax' );
|
||||
|
||||
$ajax_data = $ajax->get_current_action_data();
|
||||
|
||||
$is_autosave_action = $ajax_data && 'save_builder' === $ajax_data['action'] && Document::STATUS_AUTOSAVE === $ajax_data['data']['status'];
|
||||
|
||||
// Don't allow WP to update the parent page template.
|
||||
// (during `wp_update_post` from page-settings or save_plain_text).
|
||||
if ( $is_autosave_action && ! wp_is_post_autosave( $object_id ) && Document::STATUS_DRAFT !== get_post_status( $object_id ) ) {
|
||||
$check = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $check;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support `wp_body_open` action, available since WordPress 5.2.
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @access public
|
||||
*/
|
||||
public static function body_open() {
|
||||
wp_body_open();
|
||||
}
|
||||
|
||||
/**
|
||||
* Page templates module constructor.
|
||||
*
|
||||
* Initializing Elementor page templates module.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'init', [ $this, 'add_wp_templates_support' ] );
|
||||
|
||||
add_filter( 'template_include', [ $this, 'template_include' ], 11 /* After Plugins/WooCommerce */ );
|
||||
|
||||
add_action( 'elementor/documents/register_controls', [ $this, 'action_register_template_control' ] );
|
||||
|
||||
add_filter( 'update_post_metadata', [ $this, 'filter_update_meta' ], 10, 3 );
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user