first commit
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\AdminTopBar;
|
||||
|
||||
use ElementorPro\Plugin;
|
||||
use ElementorPro\Base\Module_Base;
|
||||
use ElementorPro\Core\Connect\Apps\Activate;
|
||||
use ElementorPro\License\API;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends Module_Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'admin-top-bar';
|
||||
}
|
||||
|
||||
/**
|
||||
* Module constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_action( 'elementor/admin-top-bar/init', function ( $module ) {
|
||||
$settings = $module->get_settings();
|
||||
$current_screen = null;
|
||||
|
||||
// For BC support.
|
||||
// when the action 'elementor/admin-top-bar/init' triggered before screen is registered.
|
||||
// TODO: need to remove if elementor core version 3.5.0 is stable
|
||||
if ( function_exists( 'get_current_screen' ) ) {
|
||||
$current_screen = get_current_screen();
|
||||
}
|
||||
|
||||
/** @var Activate $activate */
|
||||
$activate = Plugin::elementor()->common->get_component( 'connect' )->get_app( 'activate' );
|
||||
|
||||
$settings['is_user_connected'] = $settings['is_user_connected'] && API::is_license_active();
|
||||
$settings['connect_url'] = ! API::is_license_active() ?
|
||||
$activate->get_admin_url( 'authorize', [
|
||||
'utm_source' => 'top-bar',
|
||||
'utm_medium' => 'wp-dash',
|
||||
'utm_campaign' => 'connect-and-activate-license',
|
||||
'utm_content' => $current_screen ? $current_screen->id : '',
|
||||
] ) :
|
||||
$settings['connect_url'];
|
||||
|
||||
$module->set_settings( $settings );
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AnimatedHeadline;
|
||||
|
||||
use ElementorPro\Base\Module_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends Module_Base {
|
||||
|
||||
public function get_widgets() {
|
||||
return [
|
||||
'Animated_Headline',
|
||||
];
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'animated-headline';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,619 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AnimatedHeadline\Widgets;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use Elementor\Core\Kits\Documents\Tabs\Global_Colors;
|
||||
use Elementor\Core\Kits\Documents\Tabs\Global_Typography;
|
||||
use Elementor\Group_Control_Typography;
|
||||
use Elementor\Group_Control_Text_Stroke;
|
||||
use Elementor\Modules\DynamicTags\Module as TagsModule;
|
||||
use Elementor\Utils;
|
||||
use ElementorPro\Base\Base_Widget;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Animated_Headline extends Base_Widget {
|
||||
|
||||
public function get_name() {
|
||||
return 'animated-headline';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'Animated Headline', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_icon() {
|
||||
return 'eicon-animated-headline';
|
||||
}
|
||||
|
||||
public function get_keywords() {
|
||||
return [ 'headline', 'heading', 'animation', 'title', 'text' ];
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
$this->start_controls_section(
|
||||
'text_elements',
|
||||
[
|
||||
'label' => esc_html__( 'Headline', 'elementor-pro' ),
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'headline_style',
|
||||
[
|
||||
'label' => esc_html__( 'Style', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => 'highlight',
|
||||
'options' => [
|
||||
'highlight' => esc_html__( 'Highlighted', 'elementor-pro' ),
|
||||
'rotate' => esc_html__( 'Rotating', 'elementor-pro' ),
|
||||
],
|
||||
'prefix_class' => 'elementor-headline--style-',
|
||||
'render_type' => 'template',
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'animation_type',
|
||||
[
|
||||
'label' => esc_html__( 'Animation', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => [
|
||||
'typing' => 'Typing',
|
||||
'clip' => 'Clip',
|
||||
'flip' => 'Flip',
|
||||
'swirl' => 'Swirl',
|
||||
'blinds' => 'Blinds',
|
||||
'drop-in' => 'Drop-in',
|
||||
'wave' => 'Wave',
|
||||
'slide' => 'Slide',
|
||||
'slide-down' => 'Slide Down',
|
||||
],
|
||||
'default' => 'typing',
|
||||
'condition' => [
|
||||
'headline_style' => 'rotate',
|
||||
],
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'marker',
|
||||
[
|
||||
'label' => esc_html__( 'Shape', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => 'circle',
|
||||
'options' => [
|
||||
'circle' => _x( 'Circle', 'Shapes', 'elementor-pro' ),
|
||||
'curly' => _x( 'Curly', 'Shapes', 'elementor-pro' ),
|
||||
'underline' => _x( 'Underline', 'Shapes', 'elementor-pro' ),
|
||||
'double' => _x( 'Double', 'Shapes', 'elementor-pro' ),
|
||||
'double_underline' => _x( 'Double Underline', 'Shapes', 'elementor-pro' ),
|
||||
'underline_zigzag' => _x( 'Underline Zigzag', 'Shapes', 'elementor-pro' ),
|
||||
'diagonal' => _x( 'Diagonal', 'Shapes', 'elementor-pro' ),
|
||||
'strikethrough' => _x( 'Strikethrough', 'Shapes', 'elementor-pro' ),
|
||||
'x' => 'X',
|
||||
],
|
||||
'render_type' => 'template',
|
||||
'condition' => [
|
||||
'headline_style' => 'highlight',
|
||||
],
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'before_text',
|
||||
[
|
||||
'label' => esc_html__( 'Before Text', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXT,
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
'categories' => [
|
||||
TagsModule::TEXT_CATEGORY,
|
||||
],
|
||||
],
|
||||
'default' => esc_html__( 'This page is', 'elementor-pro' ),
|
||||
'placeholder' => esc_html__( 'Enter your headline', 'elementor-pro' ),
|
||||
'label_block' => true,
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'highlighted_text',
|
||||
[
|
||||
'label' => esc_html__( 'Highlighted Text', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXT,
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
'categories' => [
|
||||
TagsModule::TEXT_CATEGORY,
|
||||
],
|
||||
],
|
||||
'default' => esc_html__( 'Amazing', 'elementor-pro' ),
|
||||
'label_block' => true,
|
||||
'condition' => [
|
||||
'headline_style' => 'highlight',
|
||||
],
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'rotating_text',
|
||||
[
|
||||
'label' => esc_html__( 'Rotating Text', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXTAREA,
|
||||
'placeholder' => esc_html__( 'Enter each word in a separate line', 'elementor-pro' ),
|
||||
'default' => "Better\nBigger\nFaster",
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
'categories' => [
|
||||
TagsModule::TEXT_CATEGORY,
|
||||
],
|
||||
],
|
||||
'condition' => [
|
||||
'headline_style' => 'rotate',
|
||||
],
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'after_text',
|
||||
[
|
||||
'label' => esc_html__( 'After Text', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXT,
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
'categories' => [
|
||||
TagsModule::TEXT_CATEGORY,
|
||||
],
|
||||
],
|
||||
'placeholder' => esc_html__( 'Enter your headline', 'elementor-pro' ),
|
||||
'label_block' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'loop',
|
||||
[
|
||||
'label' => esc_html__( 'Infinite Loop', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'default' => 'yes',
|
||||
'render_type' => 'template',
|
||||
'frontend_available' => true,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}}' => '--iteration-count: infinite',
|
||||
],
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'highlight_animation_duration',
|
||||
[
|
||||
'label' => esc_html__( 'Duration', 'elementor-pro' ) . ' (ms)',
|
||||
'type' => Controls_Manager::NUMBER,
|
||||
'default' => 1200,
|
||||
'render_type' => 'template',
|
||||
'frontend_available' => true,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}}' => '--animation-duration: {{VALUE}}ms',
|
||||
],
|
||||
'condition' => [
|
||||
'headline_style' => 'highlight',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'highlight_iteration_delay',
|
||||
[
|
||||
'label' => esc_html__( 'Delay', 'elementor-pro' ) . ' (ms)',
|
||||
'type' => Controls_Manager::NUMBER,
|
||||
'default' => 8000,
|
||||
'render_type' => 'template',
|
||||
'frontend_available' => true,
|
||||
'condition' => [
|
||||
'headline_style' => 'highlight',
|
||||
'loop' => 'yes',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'rotate_iteration_delay',
|
||||
[
|
||||
'label' => esc_html__( 'Duration', 'elementor-pro' ) . ' (ms)',
|
||||
'type' => Controls_Manager::NUMBER,
|
||||
'default' => 2500,
|
||||
'render_type' => 'template',
|
||||
'frontend_available' => true,
|
||||
'condition' => [
|
||||
'headline_style' => 'rotate',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'link',
|
||||
[
|
||||
'label' => esc_html__( 'Link', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::URL,
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'alignment',
|
||||
[
|
||||
'label' => esc_html__( 'Alignment', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::CHOOSE,
|
||||
'options' => [
|
||||
'left' => [
|
||||
'title' => esc_html__( 'Left', 'elementor-pro' ),
|
||||
'icon' => 'eicon-text-align-left',
|
||||
],
|
||||
'center' => [
|
||||
'title' => esc_html__( 'Center', 'elementor-pro' ),
|
||||
'icon' => 'eicon-text-align-center',
|
||||
],
|
||||
'right' => [
|
||||
'title' => esc_html__( 'Right', 'elementor-pro' ),
|
||||
'icon' => 'eicon-text-align-right',
|
||||
],
|
||||
],
|
||||
'default' => 'center',
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-headline' => 'text-align: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'tag',
|
||||
[
|
||||
'label' => esc_html__( 'HTML Tag', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => [
|
||||
'h1' => 'H1',
|
||||
'h2' => 'H2',
|
||||
'h3' => 'H3',
|
||||
'h4' => 'H4',
|
||||
'h5' => 'H5',
|
||||
'h6' => 'H6',
|
||||
'div' => 'div',
|
||||
'span' => 'span',
|
||||
'p' => 'p',
|
||||
],
|
||||
'default' => 'h3',
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_style_marker',
|
||||
[
|
||||
'label' => esc_html__( 'Shape', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
'condition' => [
|
||||
'headline_style' => 'highlight',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'marker_color',
|
||||
[
|
||||
'label' => esc_html__( 'Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'global' => [
|
||||
'default' => Global_Colors::COLOR_ACCENT,
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-headline-dynamic-wrapper path' => 'stroke: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'stroke_width',
|
||||
[
|
||||
'label' => esc_html__( 'Width', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'min' => 1,
|
||||
'max' => 20,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 2,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 2,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-headline-dynamic-wrapper path' => 'stroke-width: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'above_content',
|
||||
[
|
||||
'label' => esc_html__( 'Bring to Front', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-headline-dynamic-wrapper svg' => 'z-index: 2',
|
||||
'{{WRAPPER}} .elementor-headline-dynamic-text' => 'z-index: auto',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'rounded_edges',
|
||||
[
|
||||
'label' => esc_html__( 'Rounded Edges', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-headline-dynamic-wrapper path' => 'stroke-linecap: round; stroke-linejoin: round',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_style_text',
|
||||
[
|
||||
'label' => esc_html__( 'Headline', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'title_color',
|
||||
[
|
||||
'label' => esc_html__( 'Text Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'global' => [
|
||||
'default' => Global_Colors::COLOR_SECONDARY,
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-headline-plain-text' => 'color: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Typography::get_type(),
|
||||
[
|
||||
'name' => 'title_typography',
|
||||
'global' => [
|
||||
'default' => Global_Typography::TYPOGRAPHY_PRIMARY,
|
||||
],
|
||||
'selector' => '{{WRAPPER}} .elementor-headline',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Text_Stroke::get_type(),
|
||||
[
|
||||
'name' => 'text_stroke',
|
||||
'selector' => '{{WRAPPER}} .elementor-headline .elementor-headline-plain-text',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'heading_words_style',
|
||||
[
|
||||
'type' => Controls_Manager::HEADING,
|
||||
'label' => esc_html__( 'Animated Text', 'elementor-pro' ),
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'words_color',
|
||||
[
|
||||
'label' => esc_html__( 'Text Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'global' => [
|
||||
'default' => Global_Colors::COLOR_SECONDARY,
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}}' => '--dynamic-text-color: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Typography::get_type(),
|
||||
[
|
||||
'name' => 'words_typography',
|
||||
'global' => [
|
||||
'default' => Global_Typography::TYPOGRAPHY_PRIMARY,
|
||||
],
|
||||
'selector' => '{{WRAPPER}} .elementor-headline-dynamic-text',
|
||||
'exclude' => [ 'font_size' ],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Text_Stroke::get_type(),
|
||||
[
|
||||
'name' => 'animated_text_stroke',
|
||||
'selector' => '{{WRAPPER}} .elementor-headline .elementor-headline-dynamic-wrapper',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'typing_animation_highlight_colors',
|
||||
[
|
||||
'type' => Controls_Manager::HEADING,
|
||||
'label' => esc_html__( 'Selected Text', 'elementor-pro' ),
|
||||
'separator' => 'before',
|
||||
'condition' => [
|
||||
'headline_style' => 'rotate',
|
||||
'animation_type' => 'typing',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'highlighted_text_background_color',
|
||||
[
|
||||
'label' => esc_html__( 'Selection Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}}' => '--typing-selected-bg-color: {{VALUE}}',
|
||||
],
|
||||
'condition' => [
|
||||
'headline_style' => 'rotate',
|
||||
'animation_type' => 'typing',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'highlighted_text_color',
|
||||
[
|
||||
'label' => esc_html__( 'Text Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}}' => '--typing-selected-color: {{VALUE}}',
|
||||
],
|
||||
'condition' => [
|
||||
'headline_style' => 'rotate',
|
||||
'animation_type' => 'typing',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
}
|
||||
|
||||
protected function render() {
|
||||
$settings = $this->get_settings_for_display();
|
||||
|
||||
$tag = Utils::validate_html_tag( $settings['tag'] );
|
||||
|
||||
$this->add_render_attribute( 'headline', 'class', 'elementor-headline' );
|
||||
|
||||
if ( 'rotate' === $settings['headline_style'] ) {
|
||||
$this->add_render_attribute( 'headline', 'class', 'elementor-headline-animation-type-' . $settings['animation_type'] );
|
||||
|
||||
$is_letter_animation = in_array( $settings['animation_type'], [ 'typing', 'swirl', 'blinds', 'wave' ] );
|
||||
|
||||
if ( $is_letter_animation ) {
|
||||
$this->add_render_attribute( 'headline', 'class', 'elementor-headline-letters' );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $settings['link']['url'] ) ) {
|
||||
$this->add_link_attributes( 'url', $settings['link'] );
|
||||
?>
|
||||
<a <?php $this->print_render_attribute_string( 'url' ); ?>>
|
||||
|
||||
<?php
|
||||
}
|
||||
|
||||
?>
|
||||
<<?php Utils::print_validated_html_tag( $tag ); ?> <?php $this->print_render_attribute_string( 'headline' ); ?>>
|
||||
<?php if ( ! empty( $settings['before_text'] ) ) : ?>
|
||||
<span class="elementor-headline-plain-text elementor-headline-text-wrapper"><?php $this->print_unescaped_setting( 'before_text' ); ?></span>
|
||||
<?php endif; ?>
|
||||
<span class="elementor-headline-dynamic-wrapper elementor-headline-text-wrapper">
|
||||
<?php if ( 'rotate' === $settings['headline_style'] && $settings['rotating_text'] ) :
|
||||
$rotating_text = explode( "\n", $settings['rotating_text'] );
|
||||
foreach ( $rotating_text as $key => $text ) : ?>
|
||||
<span class="elementor-headline-dynamic-text<?php echo 1 > $key ? ' elementor-headline-text-active' : ''; ?>">
|
||||
<?php Utils::print_unescaped_internal_string( str_replace( ' ', ' ', $text ) ); ?>
|
||||
</span>
|
||||
<?php endforeach; ?>
|
||||
<?php elseif ( 'highlight' === $settings['headline_style'] && ! empty( $settings['highlighted_text'] ) ) : ?>
|
||||
<span class="elementor-headline-dynamic-text elementor-headline-text-active"><?php $this->print_unescaped_setting( 'highlighted_text' ); ?></span>
|
||||
<?php endif ?>
|
||||
</span>
|
||||
<?php if ( ! empty( $settings['after_text'] ) ) : ?>
|
||||
<span class="elementor-headline-plain-text elementor-headline-text-wrapper"><?php $this->print_unescaped_setting( 'after_text' ); ?></span>
|
||||
<?php endif; ?>
|
||||
</<?php Utils::print_validated_html_tag( $tag ); ?>>
|
||||
<?php
|
||||
|
||||
if ( ! empty( $settings['link']['url'] ) ) {
|
||||
echo '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render Animated Headline widget output in the editor.
|
||||
*
|
||||
* Written as a Backbone JavaScript template and used to generate the live preview.
|
||||
*
|
||||
* @since 2.9.0
|
||||
* @access protected
|
||||
*/
|
||||
protected function content_template() {
|
||||
?>
|
||||
<#
|
||||
var headlineClasses = 'elementor-headline',
|
||||
tag = elementor.helpers.validateHTMLTag( settings.tag );
|
||||
|
||||
if ( 'rotate' === settings.headline_style ) {
|
||||
headlineClasses += ' elementor-headline-animation-type-' + settings.animation_type;
|
||||
|
||||
var isLetterAnimation = -1 !== [ 'typing', 'swirl', 'blinds', 'wave' ].indexOf( settings.animation_type );
|
||||
|
||||
if ( isLetterAnimation ) {
|
||||
headlineClasses += ' elementor-headline-letters';
|
||||
}
|
||||
}
|
||||
|
||||
if ( settings.link.url ) { #>
|
||||
<a href="#">
|
||||
<# } #>
|
||||
<{{{ tag }}} class="{{{ headlineClasses }}}">
|
||||
<# if ( settings.before_text ) { #>
|
||||
<span class="elementor-headline-plain-text elementor-headline-text-wrapper">{{{ settings.before_text }}}</span>
|
||||
<# } #>
|
||||
|
||||
<# if ( settings.rotating_text ) { #>
|
||||
<span class="elementor-headline-dynamic-wrapper elementor-headline-text-wrapper">
|
||||
<# if ( 'rotate' === settings.headline_style && settings.rotating_text ) {
|
||||
var rotatingText = ( settings.rotating_text || '' ).split( '\n' );
|
||||
for ( var i = 0; i < rotatingText.length; i++ ) {
|
||||
var statusClass = 0 === i ? 'elementor-headline-text-active' : ''; #>
|
||||
<span class="elementor-headline-dynamic-text {{ statusClass }}">
|
||||
{{{ rotatingText[ i ].replace( ' ', ' ' ) }}}
|
||||
</span>
|
||||
<# }
|
||||
}
|
||||
|
||||
else if ( 'highlight' === settings.headline_style && settings.highlighted_text ) { #>
|
||||
<span class="elementor-headline-dynamic-text elementor-headline-text-active">{{{ settings.highlighted_text }}}</span>
|
||||
<# } #>
|
||||
</span>
|
||||
<# } #>
|
||||
|
||||
<# if ( settings.after_text ) { #>
|
||||
<span class="elementor-headline-plain-text elementor-headline-text-wrapper">{{{ settings.after_text }}}</span>
|
||||
<# } #>
|
||||
</{{{ tag }}}>
|
||||
<# if ( settings.link.url ) { #>
|
||||
</a>
|
||||
<# } #>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\Announcements;
|
||||
|
||||
use Elementor\Core\Base\App as BaseApp;
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_filter( 'elementor/announcements/raw_announcements', function ( $raw_announcements ) {
|
||||
$raw_announcement = [
|
||||
'title' => __( 'Keep Your Website’s Shine On', 'elementor-pro' ),
|
||||
'description' => __( '<p>Your Elementor Pro subscription has expired. Renew it now to regain access to the Pro features that elevate your website.</p>
|
||||
<ul>
|
||||
<li>Manage and edit every part of your website, including pages, templates, headers, footers, and more.</li>
|
||||
<li>Increase engagement and conversion with Elementor’s marketing features including Forms, and Popups.</li>
|
||||
<li>Update your website’s content and design using Elementor Pro’s professional widgets and features for any need.</li>
|
||||
<li>Keep your website secure and compatible by updating your Elementor Pro website to the latest version.</li>
|
||||
</ul>', 'elementor-pro' ),
|
||||
'media' => [
|
||||
'type' => 'image',
|
||||
'src' => ELEMENTOR_PRO_ASSETS_URL . 'images/announcements/license-expired.png?' . ELEMENTOR_PRO_VERSION,
|
||||
],
|
||||
'cta' => [
|
||||
[
|
||||
'label' => __( 'Renew Now', 'elementor-pro' ),
|
||||
'variant' => 'primary',
|
||||
'target' => '_blank',
|
||||
'url' => 'https://go.elementor.com/renew-license-editor-expired-modal/',
|
||||
],
|
||||
[
|
||||
'label' => __( 'Learn More', 'elementor-pro' ),
|
||||
'target' => '_blank',
|
||||
'url' => 'https://go.elementor.com//learn-more-editor-expired-modal/',
|
||||
],
|
||||
],
|
||||
'triggers' => [
|
||||
[
|
||||
'action' => 'isLicenseExpired',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
array_unshift( $raw_announcements, $raw_announcement );
|
||||
|
||||
return $raw_announcements;
|
||||
}, 400 );
|
||||
|
||||
add_filter( 'elementor/announcements/trigger_object', function( $object_trigger, $trigger ) {
|
||||
if ( ! empty( $trigger['action'] ) && 'isLicenseExpired' === $trigger['action'] ) {
|
||||
$object_trigger = new Triggers\IsLicenseExpired();
|
||||
}
|
||||
|
||||
return $object_trigger;
|
||||
}, 400, 2 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\Announcements\Triggers;
|
||||
|
||||
use Elementor\Modules\Announcements\Classes\Trigger_Base;
|
||||
use ElementorPro\License\API;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class IsLicenseExpired extends Trigger_Base {
|
||||
|
||||
const META_KEY = '_elementor_pro_announcements_license_expired';
|
||||
|
||||
const MUTED_PERIOD = 1;
|
||||
|
||||
public function after_triggered() {
|
||||
update_user_meta( get_current_user_id(), self::META_KEY, time() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function is_active(): bool {
|
||||
if ( ! API::is_license_expired() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$dismissed_time = get_user_meta( get_current_user_id(), self::META_KEY, true );
|
||||
|
||||
if ( ! empty( $dismissed_time ) && $dismissed_time > strtotime( '-' . static::MUTED_PERIOD . ' days' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager\AssetTypes\AdminMenuItems;
|
||||
|
||||
use Elementor\Core\Admin\Menu\Interfaces\Admin_Menu_Item;
|
||||
use Elementor\Settings;
|
||||
use ElementorPro\Modules\AssetsManager\AssetTypes\Fonts_Manager;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Custom_Fonts_Menu_Item implements Admin_Menu_Item {
|
||||
public function get_capability() {
|
||||
return Fonts_Manager::CAPABILITY;
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Custom Fonts', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_parent_slug() {
|
||||
return Settings::PAGE_ID;
|
||||
}
|
||||
|
||||
public function get_position() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function is_visible() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager\AssetTypes\AdminMenuItems;
|
||||
|
||||
use ElementorPro\Modules\Tiers\AdminMenuItems\Base_Promotion_Item;
|
||||
use ElementorPro\License\API;
|
||||
use ElementorPro\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Custom_Fonts_Promotion_Menu_Item extends Base_Promotion_Item {
|
||||
public function get_name() {
|
||||
return 'custom-fonts-promotion';
|
||||
}
|
||||
|
||||
public function get_position() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function get_cta_url() {
|
||||
$connect_url = Plugin::instance()->license_admin->get_connect_url( [
|
||||
'utm_source' => 'wp-custom-fonts',
|
||||
'utm_medium' => 'wp-dash',
|
||||
'utm_campaign' => 'connect-and-activate-license',
|
||||
] );
|
||||
|
||||
$renew_url = 'https://go.elementor.com/renew-custom-fonts/';
|
||||
|
||||
return API::is_license_expired()
|
||||
? $renew_url
|
||||
: $connect_url;
|
||||
}
|
||||
|
||||
public function get_cta_text() {
|
||||
return API::is_license_expired()
|
||||
? esc_html__( 'Renew now', 'elementor-pro' )
|
||||
: esc_html__( 'Connect & Activate', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Custom Fonts', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_page_title() {
|
||||
return esc_html__( 'Custom Fonts', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_promotion_title() {
|
||||
return esc_html__( 'Add Your Custom Fonts', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_promotion_description() {
|
||||
return esc_html__(
|
||||
'Custom Fonts allows you to add your self-hosted fonts and use them on your Elementor projects to create a unique brand language.',
|
||||
'elementor-pro'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use get_promotion_description instead
|
||||
* @return void
|
||||
*/
|
||||
public function render_promotion_description() {
|
||||
echo $this->get_promotion_description(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager\AssetTypes\AdminMenuItems;
|
||||
|
||||
use Elementor\Core\Admin\Menu\Interfaces\Admin_Menu_Item;
|
||||
use Elementor\Settings;
|
||||
use ElementorPro\Modules\AssetsManager\AssetTypes\Icons_Manager;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Custom_Icons_Menu_Item implements Admin_Menu_Item {
|
||||
public function get_capability() {
|
||||
return Icons_Manager::CAPABILITY;
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Custom Icons', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_parent_slug() {
|
||||
return Settings::PAGE_ID;
|
||||
}
|
||||
|
||||
public function get_position() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function is_visible() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager\AssetTypes\AdminMenuItems;
|
||||
|
||||
use ElementorPro\Modules\Tiers\AdminMenuItems\Base_Promotion_Item;
|
||||
use ElementorPro\License\API;
|
||||
use ElementorPro\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Custom_Icons_Promotion_Menu_Item extends Base_Promotion_Item {
|
||||
public function get_name() {
|
||||
return 'custom-icons-promotion';
|
||||
}
|
||||
|
||||
public function get_cta_url() {
|
||||
$connect_url = Plugin::instance()->license_admin->get_connect_url( [
|
||||
'utm_source' => 'wp-custom-icons',
|
||||
'utm_medium' => 'wp-dash',
|
||||
'utm_campaign' => 'connect-and-activate-license',
|
||||
] );
|
||||
|
||||
$renew_url = 'https://go.elementor.com/renew-custom-icons/';
|
||||
|
||||
return API::is_license_expired()
|
||||
? $renew_url
|
||||
: $connect_url;
|
||||
}
|
||||
|
||||
public function get_position() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function get_cta_text() {
|
||||
return API::is_license_expired()
|
||||
? esc_html__( 'Renew now', 'elementor-pro' )
|
||||
: esc_html__( 'Connect & Activate', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Custom Icons', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_page_title() {
|
||||
return esc_html__( 'Custom Icons', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_promotion_title() {
|
||||
return esc_html__( 'Add Your Custom Icons', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_promotion_description() {
|
||||
return esc_html__(
|
||||
'Don\'t rely solely on the FontAwesome icons everyone else is using! Differentiate your website and your style with custom icons you can upload from your favorite icons source.',
|
||||
'elementor-pro'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use get_promotion_description instead
|
||||
* @return void
|
||||
*/
|
||||
public function render_promotion_description() {
|
||||
echo $this->get_promotion_description(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,615 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager\AssetTypes;
|
||||
|
||||
use Elementor\Core\Admin\Menu\Admin_Menu_Manager;
|
||||
use Elementor\Utils;
|
||||
use ElementorPro\Core\Utils as Pro_Utils;
|
||||
use Elementor\Core\Common\Modules\Ajax\Module as Ajax;
|
||||
use ElementorPro\Core\Behaviors\Feature_Lock;
|
||||
use ElementorPro\License\API;
|
||||
use ElementorPro\Modules\AssetsManager\AssetTypes\AdminMenuItems\Custom_Fonts_Menu_Item;
|
||||
use ElementorPro\Modules\AssetsManager\AssetTypes\AdminMenuItems\Custom_Fonts_Promotion_Menu_Item;
|
||||
use ElementorPro\Modules\AssetsManager\Classes;
|
||||
use Elementor\Settings;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Fonts_Manager {
|
||||
|
||||
const CAPABILITY = 'manage_options';
|
||||
|
||||
const CPT = 'elementor_font';
|
||||
|
||||
const TAXONOMY = 'elementor_font_type';
|
||||
|
||||
const FONTS_OPTION_NAME = 'elementor_fonts_manager_fonts';
|
||||
|
||||
const FONTS_NAME_TYPE_OPTION_NAME = 'elementor_fonts_manager_font_types';
|
||||
|
||||
const MENU_SLUG = 'edit.php?post_type=' . self::CPT;
|
||||
|
||||
const PROMOTION_MENU_SLUG = 'e-custom-fonts';
|
||||
|
||||
private $post_type_object;
|
||||
|
||||
private $taxonomy_object;
|
||||
|
||||
private $enqueued_fonts = [];
|
||||
|
||||
protected $font_types = [];
|
||||
|
||||
private $has_fonts = null;
|
||||
|
||||
/**
|
||||
* get a font type object for a given type
|
||||
*
|
||||
* @param null $type
|
||||
*
|
||||
* @return array|bool|\ElementorPro\Modules\AssetsManager\Classes\Font_Base
|
||||
*/
|
||||
public function get_font_type_object( $type = null ) {
|
||||
if ( null === $type ) {
|
||||
return $this->font_types;
|
||||
}
|
||||
|
||||
if ( isset( $this->font_types[ $type ] ) ) {
|
||||
return $this->font_types[ $type ];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a font type to the font manager
|
||||
*
|
||||
* @param string $font_type
|
||||
* @param Classes\Font_Base $instance
|
||||
*/
|
||||
public function add_font_type( $font_type, $instance ) {
|
||||
$this->font_types[ $font_type ] = $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register elementor font custom post type and elementor font type custom taxonomy
|
||||
*/
|
||||
public function register_post_type_and_tax() {
|
||||
$labels = [
|
||||
'name' => _x( 'Custom Fonts', 'CPT Name', 'elementor-pro' ),
|
||||
'singular_name' => _x( 'Font', 'CPT Singular Name', 'elementor-pro' ),
|
||||
'add_new' => esc_html__( 'Add New', 'elementor-pro' ),
|
||||
'add_new_item' => esc_html__( 'Add New Font', 'elementor-pro' ),
|
||||
'edit_item' => esc_html__( 'Edit Font', 'elementor-pro' ),
|
||||
'new_item' => esc_html__( 'New Font', 'elementor-pro' ),
|
||||
'all_items' => esc_html__( 'All Fonts', 'elementor-pro' ),
|
||||
'view_item' => esc_html__( 'View Font', 'elementor-pro' ),
|
||||
'search_items' => esc_html__( 'Search Font', 'elementor-pro' ),
|
||||
'not_found' => esc_html__( 'No fonts found', 'elementor-pro' ),
|
||||
'not_found_in_trash' => esc_html__( 'No fonts found in trash', 'elementor-pro' ),
|
||||
'parent_item_colon' => '',
|
||||
'menu_name' => _x( 'Custom Fonts', 'CPT Menu Name', 'elementor-pro' ),
|
||||
];
|
||||
|
||||
$args = [
|
||||
'labels' => $labels,
|
||||
'public' => false,
|
||||
'rewrite' => false,
|
||||
'show_ui' => true,
|
||||
'show_in_menu' => false,
|
||||
'show_in_nav_menus' => false,
|
||||
'exclude_from_search' => true,
|
||||
'capability_type' => 'post',
|
||||
'hierarchical' => false,
|
||||
'supports' => [ 'title' ],
|
||||
];
|
||||
|
||||
$this->post_type_object = register_post_type( self::CPT, $args );
|
||||
|
||||
$taxonomy_labels = [
|
||||
'name' => _x( 'Font Types', 'Font type taxonomy general name', 'elementor-pro' ),
|
||||
'singular_name' => _x( 'Font Type', 'Font type singular name', 'elementor-pro' ),
|
||||
'search_items' => esc_html__( 'Search Font Types', 'elementor-pro' ),
|
||||
'popular_items' => esc_html__( 'Popular Font Types', 'elementor-pro' ),
|
||||
'all_items' => esc_html__( 'All Font Types', 'elementor-pro' ),
|
||||
'edit_item' => esc_html__( 'Edit Font Type', 'elementor-pro' ),
|
||||
'update_item' => esc_html__( 'Update Font Type', 'elementor-pro' ),
|
||||
'add_new_item' => esc_html__( 'Add New Font Type', 'elementor-pro' ),
|
||||
'new_item_name' => esc_html__( 'New Font Type Name', 'elementor-pro' ),
|
||||
'separate_items_with_commas' => esc_html__( 'Separate Font Types with commas', 'elementor-pro' ),
|
||||
'add_or_remove_items' => esc_html__( 'Add or remove Font Types', 'elementor-pro' ),
|
||||
'choose_from_most_used' => esc_html__( 'Choose from the most used Font Types', 'elementor-pro' ),
|
||||
'not_found' => esc_html__( 'No Font Types found.', 'elementor-pro' ),
|
||||
'menu_name' => esc_html__( 'Font Types', 'elementor-pro' ),
|
||||
];
|
||||
|
||||
$taxonomy_args = [
|
||||
'labels' => $taxonomy_labels,
|
||||
'hierarchical' => false,
|
||||
'show_ui' => true,
|
||||
'show_in_nav_menus' => false,
|
||||
'query_var' => is_admin(),
|
||||
'rewrite' => false,
|
||||
'public' => false,
|
||||
'meta_box_cb' => [ $this, 'print_taxonomy_metabox' ],
|
||||
];
|
||||
|
||||
$this->taxonomy_object = register_taxonomy( self::TAXONOMY, self::CPT, $taxonomy_args );
|
||||
}
|
||||
|
||||
public function post_updated_messages( $messages ) {
|
||||
$messages[ self::CPT ] = [
|
||||
0 => '', // Unused. Messages start at index 1.
|
||||
1 => esc_html__( 'Font updated.', 'elementor-pro' ),
|
||||
2 => esc_html__( 'Custom field updated.', 'elementor-pro' ),
|
||||
3 => esc_html__( 'Custom field deleted.', 'elementor-pro' ),
|
||||
4 => esc_html__( 'Font updated.', 'elementor-pro' ),
|
||||
/* translators: %s: Date and time of the revision. */
|
||||
5 => isset( $_GET['revision'] ) ? sprintf( esc_html__( 'Font restored to revision from %s', 'elementor-pro' ), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
|
||||
6 => esc_html__( 'Font saved.', 'elementor-pro' ),
|
||||
7 => esc_html__( 'Font saved.', 'elementor-pro' ),
|
||||
8 => esc_html__( 'Font submitted.', 'elementor-pro' ),
|
||||
9 => esc_html__( 'Font updated.', 'elementor-pro' ),
|
||||
10 => esc_html__( 'Font draft updated.', 'elementor-pro' ),
|
||||
];
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print Font Type metabox
|
||||
*
|
||||
* @param $post
|
||||
* @param $box
|
||||
*/
|
||||
public function print_taxonomy_metabox( $post, $box ) {
|
||||
wp_nonce_field( self::CPT, self::CPT . '_nonce' );
|
||||
$name = self::TAXONOMY;
|
||||
?>
|
||||
<div id="taxonomy-<?php echo esc_attr( $name ); ?>" class="categorydiv">
|
||||
<?php
|
||||
$term_obj = wp_get_object_terms( $post->ID, $name );
|
||||
$slug = false;
|
||||
if ( is_array( $term_obj ) && isset( $term_obj[0] ) ) {
|
||||
$slug = $term_obj[0]->slug;
|
||||
}
|
||||
$options = '';
|
||||
foreach ( $this->font_types as $type => $instance ) {
|
||||
$options .= sprintf( '<option value="%s"%s>%s</option>' . "\n", $type, selected( $slug, $type, false ), $instance->get_name() );
|
||||
}
|
||||
?>
|
||||
<select class="widefat" name="<?php echo esc_attr( $name ); ?>">
|
||||
<?php Utils::print_unescaped_internal_string( $options ); ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Font manager link to admin menu
|
||||
*/
|
||||
private function register_admin_menu( Admin_Menu_Manager $admin_menu_manager ) {
|
||||
if ( $this->can_use_custom_fonts() ) {
|
||||
$admin_menu_manager->register( static::MENU_SLUG, new Custom_Fonts_Menu_Item() );
|
||||
} else {
|
||||
$admin_menu_manager->register( static::PROMOTION_MENU_SLUG, new Custom_Fonts_Promotion_Menu_Item() );
|
||||
}
|
||||
}
|
||||
|
||||
private function can_use_custom_fonts() {
|
||||
return ( API::is_license_active() || $this->has_fonts() );
|
||||
}
|
||||
|
||||
private function has_fonts() {
|
||||
if ( null !== $this->has_fonts ) {
|
||||
return $this->has_fonts;
|
||||
}
|
||||
|
||||
$existing_fonts = new \WP_Query( [
|
||||
'post_type' => static::CPT,
|
||||
'posts_per_page' => 1,
|
||||
] );
|
||||
|
||||
$this->has_fonts = $existing_fonts->post_count > 0;
|
||||
|
||||
return $this->has_fonts;
|
||||
}
|
||||
|
||||
public function redirect_admin_old_page_to_new() {
|
||||
if ( ! empty( $_GET['page'] ) && 'elementor_custom_fonts' === $_GET['page'] ) {
|
||||
wp_safe_redirect( admin_url( static::MENU_SLUG ) );
|
||||
die;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render preview column in font manager admin listing
|
||||
*
|
||||
* @param $column
|
||||
* @param $post_id
|
||||
*/
|
||||
public function render_columns( $column, $post_id ) {
|
||||
if ( 'font_preview' === $column ) {
|
||||
$font_type = $this->get_font_type_by_post_id( $post_id, true );
|
||||
|
||||
if ( false === $font_type ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$font_type->render_preview_column( $post_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle editor request to embed/link font CSS per font type
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function assets_manager_panel_action_data( array $data ) {
|
||||
$document = Pro_Utils::_unstable_get_document_for_edit( $data['editor_post_id'] );
|
||||
|
||||
if ( empty( $data['type'] ) ) {
|
||||
throw new \Exception( 'Font type is required.' );
|
||||
}
|
||||
|
||||
if ( empty( $data['font'] ) ) {
|
||||
throw new \Exception( 'Font is required.' );
|
||||
}
|
||||
|
||||
$asset = $this->get_font_type_object( $data['type'] );
|
||||
|
||||
if ( ! $asset ) {
|
||||
throw new \Exception( 'Font type not found.' );
|
||||
}
|
||||
|
||||
try {
|
||||
return $asset->handle_panel_request( $data );
|
||||
|
||||
} catch ( \Exception $exception ) {
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up admin Font manager admin listing
|
||||
*/
|
||||
public function clean_admin_listing_page() {
|
||||
global $typenow;
|
||||
|
||||
if ( self::CPT !== $typenow ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_filter( 'months_dropdown_results', '__return_empty_array' );
|
||||
add_action( 'manage_' . self::CPT . '_posts_custom_column', [ $this, 'render_columns' ], 10, 2 );
|
||||
add_filter( 'display_post_states', [ $this, 'display_post_states' ], 10, 2 );
|
||||
add_filter( 'screen_options_show_screen', '__return_false' );
|
||||
}
|
||||
|
||||
public function update_enter_title_here( $title, $post ) {
|
||||
if ( isset( $post->post_type ) && self::CPT === $post->post_type ) {
|
||||
return esc_html__( 'Enter Font Family', 'elementor-pro' );
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
public function post_row_actions( $actions, $post ) {
|
||||
if ( self::CPT !== $post->post_type ) {
|
||||
return $actions;
|
||||
}
|
||||
|
||||
unset( $actions['inline hide-if-no-js'] );
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
public function display_post_states( $post_states, $post ) {
|
||||
$font_type = $this->get_font_type_by_post_id( $post->ID, true );
|
||||
|
||||
if ( false !== $font_type ) {
|
||||
$font_type->get_font_variations_count( $post->ID );
|
||||
}
|
||||
|
||||
return $post_states;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define which columns to display in font manager admin listing
|
||||
*
|
||||
* @param $columns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function manage_columns( $columns ) {
|
||||
return [
|
||||
'cb' => '<input type="checkbox" />',
|
||||
'title' => esc_html__( 'Font Family', 'elementor-pro' ),
|
||||
'font_preview' => esc_html__( 'Preview', 'elementor-pro' ),
|
||||
];
|
||||
}
|
||||
|
||||
public function register_fonts_in_control( $fonts ) {
|
||||
$custom_fonts = $this->get_font_types();
|
||||
if ( empty( $custom_fonts ) ) {
|
||||
$this->generate_fonts_list();
|
||||
$custom_fonts = $this->get_font_types();
|
||||
}
|
||||
|
||||
return array_replace( $custom_fonts, $fonts );
|
||||
}
|
||||
|
||||
public function register_fonts_groups( $font_groups ) {
|
||||
$new_groups = [];
|
||||
|
||||
foreach ( $this->get_font_type_object() as $type => $instance ) {
|
||||
$new_groups[ $type ] = $instance->get_name();
|
||||
}
|
||||
|
||||
return array_replace( $new_groups, $font_groups );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Font type for any given post id
|
||||
*
|
||||
* @param $post_id
|
||||
* @param bool $return_object
|
||||
*
|
||||
* @return array|bool|Classes\Font_Base
|
||||
*/
|
||||
private function get_font_type_by_post_id( $post_id, $return_object = false ) {
|
||||
$term_obj = get_the_terms( $post_id, self::TAXONOMY );
|
||||
|
||||
if ( is_array( $term_obj ) ) {
|
||||
$type_obj = array_shift( $term_obj );
|
||||
|
||||
if ( false === $return_object ) {
|
||||
return $type_obj->slug;
|
||||
}
|
||||
|
||||
return $this->get_font_type_object( $type_obj->slug );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get font manager fonts as font family => font type array
|
||||
* @return array
|
||||
*/
|
||||
private function get_font_types() {
|
||||
static $font_types = false;
|
||||
|
||||
if ( ! $font_types ) {
|
||||
$font_types = get_option( self::FONTS_NAME_TYPE_OPTION_NAME, [] );
|
||||
}
|
||||
|
||||
return $font_types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a list of all Font Manager fonts and stores it in the options table
|
||||
* @return array
|
||||
*/
|
||||
private function generate_fonts_list() {
|
||||
$fonts = new \WP_Query( [
|
||||
'post_type' => self::CPT,
|
||||
'posts_per_page' => -1,
|
||||
] );
|
||||
|
||||
$new_fonts = [];
|
||||
$font_types = [];
|
||||
foreach ( $fonts->posts as $font ) {
|
||||
$font_type = $this->get_font_type_by_post_id( $font->ID, true );
|
||||
if ( false === $font_type ) {
|
||||
continue;
|
||||
}
|
||||
$font_types = array_replace( $font_types, $font_type->get_font_family_type( $font->ID, $font->post_title ) );
|
||||
$new_fonts = array_replace( $new_fonts, $font_type->get_font_data( $font->ID, $font->post_title ) );
|
||||
}
|
||||
|
||||
update_option( self::FONTS_NAME_TYPE_OPTION_NAME, $font_types );
|
||||
update_option( self::FONTS_OPTION_NAME, $new_fonts );
|
||||
|
||||
return $new_fonts;
|
||||
}
|
||||
|
||||
/**
|
||||
* runs on Elementor font post save and calls the font type handler save meta method
|
||||
*
|
||||
* @param int $post_id
|
||||
* @param \WP_Post $post
|
||||
* @param bool $update
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function save_post_meta( $post_id, $post, $update ) {
|
||||
// If this is an autosave, our form has not been submitted,
|
||||
// so we don't want to do anything.
|
||||
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
// Check the user's permissions.
|
||||
if ( ! current_user_can( 'edit_post', $post_id ) ) {
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
// Check if our nonce is set.
|
||||
if ( ! isset( $_POST[ self::CPT . '_nonce' ] ) ) {
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
// Verify that the nonce is valid.
|
||||
if ( ! wp_verify_nonce(
|
||||
Pro_Utils::_unstable_get_super_global_value( $_POST, self::CPT . '_nonce' ),
|
||||
self::CPT
|
||||
) ) {
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
// Save font type
|
||||
// only custom for now
|
||||
$custom_font = $this->get_font_type_object( 'custom' );
|
||||
|
||||
wp_set_object_terms( $post_id, $custom_font->get_type(), self::TAXONOMY );
|
||||
|
||||
// Let Font type handle saving
|
||||
// Sanitize the whole $_POST array
|
||||
$custom_font->save_meta( $post_id, Pro_Utils::_unstable_get_super_global_value( [ 'data' => $_POST ], 'data' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to clean font list on save/update
|
||||
*/
|
||||
public function clear_fonts_list() {
|
||||
delete_option( self::FONTS_OPTION_NAME );
|
||||
delete_option( self::FONTS_NAME_TYPE_OPTION_NAME );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fonts array form the database or generate a new list if $force is set to true
|
||||
*
|
||||
* @param bool $force
|
||||
*
|
||||
* @return array|bool|mixed
|
||||
*/
|
||||
public function get_fonts() {
|
||||
static $fonts = false;
|
||||
|
||||
if ( false !== $fonts ) {
|
||||
return $fonts;
|
||||
}
|
||||
|
||||
$fonts = $this->generate_fonts_list();
|
||||
|
||||
$fonts = get_option( self::FONTS_OPTION_NAME, false );
|
||||
|
||||
return $fonts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue fonts css
|
||||
*
|
||||
* @param $post_css
|
||||
*/
|
||||
public function enqueue_fonts( $post_css ) {
|
||||
$used_fonts = $post_css->get_fonts();
|
||||
$font_manager_fonts = $this->get_fonts();
|
||||
$font_types = $this->get_font_types();
|
||||
|
||||
foreach ( $used_fonts as $font_family ) {
|
||||
if ( ! isset( $font_types[ $font_family ] ) || in_array( $font_family, $this->enqueued_fonts ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$font_type = $this->get_font_type_object( $font_types[ $font_family ] );
|
||||
if ( ! $font_type ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$font_data = [];
|
||||
if ( isset( $font_manager_fonts[ $font_family ] ) ) {
|
||||
$font_data = $font_manager_fonts[ $font_family ];
|
||||
}
|
||||
$font_type->enqueue_font( $font_family, $font_data, $post_css );
|
||||
|
||||
$this->enqueued_fonts[] = $font_family;
|
||||
}
|
||||
}
|
||||
|
||||
public function register_ajax_actions( Ajax $ajax ) {
|
||||
$ajax->register_ajax_action( 'pro_assets_manager_panel_action_data', [ $this, 'assets_manager_panel_action_data' ] );
|
||||
}
|
||||
|
||||
public function add_finder_item( array $categories ) {
|
||||
$categories['settings']['items']['custom-fonts'] = [
|
||||
'title' => esc_html__( 'Custom Fonts', 'elementor-pro' ),
|
||||
'icon' => 'typography',
|
||||
'url' => admin_url( static::MENU_SLUG ),
|
||||
'keywords' => [ 'custom', 'fonts', 'elementor' ],
|
||||
];
|
||||
|
||||
if ( ! $this->can_use_custom_fonts() ) {
|
||||
$lock = new Feature_Lock( [ 'type' => 'custom-font' ] );
|
||||
|
||||
$categories['settings']['items']['custom-fonts']['lock'] = $lock->get_config();
|
||||
}
|
||||
|
||||
return $categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Font Manager action and filter hooks
|
||||
*/
|
||||
protected function actions() {
|
||||
add_action( 'init', [ $this, 'register_post_type_and_tax' ] );
|
||||
|
||||
if ( is_admin() ) {
|
||||
add_action( 'init', [ $this, 'redirect_admin_old_page_to_new' ] );
|
||||
|
||||
add_action( 'elementor/admin/menu/register', function ( Admin_Menu_Manager $admin_menu_manager ) {
|
||||
$this->register_admin_menu( $admin_menu_manager );
|
||||
} );
|
||||
|
||||
// TODO: BC - Remove after `Admin_Menu_Manager` will be the standard.
|
||||
add_action( 'admin_menu', function () {
|
||||
if ( did_action( 'elementor/admin/menu/register' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$menu_title = _x( 'Custom Fonts', 'Elementor Font', 'elementor-pro' );
|
||||
|
||||
add_submenu_page(
|
||||
Settings::PAGE_ID,
|
||||
$menu_title,
|
||||
$menu_title,
|
||||
self::CAPABILITY,
|
||||
static::MENU_SLUG
|
||||
);
|
||||
}, 50 );
|
||||
|
||||
add_action( 'admin_head', [ $this, 'clean_admin_listing_page' ] );
|
||||
}
|
||||
|
||||
// TODO: Maybe just ignore all of those when the user can't use custom fonts?
|
||||
add_filter( 'post_row_actions', [ $this, 'post_row_actions' ], 10, 2 );
|
||||
add_filter( 'manage_' . self::CPT . '_posts_columns', [ $this, 'manage_columns' ], 100 );
|
||||
add_action( 'save_post_' . self::CPT, [ $this, 'save_post_meta' ], 10, 3 );
|
||||
add_action( 'save_post_' . self::CPT, [ $this, 'clear_fonts_list' ], 100 );
|
||||
|
||||
add_filter( 'elementor/fonts/groups', [ $this, 'register_fonts_groups' ] );
|
||||
add_filter( 'elementor/fonts/additional_fonts', [ $this, 'register_fonts_in_control' ] );
|
||||
add_filter( 'elementor/finder/categories', [ $this, 'add_finder_item' ] );
|
||||
add_action( 'elementor/css-file/post/parse', [ $this, 'enqueue_fonts' ] );
|
||||
add_action( 'elementor/css-file/global/parse', [ $this, 'enqueue_fonts' ] );
|
||||
add_filter( 'post_updated_messages', [ $this, 'post_updated_messages' ] );
|
||||
add_filter( 'enter_title_here', [ $this, 'update_enter_title_here' ], 10, 2 );
|
||||
|
||||
// Ajax.
|
||||
add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_actions' ] );
|
||||
|
||||
/**
|
||||
* Elementor fonts manager loaded.
|
||||
*
|
||||
* Fires after the fonts manager was fully loaded and instantiated.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param Fonts_Manager $this An instance of fonts manager.
|
||||
*/
|
||||
do_action( 'elementor_pro/fonts_manager_loaded', $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fonts_Manager constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->actions();
|
||||
$this->add_font_type( 'custom', new Fonts\Custom_Fonts() );
|
||||
$this->add_font_type( 'typekit', new Fonts\Typekit_Fonts() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,467 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager\AssetTypes\Fonts;
|
||||
|
||||
use Elementor\Core\Files\Assets\Files_Upload_Handler;
|
||||
use Elementor\Core\Files\CSS\Base;
|
||||
use ElementorPro\Modules\AssetsManager\Classes;
|
||||
use ElementorPro\Modules\AssetsManager\AssetTypes\Fonts_Manager;
|
||||
use ElementorPro\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Custom_Fonts extends Classes\Font_Base {
|
||||
|
||||
const FONT_META_KEY = 'elementor_font_files';
|
||||
const FONT_FACE_META_KEY = 'elementor_font_face';
|
||||
|
||||
public function get_name() {
|
||||
return esc_html__( 'Custom Fonts', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_type() {
|
||||
return 'custom';
|
||||
}
|
||||
|
||||
private function get_file_types() {
|
||||
return [
|
||||
'woff' => 'font/woff|application/font-woff|application/x-font-woff|application/octet-stream',
|
||||
'woff2' => 'font/woff2|application/octet-stream|font/x-woff2',
|
||||
'ttf' => 'application/x-font-ttf|application/octet-stream|font/ttf',
|
||||
'svg' => 'image/svg+xml|application/octet-stream|image/x-svg+xml',
|
||||
'eot' => 'application/vnd.ms-fontobject|application/octet-stream|application/x-vnd.ms-fontobject',
|
||||
];
|
||||
}
|
||||
|
||||
public function add_meta_box() {
|
||||
add_meta_box(
|
||||
'elementor-font-' . $this->get_type() . 'metabox',
|
||||
__( 'Manage Your Font Files', 'elementor-pro' ),
|
||||
[ $this, 'render_metabox' ],
|
||||
Fonts_Manager::CPT,
|
||||
'normal',
|
||||
'default'
|
||||
);
|
||||
}
|
||||
|
||||
public function render_metabox( $post ) {
|
||||
wp_enqueue_media();
|
||||
|
||||
$fields = [
|
||||
[
|
||||
'id' => 'open_div',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'attributes' => [
|
||||
'class' => 'repeater-content-top',
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => 'font_weight',
|
||||
'field_type' => 'select',
|
||||
'label' => esc_html__( 'Weight', 'elementor-pro' ) . ':',
|
||||
'extra_attributes' => [
|
||||
'class' => 'font_weight',
|
||||
],
|
||||
'options' => $this->get_font_weight_options(),
|
||||
],
|
||||
[
|
||||
'id' => 'font_style',
|
||||
'field_type' => 'select',
|
||||
'label' => esc_html__( 'Style', 'elementor-pro' ) . ':',
|
||||
'extra_attributes' => [
|
||||
'class' => 'font_style',
|
||||
],
|
||||
'options' => $this->get_font_style_options(),
|
||||
],
|
||||
[
|
||||
'id' => 'preview_label',
|
||||
'field_type' => 'html',
|
||||
'label' => false,
|
||||
'raw_html' => sprintf( '<div class="inline-preview">%s</div>', esc_html__( 'Elementor Is Making the Web Beautiful!!!', 'elementor-pro' ) ),
|
||||
],
|
||||
[
|
||||
'id' => 'toolbar',
|
||||
'field_type' => 'toolbar',
|
||||
'label' => false,
|
||||
],
|
||||
[
|
||||
'id' => 'close_div',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'close' => true,
|
||||
],
|
||||
[
|
||||
'id' => 'open_div',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'attributes' => [
|
||||
'class' => 'repeater-content-bottom',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
foreach ( $this->get_file_types() as $type => $mine ) {
|
||||
$fields[] = [
|
||||
'id' => $type,
|
||||
'field_type' => 'file',
|
||||
'mine' => str_replace( '|', ',', $mine ),
|
||||
'ext' => $type,
|
||||
/* translators: %s: Font file format. */
|
||||
'label' => sprintf( esc_html__( '%s File', 'elementor-pro' ), strtoupper( $type ) ),
|
||||
/* translators: %s: Font file format. */
|
||||
'box_title' => sprintf( esc_html__( 'Upload font .%s file', 'elementor-pro' ), $type ),
|
||||
/* translators: %s: Font file format. */
|
||||
'box_action' => sprintf( esc_html__( 'Select .%s file', 'elementor-pro' ), $type ),
|
||||
'preview_anchor' => 'none',
|
||||
'description' => $this->get_file_type_description( $type ),
|
||||
];
|
||||
}
|
||||
|
||||
$fields[] = [
|
||||
'id' => 'close_div',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'close' => true,
|
||||
];
|
||||
|
||||
$font_data = get_post_meta( $post->ID, self::FONT_META_KEY, true );
|
||||
|
||||
$repeater = [
|
||||
'fields' => $fields,
|
||||
'id' => 'font_face',
|
||||
'label' => false,
|
||||
'add_label' => esc_html__( 'Add Font Variation', 'elementor-pro' ),
|
||||
'toggle_title' => esc_html__( 'Edit', 'elementor-pro' ),
|
||||
'remove_title' => esc_html__( 'Delete', 'elementor-pro' ),
|
||||
'field_type' => 'repeater',
|
||||
'row_label' => [
|
||||
'default' => 'Settings',
|
||||
'selector' => '.font_weight',
|
||||
],
|
||||
'saved' => $font_data,
|
||||
];
|
||||
|
||||
$this->print_metabox( [ $repeater ] );
|
||||
|
||||
// PHPCS - Dedicated for CSS.
|
||||
printf( '<style>%s</style>', get_post_meta( $post->ID, self::FONT_FACE_META_KEY, true ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
public function save_meta( $post_id, $data ) {
|
||||
if ( ! isset( $data['font_face'] ) || ! is_array( $data['font_face'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanitize a little
|
||||
$font_face = [];
|
||||
foreach ( $data['font_face'] as $font_data ) {
|
||||
$font_face[] = $this->sanitize_text_field_recursive( $font_data );
|
||||
}
|
||||
|
||||
// All good save the files array
|
||||
update_post_meta( $post_id, self::FONT_META_KEY, $font_face );
|
||||
|
||||
// Save font face
|
||||
update_post_meta( $post_id, self::FONT_FACE_META_KEY, $this->generate_font_face( $post_id ) );
|
||||
}
|
||||
|
||||
public function upload_mimes( $mine_types ) {
|
||||
if ( current_user_can( Fonts_Manager::CAPABILITY ) && $this->is_elementor_font_upload() ) {
|
||||
foreach ( $this->get_file_types() as $type => $mine ) {
|
||||
if ( ! isset( $mine_types[ $type ] ) ) {
|
||||
$mine_types[ $type ] = $mine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $mine_types;
|
||||
}
|
||||
|
||||
public function wp_handle_upload_prefilter( $file ) {
|
||||
if ( ! $this->is_elementor_font_upload() ) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
$ext = pathinfo( $file['name'], PATHINFO_EXTENSION );
|
||||
|
||||
if ( 'svg' !== $ext ) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var \Elementor\Core\Files\Assets\Svg\Svg_Handler $svg_handler;
|
||||
*/
|
||||
$svg_handler = Plugin::elementor()->assets_manager->get_asset( 'svg-handler' );
|
||||
|
||||
if ( Files_Upload_Handler::file_sanitizer_can_run() && ! $svg_handler->sanitize_svg( $file['tmp_name'] ) ) {
|
||||
$file['error'] = esc_html__( 'Invalid SVG Format, file not uploaded for security reasons', 'elementor-pro' );
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
private function is_elementor_font_upload() {
|
||||
return isset( $_POST['uploadTypeCaller'] ) && 'elementor-admin-font-upload' === $_POST['uploadTypeCaller']; // phpcs:ignore
|
||||
}
|
||||
|
||||
/**
|
||||
* A workaround for upload validation which relies on a PHP extension (fileinfo) with inconsistent reporting behaviour.
|
||||
* ref: https://core.trac.wordpress.org/ticket/39550
|
||||
* ref: https://core.trac.wordpress.org/ticket/40175
|
||||
*/
|
||||
public function filter_fix_wp_check_filetype_and_ext( $data, $file, $filename, $mimes ) {
|
||||
if ( ! empty( $data['ext'] ) && ! empty( $data['type'] ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$registered_file_types = $this->get_file_types();
|
||||
$filetype = wp_check_filetype( $filename, $mimes );
|
||||
|
||||
if ( ! isset( $registered_file_types[ $filetype['ext'] ] ) ) {
|
||||
return $data;
|
||||
}
|
||||
// Fix incorrect file mime type
|
||||
$filetype['type'] = explode( '|', $filetype['type'] )[0];
|
||||
|
||||
return [
|
||||
'ext' => $filetype['ext'],
|
||||
'type' => $filetype['type'],
|
||||
'proper_filename' => $data['proper_filename'],
|
||||
];
|
||||
}
|
||||
|
||||
public function generate_font_face( $post_id ) {
|
||||
$saved = get_post_meta( $post_id, self::FONT_META_KEY, true );
|
||||
if ( ! is_array( $saved ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$font_family = get_the_title( $post_id );
|
||||
$font_face = '';
|
||||
|
||||
foreach ( $saved as $font_data ) {
|
||||
$font_face .= $this->get_font_face_from_data( $font_family, $font_data ) . PHP_EOL;
|
||||
}
|
||||
|
||||
return $font_face;
|
||||
}
|
||||
|
||||
public function get_font_face_from_data( $font_family, $data ) {
|
||||
$src = [];
|
||||
foreach ( [ 'eot', 'woff2', 'woff', 'ttf', 'svg' ] as $type ) {
|
||||
if ( ! isset( $data[ $type ] ) || ! isset( $data[ $type ]['url'] ) || empty( $data[ $type ]['url'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( 'svg' === $type ) {
|
||||
$data[ $type ]['url'] .= '#' . str_replace( ' ', '', $font_family );
|
||||
}
|
||||
|
||||
$src[] = $this->get_font_src_per_type( $type, $data[ $type ]['url'] );
|
||||
}
|
||||
|
||||
$font_face = '@font-face {' . PHP_EOL;
|
||||
$font_face .= "\tfont-family: '" . $font_family . "';" . PHP_EOL;
|
||||
$font_face .= "\tfont-style: " . $data['font_style'] . ';' . PHP_EOL;
|
||||
$font_face .= "\tfont-weight: " . $data['font_weight'] . ';' . PHP_EOL;
|
||||
$font_face .= "\tfont-display: " . apply_filters( 'elementor_pro/custom_fonts/font_display', 'auto', $font_family, $data ) . ';' . PHP_EOL;
|
||||
|
||||
if ( isset( $data['eot'] ) && isset( $data['eot']['url'] ) && ! empty( $data['eot']['url'] ) ) {
|
||||
$font_face .= "\tsrc: url('" . esc_attr( $data['eot']['url'] ) . "');" . PHP_EOL;
|
||||
}
|
||||
|
||||
$font_face .= "\tsrc: " . implode( ',' . PHP_EOL . "\t\t", $src ) . ';' . PHP_EOL . '}';
|
||||
|
||||
return $font_face;
|
||||
}
|
||||
|
||||
private function get_font_src_per_type( $type, $url ) {
|
||||
$src = 'url(\'' . esc_attr( $url ) . '\') ';
|
||||
switch ( $type ) {
|
||||
case 'woff':
|
||||
case 'woff2':
|
||||
case 'svg':
|
||||
$src .= 'format(\'' . $type . '\')';
|
||||
break;
|
||||
|
||||
case 'ttf':
|
||||
$src .= 'format(\'truetype\')';
|
||||
break;
|
||||
|
||||
case 'eot':
|
||||
$src = 'url(\'' . esc_attr( $url ) . '?#iefix\') format(\'embedded-opentype\')';
|
||||
break;
|
||||
}
|
||||
|
||||
return $src;
|
||||
}
|
||||
|
||||
public function get_fonts( $force = false ) {
|
||||
$fonts = get_option( self::FONTS_OPTION_NAME, false );
|
||||
if ( $fonts && ! $force ) {
|
||||
return $fonts;
|
||||
}
|
||||
|
||||
add_filter( 'posts_fields', [ $this, 'posts_fields' ] );
|
||||
$fonts = new \WP_Query( [
|
||||
'post_type' => Fonts_Manager::CPT,
|
||||
'posts_per_page' => -1,
|
||||
] );
|
||||
remove_filter( 'posts_fields', [ $this, 'posts_fields' ] );
|
||||
|
||||
$new_fonts = [];
|
||||
foreach ( $fonts->posts as $font ) {
|
||||
$new_fonts[ $font->post_title ] = 'custom';
|
||||
}
|
||||
|
||||
update_option( self::FONTS_OPTION_NAME, $new_fonts );
|
||||
|
||||
return $new_fonts;
|
||||
}
|
||||
|
||||
private function get_font_face_by_font_family( $font_family ) {
|
||||
global $wpdb;
|
||||
|
||||
$id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type = %s LIMIT 1", $font_family, Fonts_Manager::CPT ) );
|
||||
|
||||
if ( $id ) {
|
||||
return get_post_meta( $id, self::FONT_FACE_META_KEY, true );
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public function render_preview_column( $post_id ) {
|
||||
$font_face = get_post_meta( $post_id, self::FONT_FACE_META_KEY, true );
|
||||
|
||||
if ( ! $font_face ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// PHPCS - the variable $font_face is CSS. the property $this->font_preview_phrase is safe.
|
||||
printf( '<style>%s</style><span style="font-family: \'%s\';">%s</span>', $font_face, esc_html( get_the_title( $post_id ) ), $this->font_preview_phrase ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
public function get_font_family_type( $post_id, $post_title ) {
|
||||
return [
|
||||
$post_title => $this->get_type(),
|
||||
];
|
||||
}
|
||||
|
||||
public function get_font_data( $post_id, $post_title ) {
|
||||
return [
|
||||
$post_title => [
|
||||
'font_face' => $this->generate_font_face( $post_id ),
|
||||
'post_id' => $post_id,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function get_font_variations_count( $post_id ) {
|
||||
$data = get_post_meta( $post_id, self::FONT_META_KEY, true );
|
||||
if ( ! empty( $data ) && count( $data ) > 0 ) {
|
||||
echo sprintf( '<span class="font-variations-count">%d</span>', count( $data ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $font_family
|
||||
* @param array $font_data
|
||||
* @param Base $post_css
|
||||
*/
|
||||
public function enqueue_font( $font_family, $font_data, $post_css ) {
|
||||
$font_faces = isset( $font_data['font_face'] ) ? $font_data['font_face'] : $this->get_font_face_by_font_family( $font_family );
|
||||
// Add a css comment
|
||||
$custom_css = '/* Start Custom Fonts CSS */' . $font_faces . '/* End Custom Fonts CSS */';
|
||||
$post_css->get_stylesheet()->add_raw_css( $custom_css );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function handle_panel_request( array $data ) {
|
||||
$font_family = sanitize_text_field( $data['font'] );
|
||||
|
||||
$font_face = $this->get_font_face_by_font_family( $font_family );
|
||||
|
||||
if ( empty( $font_face ) ) {
|
||||
/* translators: %s: Font family. */
|
||||
$error_message = sprintf( esc_html__( 'Font %s was not found.', 'elementor-pro' ), $font_family );
|
||||
|
||||
throw new \Exception( $error_message );
|
||||
}
|
||||
|
||||
return [
|
||||
'font_face' => $font_face,
|
||||
];
|
||||
}
|
||||
|
||||
private function get_font_style_options() {
|
||||
return [
|
||||
'normal' => esc_html__( 'Normal', 'elementor-pro' ),
|
||||
'italic' => esc_html__( 'Italic', 'elementor-pro' ),
|
||||
'oblique' => esc_html__( 'Oblique', 'elementor-pro' ),
|
||||
];
|
||||
}
|
||||
|
||||
private function get_font_weight_options() {
|
||||
return [
|
||||
'normal' => esc_html__( 'Normal', 'elementor-pro' ),
|
||||
'bold' => esc_html__( 'Bold', 'elementor-pro' ),
|
||||
'100' => '100',
|
||||
'200' => '200',
|
||||
'300' => '300',
|
||||
'400' => '400',
|
||||
'500' => '500',
|
||||
'600' => '600',
|
||||
'700' => '700',
|
||||
'800' => '800',
|
||||
'900' => '900',
|
||||
];
|
||||
}
|
||||
|
||||
private function get_file_type_description( $file_type ) {
|
||||
$descriptions = [
|
||||
'eot' => esc_html__( 'Embedded OpenType, Used by IE6-IE9 Browsers', 'elementor-pro' ),
|
||||
'woff2' => esc_html__( 'The Web Open Font Format 2, Used by Super Modern Browsers', 'elementor-pro' ),
|
||||
'woff' => esc_html__( 'The Web Open Font Format, Used by Modern Browsers', 'elementor-pro' ),
|
||||
'ttf' => esc_html__( 'TrueType Fonts, Used for better supporting Safari, Android, iOS', 'elementor-pro' ),
|
||||
'svg' => esc_html__( 'SVG fonts allow SVG to be used as glyphs when displaying text, Used by Legacy iOS', 'elementor-pro' ),
|
||||
];
|
||||
|
||||
return isset( $descriptions[ $file_type ] ) ? $descriptions[ $file_type ] : '';
|
||||
}
|
||||
|
||||
private function replace_urls( $rows_affected, $from, $to ) {
|
||||
global $wpdb;
|
||||
|
||||
$rows_affected = $wpdb->query(
|
||||
"UPDATE {$wpdb->postmeta} " .
|
||||
$wpdb->prepare( 'SET `meta_value` = REPLACE(`meta_value`, %s, %s) ', $from, $to ) .
|
||||
'WHERE `meta_key` = \'' . self::FONT_FACE_META_KEY . '\''
|
||||
);
|
||||
|
||||
return $rows_affected;
|
||||
}
|
||||
|
||||
protected function actions() {
|
||||
parent::actions();
|
||||
|
||||
add_filter( 'elementor/tools/replace-urls', function( $rows_affected, $from, $to ) {
|
||||
return $this->replace_urls( $rows_affected, $from, $to );
|
||||
}, 10, 3 );
|
||||
add_filter( 'wp_check_filetype_and_ext', [ $this, 'filter_fix_wp_check_filetype_and_ext' ], 10, 4 );
|
||||
add_filter( 'wp_handle_upload_prefilter', [ $this, 'wp_handle_upload_prefilter' ] );
|
||||
add_filter( 'upload_mimes', [ $this, 'upload_mimes' ] );
|
||||
add_action( 'add_meta_boxes_' . Fonts_Manager::CPT, [ $this, 'add_meta_box' ] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager\AssetTypes\Fonts;
|
||||
|
||||
use ElementorPro\Core\Utils;
|
||||
use ElementorPro\Modules\AssetsManager\AssetTypes\Fonts_Manager;
|
||||
use ElementorPro\Modules\AssetsManager\Classes\Font_Base;
|
||||
use Elementor\Settings;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Typekit_Fonts extends Font_Base {
|
||||
|
||||
const TYPEKIT_KIT_ID_OPTION_NAME = 'typekit-kit-id';
|
||||
|
||||
const TYPEKIT_FONTS_OPTION_NAME = 'elementor_typekit-data';
|
||||
|
||||
const TYPEKIT_FONTS_LINK = 'https://use.typekit.net/%s.css';
|
||||
|
||||
protected $kit_enqueued = false;
|
||||
|
||||
protected $error = '';
|
||||
|
||||
private $api_base = 'https://typekit.com/api/v1/json/kits';
|
||||
|
||||
private function get_typekit_fonts() {
|
||||
return get_option( self::TYPEKIT_FONTS_OPTION_NAME, false );
|
||||
}
|
||||
|
||||
private function get_typekit_kit_id() {
|
||||
return get_option( 'elementor_' . self::TYPEKIT_KIT_ID_OPTION_NAME, false );
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return esc_html__( 'Adobe Fonts (TypeKit)', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_type() {
|
||||
return 'typekit';
|
||||
}
|
||||
|
||||
private function fetch_typekit_data() {
|
||||
$kit_id = $this->get_typekit_kit_id();
|
||||
if ( ! $kit_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = wp_remote_get( $this->api_base . '/' . $kit_id . '/published' );
|
||||
|
||||
// Response is a WP_Error object
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Response code is not success
|
||||
$response_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
$response_body = json_decode( wp_remote_retrieve_body( $response ) );
|
||||
if ( 200 !== $response_code ) {
|
||||
switch ( $response_code ) {
|
||||
case 404:
|
||||
$this->error = esc_html__( 'Project not found.', 'elementor-pro' );
|
||||
break;
|
||||
default:
|
||||
$this->error = $response_code;
|
||||
if ( isset( $response_body->errors ) ) {
|
||||
$this->error .= ': ' . implode( ', ', $response_body->errors );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $response_body ) {
|
||||
$this->error = esc_html__( 'No project data was returned.', 'elementor-pro' );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expected Json response example
|
||||
* {
|
||||
* "kit": {
|
||||
* "id": "nmm7qvq",
|
||||
* "families": [
|
||||
* {
|
||||
* "id": "hmqz",
|
||||
* "name": "Adobe Caslon Pro",
|
||||
* "slug": "adobe-caslon-pro",
|
||||
* "css_names": [
|
||||
* "adobe-caslon-pro"
|
||||
* ],
|
||||
* "css_stack": "\"adobe-caslon-pro\",serif",
|
||||
* "variations": [ "n6","i6","i7" ]
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
if ( ! is_object( $response_body ) || ! isset( $response_body->kit ) || ! isset( $response_body->kit->families ) || ! is_array( $response_body->kit->families ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$families = [];
|
||||
foreach ( $response_body->kit->families as $font_family ) {
|
||||
$font_css = isset( $font_family->css_names[0] ) ? $font_family->css_names[0] : $font_family->slug;
|
||||
$families[ $font_css ] = $this->get_type();
|
||||
}
|
||||
update_option( self::TYPEKIT_FONTS_OPTION_NAME, $families );
|
||||
|
||||
return $families;
|
||||
}
|
||||
|
||||
private function get_kit_fonts() {
|
||||
$typekit_fonts = $this->get_typekit_fonts();
|
||||
if ( ! $typekit_fonts ) {
|
||||
$typekit_fonts = $this->fetch_typekit_data();
|
||||
}
|
||||
|
||||
return $typekit_fonts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function handle_panel_request( array $data ) {
|
||||
$font_family = sanitize_text_field( $data['font'] );
|
||||
|
||||
$typekit_fonts = $this->get_kit_fonts();
|
||||
|
||||
if ( ! $typekit_fonts || ! is_array( $typekit_fonts ) ) {
|
||||
throw new \Exception( 'Error with TypeKit fonts.' );
|
||||
}
|
||||
|
||||
if ( ! in_array( $font_family, array_keys( $typekit_fonts ) ) ) {
|
||||
throw new \Exception( 'Font missing in Project.' );
|
||||
}
|
||||
|
||||
$kit_id = $this->get_typekit_kit_id();
|
||||
|
||||
return [ 'font_url' => sprintf( self::TYPEKIT_FONTS_LINK, $kit_id ) ];
|
||||
}
|
||||
|
||||
public function sanitize_kit_id_settings( $input ) {
|
||||
if ( empty( $input ) ) {
|
||||
delete_option( self::TYPEKIT_FONTS_OPTION_NAME );
|
||||
}
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
public function register_admin_fields( Settings $settings ) {
|
||||
$fonts = $this->get_typekit_fonts();
|
||||
$button_label = esc_html__( 'Get Project ID', 'elementor-pro' );
|
||||
$found_label = '<span class="elementor-pro-typekit-count">{{count}}</span> ' . esc_html__( 'Fonts Families Found in project. Please note that typekit takes a few minutes to sync once you publish or update a project.', 'elementor-pro' );
|
||||
if ( $fonts && is_array( $fonts ) ) {
|
||||
$button_label = esc_html__( 'Sync Project', 'elementor-pro' );
|
||||
}
|
||||
$settings->add_section( Settings::TAB_INTEGRATIONS, 'typekit', [
|
||||
'callback' => function() {
|
||||
echo '<hr><h2>' . esc_html__( 'Adobe Fonts (TypeKit)', 'elementor-pro' ) . '</h2>';
|
||||
esc_html_e( 'TypeKit partners with the world’s leading type foundries to bring thousands of beautiful fonts to designers every day.', 'elementor-pro' );
|
||||
},
|
||||
'fields' => [
|
||||
self::TYPEKIT_KIT_ID_OPTION_NAME => [
|
||||
'label' => esc_html__( 'Project ID', 'elementor-pro' ),
|
||||
'field_args' => [
|
||||
'type' => 'text',
|
||||
'desc' => sprintf(
|
||||
/* translators: 1: Link opening tag, 2: Link closing tag. */
|
||||
esc_html__( 'Enter Your %1$sTypeKit Project ID%2$s.', 'elementor-pro' ),
|
||||
'<a href="https://fonts.adobe.com/typekit" target="_blank">',
|
||||
'</a>'
|
||||
),
|
||||
],
|
||||
'setting_args' => [
|
||||
'sanitize_callback' => [ $this, 'sanitize_kit_id_settings' ],
|
||||
],
|
||||
],
|
||||
'validate_api_data' => [
|
||||
'field_args' => [
|
||||
'type' => 'raw_html',
|
||||
'html' => sprintf( '<button data-found="%s" data-action="%s" data-nonce="%s" class="button elementor-button-spinner" id="elementor_pro_typekit_validate_button">%s</button><br><p><span class="elementor-pro-typekit-data hidden"></span></p>',
|
||||
esc_html( $found_label ),
|
||||
self::TYPEKIT_KIT_ID_OPTION_NAME . '_fetch',
|
||||
wp_create_nonce( self::TYPEKIT_KIT_ID_OPTION_NAME ),
|
||||
$button_label
|
||||
),
|
||||
],
|
||||
],
|
||||
],
|
||||
] );
|
||||
}
|
||||
|
||||
public function register_fonts_in_control( $fonts ) {
|
||||
$typekit_fonts = $this->get_kit_fonts();
|
||||
if ( $typekit_fonts ) {
|
||||
return array_merge( $typekit_fonts, $fonts );
|
||||
}
|
||||
|
||||
return $fonts;
|
||||
}
|
||||
|
||||
public function print_font_link( $font ) {
|
||||
if ( $this->kit_enqueued ) {
|
||||
return;
|
||||
}
|
||||
if ( $this->is_font_in_kit( $font ) ) {
|
||||
$kit_url = sprintf( self::TYPEKIT_FONTS_LINK, $this->get_typekit_kit_id() );
|
||||
echo '<link rel="stylesheet" type="text/css" href="' . esc_url( $kit_url ) . '">';
|
||||
$this->kit_enqueued = true;
|
||||
}
|
||||
}
|
||||
|
||||
private function is_font_in_kit( $font ) {
|
||||
$kit_fonts = $this->get_kit_fonts();
|
||||
if ( ! $kit_fonts || ! is_array( $kit_fonts ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return in_array( $font, array_keys( $kit_fonts ) );
|
||||
}
|
||||
|
||||
public function integrations_admin_ajax_handler() {
|
||||
check_ajax_referer( self::TYPEKIT_KIT_ID_OPTION_NAME, '_nonce' );
|
||||
|
||||
if ( ! current_user_can( Fonts_Manager::CAPABILITY ) ) {
|
||||
wp_send_json_error( 'Permission denied' );
|
||||
}
|
||||
|
||||
$kit_id = Utils::_unstable_get_super_global_value( $_POST, 'kit_id' );
|
||||
|
||||
if ( ! $kit_id ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
$fonts = [];
|
||||
try {
|
||||
update_option( 'elementor_' . self::TYPEKIT_KIT_ID_OPTION_NAME, sanitize_text_field( $kit_id ) );
|
||||
$fonts = $this->fetch_typekit_data();
|
||||
} catch ( \Exception $exception ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
wp_send_json_success( [
|
||||
'fonts' => $fonts,
|
||||
'count' => count( $fonts ),
|
||||
] );
|
||||
}
|
||||
|
||||
protected function actions() {
|
||||
parent::actions();
|
||||
if ( is_admin() ) {
|
||||
add_action( 'elementor/admin/after_create_settings/' . Settings::PAGE_ID, [ $this, 'register_admin_fields' ], 100 );
|
||||
}
|
||||
add_filter( 'elementor/fonts/additional_fonts', [ $this, 'register_fonts_in_control' ] );
|
||||
add_action( 'elementor/fonts/print_font_links/' . $this->get_type(), [ $this, 'print_font_link' ] );
|
||||
add_action( 'wp_ajax_elementor_pro_admin_fetch_fonts', [ $this, 'integrations_admin_ajax_handler' ] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager\AssetTypes;
|
||||
|
||||
use Elementor\Core\Admin\Menu\Admin_Menu_Manager;
|
||||
use ElementorPro\Core\Behaviors\Feature_Lock;
|
||||
use ElementorPro\License\API;
|
||||
use ElementorPro\Modules\AssetsManager\AssetTypes\AdminMenuItems\Custom_Icons_Menu_Item;
|
||||
use ElementorPro\Modules\AssetsManager\AssetTypes\AdminMenuItems\Custom_Icons_Promotion_Menu_Item;
|
||||
use ElementorPro\Modules\AssetsManager\Classes;
|
||||
use Elementor\Settings;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Icons_Manager {
|
||||
|
||||
const CAPABILITY = 'manage_options';
|
||||
|
||||
const CPT = 'elementor_icons';
|
||||
|
||||
const FONTS_OPTION_NAME = 'elementor_fonts_manager_fonts';
|
||||
|
||||
const FONTS_NAME_TYPE_OPTION_NAME = 'elementor_fonts_manager_font_types';
|
||||
|
||||
const MENU_SLUG = 'edit.php?post_type=' . self::CPT;
|
||||
|
||||
const PROMOTION_MENU_SLUG = 'e-custom-icons';
|
||||
|
||||
private $post_type_object;
|
||||
|
||||
private $enqueued_fonts = [];
|
||||
|
||||
protected $icon_types = [];
|
||||
|
||||
private $has_icons = null;
|
||||
|
||||
/**
|
||||
* get a font type object for a given type
|
||||
*
|
||||
* @param null $type
|
||||
*
|
||||
* @return array|bool|\ElementorPro\Modules\AssetsManager\Classes\Font_Base
|
||||
*/
|
||||
public function get_icon_type_object( $type = null ) {
|
||||
if ( null === $type ) {
|
||||
return $this->icon_types;
|
||||
}
|
||||
|
||||
if ( isset( $this->icon_types[ $type ] ) ) {
|
||||
return $this->icon_types[ $type ];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a font type to the font manager
|
||||
*
|
||||
* @param string $icon_type
|
||||
* @param Classes\Assets_Base $instance
|
||||
*/
|
||||
public function add_icon_type( $icon_type, $instance ) {
|
||||
$this->icon_types[ $icon_type ] = $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register elementor icon set custom post type
|
||||
*/
|
||||
public function register_post_type() {
|
||||
$labels = [
|
||||
'name' => _x( 'Custom Icons', 'CPT Name', 'elementor-pro' ),
|
||||
'singular_name' => _x( 'Icon Set', 'CPT Singular Name', 'elementor-pro' ),
|
||||
'add_new' => esc_html__( 'Add New', 'elementor-pro' ),
|
||||
'add_new_item' => esc_html__( 'Add New Icon Set', 'elementor-pro' ),
|
||||
'edit_item' => esc_html__( 'Edit Icon Set', 'elementor-pro' ),
|
||||
'new_item' => esc_html__( 'New Icon Set', 'elementor-pro' ),
|
||||
'all_items' => esc_html__( 'All Icons', 'elementor-pro' ),
|
||||
'view_item' => esc_html__( 'View Icon', 'elementor-pro' ),
|
||||
'search_items' => esc_html__( 'Search Icon Set', 'elementor-pro' ),
|
||||
'not_found' => esc_html__( 'No icons found', 'elementor-pro' ),
|
||||
'not_found_in_trash' => esc_html__( 'No icons found in trash', 'elementor-pro' ),
|
||||
'parent_item_colon' => '',
|
||||
'menu_name' => _x( 'Custom Icons', 'CPT Menu Name', 'elementor-pro' ),
|
||||
];
|
||||
|
||||
$args = [
|
||||
'labels' => $labels,
|
||||
'public' => false,
|
||||
'rewrite' => false,
|
||||
'show_ui' => true,
|
||||
'show_in_menu' => false,
|
||||
'show_in_nav_menus' => false,
|
||||
'exclude_from_search' => true,
|
||||
'capability_type' => 'post',
|
||||
'hierarchical' => false,
|
||||
'supports' => [ 'title' ],
|
||||
];
|
||||
|
||||
$this->post_type_object = register_post_type( self::CPT, $args );
|
||||
}
|
||||
|
||||
public function post_updated_messages( $messages ) {
|
||||
$messages[ self::CPT ] = [
|
||||
0 => '', // Unused. Messages start at index 1.
|
||||
1 => esc_html__( 'Icon Set updated.', 'elementor-pro' ),
|
||||
2 => esc_html__( 'Custom field updated.', 'elementor-pro' ),
|
||||
3 => esc_html__( 'Custom field deleted.', 'elementor-pro' ),
|
||||
4 => esc_html__( 'Icon Set updated.', 'elementor-pro' ),
|
||||
/* translators: %s: Date and time of the revision. */
|
||||
5 => isset( $_GET['revision'] ) ? sprintf( esc_html__( 'Icon Set restored to revision from %s', 'elementor-pro' ), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
|
||||
6 => esc_html__( 'Icon Set saved.', 'elementor-pro' ),
|
||||
7 => esc_html__( 'Icon Set saved.', 'elementor-pro' ),
|
||||
8 => esc_html__( 'Icon Set submitted.', 'elementor-pro' ),
|
||||
9 => esc_html__( 'Icon Set updated.', 'elementor-pro' ),
|
||||
10 => esc_html__( 'Icon Set draft updated.', 'elementor-pro' ),
|
||||
];
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Font manager link to admin menu
|
||||
*/
|
||||
private function register_admin_menu( Admin_Menu_Manager $admin_menu_manager ) {
|
||||
if ( $this->can_use_custom_icons() ) {
|
||||
$admin_menu_manager->register( static::MENU_SLUG, new Custom_Icons_Menu_Item() );
|
||||
} else {
|
||||
$admin_menu_manager->register( static::PROMOTION_MENU_SLUG, new Custom_Icons_Promotion_Menu_Item() );
|
||||
}
|
||||
}
|
||||
|
||||
private function can_use_custom_icons() {
|
||||
return ( API::is_license_active() || $this->has_icons() );
|
||||
}
|
||||
|
||||
private function has_icons() {
|
||||
if ( null !== $this->has_icons ) {
|
||||
return $this->has_icons;
|
||||
}
|
||||
|
||||
$existing_icons = new \WP_Query( [
|
||||
'post_type' => static::CPT,
|
||||
'posts_per_page' => 1,
|
||||
] );
|
||||
|
||||
$this->has_icons = $existing_icons->post_count > 0;
|
||||
|
||||
return $this->has_icons;
|
||||
}
|
||||
|
||||
public function redirect_admin_old_page_to_new() {
|
||||
if ( ! empty( $_GET['page'] ) && 'elementor_custom_icons' === $_GET['page'] ) {
|
||||
wp_safe_redirect( admin_url( static::MENU_SLUG ) );
|
||||
die;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up admin Font manager admin listing
|
||||
*/
|
||||
public function clean_admin_listing_page() {
|
||||
global $typenow;
|
||||
|
||||
if ( self::CPT !== $typenow ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_filter( 'months_dropdown_results', '__return_empty_array' );
|
||||
add_filter( 'screen_options_show_screen', '__return_false' );
|
||||
}
|
||||
|
||||
public function post_row_actions( $actions, $post ) {
|
||||
if ( self::CPT !== $post->post_type ) {
|
||||
return $actions;
|
||||
}
|
||||
|
||||
unset( $actions['inline hide-if-no-js'] );
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
public function add_finder_item( array $categories ) {
|
||||
$categories['settings']['items']['custom-icons'] = [
|
||||
'title' => esc_html__( 'Custom Icons', 'elementor-pro' ),
|
||||
'icon' => 'favorite',
|
||||
'url' => admin_url( static::MENU_SLUG ),
|
||||
'keywords' => [ 'custom', 'icons', 'elementor' ],
|
||||
];
|
||||
|
||||
if ( ! $this->can_use_custom_icons() ) {
|
||||
$lock = new Feature_Lock( [ 'type' => 'custom-icon' ] );
|
||||
|
||||
$categories['settings']['items']['custom-icons']['lock'] = $lock->get_config();
|
||||
}
|
||||
|
||||
return $categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Font Manager action and filter hooks
|
||||
*/
|
||||
protected function actions() {
|
||||
add_action( 'init', [ $this, 'register_post_type' ] );
|
||||
|
||||
if ( is_admin() ) {
|
||||
add_action( 'init', [ $this, 'redirect_admin_old_page_to_new' ] );
|
||||
|
||||
add_action( 'elementor/admin/menu/register', function ( Admin_Menu_Manager $admin_menu_manager ) {
|
||||
$this->register_admin_menu( $admin_menu_manager );
|
||||
} );
|
||||
|
||||
// TODO: BC - Remove after `Admin_Menu_Manager` will be the standard.
|
||||
add_action( 'admin_menu', function () {
|
||||
if ( did_action( 'elementor/admin/menu/register' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$menu_title = _x( 'Custom Icons', 'Elementor Font', 'elementor-pro' );
|
||||
|
||||
add_submenu_page(
|
||||
Settings::PAGE_ID,
|
||||
$menu_title,
|
||||
$menu_title,
|
||||
self::CAPABILITY,
|
||||
static::MENU_SLUG
|
||||
);
|
||||
}, 50 );
|
||||
|
||||
add_action( 'admin_head', [ $this, 'clean_admin_listing_page' ] );
|
||||
}
|
||||
|
||||
// TODO: Maybe just ignore all of those when the user can't use custom icons?
|
||||
add_filter( 'post_updated_messages', [ $this, 'post_updated_messages' ] );
|
||||
add_filter( 'post_row_actions', [ $this, 'post_row_actions' ], 10, 2 );
|
||||
|
||||
add_filter( 'elementor/finder/categories', [ $this, 'add_finder_item' ] );
|
||||
|
||||
/**
|
||||
* Elementor icons manager loaded.
|
||||
*
|
||||
* Fires after the icons manager was fully loaded and instantiated.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param Fonts_Manager $this An instance of icons manager.
|
||||
*/
|
||||
do_action( 'elementor_pro/icons_manager_loaded', $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fonts_Manager constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->actions();
|
||||
$this->add_icon_type( 'custom', new Icons\Custom_Icons() );
|
||||
$this->add_icon_type( 'font-awesome-pro', new Icons\Font_Awesome_Pro() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,503 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager\AssetTypes\Icons;
|
||||
|
||||
use Elementor\Core\Utils\Exceptions;
|
||||
use ElementorPro\Core\Utils;
|
||||
use ElementorPro\Modules\AssetsManager\Classes\Assets_Base;
|
||||
use ElementorPro\Modules\AssetsManager\AssetTypes\Icons_Manager;
|
||||
use Elementor\Core\Common\Modules\Ajax\Module as Ajax;
|
||||
use ElementorPro\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Custom_Icons extends Assets_Base {
|
||||
|
||||
const META_KEY = 'elementor_custom_icon_set_config';
|
||||
const OPTION_NAME = 'elementor_custom_icon_sets_config';
|
||||
|
||||
public $current_post_id = 0;
|
||||
|
||||
public function get_name() {
|
||||
return esc_html__( 'Custom Icons', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_type() {
|
||||
return 'custom-icons';
|
||||
}
|
||||
|
||||
public function add_meta_box() {
|
||||
add_meta_box(
|
||||
'elementor-custom-icons-metabox',
|
||||
__( 'Icon Set', 'elementor-pro' ),
|
||||
[ $this, 'render_metabox' ],
|
||||
Icons_Manager::CPT,
|
||||
'normal',
|
||||
'default'
|
||||
);
|
||||
}
|
||||
|
||||
public static function get_icon_set_config( $id ) {
|
||||
return get_post_meta( $id, self::META_KEY, true );
|
||||
}
|
||||
|
||||
public function render_metabox( $post ) {
|
||||
wp_enqueue_media();
|
||||
|
||||
$save_data = self::get_icon_set_config( $post->ID );
|
||||
|
||||
$fields = [
|
||||
[
|
||||
'id' => 'open_div',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'attributes' => [
|
||||
'class' => 'elementor-custom-icons-metabox',
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => 'zip_upload',
|
||||
'field_type' => 'dropzone',
|
||||
'accept' => 'zip,application/octet-stream,application/zip,application/x-zip,application/x-zip-compressed',
|
||||
'label' => false,
|
||||
'sub-label' => esc_html__( 'Your Fontello, IcoMoon or Fontastic .zip file', 'elementor-pro' ),
|
||||
],
|
||||
[
|
||||
'id' => 'close_div',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'close' => true,
|
||||
],
|
||||
[
|
||||
'id' => self::META_KEY,
|
||||
'name' => self::META_KEY,
|
||||
'field_type' => 'input',
|
||||
'input_type' => 'hidden',
|
||||
'label' => false,
|
||||
'value' => $save_data,
|
||||
'saved' => $save_data,
|
||||
],
|
||||
[
|
||||
'id' => Icons_Manager::CPT . '_nonce',
|
||||
'name' => Icons_Manager::CPT . '_nonce',
|
||||
'field_type' => 'input',
|
||||
'input_type' => 'hidden',
|
||||
'label' => false,
|
||||
'value' => wp_create_nonce( Icons_Manager::CPT ),
|
||||
],
|
||||
];
|
||||
|
||||
foreach ( $fields as $field ) {
|
||||
$field['saved'] = isset( $field['saved'] ) ? $field['saved'] : '';
|
||||
}
|
||||
|
||||
$this->print_metabox( $fields );
|
||||
}
|
||||
|
||||
public function save_post_meta( $post_id, $post, $update ) {
|
||||
// If this is an autosave, our form has not been submitted,
|
||||
// so we don't want to do anything.
|
||||
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
// Check the user's permissions.
|
||||
if ( ! current_user_can( 'edit_post', $post_id ) ) {
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
// Check if our nonce is set.
|
||||
if ( ! isset( $_POST[ Icons_Manager::CPT . '_nonce' ] ) ) {
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
// Verify that the nonce is valid.
|
||||
if ( ! wp_verify_nonce(
|
||||
Utils::_unstable_get_super_global_value( $_POST, Icons_Manager::CPT . '_nonce' ),
|
||||
Icons_Manager::CPT
|
||||
) ) {
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
if ( ! isset( $_POST[ self::META_KEY ] ) ) {
|
||||
return delete_post_meta( $post_id, self::META_KEY );
|
||||
}
|
||||
|
||||
// PHPCS - It will be sanitized in the next line.
|
||||
$json = json_decode( stripslashes_deep( $_POST[ self::META_KEY ] ), true ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
foreach ( $json as $property => $value ) {
|
||||
$json[ $property ] = $this->sanitize_text_field_recursive( $value );
|
||||
}
|
||||
|
||||
// All good save the files array
|
||||
update_post_meta( $post_id, self::META_KEY, json_encode( $json ) );
|
||||
|
||||
// Force refresh of list in Options Table
|
||||
self::clear_icon_list_option();
|
||||
}
|
||||
|
||||
public static function get_supported_icon_sets() {
|
||||
$icon_sets = [
|
||||
'fontastic' => __NAMESPACE__ . '\IconSets\Fontastic',
|
||||
'fontello' => __NAMESPACE__ . '\IconSets\Fontello',
|
||||
'icomoon' => __NAMESPACE__ . '\IconSets\Icomoon',
|
||||
];
|
||||
|
||||
$additional_icon_sets = [];
|
||||
|
||||
/**
|
||||
* Additional icon sets.
|
||||
*
|
||||
* Filters the icon types supported by Elementor Pro.
|
||||
*
|
||||
* By default Elementor Pro supports 'fontastic', 'fontello' and 'icomoon'.
|
||||
* This hook allows developers to add additional icon sets.
|
||||
*
|
||||
* @param array $additional_icon_sets Additional icon sets.
|
||||
*/
|
||||
$additional_icon_sets = apply_filters( 'elementor_pro/icons_manager/custom_icons/additional_supported_types', $additional_icon_sets );
|
||||
|
||||
return array_merge( $additional_icon_sets, $icon_sets );
|
||||
}
|
||||
|
||||
private function get_active_icon_sets() {
|
||||
$icons = new \WP_Query( [
|
||||
'post_type' => Icons_Manager::CPT,
|
||||
'posts_per_page' => -1,
|
||||
] );
|
||||
$custom_icon_sets = [];
|
||||
foreach ( $icons->posts as $icon_set ) {
|
||||
$set_config = json_decode( self::get_icon_set_config( $icon_set->ID ), true );
|
||||
$set_config['custom_icon_post_id'] = $icon_set->ID;
|
||||
$set_config['label'] = $icon_set->post_title;
|
||||
$custom_icon_sets[ $set_config['name'] ] = $set_config;
|
||||
}
|
||||
return $custom_icon_sets;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_wp_filesystem
|
||||
* @return \WP_Filesystem_Base
|
||||
*/
|
||||
public static function get_wp_filesystem() {
|
||||
global $wp_filesystem;
|
||||
if ( empty( $wp_filesystem ) ) {
|
||||
require_once ABSPATH . '/wp-admin/includes/file.php';
|
||||
WP_Filesystem();
|
||||
}
|
||||
return $wp_filesystem;
|
||||
}
|
||||
|
||||
private function upload() {
|
||||
$file = Utils::_unstable_get_super_global_value( $_FILES, 'zip_upload' );
|
||||
$filename = $file['name'];
|
||||
$ext = pathinfo( $filename, PATHINFO_EXTENSION );
|
||||
if ( 'zip' !== $ext ) {
|
||||
unlink( $filename );
|
||||
return new \WP_Error( 'unsupported_file', esc_html__( 'Only zip files are allowed', 'elementor-pro' ) );
|
||||
}
|
||||
if ( ! function_exists( 'wp_handle_upload' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
}
|
||||
// Handler upload archive file.
|
||||
$upload_result = wp_handle_upload( $file, [ 'test_form' => false ] );
|
||||
if ( isset( $upload_result['error'] ) ) {
|
||||
unlink( $filename );
|
||||
return new \WP_Error( 'upload_error', $upload_result['error'] );
|
||||
}
|
||||
return $upload_result['file'];
|
||||
}
|
||||
|
||||
private function extract_zip( $file, $to ) {
|
||||
// TODO: Move to core as a util.
|
||||
$valid_field_types = [
|
||||
'css',
|
||||
'eot',
|
||||
'html',
|
||||
'json',
|
||||
'otf',
|
||||
'svg',
|
||||
'ttf',
|
||||
'txt',
|
||||
'woff',
|
||||
'woff2',
|
||||
];
|
||||
|
||||
$zip = new \ZipArchive();
|
||||
|
||||
$zip->open( $file );
|
||||
|
||||
$valid_entries = [];
|
||||
|
||||
// phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
for ( $i = 0; $i < $zip->numFiles; $i++ ) {
|
||||
$zipped_file_name = $zip->getNameIndex( $i );
|
||||
$dirname = pathinfo( $zipped_file_name, PATHINFO_DIRNAME );
|
||||
|
||||
// Skip the OS X-created __MACOSX directory.
|
||||
if ( '__MACOSX/' === substr( $dirname, 0, 9 ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$zipped_extension = pathinfo( $zipped_file_name, PATHINFO_EXTENSION );
|
||||
// Skip files with transversal paths.
|
||||
if ( strpos( $zipped_file_name, '..' ) !== false ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( in_array( $zipped_extension, $valid_field_types, true ) ) {
|
||||
$valid_entries[] = $zipped_file_name;
|
||||
}
|
||||
}
|
||||
|
||||
$unzip_result = false;
|
||||
|
||||
if ( ! empty( $valid_entries ) ) {
|
||||
$unzip_result = $zip->extractTo( $to, $valid_entries );
|
||||
}
|
||||
|
||||
if ( ! $unzip_result ) {
|
||||
$unzip_result = new \WP_Error( 'error', esc_html__( 'Could not unzip or empty archive.', 'elementor-pro' ) );
|
||||
}
|
||||
|
||||
@unlink( $file );
|
||||
|
||||
return $unzip_result; // TRUE | WP_Error instance.
|
||||
}
|
||||
|
||||
private function upload_and_extract_zip() {
|
||||
$zip_file = $this->upload();
|
||||
if ( is_wp_error( $zip_file ) ) {
|
||||
return $zip_file;
|
||||
}
|
||||
$filesystem = self::get_wp_filesystem();
|
||||
$extract_to = trailingslashit( get_temp_dir() . pathinfo( $zip_file, PATHINFO_FILENAME ) );
|
||||
|
||||
$unzipped = $this->extract_zip( $zip_file, $extract_to );
|
||||
if ( is_wp_error( $unzipped ) ) {
|
||||
return $unzipped;
|
||||
}
|
||||
|
||||
// Find the right folder.
|
||||
$source_files = array_keys( $filesystem->dirlist( $extract_to ) );
|
||||
if ( count( $source_files ) === 0 ) {
|
||||
return new \WP_Error( 'incompatible_archive', esc_html__( 'Incompatible archive', 'elementor-pro' ) );
|
||||
}
|
||||
|
||||
if ( 1 === count( $source_files ) && $filesystem->is_dir( $extract_to . $source_files[0] ) ) {
|
||||
$directory = $extract_to . trailingslashit( $source_files[0] );
|
||||
} else {
|
||||
$directory = $extract_to;
|
||||
}
|
||||
return [
|
||||
'directory' => $directory,
|
||||
'extracted_to' => $extract_to,
|
||||
];
|
||||
}
|
||||
|
||||
public function custom_icons_upload_handler( $data ) {
|
||||
if ( ! current_user_can( Icons_Manager::CAPABILITY ) ) {
|
||||
return new \WP_Error( Exceptions::FORBIDDEN, 'Access denied.' );
|
||||
}
|
||||
|
||||
$this->current_post_id = $data['post_id'];
|
||||
$results = $this->upload_and_extract_zip();
|
||||
if ( is_wp_error( $results ) ) {
|
||||
return $results;
|
||||
}
|
||||
$supported_icon_sets = self::get_supported_icon_sets();
|
||||
foreach ( $supported_icon_sets as $key => $handler ) {
|
||||
/**
|
||||
* @var IconSets\Icon_Set_Base $icon_set_handler
|
||||
*/
|
||||
$icon_set_handler = new $handler( $results['directory'] );
|
||||
|
||||
if ( ! $icon_set_handler ) {
|
||||
continue;
|
||||
}
|
||||
if ( ! $icon_set_handler->is_valid() ) {
|
||||
continue;
|
||||
}
|
||||
$icon_set_handler->handle_new_icon_set();
|
||||
$icon_set_handler->move_files( $this->current_post_id );
|
||||
$config = $icon_set_handler->build_config();
|
||||
|
||||
// Notify about duplicate prefix
|
||||
if ( self::icon_set_prefix_exists( $config['prefix'] ) ) {
|
||||
$config['duplicate_prefix'] = true;
|
||||
}
|
||||
return [
|
||||
'config' => $config,
|
||||
];
|
||||
}
|
||||
return new \WP_Error( 'unsupported_zip_format', esc_html__( 'The zip file provided is not supported!', 'elementor-pro' ) );
|
||||
}
|
||||
|
||||
public function handle_delete_icon_set( $post_id ) {
|
||||
if ( Icons_Manager::CPT !== get_post_type( $post_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove all assets related to this icon set
|
||||
$attachments = get_attached_media( '', $post_id );
|
||||
|
||||
foreach ( $attachments as $attachment ) {
|
||||
wp_delete_attachment( $attachment->ID, 'true' );
|
||||
}
|
||||
|
||||
// remove icon set assets directory
|
||||
$icon_set_dir = get_post_meta( $post_id, '_elementor_icon_set_path', true );
|
||||
if ( ! empty( $icon_set_dir ) && is_dir( $icon_set_dir ) ) {
|
||||
$this::get_wp_filesystem()->rmdir( $icon_set_dir, true );
|
||||
}
|
||||
|
||||
// Force refresh of list in Options Table
|
||||
self::clear_icon_list_option();
|
||||
}
|
||||
|
||||
public static function clear_icon_list_option() {
|
||||
delete_option( self::OPTION_NAME );
|
||||
}
|
||||
|
||||
public function display_post_states( $post_states, $post ) {
|
||||
if ( 'publish' !== $post->post_status || Icons_Manager::CPT !== $post->post_type ) {
|
||||
return $post_states;
|
||||
}
|
||||
|
||||
$data = json_decode( self::get_icon_set_config( $post->ID ) );
|
||||
if ( ! empty( $data->count ) ) {
|
||||
echo sprintf( '<span class="font-variations-count">%d</span>', esc_html( $data->count ) );
|
||||
}
|
||||
|
||||
return $post_states;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render preview column in font manager admin listing
|
||||
*
|
||||
* @param $column
|
||||
* @param $post_id
|
||||
*/
|
||||
public function render_columns( $column, $post_id ) {
|
||||
if ( 'icons_prefix' === $column ) {
|
||||
$data = json_decode( self::get_icon_set_config( $post_id ) );
|
||||
if ( ! empty( $data->prefix ) ) {
|
||||
echo '<pre>' . esc_html( '.' . $data->prefix ) . '</pre>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Define which columns to display in font manager admin listing
|
||||
*
|
||||
* @param $columns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function manage_columns( $columns ) {
|
||||
return [
|
||||
'cb' => '<input type="checkbox" />',
|
||||
'title' => esc_html__( 'Icon Set', 'elementor-pro' ),
|
||||
'icons_prefix' => esc_html__( 'CSS Prefix', 'elementor-pro' ),
|
||||
];
|
||||
}
|
||||
|
||||
public function update_enter_title_here( $title, $post ) {
|
||||
if ( isset( $post->post_type ) && Icons_Manager::CPT === $post->post_type ) {
|
||||
return esc_html__( 'Enter Icon Set Name', 'elementor-pro' );
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
public function register_ajax_actions( Ajax $ajax ) {
|
||||
$ajax->register_ajax_action( 'pro_assets_manager_custom_icon_upload', [ $this, 'custom_icons_upload_handler' ] );
|
||||
}
|
||||
|
||||
public function register_icon_libraries_control( $additional_sets ) {
|
||||
return array_replace( $additional_sets, self::get_custom_icons_config() );
|
||||
}
|
||||
|
||||
public function add_custom_icon_templates( $current_screen ) {
|
||||
if ( 'elementor_icons' !== $current_screen->id || 'post' !== $current_screen->base ) {
|
||||
return;
|
||||
}
|
||||
Plugin::elementor()->common->add_template( __DIR__ . '/templates.php' );
|
||||
}
|
||||
|
||||
public function add_custom_icons_url( $config ) {
|
||||
$config['customIconsURL'] = admin_url( 'edit.php?post_type=' . Icons_Manager::CPT );
|
||||
return $config;
|
||||
}
|
||||
|
||||
public static function get_custom_icons_config() {
|
||||
$config = get_option( self::OPTION_NAME, false );
|
||||
if ( false === $config ) {
|
||||
$icons = new \WP_Query( [
|
||||
'post_type' => Icons_Manager::CPT,
|
||||
'posts_per_page' => -1,
|
||||
'post_status' => 'publish',
|
||||
] );
|
||||
$config = [];
|
||||
foreach ( $icons->posts as $icon_set ) {
|
||||
$set_config = json_decode( self::get_icon_set_config( $icon_set->ID ), true );
|
||||
$set_config['custom_icon_post_id'] = $icon_set->ID;
|
||||
$set_config['label'] = $icon_set->post_title;
|
||||
if ( isset( $set_config['fetchJson'] ) ) {
|
||||
unset( $set_config['icons'] );
|
||||
}
|
||||
$config[ $set_config['name'] ] = $set_config;
|
||||
}
|
||||
update_option( self::OPTION_NAME, $config );
|
||||
}
|
||||
return $config;
|
||||
}
|
||||
|
||||
public static function icon_set_prefix_exists( $prefix ) {
|
||||
$config = self::get_custom_icons_config();
|
||||
if ( empty( $config ) ) {
|
||||
return false;
|
||||
}
|
||||
foreach ( $config as $icon_set_name => $icon_config ) {
|
||||
if ( $prefix === $icon_config['prefix'] ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function transition_post_status( $new_status, $old_status, $post ) {
|
||||
if ( Icons_Manager::CPT !== $post->post_type ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'publish' === $old_status && 'publish' !== $new_status ) {
|
||||
$this->clear_icon_list_option();
|
||||
}
|
||||
}
|
||||
|
||||
protected function actions() {
|
||||
|
||||
parent::actions();
|
||||
if ( is_admin() ) {
|
||||
add_action( 'add_meta_boxes_' . Icons_Manager::CPT, [ $this, 'add_meta_box' ] );
|
||||
add_action( 'save_post_' . Icons_Manager::CPT, [ $this, 'save_post_meta' ], 10, 3 );
|
||||
add_filter( 'display_post_states', [ $this, 'display_post_states' ], 10, 2 );
|
||||
add_action( 'manage_' . Icons_Manager::CPT . '_posts_custom_column', [ $this, 'render_columns' ], 10, 2 );
|
||||
add_filter( 'enter_title_here', [ $this, 'update_enter_title_here' ], 10, 2 );
|
||||
add_filter( 'manage_' . Icons_Manager::CPT . '_posts_columns', [ $this, 'manage_columns' ], 100 );
|
||||
add_action( 'current_screen', [ $this, 'add_custom_icon_templates' ] );
|
||||
}
|
||||
|
||||
add_action( 'transition_post_status', [ $this, 'transition_post_status' ], 10, 3 );
|
||||
add_action( 'before_delete_post', [ $this, 'handle_delete_icon_set' ] );
|
||||
add_filter( 'elementor/icons_manager/additional_tabs', [ $this, 'register_icon_libraries_control' ] );
|
||||
add_filter( 'elementor/editor/localize_settings', [ $this, 'add_custom_icons_url' ] );
|
||||
|
||||
// Ajax.
|
||||
add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_actions' ] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager\AssetTypes\Icons;
|
||||
|
||||
use ElementorPro\Modules\AssetsManager\Classes\Assets_Base;
|
||||
use Elementor\Settings;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Font_Awesome_Pro extends Assets_Base {
|
||||
|
||||
const FA_KIT_ID_OPTION_NAME = 'font_awesome_pro_kit_id';
|
||||
|
||||
const FA_KIT_SCRIPT_LINK = 'https://kit.fontawesome.com/%s.js';
|
||||
|
||||
public function get_name() {
|
||||
return esc_html__( 'Font Awesome Pro', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_type() {
|
||||
return 'font-awesome-pro';
|
||||
}
|
||||
|
||||
private function get_kit_id() {
|
||||
return get_option( 'elementor_' . self::FA_KIT_ID_OPTION_NAME, false );
|
||||
}
|
||||
|
||||
public function replace_font_awesome_pro( $settings ) {
|
||||
$json_url = ELEMENTOR_PRO_ASSETS_URL . 'lib/font-awesome-pro/%s.js';
|
||||
$icons['fa-regular'] = [
|
||||
'name' => 'fa-regular',
|
||||
'label' => esc_html__( 'Font Awesome - Regular Pro', 'elementor-pro' ),
|
||||
'url' => false,
|
||||
'enqueue' => false,
|
||||
'prefix' => 'fa-',
|
||||
'displayPrefix' => 'far',
|
||||
'labelIcon' => 'fab fa-font-awesome-alt',
|
||||
'ver' => '5.15.1-pro',
|
||||
'fetchJson' => sprintf( $json_url, 'regular' ),
|
||||
'native' => true,
|
||||
];
|
||||
$icons['fa-solid'] = [
|
||||
'name' => 'fa-solid',
|
||||
'label' => esc_html__( 'Font Awesome - Solid Pro', 'elementor-pro' ),
|
||||
'url' => false,
|
||||
'enqueue' => false,
|
||||
'prefix' => 'fa-',
|
||||
'displayPrefix' => 'fas',
|
||||
'labelIcon' => 'fab fa-font-awesome',
|
||||
'ver' => '5.15.1-pro',
|
||||
'fetchJson' => sprintf( $json_url, 'solid' ),
|
||||
'native' => true,
|
||||
];
|
||||
$icons['fa-brands'] = [
|
||||
'name' => 'fa-brands',
|
||||
'label' => esc_html__( 'Font Awesome - Brands Pro', 'elementor-pro' ),
|
||||
'url' => false,
|
||||
'enqueue' => false,
|
||||
'prefix' => 'fa-',
|
||||
'displayPrefix' => 'fab',
|
||||
'labelIcon' => 'fab fa-font-awesome-flag',
|
||||
'ver' => '5.15.1-pro',
|
||||
'fetchJson' => sprintf( $json_url, 'brands' ),
|
||||
'native' => true,
|
||||
];
|
||||
$icons['fa-light'] = [
|
||||
'name' => 'fa-light',
|
||||
'label' => esc_html__( 'Font Awesome - Light Pro', 'elementor-pro' ),
|
||||
'url' => false,
|
||||
'enqueue' => false,
|
||||
'prefix' => 'fa-',
|
||||
'displayPrefix' => 'fal',
|
||||
'labelIcon' => 'fal fa-flag',
|
||||
'ver' => '5.15.1-pro',
|
||||
'fetchJson' => sprintf( $json_url, 'light' ),
|
||||
'native' => true,
|
||||
];
|
||||
$icons['fa-duotone'] = [
|
||||
'name' => 'fa-duotone',
|
||||
'label' => esc_html__( 'Font Awesome - Duotone Pro', 'elementor-pro' ),
|
||||
'url' => false,
|
||||
'enqueue' => false,
|
||||
'prefix' => 'fa-',
|
||||
'displayPrefix' => 'fad',
|
||||
'labelIcon' => 'fad fa-flag',
|
||||
'ver' => '5.15.1-pro',
|
||||
'fetchJson' => sprintf( $json_url, 'duotone' ),
|
||||
'native' => true,
|
||||
];
|
||||
// remove Free
|
||||
unset(
|
||||
$settings['fa-solid'],
|
||||
$settings['fa-regular'],
|
||||
$settings['fa-brands']
|
||||
);
|
||||
return array_merge( $icons, $settings );
|
||||
}
|
||||
|
||||
public function register_admin_fields( Settings $settings ) {
|
||||
$settings->add_section( Settings::TAB_INTEGRATIONS, 'font_awesome_pro', [
|
||||
'callback' => function() {
|
||||
echo '<hr><h2>' . esc_html__( 'Font Awesome Pro', 'elementor-pro' ) . '</h2>';
|
||||
esc_html_e( 'Font Awesome, the web\'s most popular icon set and toolkit, Pro Integration', 'elementor-pro' );
|
||||
},
|
||||
'fields' => [
|
||||
self::FA_KIT_ID_OPTION_NAME => [
|
||||
'label' => esc_html__( 'Kit ID', 'elementor-pro' ),
|
||||
'field_args' => [
|
||||
'type' => 'text',
|
||||
'desc' => sprintf(
|
||||
/* translators: 1: Link opening tag, 2: Link closing tag. */
|
||||
esc_html__( 'Enter Your %1$sFont Awesome Pro Kit ID%2$s.', 'elementor-pro' ),
|
||||
'<a href="https://fontawesome.com/kits" target="_blank">',
|
||||
'</a>'
|
||||
),
|
||||
],
|
||||
'setting_args' => [
|
||||
'sanitize_callback' => [ $this, 'sanitize_kit_id_settings' ],
|
||||
],
|
||||
],
|
||||
'validate_api_data' => [
|
||||
'field_args' => [
|
||||
'type' => 'raw_html',
|
||||
'html' => sprintf( '<button data-action="%s" data-nonce="%s" class="button elementor-button-spinner" id="elementor_pro_fa_pro_validate_button">%s</button><br><p><span class="elementor-pro-fa_pro_data hidden"></span></p>',
|
||||
self::FA_KIT_ID_OPTION_NAME . '_fetch',
|
||||
wp_create_nonce( self::FA_KIT_ID_OPTION_NAME ),
|
||||
__( 'Validate Kit ID', 'elementor-pro' )
|
||||
),
|
||||
],
|
||||
],
|
||||
],
|
||||
] );
|
||||
}
|
||||
|
||||
public function enqueue_kit_js() {
|
||||
wp_enqueue_script( 'font-awesome-pro', sprintf( self::FA_KIT_SCRIPT_LINK, $this->get_kit_id() ), [], ELEMENTOR_PRO_VERSION );
|
||||
}
|
||||
|
||||
public function sanitize_kit_id_settings( $input ) {
|
||||
if ( empty( $input ) ) {
|
||||
delete_option( 'elementor_' . self::FA_KIT_ID_OPTION_NAME );
|
||||
}
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
protected function actions() {
|
||||
parent::actions();
|
||||
|
||||
if ( is_admin() ) {
|
||||
add_action( 'elementor/admin/after_create_settings/' . Settings::PAGE_ID, [ $this, 'register_admin_fields' ], 100 );
|
||||
}
|
||||
|
||||
if ( $this->get_kit_id() ) {
|
||||
add_filter( 'elementor/icons_manager/native', [ $this, 'replace_font_awesome_pro' ] );
|
||||
add_action( 'elementor/editor/after_enqueue_scripts', [ $this, 'enqueue_kit_js' ] );
|
||||
add_action( 'elementor/frontend/after_enqueue_scripts', [ $this, 'enqueue_kit_js' ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager\AssetTypes\Icons\IconSets;
|
||||
|
||||
use ElementorPro\Core\Utils;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Fontastic extends Icon_Set_Base {
|
||||
|
||||
protected $data = '';
|
||||
protected $data_file = 'icons-reference.html';
|
||||
protected $stylesheet_file = 'styles.css';
|
||||
protected $allowed_zipped_files = [ 'icons-reference.html', 'styles.css', 'fonts/' ];
|
||||
protected $allowed_webfont_extensions = [ 'woff', 'ttf', 'svg', 'eot' ];
|
||||
|
||||
protected function prepare() {
|
||||
$this->data = Utils::_unstable_file_get_contents( $this->directory . $this->stylesheet_file );
|
||||
$this->dir_name = $this->get_unique_name();
|
||||
}
|
||||
|
||||
public function get_type() {
|
||||
return esc_html__( 'Fontastic', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function is_valid() {
|
||||
if ( ! file_exists( $this->directory . $this->data_file ) ) {
|
||||
return false; // missing data file
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function extract_icon_list() {
|
||||
$pattern = '/\.' . $this->get_prefix() . '(.*)\:before\s\{/';
|
||||
preg_match_all( $pattern, $this->data, $icons_matches );
|
||||
if ( empty( $icons_matches[1] ) ) {
|
||||
return false; // missing icons list
|
||||
}
|
||||
$icons = [];
|
||||
foreach ( $icons_matches[1] as $icon ) {
|
||||
$icons[] = $icon;
|
||||
}
|
||||
return $icons;
|
||||
}
|
||||
|
||||
protected function get_prefix() {
|
||||
static $set_prefix = null;
|
||||
if ( null === $set_prefix ) {
|
||||
$pattern = '/class\^="(.*)?"/';
|
||||
preg_match_all( $pattern, $this->data, $prefix );
|
||||
if ( ! isset( $prefix[1][0] ) ) {
|
||||
return false; // missing css_prefix_text
|
||||
}
|
||||
$set_prefix = $prefix[1][0];
|
||||
}
|
||||
return $set_prefix;
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
static $set_name = null;
|
||||
if ( null === $set_name ) {
|
||||
$pattern = '/font-family: "(.*)"/';
|
||||
preg_match_all( $pattern, $this->data, $name );
|
||||
if ( ! isset( $name[1][0] ) ) {
|
||||
return false; // missing name
|
||||
}
|
||||
$set_name = $name[1][0];
|
||||
}
|
||||
return $set_name;
|
||||
}
|
||||
|
||||
protected function get_stylesheet( $unique_name = '' ) {
|
||||
return $this->get_url() . '/' . $this->stylesheet_file;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager\AssetTypes\Icons\IconSets;
|
||||
|
||||
use ElementorPro\Core\Utils;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Fontello extends Icon_Set_Base {
|
||||
|
||||
protected $data_file = 'config.json';
|
||||
protected $stylesheet_file = '';
|
||||
protected $allowed_zipped_files = [ 'config.json', 'demo.html', 'README.txt', 'LICENSE.txt', 'css/', 'font/' ];
|
||||
protected $allowed_webfont_extensions = [ 'woff', 'woff2', 'ttf', 'svg', 'otf' ];
|
||||
|
||||
protected function prepare() {
|
||||
$this->remove_fontello_styling();
|
||||
$this->dir_name = $this->get_unique_name();
|
||||
}
|
||||
|
||||
public function get_type() {
|
||||
return esc_html__( 'Fontello', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function is_valid() {
|
||||
if ( ! file_exists( $this->directory . $this->data_file ) ) {
|
||||
return false; // missing data file
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function remove_fontello_styling() {
|
||||
$filename = $this->directory . 'css/' . $this->get_name() . '.css';
|
||||
$stylesheet = Utils::_unstable_file_get_contents( $filename );
|
||||
$stylesheet = str_replace( [ 'margin-left: .2em;', 'margin-right: .2em;' ], [ '', '' ], $stylesheet );
|
||||
file_put_contents( $filename, $stylesheet );
|
||||
}
|
||||
|
||||
private function get_json() {
|
||||
return json_decode( Utils::_unstable_file_get_contents( $this->directory . $this->data_file ) );
|
||||
}
|
||||
|
||||
protected function extract_icon_list() {
|
||||
$config = $this->get_json();
|
||||
if ( ! isset( $config->glyphs ) ) {
|
||||
return false; // missing icons list
|
||||
}
|
||||
$icons = [];
|
||||
foreach ( $config->glyphs as $icon ) {
|
||||
$icons[] = $icon->css;
|
||||
}
|
||||
return $icons;
|
||||
}
|
||||
|
||||
protected function get_prefix() {
|
||||
$config = $this->get_json();
|
||||
if ( ! isset( $config->css_prefix_text ) ) {
|
||||
return false; // missing css_prefix_text
|
||||
}
|
||||
return $config->css_prefix_text;
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
$config = $this->get_json();
|
||||
if ( ! isset( $config->name ) ) {
|
||||
return false; // missing name
|
||||
}
|
||||
return $config->name;
|
||||
}
|
||||
|
||||
protected function get_stylesheet() {
|
||||
$name = $this->get_name();
|
||||
if ( ! $name ) {
|
||||
return false; // missing name
|
||||
}
|
||||
return $this->get_url() . '/css/' . $name . '.css';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager\AssetTypes\Icons\IconSets;
|
||||
|
||||
use ElementorPro\Core\Utils;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Icomoon extends Icon_Set_Base {
|
||||
|
||||
protected $data_file = 'selection.json';
|
||||
protected $stylesheet_file = 'style.css';
|
||||
protected $allowed_zipped_files = [ 'selection.json', 'demo.html', 'Read Mw.txt', 'demo-files/', 'fonts/' ];
|
||||
protected $allowed_webfont_extensions = [ 'woff', 'ttf', 'svg', 'eot' ];
|
||||
|
||||
protected function prepare() {
|
||||
$this->dir_name = $this->get_unique_name();
|
||||
return [];
|
||||
}
|
||||
|
||||
public function get_type() {
|
||||
return esc_html__( 'Icomoon', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function is_valid() {
|
||||
if ( ! file_exists( $this->directory . $this->data_file ) ) {
|
||||
return false; // missing data file
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function get_json() {
|
||||
return json_decode( Utils::_unstable_file_get_contents( $this->directory . $this->data_file ) );
|
||||
}
|
||||
|
||||
protected function extract_icon_list() {
|
||||
$config = $this->get_json();
|
||||
if ( ! isset( $config->icons ) ) {
|
||||
return false; // missing icons list
|
||||
}
|
||||
$icons = [];
|
||||
foreach ( $config->icons as $icon ) {
|
||||
$icons[] = $icon->properties->name;
|
||||
}
|
||||
return $icons;
|
||||
}
|
||||
|
||||
protected function get_prefix() {
|
||||
$config = $this->get_json();
|
||||
if ( ! isset( $config->preferences->fontPref->prefix ) ) {
|
||||
return false; // missing css_prefix_text
|
||||
}
|
||||
return $config->preferences->fontPref->prefix;
|
||||
}
|
||||
|
||||
protected function get_display_prefix() {
|
||||
$config = $this->get_json();
|
||||
if ( ! isset( $config->preferences->fontPref->classSelector ) ) {
|
||||
return false; // missing css_prefix_text
|
||||
}
|
||||
return str_replace( '.', '', $config->preferences->fontPref->classSelector );
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
$config = $this->get_json();
|
||||
if ( ! isset( $config->metadata->name ) ) {
|
||||
return false; // missing name
|
||||
}
|
||||
return $config->metadata->name;
|
||||
}
|
||||
|
||||
protected function get_stylesheet() {
|
||||
return $this->get_url( '/' . $this->stylesheet_file );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager\AssetTypes\Icons\IconSets;
|
||||
|
||||
use ElementorPro\Core\Utils;
|
||||
use ElementorPro\Modules\AssetsManager\AssetTypes\Icons\Custom_Icons;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
abstract class Icon_Set_Base {
|
||||
|
||||
protected $dir_name = '';
|
||||
protected $directory = '';
|
||||
protected $data_file = '';
|
||||
protected $stylesheet_file = '';
|
||||
protected $allowed_zipped_files = [];
|
||||
protected $files_to_save = [];
|
||||
/**
|
||||
* Webfont extensions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $allowed_webfont_extensions = [ 'woff', 'woff2', 'ttf', 'svg', 'otf', 'eot' ];
|
||||
|
||||
abstract protected function extract_icon_list();
|
||||
|
||||
abstract protected function prepare();
|
||||
|
||||
abstract protected function get_type();
|
||||
|
||||
abstract public function get_name();
|
||||
|
||||
private function is_path_dir( $path ) {
|
||||
return '/' === substr( $path, -1 );
|
||||
}
|
||||
|
||||
private function is_file_allowed( $path_name ) {
|
||||
$check = $this->directory . $path_name;
|
||||
if ( ! file_exists( $check ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( $this->is_path_dir( $path_name ) ) {
|
||||
return is_dir( $check );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* is icon set
|
||||
*
|
||||
* validate that the current uploaded zip is in this icon set format
|
||||
* @return bool
|
||||
*/
|
||||
public function is_icon_set() {
|
||||
foreach ( $this->allowed_zipped_files as $file ) {
|
||||
if ( ! $this->is_file_allowed( $file ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function is_valid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function get_display_prefix() {
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function get_prefix() {
|
||||
return '';
|
||||
}
|
||||
|
||||
public function handle_new_icon_set() {
|
||||
return $this->prepare();
|
||||
}
|
||||
|
||||
/**
|
||||
* cleanup_temp_files
|
||||
* @param \WP_Filesystem_Base $wp_filesystem
|
||||
*/
|
||||
protected function cleanup_temp_files( $wp_filesystem ) {
|
||||
$wp_filesystem->rmdir( $this->directory, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URL to uploaded file.
|
||||
*
|
||||
* @param $file_name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_file_url( $file_name ) {
|
||||
$wp_upload_dir = wp_upload_dir();
|
||||
$url = $wp_upload_dir['baseurl'] . '/elementor/custom-icons/' . $file_name;
|
||||
|
||||
/**
|
||||
* Upload file URL.
|
||||
*
|
||||
* Filters the URL to a file uploaded using custom icons.
|
||||
*
|
||||
* By default URL to a file uploaded is set to `/elementor/custom-icons/{file_name}`
|
||||
* inside the WordPress uploads folder. This hook allows developers to change this URL.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $url File URL.
|
||||
* @param string $file_name File name.
|
||||
*/
|
||||
$url = apply_filters( 'elementor_pro/icons_manager/custom_icons/url', $url, $file_name );
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
protected function get_icon_sets_dir() {
|
||||
$wp_upload_dir = wp_upload_dir();
|
||||
$path = $wp_upload_dir['basedir'] . '/elementor/custom-icons';
|
||||
|
||||
/**
|
||||
* Upload file path.
|
||||
*
|
||||
* Filters the path to a folder uploaded using custom icons.
|
||||
*
|
||||
* By default the folder path to custom icon files is set to `/elementor/custom-icons`
|
||||
* inside the WordPress uploads folder. This hook allows developers to change this path.
|
||||
*
|
||||
* @param string $path Path to custom icons uploads directory.
|
||||
*/
|
||||
$path = apply_filters( 'elementor_pro/icons_manager/custom_icons/dir', $path );
|
||||
|
||||
Utils::get_ensure_upload_dir( $path );
|
||||
return $path;
|
||||
}
|
||||
|
||||
protected function get_ensure_upload_dir( $dir = '' ) {
|
||||
$path = $this->get_icon_sets_dir();
|
||||
if ( ! empty( $dir ) ) {
|
||||
$path .= '/' . $dir;
|
||||
}
|
||||
return Utils::get_ensure_upload_dir( $path );
|
||||
}
|
||||
|
||||
public function move_files( $post_id ) {
|
||||
// @todo: save only needed files
|
||||
$wp_filesystem = Custom_Icons::get_wp_filesystem();
|
||||
$to = $this->get_ensure_upload_dir( $this->dir_name ) . '/';
|
||||
|
||||
foreach ( $wp_filesystem->dirlist( $this->directory, false, true ) as $file ) {
|
||||
$full_path = $this->directory . $file['name'];
|
||||
if ( $wp_filesystem->is_dir( $full_path ) ) {
|
||||
$wp_filesystem->mkdir( $to . $file['name'] );
|
||||
|
||||
foreach ( $file['files'] as $filename => $sub_file ) {
|
||||
$new_path = $to . $file['name'] . DIRECTORY_SEPARATOR . $filename;
|
||||
$wp_filesystem->move( $full_path . DIRECTORY_SEPARATOR . $filename, $new_path );
|
||||
$this->insert_attachment( $this->get_url() . '/' . $file['name'] . '/' . $filename, $new_path, $post_id );
|
||||
}
|
||||
} else {
|
||||
$new_path = $to . $file['name'];
|
||||
$wp_filesystem->move( $full_path, $new_path );
|
||||
$this->insert_attachment( $this->get_url() . '/' . $file['name'], $new_path, $post_id );
|
||||
}
|
||||
}
|
||||
|
||||
$this->cleanup_temp_files( $wp_filesystem );
|
||||
update_post_meta( $post_id, '_elementor_icon_set_path', $to );
|
||||
$this->directory = $to;
|
||||
}
|
||||
|
||||
private function insert_attachment( $file_url, $filename, $post_id = 0 ) {
|
||||
$attachment = [
|
||||
'file' => $filename,
|
||||
'guid' => $file_url,
|
||||
'post_parent' => $post_id,
|
||||
'post_type' => 'attachment',
|
||||
];
|
||||
$id = wp_insert_attachment( $attachment );
|
||||
return $id;
|
||||
}
|
||||
|
||||
public function get_unique_name() {
|
||||
$name = $this->get_name();
|
||||
$basename = $name;
|
||||
$counter = 1;
|
||||
while ( ! $this->is_name_unique( $name ) ) {
|
||||
$name = $basename . '-' . $counter;
|
||||
$counter++;
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
|
||||
private function is_name_unique( $name ) {
|
||||
return ! is_dir( $this->get_icon_sets_dir() . '/' . $name );
|
||||
}
|
||||
|
||||
protected function get_url( $filename = '' ) {
|
||||
return $this->get_file_url( $this->dir_name . $filename );
|
||||
}
|
||||
|
||||
protected function get_stylesheet() {
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function get_version() {
|
||||
return '1.0.0';
|
||||
}
|
||||
|
||||
protected function get_enqueue() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function build_config() {
|
||||
$icon_set_config = [
|
||||
'name' => $this->dir_name,
|
||||
'label' => ucwords( str_replace( [ '-', '_' ], ' ', $this->dir_name ) ),
|
||||
'url' => $this->get_stylesheet(),
|
||||
'enqueue' => $this->get_enqueue(),
|
||||
'prefix' => $this->get_prefix(),
|
||||
'displayPrefix' => $this->get_display_prefix(),
|
||||
'labelIcon' => 'eicon eicon-folder',
|
||||
'ver' => $this->get_version(),
|
||||
'custom_icon_type' => $this->get_type(),
|
||||
];
|
||||
|
||||
$icons = $this->extract_icon_list();
|
||||
$icon_set_config['count'] = count( $icons );
|
||||
$icon_set_config['icons'] = $icons;
|
||||
|
||||
if ( 25 < $icon_set_config['count'] ) {
|
||||
$icon_set_config['fetchJson'] = $this->store_icon_list_json( $icons );
|
||||
}
|
||||
|
||||
return $icon_set_config;
|
||||
}
|
||||
|
||||
private function store_icon_list_json( $icons ) {
|
||||
$wp_filesystem = Custom_Icons::get_wp_filesystem();
|
||||
$json_file = $this->get_ensure_upload_dir( $this->dir_name ) . '/e_icons.js';
|
||||
$wp_filesystem->put_contents( $json_file, json_encode( [ 'icons' => $icons ] ) );
|
||||
return $this->get_url() . '/e_icons.js';
|
||||
}
|
||||
|
||||
/**
|
||||
* Icon Set Base constructor.
|
||||
*
|
||||
* @param $directory
|
||||
*/
|
||||
public function __construct( $directory ) {
|
||||
$this->directory = $directory;
|
||||
return $this->is_icon_set() ? $this : false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
?>
|
||||
<script type="text/template" id="elementor-custom-icons-template-footer">
|
||||
<div class="elementor-icon-set-footer"><?php echo esc_html__( 'Created on', 'elementor-pro' ); ?>: {{day}}/{{mm}}/{{year}}, {{hour}}:{{minute}}</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="elementor-custom-icons-template-header">
|
||||
<div class="elementor-icon-set-header">
|
||||
<div><span class="elementor-icon-set-header-meta"><?php echo esc_html__( 'Name', 'elementor-pro' ); ?>: </span><span class="elementor-icon-set-header-meta-value">{{name}}</span></div>
|
||||
<div><span class="elementor-icon-set-header-meta"><?php echo esc_html__( 'CSS Prefix', 'elementor-pro' ); ?>: </span><span class="elementor-icon-set-header-meta-value">{{prefix}}</span></div>
|
||||
<div><span class="elementor-icon-set-header-meta"><?php echo esc_html__( 'Icons Count', 'elementor-pro' ); ?>: </span><span class="elementor-icon-set-header-meta-value">{{count}}</span></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="elementor-custom-icons-template-duplicate-prefix">
|
||||
<div class="elementor-icon-set-duplicate-prefix"><?php echo esc_html__( 'The Icon Set prefix already exists in your site. In order to avoid conflicts we recommend to use a unique prefix per Icon Set.', 'elementor-pro' ); ?></div>
|
||||
</script>
|
||||
@@ -0,0 +1,378 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager\Classes;
|
||||
|
||||
use Elementor\Utils;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
abstract class Assets_Base {
|
||||
|
||||
abstract public function get_name();
|
||||
|
||||
abstract public function get_type();
|
||||
|
||||
protected function actions() { }
|
||||
|
||||
public function print_metabox( $fields ) {
|
||||
?>
|
||||
<div class="elementor-metabox-content">
|
||||
<?php
|
||||
foreach ( $fields as $field ) :
|
||||
$field['saved'] = isset( $field['saved'] ) ? $field['saved'] : '';
|
||||
// PHPCS - admin fields
|
||||
echo $this->get_metabox_field_html( $field, $field['saved'] ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
endforeach;
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function get_metabox_field_html( $field, $saved ) {
|
||||
$html = '';
|
||||
|
||||
switch ( $field['field_type'] ) {
|
||||
case 'html':
|
||||
$html = $this->get_html_field( $field );
|
||||
|
||||
return $html;
|
||||
break;
|
||||
|
||||
case 'html_tag':
|
||||
$html = $this->get_html_tag( $field );
|
||||
|
||||
return $html;
|
||||
break;
|
||||
|
||||
case 'toolbar':
|
||||
$html = $this->get_repeater_tools( $field );
|
||||
break;
|
||||
|
||||
case 'input':
|
||||
$html = $this->get_input_field( $field );
|
||||
break;
|
||||
|
||||
case 'select':
|
||||
$html = $this->get_select_field( $field, $saved );
|
||||
break;
|
||||
|
||||
case 'textarea':
|
||||
$html = $this->get_textarea_field( $field, $saved );
|
||||
break;
|
||||
|
||||
case 'file':
|
||||
$html = $this->get_file_field( $field, $saved );
|
||||
break;
|
||||
|
||||
case 'repeater':
|
||||
$html = $this->get_repeater_field( $field, $saved );
|
||||
break;
|
||||
|
||||
case 'dropzone':
|
||||
$html = $this->get_dropzone_field( $field, $saved );
|
||||
break;
|
||||
|
||||
case 'checkbox':
|
||||
return $this->get_checkbox_field( $field, $saved );
|
||||
|
||||
default:
|
||||
$method = 'get_' . $field['field_type'] . 'field';
|
||||
if ( method_exists( $this, $method ) ) {
|
||||
$html = call_user_func( [ $this, $method ], $field, $saved );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $this->get_field_row( $field, $html );
|
||||
}
|
||||
|
||||
public function get_field_label( $field ) {
|
||||
if ( ! isset( $field['label'] ) || false === $field['label'] ) {
|
||||
return '';
|
||||
}
|
||||
$id = $field['id'];
|
||||
if ( 'file' === $field['field_type'] ) {
|
||||
$id .= $field['field_type'];
|
||||
}
|
||||
|
||||
return '<p class="elementor-field-label"><label for="' . esc_attr( $id ) . '">' . $field['label'] . '</label></p>';
|
||||
}
|
||||
|
||||
public function get_input_field( $attributes ) {
|
||||
if ( isset( $attributes['input_type'] ) ) {
|
||||
$attributes['type'] = $attributes['input_type'];
|
||||
unset( $attributes['input_type'] );
|
||||
}
|
||||
$input = '<input ' . $this->get_attribute_string( $attributes ) . '>';
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
public function get_attribute_string( $attributes, $field = [] ) {
|
||||
if ( isset( $field['extra_attributes'] ) && is_array( $field['extra_attributes'] ) ) {
|
||||
$attributes = array_merge( $attributes, $field['extra_attributes'] );
|
||||
}
|
||||
$attributes_array = [];
|
||||
foreach ( $attributes as $name => $value ) {
|
||||
$attributes_array[] = sprintf( '%s="%s"', $name, esc_attr( $value ) );
|
||||
}
|
||||
|
||||
return implode( ' ', $attributes_array );
|
||||
}
|
||||
|
||||
public function get_select_field( $field, $selected = '' ) {
|
||||
$input = '<select ';
|
||||
$input .= $this->get_attribute_string( [
|
||||
'name' => $field['id'],
|
||||
'id' => $field['id'],
|
||||
], $field );
|
||||
|
||||
$input .= '>' . "\n";
|
||||
foreach ( $field['options'] as $value => $label ) {
|
||||
$input .= '<option value="' . $value . '" ' . selected( $selected, $value, false ) . '>' . esc_attr( $label ) . '</option>' . PHP_EOL;
|
||||
}
|
||||
|
||||
return $input . '</select>';
|
||||
}
|
||||
|
||||
public function get_textarea_field( $field, $html ) {
|
||||
$input = '<textarea ';
|
||||
$input .= $this->get_attribute_string( [
|
||||
'name' => $field['id'],
|
||||
'id' => $field['id'],
|
||||
], $field );
|
||||
|
||||
$input .= '>' . esc_textarea( $html ) . '</textarea>';
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
public function get_file_field( $field, $saved ) {
|
||||
$value = [
|
||||
'id' => '',
|
||||
'url' => '',
|
||||
];
|
||||
|
||||
if ( isset( $saved['id'] ) && isset( $saved['url'] ) ) {
|
||||
$value = $saved;
|
||||
}
|
||||
|
||||
$html = '<ul></ul>';
|
||||
$html .= $this->get_input_field(
|
||||
[
|
||||
'type' => 'hidden',
|
||||
'name' => $field['id'] . '[id]',
|
||||
'value' => $value['id'],
|
||||
]
|
||||
);
|
||||
|
||||
$html .= $this->get_input_field(
|
||||
[
|
||||
'type' => 'text',
|
||||
'name' => $field['id'] . '[url]',
|
||||
'value' => $value['url'],
|
||||
'placeholder' => $field['description'],
|
||||
'class' => 'elementor-field-input',
|
||||
]
|
||||
);
|
||||
|
||||
$html .= $this->get_input_field(
|
||||
[
|
||||
'type' => 'button',
|
||||
'class' => 'button elementor-button elementor-upload-btn',
|
||||
'name' => $field['id'],
|
||||
'id' => $field['id'],
|
||||
'value' => '',
|
||||
'data-preview_anchor' => isset( $field['preview_anchor'] ) ? $field['preview_anchor'] : 'none',
|
||||
'data-mime_type' => isset( $field['mine'] ) ? $field['mine'] : '',
|
||||
'data-ext' => isset( $field['ext'] ) ? $field['ext'] : '',
|
||||
'data-upload_text' => esc_html__( 'Upload', 'elementor-pro' ),
|
||||
'data-remove_text' => esc_html__( 'Delete', 'elementor-pro' ),
|
||||
'data-box_title' => isset( $field['box_title'] ) ? $field['box_title'] : '',
|
||||
'data-box_action' => isset( $field['box_action'] ) ? $field['box_action'] : '',
|
||||
]
|
||||
);
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public function get_html_field( $field ) {
|
||||
return $field['raw_html'];
|
||||
}
|
||||
|
||||
public function get_dropzone_field( $field ) {
|
||||
ob_start();
|
||||
$input_attributes = [
|
||||
'type' => 'file',
|
||||
'name' => $field['id'],
|
||||
'id' => $field['id'],
|
||||
'accept' => $field['accept'],
|
||||
'class' => 'box__file',
|
||||
];
|
||||
if ( ! empty( $field['multiple'] ) ) {
|
||||
$input_attributes['multiple'] = true;
|
||||
}
|
||||
$input_html = $this->get_input_field( $input_attributes );
|
||||
$field['label'] = '<h4><span class="box__dragndrop">' . esc_html__( 'Drag & Drop to Upload', 'elementor-pro' ) . '</span></h4>';
|
||||
if ( ! empty( $field['sub-label'] ) ) {
|
||||
$field['label'] .= '<h5>' . $field['sub-label'] . '</h5>';
|
||||
}
|
||||
?>
|
||||
<div class="elementor-dropzone-field">
|
||||
<div class="box__input">
|
||||
<div class="elementor--dropzone--upload__icon">
|
||||
<i class="eicon-library-upload"></i>
|
||||
</div>
|
||||
<?php echo $input_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php echo $this->get_field_label( $field ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<div class="elementor-button elementor--dropzone--upload__browse">
|
||||
<span><?php esc_html_e( 'Click here to browse', 'elementor-pro' ); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box__uploading"><?php esc_html_e( 'Uploading…', 'elementor-pro' ); ?></div>
|
||||
<div class="box__success"><?php esc_html_e( 'Done!', 'elementor-pro' ); ?></div>
|
||||
<div class="box__error"><?php esc_html_e( 'Error!', 'elementor-pro' ); ?> <span></span>.</div>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
public function get_repeater_field( $field, $saved ) {
|
||||
$id = $field['id'];
|
||||
$js_id = 'repeater_' . Utils::generate_random_string();
|
||||
$add_label = isset( $field['add_label'] ) ? $field['add_label'] : esc_html__( 'Add item', 'elementor-pro' );
|
||||
$row_label = isset( $field['row_label'] ) ? $field['row_label'] : esc_html__( 'Row', 'elementor-pro' );
|
||||
$row_label_html_args = [
|
||||
'id' => 'row_label_' . $js_id,
|
||||
'class' => 'repeater-title hidden',
|
||||
];
|
||||
|
||||
if ( is_array( $row_label ) ) {
|
||||
$label = $row_label['default'];
|
||||
$row_label_html_args['data-default'] = $row_label['default'];
|
||||
$row_label_html_args['data-selector'] = $row_label['selector'];
|
||||
} else {
|
||||
$label = $row_label;
|
||||
$row_label_html_args['data-default'] = $row_label;
|
||||
}
|
||||
|
||||
$row_label_html = '<span ' . $this->get_attribute_string( $row_label_html_args ) . '>' . $label . '</span>';
|
||||
ob_start();
|
||||
?>
|
||||
<script type="text/template" id="<?php echo esc_attr( $js_id . '_block' ); ?>">
|
||||
<div class="repeater-block block-visible">
|
||||
<?php
|
||||
echo $row_label_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $this->get_repeater_tools( $field ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
?>
|
||||
<div class="repeater-content form-table">
|
||||
<?php
|
||||
foreach ( $field['fields'] as $sub_field ) {
|
||||
$sub_field['real_id'] = $id;
|
||||
$sub_field['id'] = $id . '[__counter__][' . $sub_field['id'] . ']';
|
||||
echo $this->get_metabox_field_html( $sub_field, '' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<?php
|
||||
$counter = 0;
|
||||
$row_label_html_args['class'] = 'repeater-title';
|
||||
|
||||
$row_label_html = '<span ' . $this->get_attribute_string( $row_label_html_args ) . '>' . $label . '</span>';
|
||||
if ( is_array( $saved ) && count( $saved ) > 0 ) {
|
||||
foreach ( (array) $saved as $key => $item ) {
|
||||
echo '<div class="repeater-block">';
|
||||
echo $row_label_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $this->get_repeater_tools( $field ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<div class="repeater-content hidden form-table">';
|
||||
foreach ( $field['fields'] as $sub_field ) {
|
||||
$default = isset( $sub_field['default'] ) ? $sub_field['default'] : '';
|
||||
$item_meta = isset( $item[ $sub_field['id'] ] ) ? $item[ $sub_field['id'] ] : $default;
|
||||
$sub_field['real_id'] = $sub_field['id'];
|
||||
$sub_field['id'] = $id . '[' . $counter . '][' . $sub_field['id'] . ']';
|
||||
echo $this->get_metabox_field_html( $sub_field, $item_meta ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
echo '</div>'; // end table
|
||||
echo '</div>';
|
||||
$counter++;
|
||||
}
|
||||
}
|
||||
echo '<input type="button" class="button elementor-button add-repeater-row" value="' . esc_attr( $add_label ) . '" data-template-id="' . esc_html( $js_id ) . '_block">';
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
public function get_checkbox_field( $field, $saved ) {
|
||||
Utils::print_unescaped_internal_string( $this->get_field_row( $field, '' ) );
|
||||
|
||||
echo '<div id="' . esc_attr( $field['id'] ) . '" class="elementor-field-checkboxes">';
|
||||
|
||||
foreach ( $field['options'] as $checkbox_key => $label ) {
|
||||
$name = $field['id'] . '_' . $checkbox_key;
|
||||
|
||||
$checked = ! empty( $saved ) && in_array( $checkbox_key, $saved, true ) ? 'checked' : '';
|
||||
|
||||
echo '<input name="' . esc_attr( $name ) . '" type="checkbox" ' . esc_attr( $checked ) . '><span class="label">' . esc_html( $label ) . '</span></input>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
private function get_html_tag( $field ) {
|
||||
$tag = isset( $field['tag'] ) ? $field['tag'] : 'div';
|
||||
if ( isset( $field['close'] ) && true === $field['close'] ) {
|
||||
return '</' . $tag . '>';
|
||||
}
|
||||
|
||||
return '<' . $tag . ' ' . $this->get_attribute_string( $field['attributes'] ) . '>';
|
||||
}
|
||||
|
||||
private function get_repeater_tools( $field ) {
|
||||
$confirm = isset( $field['confirm'] ) ? $field['confirm'] : esc_html__( 'Are you sure?', 'elementor-pro' );
|
||||
$remove_title = isset( $field['remove_title'] ) ? $field['remove_title'] : esc_html__( 'Delete', 'elementor-pro' );
|
||||
$toggle_title = isset( $field['toggle_title'] ) ? $field['toggle_title'] : esc_html__( 'Edit', 'elementor-pro' );
|
||||
$close_title = isset( $field['close_title'] ) ? $field['close_title'] : esc_html__( 'Close', 'elementor-pro' );
|
||||
|
||||
return '<span class="elementor-repeater-tool-btn close-repeater-row" title="' . esc_attr( $close_title ) . '">
|
||||
<i class="eicon-times" aria-hidden="true"></i>' . $close_title . '
|
||||
</span>
|
||||
<span class="elementor-repeater-tool-btn toggle-repeater-row" title="' . esc_attr( $toggle_title ) . '">
|
||||
<i class="eicon-edit" aria-hidden="true"></i>' . $toggle_title . '
|
||||
</span>
|
||||
<span class="elementor-repeater-tool-btn remove-repeater-row" data-confirm="' . $confirm . '" title="' . esc_attr( $remove_title ) . '">
|
||||
<i class="eicon-trash" aria-hidden="true"></i>' . $remove_title . '
|
||||
</span>';
|
||||
}
|
||||
|
||||
public function get_field_row( $field, $field_html ) {
|
||||
$description = '';
|
||||
$css_id = isset( $field['id'] ) ? ' ' . $field['id'] : '';
|
||||
|
||||
if ( isset( $field['real_id'] ) ) {
|
||||
$css_id = ' ' . $field['real_id'];
|
||||
}
|
||||
|
||||
$css_id .= ' elementor-field-' . $field['field_type'];
|
||||
|
||||
return '<div class="elementor-field' . $css_id . '">' . $this->get_field_label( $field ) . $field_html . $description . '</div>';
|
||||
}
|
||||
|
||||
public function sanitize_text_field_recursive( $data ) {
|
||||
if ( is_array( $data ) ) {
|
||||
foreach ( $data as $key => $value ) {
|
||||
$data[ $key ] = $this->sanitize_text_field_recursive( $value );
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
return sanitize_text_field( $data );
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
$this->actions();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager\Classes;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
|
||||
class Font_Base extends Assets_Base {
|
||||
|
||||
const FONTS_OPTION_NAME = 'elementor_fonts_manager_fonts';
|
||||
|
||||
protected $font_preview_phrase = '';
|
||||
|
||||
protected function actions() {}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->font_preview_phrase = esc_html__( 'Elementor Is Making the Web Beautiful!!!', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return '';
|
||||
}
|
||||
|
||||
public function get_type() {
|
||||
return '';
|
||||
}
|
||||
|
||||
public function handle_panel_request( array $data ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
public function get_fonts( $force = false ) {}
|
||||
|
||||
public function enqueue_font( $font_family, $font_data, $post_css ) {}
|
||||
|
||||
public function get_font_family_type( $post_id, $post_title ) {}
|
||||
|
||||
public function get_font_data( $post_id, $post_title ) {}
|
||||
|
||||
public function render_preview_column( $post_id ) {}
|
||||
|
||||
public function get_font_variations_count( $post_id ) {}
|
||||
|
||||
public function save_meta( $post_id, $data ) {}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\AssetsManager;
|
||||
|
||||
use ElementorPro\Base\Module_Base;
|
||||
use ElementorPro\Modules\AssetsManager\AssetTypes;
|
||||
use ElementorPro\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends Module_Base {
|
||||
|
||||
private $asset_managers = [];
|
||||
|
||||
public function get_name() {
|
||||
return 'assets-manager';
|
||||
}
|
||||
|
||||
public function add_asset_manager( $name, $instance ) {
|
||||
$this->asset_managers[ $name ] = $instance;
|
||||
}
|
||||
|
||||
public function get_assets_manager( $id = null ) {
|
||||
if ( $id ) {
|
||||
if ( ! isset( $this->asset_managers[ $id ] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->asset_managers[ $id ];
|
||||
}
|
||||
|
||||
return $this->asset_managers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.1.0
|
||||
*/
|
||||
public function localize_settings() {
|
||||
Plugin::elementor()->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.1.0' );
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->add_asset_manager( 'font', new AssetTypes\Fonts_Manager() );
|
||||
$this->add_asset_manager( 'icon', new AssetTypes\Icons_Manager() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\Blockquote;
|
||||
|
||||
use ElementorPro\Base\Module_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends Module_Base {
|
||||
|
||||
public function get_widgets() {
|
||||
return [
|
||||
'Blockquote',
|
||||
];
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'blockquote';
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\CallToAction;
|
||||
|
||||
use ElementorPro\Base\Module_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Module extends Module_Base {
|
||||
|
||||
public function get_widgets() {
|
||||
return [
|
||||
'Call_To_Action',
|
||||
];
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'call-to-action';
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
23
wp-content/plugins/elementor-pro/modules/carousel/module.php
Normal file
23
wp-content/plugins/elementor-pro/modules/carousel/module.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\Carousel;
|
||||
|
||||
use ElementorPro\Base\Module_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends Module_Base {
|
||||
|
||||
public function get_widgets() {
|
||||
return [
|
||||
'Media_Carousel',
|
||||
'Testimonial_Carousel',
|
||||
'Reviews',
|
||||
];
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'carousel';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,627 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\Carousel\Widgets;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use Elementor\Group_Control_Image_Size;
|
||||
use Elementor\Icons_Manager;
|
||||
use Elementor\Repeater;
|
||||
use ElementorPro\Base\Base_Widget;
|
||||
use ElementorPro\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
abstract class Base extends Base_Widget {
|
||||
|
||||
private $slide_prints_count = 0;
|
||||
|
||||
public function get_script_depends() {
|
||||
return [ 'imagesloaded' ];
|
||||
}
|
||||
|
||||
abstract protected function add_repeater_controls( Repeater $repeater );
|
||||
|
||||
abstract protected function get_repeater_defaults();
|
||||
|
||||
abstract protected function print_slide( array $slide, array $settings, $element_key );
|
||||
|
||||
protected function register_controls() {
|
||||
$this->start_controls_section(
|
||||
'section_slides',
|
||||
[
|
||||
'label' => esc_html__( 'Slides', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_CONTENT,
|
||||
]
|
||||
);
|
||||
|
||||
$repeater = new Repeater();
|
||||
|
||||
$this->add_repeater_controls( $repeater );
|
||||
|
||||
$this->add_control(
|
||||
'slides',
|
||||
[
|
||||
'label' => esc_html__( 'Slides', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::REPEATER,
|
||||
'fields' => $repeater->get_controls(),
|
||||
'default' => $this->get_repeater_defaults(),
|
||||
'separator' => 'after',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'effect',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'label' => esc_html__( 'Effect', 'elementor-pro' ),
|
||||
'default' => 'slide',
|
||||
'options' => [
|
||||
'slide' => esc_html__( 'Slide', 'elementor-pro' ),
|
||||
'fade' => esc_html__( 'Fade', 'elementor-pro' ),
|
||||
'cube' => esc_html__( 'Cube', 'elementor-pro' ),
|
||||
],
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$slides_per_view = range( 1, 10 );
|
||||
$slides_per_view = array_combine( $slides_per_view, $slides_per_view );
|
||||
|
||||
$this->add_responsive_control(
|
||||
'slides_per_view',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'label' => esc_html__( 'Slides Per View', 'elementor-pro' ),
|
||||
'options' => [ '' => esc_html__( 'Default', 'elementor-pro' ) ] + $slides_per_view,
|
||||
'inherit_placeholders' => false,
|
||||
'condition' => [
|
||||
'effect' => 'slide',
|
||||
],
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'slides_to_scroll',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'label' => esc_html__( 'Slides to Scroll', 'elementor-pro' ),
|
||||
'description' => esc_html__( 'Set how many slides are scrolled per swipe.', 'elementor-pro' ),
|
||||
'options' => [ '' => esc_html__( 'Default', 'elementor-pro' ) ] + $slides_per_view,
|
||||
'inherit_placeholders' => false,
|
||||
'condition' => [
|
||||
'effect' => 'slide',
|
||||
],
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'height',
|
||||
[
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'label' => esc_html__( 'Height', 'elementor-pro' ),
|
||||
'size_units' => [ 'px', 'em', 'rem', 'vh', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'min' => 100,
|
||||
'max' => 1000,
|
||||
],
|
||||
'em' => [
|
||||
'min' => 10,
|
||||
'max' => 100,
|
||||
],
|
||||
'rem' => [
|
||||
'min' => 10,
|
||||
'max' => 100,
|
||||
],
|
||||
'vh' => [
|
||||
'min' => 20,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-main-swiper' => 'height: {{SIZE}}{{UNIT}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'width',
|
||||
[
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'label' => esc_html__( 'Width', 'elementor-pro' ),
|
||||
'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'min' => 100,
|
||||
'max' => 1140,
|
||||
],
|
||||
'%' => [
|
||||
'min' => 50,
|
||||
],
|
||||
],
|
||||
'default' => [
|
||||
'unit' => '%',
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-main-swiper' => 'width: {{SIZE}}{{UNIT}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_additional_options',
|
||||
[
|
||||
'label' => esc_html__( 'Additional Options', 'elementor-pro' ),
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'show_arrows',
|
||||
[
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'label' => esc_html__( 'Arrows', 'elementor-pro' ),
|
||||
'default' => 'yes',
|
||||
'label_off' => esc_html__( 'Hide', 'elementor-pro' ),
|
||||
'label_on' => esc_html__( 'Show', 'elementor-pro' ),
|
||||
'prefix_class' => 'elementor-arrows-',
|
||||
'render_type' => 'template',
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pagination',
|
||||
[
|
||||
'label' => esc_html__( 'Pagination', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => 'bullets',
|
||||
'options' => [
|
||||
'' => esc_html__( 'None', 'elementor-pro' ),
|
||||
'bullets' => esc_html__( 'Dots', 'elementor-pro' ),
|
||||
'fraction' => esc_html__( 'Fraction', 'elementor-pro' ),
|
||||
'progressbar' => esc_html__( 'Progress', 'elementor-pro' ),
|
||||
],
|
||||
'prefix_class' => 'elementor-pagination-type-',
|
||||
'render_type' => 'template',
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'speed',
|
||||
[
|
||||
'label' => esc_html__( 'Transition Duration', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::NUMBER,
|
||||
'default' => 500,
|
||||
'render_type' => 'none',
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'autoplay',
|
||||
[
|
||||
'label' => esc_html__( 'Autoplay', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'default' => 'yes',
|
||||
'separator' => 'before',
|
||||
'render_type' => 'none',
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'autoplay_speed',
|
||||
[
|
||||
'label' => esc_html__( 'Autoplay Speed', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::NUMBER,
|
||||
'default' => 5000,
|
||||
'condition' => [
|
||||
'autoplay' => 'yes',
|
||||
],
|
||||
'render_type' => 'none',
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'loop',
|
||||
[
|
||||
'label' => esc_html__( 'Infinite Loop', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'default' => 'yes',
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pause_on_hover',
|
||||
[
|
||||
'label' => esc_html__( 'Pause on Hover', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'default' => 'yes',
|
||||
'condition' => [
|
||||
'autoplay' => 'yes',
|
||||
],
|
||||
'render_type' => 'none',
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pause_on_interaction',
|
||||
[
|
||||
'label' => esc_html__( 'Pause on Interaction', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'default' => 'yes',
|
||||
'condition' => [
|
||||
'autoplay' => 'yes',
|
||||
],
|
||||
'render_type' => 'none',
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Image_Size::get_type(),
|
||||
[
|
||||
'name' => 'image_size',
|
||||
'default' => 'full',
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'lazyload',
|
||||
[
|
||||
'label' => esc_html__( 'Lazyload', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'separator' => 'before',
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_slides_style',
|
||||
[
|
||||
'label' => esc_html__( 'Slides', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
]
|
||||
);
|
||||
|
||||
$space_between_config = [
|
||||
'label' => esc_html__( 'Space Between', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 50,
|
||||
],
|
||||
],
|
||||
'render_type' => 'none',
|
||||
'frontend_available' => true,
|
||||
];
|
||||
|
||||
// TODO: Once Core 3.4.0 is out, get the active devices using Breakpoints/Manager::get_active_devices_list().
|
||||
$active_breakpoint_instances = Plugin::elementor()->breakpoints->get_active_breakpoints();
|
||||
// Devices need to be ordered from largest to smallest.
|
||||
$active_devices = array_reverse( array_keys( $active_breakpoint_instances ) );
|
||||
|
||||
// Add desktop in the correct position.
|
||||
if ( in_array( 'widescreen', $active_devices, true ) ) {
|
||||
$active_devices = array_merge( array_slice( $active_devices, 0, 1 ), [ 'desktop' ], array_slice( $active_devices, 1 ) );
|
||||
} else {
|
||||
$active_devices = array_merge( [ 'desktop' ], $active_devices );
|
||||
}
|
||||
|
||||
foreach ( $active_devices as $active_device ) {
|
||||
$space_between_config[ $active_device . '_default' ] = [
|
||||
'size' => 10,
|
||||
];
|
||||
}
|
||||
|
||||
$this->add_responsive_control(
|
||||
'space_between',
|
||||
$space_between_config
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'slide_background_color',
|
||||
[
|
||||
'label' => esc_html__( 'Background Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-main-swiper .swiper-slide' => 'background-color: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'slide_border_size',
|
||||
[
|
||||
'label' => esc_html__( 'Border Width', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::DIMENSIONS,
|
||||
'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-main-swiper .swiper-slide' => 'border-width: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'slide_border_radius',
|
||||
[
|
||||
'label' => esc_html__( 'Border Radius', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
|
||||
'range' => [
|
||||
'%' => [
|
||||
'max' => 50,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-main-swiper .swiper-slide' => 'border-radius: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'slide_border_color',
|
||||
[
|
||||
'label' => esc_html__( 'Border Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-main-swiper .swiper-slide' => 'border-color: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'slide_padding',
|
||||
[
|
||||
'label' => esc_html__( 'Padding', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::DIMENSIONS,
|
||||
'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-main-swiper .swiper-slide' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}}',
|
||||
],
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_navigation',
|
||||
[
|
||||
'label' => esc_html__( 'Navigation', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'heading_arrows',
|
||||
[
|
||||
'label' => esc_html__( 'Arrows', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::HEADING,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'arrows_size',
|
||||
[
|
||||
'label' => esc_html__( 'Size', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
|
||||
'default' => [
|
||||
'size' => 20,
|
||||
],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 100,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 10,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 10,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-swiper-button' => 'font-size: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'arrows_color',
|
||||
[
|
||||
'label' => esc_html__( 'Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-swiper-button' => 'color: {{VALUE}}',
|
||||
'{{WRAPPER}} .elementor-swiper-button svg' => 'fill: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'heading_pagination',
|
||||
[
|
||||
'label' => esc_html__( 'Pagination', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::HEADING,
|
||||
'condition' => [
|
||||
'pagination!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pagination_position',
|
||||
[
|
||||
'label' => esc_html__( 'Position', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => 'outside',
|
||||
'options' => [
|
||||
'outside' => esc_html__( 'Outside', 'elementor-pro' ),
|
||||
'inside' => esc_html__( 'Inside', 'elementor-pro' ),
|
||||
],
|
||||
'prefix_class' => 'elementor-pagination-position-',
|
||||
'condition' => [
|
||||
'pagination!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$swiper_class = Plugin::elementor()->experiments->is_feature_active( 'e_swiper_latest' ) ? 'swiper' : 'swiper-container';
|
||||
|
||||
$this->add_responsive_control(
|
||||
'pagination_size',
|
||||
[
|
||||
'label' => esc_html__( 'Size', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 100,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 10,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 10,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .swiper-pagination-bullet' => 'height: {{SIZE}}{{UNIT}}; width: {{SIZE}}{{UNIT}}',
|
||||
'{{WRAPPER}} .' . $swiper_class . '-horizontal .swiper-pagination-progressbar' => 'height: {{SIZE}}{{UNIT}}',
|
||||
'{{WRAPPER}} .swiper-pagination-fraction' => 'font-size: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
'condition' => [
|
||||
'pagination!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pagination_color_inactive',
|
||||
[
|
||||
'label' => esc_html__( 'Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
// The opacity property will override the default inactive dot color which is opacity 0.2.
|
||||
'{{WRAPPER}} .swiper-pagination-bullet:not(.swiper-pagination-bullet-active)' => 'background-color: {{VALUE}}; opacity: 1;',
|
||||
],
|
||||
'condition' => [
|
||||
'pagination!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pagination_color',
|
||||
[
|
||||
'label' => esc_html__( 'Active Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .swiper-pagination-bullet-active, {{WRAPPER}} .swiper-pagination-progressbar-fill' => 'background-color: {{VALUE}}',
|
||||
'{{WRAPPER}} .swiper-pagination-fraction' => 'color: {{VALUE}}',
|
||||
],
|
||||
'condition' => [
|
||||
'pagination!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
}
|
||||
|
||||
protected function print_slider( array $settings = null ) {
|
||||
if ( null === $settings ) {
|
||||
$settings = $this->get_settings_for_display();
|
||||
}
|
||||
|
||||
$default_settings = [
|
||||
'container_class' => 'elementor-main-swiper',
|
||||
'video_play_icon' => true,
|
||||
];
|
||||
|
||||
$settings = array_merge( $default_settings, $settings );
|
||||
|
||||
$slides_count = count( $settings['slides'] );
|
||||
$swiper_class = Plugin::elementor()->experiments->is_feature_active( 'e_swiper_latest' ) ? 'swiper' : 'swiper-container';
|
||||
?>
|
||||
<div class="elementor-swiper">
|
||||
<div class="<?php echo esc_attr( $settings['container_class'] ); ?> <?php echo esc_attr( $swiper_class ); ?>">
|
||||
<div class="swiper-wrapper">
|
||||
<?php
|
||||
foreach ( $settings['slides'] as $index => $slide ) :
|
||||
$this->slide_prints_count++;
|
||||
?>
|
||||
<div class="swiper-slide">
|
||||
<?php $this->print_slide( $slide, $settings, 'slide-' . $index . '-' . $this->slide_prints_count ); ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php if ( 1 < $slides_count ) : ?>
|
||||
<?php if ( $settings['pagination'] ) : ?>
|
||||
<div class="swiper-pagination"></div>
|
||||
<?php endif; ?>
|
||||
<?php if ( $settings['show_arrows'] ) : ?>
|
||||
<div class="elementor-swiper-button elementor-swiper-button-prev" role="button" tabindex="0">
|
||||
<?php $this->render_swiper_button( 'previous' ); ?>
|
||||
<span class="elementor-screen-only"><?php echo esc_html__( 'Previous', 'elementor-pro' ); ?></span>
|
||||
</div>
|
||||
<div class="elementor-swiper-button elementor-swiper-button-next" role="button" tabindex="0">
|
||||
<?php $this->render_swiper_button( 'next' ); ?>
|
||||
<span class="elementor-screen-only"><?php echo esc_html__( 'Next', 'elementor-pro' ); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function get_slide_image_url( $slide, array $settings ) {
|
||||
$image_url = Group_Control_Image_Size::get_attachment_image_src( $slide['image']['id'], 'image_size', $settings );
|
||||
|
||||
if ( ! $image_url ) {
|
||||
$image_url = $slide['image']['url'];
|
||||
}
|
||||
|
||||
return $image_url;
|
||||
}
|
||||
|
||||
protected function get_slide_image_alt_attribute( $slide ) {
|
||||
if ( ! empty( $slide['name'] ) ) {
|
||||
return $slide['name'];
|
||||
}
|
||||
|
||||
if ( ! empty( $slide['image']['alt'] ) ) {
|
||||
return $slide['image']['alt'];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private function render_swiper_button( $type ) {
|
||||
$direction = 'next' === $type ? 'right' : 'left';
|
||||
|
||||
if ( is_rtl() ) {
|
||||
$direction = 'right' === $direction ? 'left' : 'right';
|
||||
}
|
||||
|
||||
$icon_value = 'eicon-chevron-' . $direction;
|
||||
|
||||
Icons_Manager::render_icon( [
|
||||
'library' => 'eicons',
|
||||
'value' => $icon_value,
|
||||
], [ 'aria-hidden' => 'true' ] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,828 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\Carousel\Widgets;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use Elementor\Control_Media;
|
||||
use Elementor\Core\Kits\Documents\Tabs\Global_Typography;
|
||||
use Elementor\Embed;
|
||||
use Elementor\Group_Control_Text_Shadow;
|
||||
use Elementor\Group_Control_Typography;
|
||||
use Elementor\Icons_Manager;
|
||||
use Elementor\Repeater;
|
||||
use Elementor\Utils;
|
||||
use ElementorPro\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Media_Carousel extends Base {
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $lightbox_slide_index;
|
||||
|
||||
public function get_name() {
|
||||
return 'media-carousel';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'Media Carousel', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_icon() {
|
||||
return 'eicon-media-carousel';
|
||||
}
|
||||
|
||||
public function get_keywords() {
|
||||
return [ 'media', 'carousel', 'image', 'video', 'lightbox' ];
|
||||
}
|
||||
|
||||
protected function render() {
|
||||
$settings = $this->get_active_settings();
|
||||
|
||||
if ( $settings['overlay'] ) {
|
||||
$this->add_render_attribute( 'image-overlay', 'class', [
|
||||
'elementor-carousel-image-overlay',
|
||||
'e-overlay-animation-' . $settings['overlay_animation'],
|
||||
] );
|
||||
}
|
||||
|
||||
$this->print_slider();
|
||||
|
||||
if ( 'slideshow' !== $settings['skin'] || count( $settings['slides'] ) <= 1 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$settings['thumbs_slider'] = true;
|
||||
$settings['container_class'] = 'elementor-thumbnails-swiper';
|
||||
$settings['show_arrows'] = false;
|
||||
|
||||
$this->print_slider( $settings );
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
parent::register_controls();
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_lightbox_style',
|
||||
[
|
||||
'label' => esc_html__( 'Lightbox', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'lightbox_color',
|
||||
[
|
||||
'label' => esc_html__( 'Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'#elementor-lightbox-slideshow-{{ID}}' => 'background-color: {{VALUE}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'lightbox_ui_color',
|
||||
[
|
||||
'label' => esc_html__( 'UI Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'#elementor-lightbox-slideshow-{{ID}} .dialog-lightbox-close-button, #elementor-lightbox-slideshow-{{ID}} .elementor-swiper-button' => 'color: {{VALUE}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'lightbox_ui_hover_color',
|
||||
[
|
||||
'label' => esc_html__( 'UI Hover Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'#elementor-lightbox-slideshow-{{ID}} .dialog-lightbox-close-button:hover, #elementor-lightbox-slideshow-{{ID}} .elementor-swiper-button:hover' => 'color: {{VALUE}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'lightbox_video_width',
|
||||
[
|
||||
'label' => esc_html__( 'Video Width', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
|
||||
'default' => [
|
||||
'unit' => '%',
|
||||
],
|
||||
'range' => [
|
||||
'%' => [
|
||||
'min' => 50,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'#elementor-lightbox-slideshow-{{ID}} .elementor-video-container' => 'width: {{SIZE}}{{UNIT}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->add_injections();
|
||||
|
||||
$this->update_controls();
|
||||
}
|
||||
|
||||
protected function add_repeater_controls( Repeater $repeater ) {
|
||||
$repeater->add_control(
|
||||
'type',
|
||||
[
|
||||
'type' => Controls_Manager::CHOOSE,
|
||||
'label' => esc_html__( 'Type', 'elementor-pro' ),
|
||||
'default' => 'image',
|
||||
'options' => [
|
||||
'image' => [
|
||||
'title' => esc_html__( 'Image', 'elementor-pro' ),
|
||||
'icon' => 'eicon-image-bold',
|
||||
],
|
||||
'video' => [
|
||||
'title' => esc_html__( 'Video', 'elementor-pro' ),
|
||||
'icon' => 'eicon-video-camera',
|
||||
],
|
||||
],
|
||||
'toggle' => false,
|
||||
]
|
||||
);
|
||||
|
||||
$repeater->add_control(
|
||||
'image',
|
||||
[
|
||||
'label' => esc_html__( 'Image', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::MEDIA,
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$repeater->add_control(
|
||||
'image_link_to_type',
|
||||
[
|
||||
'label' => esc_html__( 'Link', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => [
|
||||
'' => esc_html__( 'None', 'elementor-pro' ),
|
||||
'file' => esc_html__( 'Media File', 'elementor-pro' ),
|
||||
'custom' => esc_html__( 'Custom URL', 'elementor-pro' ),
|
||||
],
|
||||
'condition' => [
|
||||
'type' => 'image',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$repeater->add_control(
|
||||
'image_link_to',
|
||||
[
|
||||
'type' => Controls_Manager::URL,
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
'placeholder' => esc_html__( 'https://your-link.com', 'elementor-pro' ),
|
||||
'show_external' => 'true',
|
||||
'condition' => [
|
||||
'type' => 'image',
|
||||
'image_link_to_type' => 'custom',
|
||||
],
|
||||
'show_label' => false,
|
||||
]
|
||||
);
|
||||
|
||||
$repeater->add_control(
|
||||
'video',
|
||||
[
|
||||
'label' => esc_html__( 'Video Link', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::URL,
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
'placeholder' => esc_html__( 'Enter your video link', 'elementor-pro' ),
|
||||
'description' => esc_html__( 'YouTube or Vimeo link', 'elementor-pro' ),
|
||||
'options' => false,
|
||||
'condition' => [
|
||||
'type' => 'video',
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
protected function get_default_slides_count() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
protected function get_repeater_defaults() {
|
||||
$placeholder_image_src = Utils::get_placeholder_image_src();
|
||||
|
||||
return array_fill( 0, $this->get_default_slides_count(), [
|
||||
'image' => [
|
||||
'url' => $placeholder_image_src,
|
||||
],
|
||||
] );
|
||||
}
|
||||
|
||||
protected function get_image_caption( $slide ) {
|
||||
$caption_type = $this->get_settings( 'caption' );
|
||||
|
||||
if ( empty( $caption_type ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$attachment_post = get_post( $slide['image']['id'] );
|
||||
|
||||
if ( 'caption' === $caption_type ) {
|
||||
return $attachment_post->post_excerpt;
|
||||
}
|
||||
|
||||
if ( 'title' === $caption_type ) {
|
||||
return $attachment_post->post_title;
|
||||
}
|
||||
|
||||
return $attachment_post->post_content;
|
||||
}
|
||||
|
||||
protected function get_image_link_to( $slide ) {
|
||||
if ( ! empty( $slide['video']['url'] ) ) {
|
||||
return $slide['image']['url'] ? $slide['image']['url'] : '#';
|
||||
}
|
||||
|
||||
if ( ! $slide['image_link_to_type'] ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( 'custom' === $slide['image_link_to_type'] ) {
|
||||
return $slide['image_link_to']['url'];
|
||||
}
|
||||
|
||||
return $slide['image']['url'];
|
||||
}
|
||||
|
||||
protected function print_slider( array $settings = null ) {
|
||||
$this->lightbox_slide_index = 0;
|
||||
|
||||
parent::print_slider( $settings );
|
||||
}
|
||||
|
||||
protected function print_slide( array $slide, array $settings, $element_key ) {
|
||||
if ( ! empty( $settings['thumbs_slider'] ) ) {
|
||||
$settings['video_play_icon'] = false;
|
||||
}
|
||||
|
||||
$this->add_render_attribute( $element_key . '-image', [
|
||||
'class' => 'elementor-carousel-image',
|
||||
'role' => 'img',
|
||||
'aria-label' => Control_Media::get_image_alt( $slide['image'] ),
|
||||
] );
|
||||
|
||||
$img_src = $this->get_slide_image_url( $slide, $settings );
|
||||
|
||||
if ( 'yes' === $settings['lazyload'] ) {
|
||||
$img_attribute['class'] = 'swiper-lazy';
|
||||
$img_attribute['data-background'] = $img_src;
|
||||
} else {
|
||||
$img_attribute['style'] = "background-image: url('" . $img_src . "')";
|
||||
}
|
||||
|
||||
$this->add_render_attribute( $element_key . '-image', $img_attribute );
|
||||
|
||||
$image_link_to = $this->get_image_link_to( $slide );
|
||||
|
||||
if ( $image_link_to && empty( $settings['thumbs_slider'] ) ) {
|
||||
if ( 'custom' === $slide['image_link_to_type'] ) {
|
||||
$this->add_link_attributes( $element_key . '_link', $slide['image_link_to'] );
|
||||
} else {
|
||||
$this->add_render_attribute( $element_key . '_link', 'href', esc_url( $image_link_to ) );
|
||||
|
||||
$this->add_lightbox_data_attributes( $element_key . '_link', $slide['image']['id'], 'yes', $this->get_id() );
|
||||
|
||||
if ( Plugin::elementor()->editor->is_edit_mode() ) {
|
||||
$this->add_render_attribute( $element_key . '_link', 'class', 'elementor-clickable' );
|
||||
}
|
||||
|
||||
$this->lightbox_slide_index++;
|
||||
}
|
||||
|
||||
if ( 'video' === $slide['type'] && $slide['video']['url'] ) {
|
||||
$embed_url_params = [
|
||||
'autoplay' => 1,
|
||||
'rel' => 0,
|
||||
'controls' => 0,
|
||||
];
|
||||
|
||||
$this->add_render_attribute( $element_key . '_link', 'data-elementor-lightbox-video', Embed::get_embed_url( $slide['video']['url'], $embed_url_params ) );
|
||||
}
|
||||
|
||||
// PHPCS - the method get_render_attribute_string is safe.
|
||||
echo '<a ' . $this->get_render_attribute_string( $element_key . '_link' ) . '>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
$this->print_slide_image( $slide, $element_key, $settings );
|
||||
|
||||
if ( $image_link_to ) {
|
||||
echo '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
protected function print_slide_image( array $slide, $element_key, array $settings ) {
|
||||
?>
|
||||
<div <?php $this->print_render_attribute_string( $element_key . '-image' ); ?>>
|
||||
|
||||
<?php if ( 'yes' === $settings['lazyload'] ) : ?>
|
||||
<div class="swiper-lazy-preloader"></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( 'video' === $slide['type'] && $settings['video_play_icon'] ) : ?>
|
||||
<div class="elementor-custom-embed-play">
|
||||
<?php
|
||||
Icons_Manager::render_icon( [
|
||||
'library' => 'eicons',
|
||||
'value' => 'eicon-play',
|
||||
], [ 'aria-hidden' => 'true' ] );
|
||||
?>
|
||||
<span class="elementor-screen-only"><?php echo esc_html__( 'Play', 'elementor-pro' ); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if ( $settings['overlay'] ) : ?>
|
||||
<div <?php $this->print_render_attribute_string( 'image-overlay' ); ?>>
|
||||
<?php
|
||||
if ( 'text' === $settings['overlay'] ) {
|
||||
echo wp_kses_post( $this->get_image_caption( $slide ) );
|
||||
} else {
|
||||
$this->render_overlay_icon( $settings['icon'] );
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
}
|
||||
|
||||
private function add_injections() {
|
||||
$this->start_injection( [
|
||||
'type' => 'section',
|
||||
'at' => 'start',
|
||||
'of' => 'section_slides',
|
||||
] );
|
||||
|
||||
$this->add_control(
|
||||
'skin',
|
||||
[
|
||||
'label' => esc_html__( 'Skin', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => 'carousel',
|
||||
'options' => [
|
||||
'carousel' => esc_html__( 'Carousel', 'elementor-pro' ),
|
||||
'slideshow' => esc_html__( 'Slideshow', 'elementor-pro' ),
|
||||
'coverflow' => esc_html__( 'Coverflow', 'elementor-pro' ),
|
||||
],
|
||||
'prefix_class' => 'elementor-skin-',
|
||||
'render_type' => 'template',
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_injection();
|
||||
|
||||
$this->start_injection( [
|
||||
'of' => 'image_size_custom_dimension',
|
||||
] );
|
||||
|
||||
$this->add_control(
|
||||
'image_fit',
|
||||
[
|
||||
'label' => esc_html__( 'Image Fit', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => '',
|
||||
'options' => [
|
||||
'' => esc_html__( 'Cover', 'elementor-pro' ),
|
||||
'contain' => esc_html__( 'Contain', 'elementor-pro' ),
|
||||
'auto' => esc_html__( 'Auto', 'elementor-pro' ),
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-main-swiper .elementor-carousel-image' => 'background-size: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_injection();
|
||||
|
||||
$this->start_injection( [
|
||||
'of' => 'pagination_color',
|
||||
] );
|
||||
|
||||
$this->add_control(
|
||||
'play_icon_title',
|
||||
[
|
||||
'label' => esc_html__( 'Play Icon', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::HEADING,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'play_icon_color',
|
||||
[
|
||||
'label' => esc_html__( 'Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-custom-embed-play i' => 'color: {{VALUE}}',
|
||||
'{{WRAPPER}} .elementor-custom-embed-play svg' => 'fill: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'play_icon_size',
|
||||
[
|
||||
'label' => esc_html__( 'Size', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'min' => 20,
|
||||
'max' => 150,
|
||||
],
|
||||
'em' => [
|
||||
'min' => 2,
|
||||
'max' => 15,
|
||||
],
|
||||
'rem' => [
|
||||
'min' => 2,
|
||||
'max' => 15,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-custom-embed-play i' => 'font-size: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Text_Shadow::get_type(),
|
||||
[
|
||||
'name' => 'play_icon_text_shadow',
|
||||
'selector' => '{{WRAPPER}} .elementor-custom-embed-play i',
|
||||
'fields_options' => [
|
||||
'text_shadow_type' => [
|
||||
'label' => _x( 'Shadow', 'Text Shadow Control', 'elementor-pro' ),
|
||||
],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_injection();
|
||||
|
||||
$this->start_injection( [
|
||||
'of' => 'pause_on_interaction',
|
||||
] );
|
||||
|
||||
$this->add_control(
|
||||
'overlay',
|
||||
[
|
||||
'label' => esc_html__( 'Overlay', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => '',
|
||||
'options' => [
|
||||
'' => esc_html__( 'None', 'elementor-pro' ),
|
||||
'text' => esc_html__( 'Text', 'elementor-pro' ),
|
||||
'icon' => esc_html__( 'Icon', 'elementor-pro' ),
|
||||
],
|
||||
'condition' => [
|
||||
'skin!' => 'slideshow',
|
||||
],
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'caption',
|
||||
[
|
||||
'label' => esc_html__( 'Caption', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => 'title',
|
||||
'options' => [
|
||||
'title' => esc_html__( 'Title', 'elementor-pro' ),
|
||||
'caption' => esc_html__( 'Caption', 'elementor-pro' ),
|
||||
'description' => esc_html__( 'Description', 'elementor-pro' ),
|
||||
],
|
||||
'condition' => [
|
||||
'skin!' => 'slideshow',
|
||||
'overlay' => 'text',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'icon',
|
||||
[
|
||||
'label' => esc_html__( 'Icon', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::CHOOSE,
|
||||
'default' => 'search-plus',
|
||||
'options' => [
|
||||
'search-plus' => [
|
||||
'icon' => 'eicon-search-bold',
|
||||
],
|
||||
'plus-circle' => [
|
||||
'icon' => 'eicon-plus-circle',
|
||||
],
|
||||
'eye' => [
|
||||
'icon' => 'eicon-preview-medium',
|
||||
],
|
||||
'link' => [
|
||||
'icon' => 'eicon-link',
|
||||
],
|
||||
],
|
||||
'condition' => [
|
||||
'skin!' => 'slideshow',
|
||||
'overlay' => 'icon',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'overlay_animation',
|
||||
[
|
||||
'label' => esc_html__( 'Animation', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => 'fade',
|
||||
'options' => [
|
||||
'fade' => 'Fade',
|
||||
'slide-up' => 'Slide Up',
|
||||
'slide-down' => 'Slide Down',
|
||||
'slide-right' => 'Slide Right',
|
||||
'slide-left' => 'Slide Left',
|
||||
'zoom-in' => 'Zoom In',
|
||||
],
|
||||
'condition' => [
|
||||
'skin!' => 'slideshow',
|
||||
'overlay!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_injection();
|
||||
|
||||
$this->start_injection( [
|
||||
'type' => 'section',
|
||||
'of' => 'section_navigation',
|
||||
] );
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_overlay',
|
||||
[
|
||||
'label' => esc_html__( 'Overlay', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
'condition' => [
|
||||
'skin!' => 'slideshow',
|
||||
'overlay!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'overlay_background_color',
|
||||
[
|
||||
'label' => esc_html__( 'Background Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-carousel-image-overlay' => 'background-color: {{VALUE}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'overlay_color',
|
||||
[
|
||||
'label' => esc_html__( 'Text Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-carousel-image-overlay' => '--e-carousel-image-overlay-color: {{VALUE}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Typography::get_type(),
|
||||
[
|
||||
'name' => 'caption_typography',
|
||||
'global' => [
|
||||
'default' => Global_Typography::TYPOGRAPHY_ACCENT,
|
||||
],
|
||||
'selector' => '{{WRAPPER}} .elementor-carousel-image-overlay',
|
||||
'condition' => [
|
||||
'overlay' => 'text',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'icon_size',
|
||||
[
|
||||
'label' => esc_html__( 'Icon Size', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-carousel-image-overlay' => '--e-carousel-image-overlay-icon-size: {{SIZE}}{{UNIT}};',
|
||||
],
|
||||
'condition' => [
|
||||
'overlay' => 'icon',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->end_injection();
|
||||
|
||||
// Slideshow
|
||||
|
||||
$this->start_injection( [
|
||||
'of' => 'effect',
|
||||
] );
|
||||
|
||||
$this->add_responsive_control(
|
||||
'slideshow_height',
|
||||
[
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'label' => esc_html__( 'Height', 'elementor-pro' ),
|
||||
'size_units' => [ 'px', 'em', 'rem', 'vh', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'min' => 20,
|
||||
'max' => 1000,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-main-swiper' => 'height: {{SIZE}}{{UNIT}};',
|
||||
],
|
||||
'condition' => [
|
||||
'skin' => 'slideshow',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'thumbs_title',
|
||||
[
|
||||
'label' => esc_html__( 'Thumbnails', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::HEADING,
|
||||
'condition' => [
|
||||
'skin' => 'slideshow',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_injection();
|
||||
|
||||
$this->start_injection( [
|
||||
'of' => 'slides_per_view',
|
||||
] );
|
||||
|
||||
$this->add_control(
|
||||
'thumbs_ratio',
|
||||
[
|
||||
'label' => esc_html__( 'Ratio', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => [
|
||||
'169' => '16:9',
|
||||
'219' => '21:9',
|
||||
'43' => '4:3',
|
||||
'11' => '1:1',
|
||||
],
|
||||
'selectors_dictionary' => [
|
||||
'169' => '16 / 9',
|
||||
'219' => '21 / 9',
|
||||
'43' => '4 / 3',
|
||||
'11' => '1 / 1',
|
||||
],
|
||||
'default' => '219',
|
||||
'condition' => [
|
||||
'skin' => 'slideshow',
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-thumbnails-swiper .elementor-carousel-image' => 'aspect-ratio: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'centered_slides',
|
||||
[
|
||||
'label' => esc_html__( 'Centered Slides', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'condition' => [
|
||||
'skin' => 'slideshow',
|
||||
],
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_injection();
|
||||
|
||||
$this->start_injection( [
|
||||
'of' => 'slides_per_view',
|
||||
] );
|
||||
|
||||
$slides_per_view = range( 1, 10 );
|
||||
|
||||
$slides_per_view = array_combine( $slides_per_view, $slides_per_view );
|
||||
|
||||
$this->add_responsive_control(
|
||||
'slideshow_slides_per_view',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'label' => esc_html__( 'Slides Per View', 'elementor-pro' ),
|
||||
'options' => [ '' => esc_html__( 'Default', 'elementor-pro' ) ] + $slides_per_view,
|
||||
'condition' => [
|
||||
'skin' => 'slideshow',
|
||||
],
|
||||
'frontend_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_injection();
|
||||
}
|
||||
|
||||
private function update_controls() {
|
||||
$carousel_controls = [
|
||||
'slides_to_scroll',
|
||||
'pagination',
|
||||
'heading_pagination',
|
||||
'pagination_size',
|
||||
'pagination_position',
|
||||
'pagination_color',
|
||||
];
|
||||
|
||||
$carousel_responsive_controls = [
|
||||
'width',
|
||||
'height',
|
||||
'slides_per_view',
|
||||
];
|
||||
|
||||
foreach ( $carousel_controls as $control_id ) {
|
||||
$this->update_control(
|
||||
$control_id,
|
||||
[
|
||||
'condition' => [
|
||||
'skin!' => 'slideshow',
|
||||
],
|
||||
],
|
||||
[ 'recursive' => true ]
|
||||
);
|
||||
}
|
||||
|
||||
foreach ( $carousel_responsive_controls as $control_id ) {
|
||||
$this->update_responsive_control(
|
||||
$control_id,
|
||||
[
|
||||
'condition' => [
|
||||
'skin!' => 'slideshow',
|
||||
],
|
||||
],
|
||||
[ 'recursive' => true ]
|
||||
);
|
||||
}
|
||||
|
||||
$this->update_responsive_control(
|
||||
'space_between',
|
||||
[
|
||||
'selectors' => [
|
||||
'{{WRAPPER}}.elementor-skin-slideshow .elementor-main-swiper' => 'margin-bottom: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
'render_type' => 'ui',
|
||||
]
|
||||
);
|
||||
|
||||
$this->update_control(
|
||||
'effect',
|
||||
[
|
||||
'condition' => [
|
||||
'skin!' => 'coverflow',
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function get_group_name() {
|
||||
return 'carousel';
|
||||
}
|
||||
|
||||
private function render_overlay_icon( $icon_name ) {
|
||||
$icon_value = 'fas fa-' . $icon_name;
|
||||
|
||||
$icon = [
|
||||
'library' => 'fa-solid',
|
||||
'value' => $icon_value,
|
||||
];
|
||||
|
||||
Icons_Manager::render_icon( $icon );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,908 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\Carousel\Widgets;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use Elementor\Core\Kits\Documents\Tabs\Global_Typography;
|
||||
use Elementor\Group_Control_Typography;
|
||||
use Elementor\Icons_Manager;
|
||||
use Elementor\Repeater;
|
||||
use Elementor\Utils;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Reviews extends Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'reviews';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'Reviews', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_icon() {
|
||||
return 'eicon-review';
|
||||
}
|
||||
|
||||
public function get_keywords() {
|
||||
return [ 'reviews', 'social', 'rating', 'testimonial', 'carousel' ];
|
||||
}
|
||||
|
||||
public function get_inline_css_depends() {
|
||||
$slides = $this->get_settings_for_display( 'slides' );
|
||||
|
||||
foreach ( $slides as $slide ) {
|
||||
if ( $slide['rating'] ) {
|
||||
return [
|
||||
[
|
||||
'name' => 'star-rating',
|
||||
'is_core_dependency' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
parent::register_controls();
|
||||
|
||||
$this->update_control(
|
||||
'slide_padding',
|
||||
[
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__header' => 'padding-top: {{TOP}}{{UNIT}}; padding-left: {{LEFT}}{{UNIT}}; padding-right: {{RIGHT}}{{UNIT}};',
|
||||
'{{WRAPPER}} .elementor-testimonial__content' => 'padding-bottom: {{BOTTOM}}{{UNIT}}; padding-left: {{LEFT}}{{UNIT}}; padding-right: {{RIGHT}}{{UNIT}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->start_injection( [
|
||||
'of' => 'slide_padding',
|
||||
] );
|
||||
|
||||
$this->add_control(
|
||||
'heading_header',
|
||||
[
|
||||
'label' => esc_html__( 'Header', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::HEADING,
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'header_background_color',
|
||||
[
|
||||
'label' => esc_html__( 'Background Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__header' => 'background-color: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'content_gap',
|
||||
[
|
||||
'label' => esc_html__( 'Gap', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 100,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 10,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 10,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__header' => 'padding-block-end: calc( {{SIZE}}{{UNIT}} / 2 )',
|
||||
'{{WRAPPER}} .elementor-testimonial__content' => 'padding-block-start: calc( {{SIZE}}{{UNIT}} / 2 )',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'show_separator',
|
||||
[
|
||||
'label' => esc_html__( 'Separator', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'label_off' => esc_html__( 'Hide', 'elementor-pro' ),
|
||||
'label_on' => esc_html__( 'Show', 'elementor-pro' ),
|
||||
'default' => 'has-separator',
|
||||
'return_value' => 'has-separator',
|
||||
'prefix_class' => 'elementor-review--',
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'separator_color',
|
||||
[
|
||||
'label' => esc_html__( 'Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__header' => 'border-block-end-color: {{VALUE}}',
|
||||
],
|
||||
'condition' => [
|
||||
'show_separator!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'separator_size',
|
||||
[
|
||||
'label' => esc_html__( 'Size', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 20,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 2,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 2,
|
||||
],
|
||||
],
|
||||
'condition' => [
|
||||
'show_separator!' => '',
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__header' => 'border-block-end-width: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_injection();
|
||||
|
||||
$this->start_injection( [
|
||||
'at' => 'before',
|
||||
'of' => 'section_navigation',
|
||||
] );
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_content_style',
|
||||
[
|
||||
'label' => esc_html__( 'Text', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'name_title_style',
|
||||
[
|
||||
'label' => esc_html__( 'Name', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::HEADING,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'name_color',
|
||||
[
|
||||
'label' => esc_html__( 'Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__name' => 'color: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Typography::get_type(),
|
||||
[
|
||||
'name' => 'name_typography',
|
||||
'selector' => '{{WRAPPER}} .elementor-testimonial__header, {{WRAPPER}} .elementor-testimonial__name',
|
||||
'global' => [
|
||||
'default' => Global_Typography::TYPOGRAPHY_PRIMARY,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'heading_title_style',
|
||||
[
|
||||
'label' => esc_html__( 'Title', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::HEADING,
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'title_color',
|
||||
[
|
||||
'label' => esc_html__( 'Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__title' => 'color: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Typography::get_type(),
|
||||
[
|
||||
'name' => 'title_typography',
|
||||
'selector' => '{{WRAPPER}} .elementor-testimonial__title',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'heading_review_style',
|
||||
[
|
||||
'label' => esc_html__( 'Review', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::HEADING,
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'content_color',
|
||||
[
|
||||
'label' => esc_html__( 'Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__text' => 'color: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Typography::get_type(),
|
||||
[
|
||||
'name' => 'content_typography',
|
||||
'selector' => '{{WRAPPER}} .elementor-testimonial__text',
|
||||
'global' => [
|
||||
'default' => Global_Typography::TYPOGRAPHY_TEXT,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_image_style',
|
||||
[
|
||||
'label' => esc_html__( 'Image', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'image_size',
|
||||
[
|
||||
'label' => esc_html__( 'Size', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 100,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 10,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 10,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__image img' => 'width: {{SIZE}}{{UNIT}}; height: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'image_gap',
|
||||
[
|
||||
'label' => esc_html__( 'Gap', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 100,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 10,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 10,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__image + cite' => 'margin-inline-start: {{SIZE}}{{UNIT}}; margin-inline-end: 0;',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'image_border_radius',
|
||||
[
|
||||
'label' => esc_html__( 'Border Radius', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__image img' => 'border-radius: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_icon_style',
|
||||
[
|
||||
'label' => esc_html__( 'Icon', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'icon_color',
|
||||
[
|
||||
'label' => esc_html__( 'Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => 'default',
|
||||
'options' => [
|
||||
'default' => esc_html__( 'Official', 'elementor-pro' ),
|
||||
'custom' => esc_html__( 'Custom', 'elementor-pro' ),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'icon_custom_color',
|
||||
[
|
||||
'label' => esc_html__( 'Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'condition' => [
|
||||
'icon_color' => 'custom',
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__icon:not(.elementor-testimonial__rating)' => 'color: {{VALUE}};',
|
||||
'{{WRAPPER}} .elementor-testimonial__icon:not(.elementor-testimonial__rating) svg' => 'fill: {{VALUE}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'icon_size',
|
||||
[
|
||||
'label' => esc_html__( 'Size', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 100,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 10,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 10,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__icon' => 'font-size: {{SIZE}}{{UNIT}}',
|
||||
'{{WRAPPER}} .elementor-testimonial__icon svg' => 'width: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_rating_style',
|
||||
[
|
||||
'label' => esc_html__( 'Rating', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'star_style',
|
||||
[
|
||||
'label' => esc_html__( 'Icon', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => [
|
||||
'star_fontawesome' => 'Font Awesome',
|
||||
'star_unicode' => 'Unicode',
|
||||
],
|
||||
'default' => 'star_fontawesome',
|
||||
'render_type' => 'template',
|
||||
'prefix_class' => 'elementor--star-style-',
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'unmarked_star_style',
|
||||
[
|
||||
'label' => esc_html__( 'Unmarked Style', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::CHOOSE,
|
||||
'options' => [
|
||||
'solid' => [
|
||||
'title' => esc_html__( 'Solid', 'elementor-pro' ),
|
||||
'icon' => 'eicon-star',
|
||||
],
|
||||
'outline' => [
|
||||
'title' => esc_html__( 'Outline', 'elementor-pro' ),
|
||||
'icon' => 'eicon-star-o',
|
||||
],
|
||||
],
|
||||
'default' => 'solid',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'star_size',
|
||||
[
|
||||
'label' => esc_html__( 'Size', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 100,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 10,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 10,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-star-rating' => 'font-size: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'star_space',
|
||||
[
|
||||
'label' => esc_html__( 'Spacing', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 50,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 5,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 5,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-star-rating i:not(:last-of-type)' => 'margin-inline-end: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'stars_color',
|
||||
[
|
||||
'label' => esc_html__( 'Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-star-rating i:before' => 'color: {{VALUE}}',
|
||||
],
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'stars_unmarked_color',
|
||||
[
|
||||
'label' => esc_html__( 'Unmarked Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-star-rating i' => 'color: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->end_injection();
|
||||
|
||||
$this->update_responsive_control(
|
||||
'width',
|
||||
[
|
||||
'selectors' => [
|
||||
'{{WRAPPER}}.elementor-arrows-yes .elementor-main-swiper' => 'width: calc( {{SIZE}}{{UNIT}} - 40px )',
|
||||
'{{WRAPPER}} .elementor-main-swiper' => 'width: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->update_responsive_control(
|
||||
'slides_per_view',
|
||||
[
|
||||
'condition' => null,
|
||||
]
|
||||
);
|
||||
|
||||
$this->update_control(
|
||||
'slides_to_scroll',
|
||||
[
|
||||
'condition' => null,
|
||||
]
|
||||
);
|
||||
|
||||
$this->remove_control( 'effect' );
|
||||
$this->remove_responsive_control( 'height' );
|
||||
$this->remove_control( 'pagination_position' );
|
||||
}
|
||||
|
||||
protected function add_repeater_controls( Repeater $repeater ) {
|
||||
$repeater->add_control(
|
||||
'image',
|
||||
[
|
||||
'label' => esc_html__( 'Image', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::MEDIA,
|
||||
'default' => [
|
||||
'url' => Utils::get_placeholder_image_src(),
|
||||
],
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$repeater->add_control(
|
||||
'name',
|
||||
[
|
||||
'label' => esc_html__( 'Name', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXT,
|
||||
'default' => esc_html__( 'John Doe', 'elementor-pro' ),
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
'ai' => [
|
||||
'active' => false,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$repeater->add_control(
|
||||
'title',
|
||||
[
|
||||
'label' => esc_html__( 'Title', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXT,
|
||||
'default' => '@username',
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$repeater->add_control(
|
||||
'rating',
|
||||
[
|
||||
'label' => esc_html__( 'Rating', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::NUMBER,
|
||||
'min' => 0,
|
||||
'max' => 5,
|
||||
'step' => 0.1,
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$repeater->add_control(
|
||||
'selected_social_icon',
|
||||
[
|
||||
'label' => esc_html__( 'Icon', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::ICONS,
|
||||
'fa4compatibility' => 'social_icon',
|
||||
'default' => [
|
||||
'value' => 'fab fa-twitter',
|
||||
'library' => 'fa-brands',
|
||||
],
|
||||
'recommended' => [
|
||||
'fa-solid' => [
|
||||
'rss',
|
||||
'shopping-cart',
|
||||
'thumbtack',
|
||||
],
|
||||
'fa-brands' => [
|
||||
'android',
|
||||
'apple',
|
||||
'behance',
|
||||
'bitbucket',
|
||||
'codepen',
|
||||
'delicious',
|
||||
'digg',
|
||||
'dribbble',
|
||||
'envelope',
|
||||
'facebook',
|
||||
'flickr',
|
||||
'foursquare',
|
||||
'github',
|
||||
'google-plus',
|
||||
'houzz',
|
||||
'instagram',
|
||||
'jsfiddle',
|
||||
'linkedin',
|
||||
'medium',
|
||||
'meetup',
|
||||
'mix',
|
||||
'mixcloud',
|
||||
'odnoklassniki',
|
||||
'pinterest',
|
||||
'product-hunt',
|
||||
'reddit',
|
||||
'skype',
|
||||
'slideshare',
|
||||
'snapchat',
|
||||
'soundcloud',
|
||||
'spotify',
|
||||
'stack-overflow',
|
||||
'steam',
|
||||
'telegram',
|
||||
'threads',
|
||||
'tripadvisor',
|
||||
'tumblr',
|
||||
'twitch',
|
||||
'twitter',
|
||||
'vimeo',
|
||||
'fa-vk',
|
||||
'weibo',
|
||||
'weixin',
|
||||
'whatsapp',
|
||||
'wordpress',
|
||||
'x-twitter',
|
||||
'xing',
|
||||
'yelp',
|
||||
'youtube',
|
||||
'500px',
|
||||
],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$repeater->add_control(
|
||||
'link',
|
||||
[
|
||||
'label' => esc_html__( 'Link', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::URL,
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
'placeholder' => esc_html__( 'https://your-link.com', 'elementor-pro' ),
|
||||
|
||||
]
|
||||
);
|
||||
|
||||
$repeater->add_control(
|
||||
'content',
|
||||
[
|
||||
'label' => esc_html__( 'Review', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXTAREA,
|
||||
'default' => esc_html__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.', 'elementor-pro' ),
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
protected function get_repeater_defaults() {
|
||||
$placeholder_image_src = Utils::get_placeholder_image_src();
|
||||
|
||||
return [
|
||||
[
|
||||
'content' => esc_html__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.', 'elementor-pro' ),
|
||||
'name' => esc_html__( 'John Doe', 'elementor-pro' ),
|
||||
'title' => '@username',
|
||||
'image' => [
|
||||
'url' => $placeholder_image_src,
|
||||
],
|
||||
],
|
||||
[
|
||||
'content' => esc_html__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.', 'elementor-pro' ),
|
||||
'name' => esc_html__( 'John Doe', 'elementor-pro' ),
|
||||
'title' => '@username',
|
||||
'image' => [
|
||||
'url' => $placeholder_image_src,
|
||||
],
|
||||
],
|
||||
[
|
||||
'content' => esc_html__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.', 'elementor-pro' ),
|
||||
'name' => esc_html__( 'John Doe', 'elementor-pro' ),
|
||||
'title' => '@username',
|
||||
'image' => [
|
||||
'url' => $placeholder_image_src,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function print_cite( $slide, $settings ) {
|
||||
if ( empty( $slide['name'] ) && empty( $slide['title'] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$html = '<cite class="elementor-testimonial__cite">';
|
||||
|
||||
if ( ! empty( $slide['name'] ) ) {
|
||||
$html .= '<span class="elementor-testimonial__name">' . $slide['name'] . '</span>';
|
||||
}
|
||||
|
||||
if ( ! empty( $slide['rating'] ) ) {
|
||||
$html .= $this->render_stars( $slide, $settings );
|
||||
}
|
||||
|
||||
if ( ! empty( $slide['title'] ) ) {
|
||||
$html .= '<span class="elementor-testimonial__title">' . $slide['title'] . '</span>';
|
||||
}
|
||||
$html .= '</cite>';
|
||||
|
||||
echo wp_kses_post( $html );
|
||||
}
|
||||
|
||||
protected function render_stars( $slide, $settings ) {
|
||||
$icon = '';
|
||||
|
||||
if ( 'star_fontawesome' === $settings['star_style'] ) {
|
||||
if ( 'outline' === $settings['unmarked_star_style'] ) {
|
||||
$icon = '';
|
||||
}
|
||||
} elseif ( 'star_unicode' === $settings['star_style'] ) {
|
||||
$icon = '★';
|
||||
|
||||
if ( 'outline' === $settings['unmarked_star_style'] ) {
|
||||
$icon = '☆';
|
||||
}
|
||||
}
|
||||
|
||||
$rating = (float) $slide['rating'] > 5 ? 5 : $slide['rating'];
|
||||
$floored_rating = (int) $rating;
|
||||
$stars_html = '';
|
||||
|
||||
for ( $stars = 1; $stars <= 5; $stars++ ) {
|
||||
if ( $stars <= $floored_rating ) {
|
||||
$stars_html .= '<i class="elementor-star-full">' . $icon . '</i>';
|
||||
} elseif ( $floored_rating + 1 === $stars && $rating !== $floored_rating ) {
|
||||
$stars_html .= '<i class="elementor-star-' . ( $rating - $floored_rating ) * 10 . '">' . $icon . '</i>';
|
||||
} else {
|
||||
$stars_html .= '<i class="elementor-star-empty">' . $icon . '</i>';
|
||||
}
|
||||
}
|
||||
|
||||
return '<div class="elementor-star-rating">' . $stars_html . '</div>';
|
||||
}
|
||||
|
||||
private function print_icon( $slide, $element_key ) {
|
||||
$migration_allowed = Icons_Manager::is_migration_allowed();
|
||||
if ( ! isset( $slide['social_icon'] ) && ! $migration_allowed ) {
|
||||
// add old default
|
||||
$slide['social_icon'] = 'fa fa-twitter';
|
||||
}
|
||||
|
||||
if ( empty( $slide['social_icon'] ) && empty( $slide['selected_social_icon'] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$migrated = isset( $slide['__fa4_migrated']['selected_social_icon'] );
|
||||
$is_new = empty( $slide['social_icon'] ) && $migration_allowed;
|
||||
$social = '';
|
||||
|
||||
if ( $is_new || $migrated ) {
|
||||
ob_start();
|
||||
Icons_Manager::render_icon( $slide['selected_social_icon'], [ 'aria-hidden' => 'true' ] );
|
||||
$icon = ob_get_clean();
|
||||
} else {
|
||||
$icon = '<i class="' . esc_attr( $slide['social_icon'] ) . '" aria-hidden="true"></i>';
|
||||
}
|
||||
|
||||
if ( ! empty( $slide['social_icon'] ) ) {
|
||||
$social = str_replace( 'fa fa-', '', $slide['social_icon'] );
|
||||
}
|
||||
|
||||
if ( ( $is_new || $migrated ) && 'svg' !== $slide['selected_social_icon']['library'] ) {
|
||||
$social = explode( ' ', $slide['selected_social_icon']['value'], 2 );
|
||||
if ( empty( $social[1] ) ) {
|
||||
$social = '';
|
||||
} else {
|
||||
$social = str_replace( 'fa-', '', $social[1] );
|
||||
}
|
||||
}
|
||||
if ( 'svg' === $slide['selected_social_icon']['library'] ) {
|
||||
$social = '';
|
||||
}
|
||||
|
||||
$this->add_render_attribute( 'icon_wrapper_' . $element_key, 'class', 'elementor-testimonial__icon elementor-icon' );
|
||||
|
||||
$icon .= '<span class="elementor-screen-only">' . esc_html__( 'Read More', 'elementor-pro' ) . '</span>';
|
||||
$this->add_render_attribute( 'icon_wrapper_' . $element_key, 'class', 'elementor-icon-' . $social );
|
||||
|
||||
// Icon is escaped above, get_render_attribute_string() is safe
|
||||
echo '<div ' . $this->get_render_attribute_string( 'icon_wrapper_' . $element_key ) . '>' . $icon . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
protected function print_slide( array $slide, array $settings, $element_key ) {
|
||||
$lazyload = 'yes' === $this->get_settings( 'lazyload' );
|
||||
|
||||
$this->add_render_attribute( $element_key . '-testimonial', [
|
||||
'class' => 'elementor-testimonial',
|
||||
] );
|
||||
|
||||
$this->add_render_attribute( $element_key . '-testimonial', [
|
||||
'class' => 'elementor-repeater-item-' . $slide['_id'],
|
||||
] );
|
||||
|
||||
if ( ! empty( $slide['image']['url'] ) ) {
|
||||
$img_src = $this->get_slide_image_url( $slide, $settings );
|
||||
|
||||
if ( $lazyload ) {
|
||||
$img_attribute['class'] = 'swiper-lazy';
|
||||
$img_attribute['data-src'] = $img_src;
|
||||
} else {
|
||||
$img_attribute['src'] = $img_src;
|
||||
}
|
||||
|
||||
$img_attribute['alt'] = $this->get_slide_image_alt_attribute( $slide );
|
||||
|
||||
$this->add_render_attribute( $element_key . '-image', $img_attribute );
|
||||
}
|
||||
|
||||
?>
|
||||
<div <?php $this->print_render_attribute_string( $element_key . '-testimonial' ); ?>>
|
||||
<?php if ( $slide['image']['url'] || ! empty( $slide['name'] ) || ! empty( $slide['title'] ) ) :
|
||||
|
||||
$link_url = empty( $slide['link']['url'] ) ? false : $slide['link']['url'];
|
||||
$header_tag = ! empty( $link_url ) ? 'a' : 'div';
|
||||
$header_element = 'header_' . $slide['_id'];
|
||||
|
||||
$this->add_render_attribute( $header_element, 'class', 'elementor-testimonial__header' );
|
||||
|
||||
if ( ! empty( $link_url ) ) {
|
||||
$this->add_link_attributes( $header_element, $slide['link'] );
|
||||
}
|
||||
?>
|
||||
<<?php Utils::print_validated_html_tag( $header_tag ); ?> <?php $this->print_render_attribute_string( $header_element ); ?>>
|
||||
<?php if ( $slide['image']['url'] ) : ?>
|
||||
<div class="elementor-testimonial__image">
|
||||
<img <?php $this->print_render_attribute_string( $element_key . '-image' ); ?>>
|
||||
<?php if ( $lazyload ) : ?>
|
||||
<div class="swiper-lazy-preloader"></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php $this->print_cite( $slide, $settings ); ?>
|
||||
<?php $this->print_icon( $slide, $element_key ); ?>
|
||||
</<?php Utils::print_validated_html_tag( $header_tag ); ?>>
|
||||
<?php endif; ?>
|
||||
<?php if ( $slide['content'] ) : ?>
|
||||
<div class="elementor-testimonial__content">
|
||||
<div class="elementor-testimonial__text">
|
||||
<?php
|
||||
// Main content allowed
|
||||
echo $slide['content']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function render() {
|
||||
$this->print_slider();
|
||||
}
|
||||
|
||||
public function get_group_name() {
|
||||
return 'carousel';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,710 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\Carousel\Widgets;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use Elementor\Core\Kits\Documents\Tabs\Global_Colors;
|
||||
use Elementor\Core\Kits\Documents\Tabs\Global_Typography;
|
||||
use Elementor\Group_Control_Typography;
|
||||
use Elementor\Group_Control_Text_Stroke;
|
||||
use Elementor\Repeater;
|
||||
use Elementor\Utils;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Testimonial_Carousel extends Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'testimonial-carousel';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'Testimonial Carousel', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_icon() {
|
||||
return 'eicon-testimonial-carousel';
|
||||
}
|
||||
|
||||
public function get_keywords() {
|
||||
return [ 'testimonial', 'carousel', 'image' ];
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
parent::register_controls();
|
||||
|
||||
$this->start_injection( [
|
||||
'of' => 'slides',
|
||||
] );
|
||||
|
||||
$this->add_control(
|
||||
'skin',
|
||||
[
|
||||
'label' => esc_html__( 'Skin', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => 'default',
|
||||
'options' => [
|
||||
'default' => esc_html__( 'Default', 'elementor-pro' ),
|
||||
'bubble' => esc_html__( 'Bubble', 'elementor-pro' ),
|
||||
],
|
||||
'prefix_class' => 'elementor-testimonial--skin-',
|
||||
'render_type' => 'template',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'layout',
|
||||
[
|
||||
'label' => esc_html__( 'Layout', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => 'image_inline',
|
||||
'options' => [
|
||||
'image_inline' => esc_html__( 'Image Inline', 'elementor-pro' ),
|
||||
'image_stacked' => esc_html__( 'Image Stacked', 'elementor-pro' ),
|
||||
'image_above' => esc_html__( 'Image Above', 'elementor-pro' ),
|
||||
'image_left' => esc_html__( 'Image Left', 'elementor-pro' ),
|
||||
'image_right' => esc_html__( 'Image Right', 'elementor-pro' ),
|
||||
],
|
||||
'prefix_class' => 'elementor-testimonial--layout-',
|
||||
'render_type' => 'template',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'alignment',
|
||||
[
|
||||
'label' => esc_html__( 'Alignment', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::CHOOSE,
|
||||
'default' => 'center',
|
||||
'options' => [
|
||||
'left' => [
|
||||
'title' => esc_html__( 'Left', 'elementor-pro' ),
|
||||
'icon' => 'eicon-text-align-left',
|
||||
],
|
||||
'center' => [
|
||||
'title' => esc_html__( 'Center', 'elementor-pro' ),
|
||||
'icon' => 'eicon-text-align-center',
|
||||
],
|
||||
'right' => [
|
||||
'title' => esc_html__( 'Right', 'elementor-pro' ),
|
||||
'icon' => 'eicon-text-align-right',
|
||||
],
|
||||
],
|
||||
'prefix_class' => 'elementor-testimonial-%s-align-',
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_injection();
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_skin_style',
|
||||
[
|
||||
'label' => esc_html__( 'Bubble', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
'condition' => [
|
||||
'skin' => 'bubble',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'background_color',
|
||||
[
|
||||
'label' => esc_html__( 'Background Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'alpha' => false,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__content, {{WRAPPER}} .elementor-testimonial__content:after' => 'background-color: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'text_padding',
|
||||
[
|
||||
'label' => esc_html__( 'Padding', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::DIMENSIONS,
|
||||
'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
|
||||
'default' => [
|
||||
'top' => '20',
|
||||
'bottom' => '20',
|
||||
'left' => '20',
|
||||
'right' => '20',
|
||||
'unit' => 'px',
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__content' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}}',
|
||||
'{{WRAPPER}}.elementor-testimonial--layout-image_left .elementor-testimonial__footer,
|
||||
{{WRAPPER}}.elementor-testimonial--layout-image_right .elementor-testimonial__footer' => 'padding-top: {{TOP}}{{UNIT}}',
|
||||
'{{WRAPPER}}.elementor-testimonial--layout-image_above .elementor-testimonial__footer,
|
||||
{{WRAPPER}}.elementor-testimonial--layout-image_inline .elementor-testimonial__footer,
|
||||
{{WRAPPER}}.elementor-testimonial--layout-image_stacked .elementor-testimonial__footer' => 'padding: 0 {{RIGHT}}{{UNIT}} 0 {{LEFT}}{{UNIT}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'border_radius',
|
||||
[
|
||||
'label' => esc_html__( 'Border Radius', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::DIMENSIONS,
|
||||
'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__content' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'border',
|
||||
[
|
||||
'label' => esc_html__( 'Border', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__content, {{WRAPPER}} .elementor-testimonial__content:after' => 'border-style: solid',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'border_color',
|
||||
[
|
||||
'label' => esc_html__( 'Border Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'default' => '#000',
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__content' => 'border-color: {{VALUE}}',
|
||||
'{{WRAPPER}} .elementor-testimonial__content:after' => 'border-color: transparent {{VALUE}} {{VALUE}} transparent',
|
||||
],
|
||||
'condition' => [
|
||||
'border' => 'yes',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'border_width',
|
||||
[
|
||||
'label' => esc_html__( 'Border Width', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 20,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 2,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 2,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__content, {{WRAPPER}} .elementor-testimonial__content:after' => 'border-width: {{SIZE}}{{UNIT}}',
|
||||
'{{WRAPPER}}.elementor-testimonial--layout-image_stacked .elementor-testimonial__content:after,
|
||||
{{WRAPPER}}.elementor-testimonial--layout-image_inline .elementor-testimonial__content:after' => 'margin-top: -{{SIZE}}{{UNIT}}',
|
||||
'{{WRAPPER}}.elementor-testimonial--layout-image_above .elementor-testimonial__content:after' => 'margin-bottom: -{{SIZE}}{{UNIT}}',
|
||||
],
|
||||
'condition' => [
|
||||
'border' => 'yes',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->start_injection( [
|
||||
'at' => 'before',
|
||||
'of' => 'section_navigation',
|
||||
] );
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_content_style',
|
||||
[
|
||||
'label' => esc_html__( 'Content', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'content_gap',
|
||||
[
|
||||
'label' => esc_html__( 'Gap', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 100,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 10,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 10,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}}.elementor-testimonial--layout-image_inline .elementor-testimonial__footer,
|
||||
{{WRAPPER}}.elementor-testimonial--layout-image_stacked .elementor-testimonial__footer' => 'margin-top: {{SIZE}}{{UNIT}}',
|
||||
'{{WRAPPER}}.elementor-testimonial--layout-image_above .elementor-testimonial__footer' => 'margin-bottom: {{SIZE}}{{UNIT}}',
|
||||
'{{WRAPPER}}.elementor-testimonial--layout-image_left .elementor-testimonial__footer' => 'padding-right: {{SIZE}}{{UNIT}}',
|
||||
'{{WRAPPER}}.elementor-testimonial--layout-image_right .elementor-testimonial__footer' => 'padding-left: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'content_color',
|
||||
[
|
||||
'label' => esc_html__( 'Text Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__text' => 'color: {{VALUE}}',
|
||||
],
|
||||
'global' => [
|
||||
'default' => Global_Colors::COLOR_TEXT,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Typography::get_type(),
|
||||
[
|
||||
'name' => 'content_typography',
|
||||
'selector' => '{{WRAPPER}} .elementor-testimonial__text',
|
||||
'global' => [
|
||||
'default' => Global_Typography::TYPOGRAPHY_TEXT,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Text_Stroke::get_type(),
|
||||
[
|
||||
'name' => 'text_stroke',
|
||||
'selector' => '{{WRAPPER}} .elementor-testimonial__text',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'name_title_style',
|
||||
[
|
||||
'label' => esc_html__( 'Name', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::HEADING,
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'name_color',
|
||||
[
|
||||
'label' => esc_html__( 'Text Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__name' => 'color: {{VALUE}}',
|
||||
],
|
||||
'global' => [
|
||||
'default' => Global_Colors::COLOR_TEXT,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Typography::get_type(),
|
||||
[
|
||||
'name' => 'name_typography',
|
||||
'selector' => '{{WRAPPER}} .elementor-testimonial__name',
|
||||
'global' => [
|
||||
'default' => Global_Typography::TYPOGRAPHY_PRIMARY,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'heading_title_style',
|
||||
[
|
||||
'label' => esc_html__( 'Title', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::HEADING,
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'title_color',
|
||||
[
|
||||
'label' => esc_html__( 'Text Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__title' => 'color: {{VALUE}}',
|
||||
],
|
||||
'global' => [
|
||||
'default' => Global_Colors::COLOR_PRIMARY,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Typography::get_type(),
|
||||
[
|
||||
'name' => 'title_typography',
|
||||
'selector' => '{{WRAPPER}} .elementor-testimonial__title',
|
||||
'global' => [
|
||||
'default' => Global_Typography::TYPOGRAPHY_SECONDARY,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_image_style',
|
||||
[
|
||||
'label' => esc_html__( 'Image', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'image_size',
|
||||
[
|
||||
'label' => esc_html__( 'Size', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 200,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 20,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 20,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__image img' => 'width: {{SIZE}}{{UNIT}}; height: {{SIZE}}{{UNIT}}',
|
||||
'{{WRAPPER}}.elementor-testimonial--layout-image_left .elementor-testimonial__content:after,
|
||||
{{WRAPPER}}.elementor-testimonial--layout-image_right .elementor-testimonial__content:after' => 'top: calc( {{text_padding.TOP}}{{text_padding.UNIT}} + ({{SIZE}}{{UNIT}} / 2) - 8px );',
|
||||
|
||||
'body:not(.rtl) {{WRAPPER}}.elementor-testimonial--layout-image_stacked:not(.elementor-testimonial--align-center):not(.elementor-testimonial--align-right) .elementor-testimonial__content:after,
|
||||
body:not(.rtl) {{WRAPPER}}.elementor-testimonial--layout-image_inline:not(.elementor-testimonial--align-center):not(.elementor-testimonial--align-right) .elementor-testimonial__content:after,
|
||||
{{WRAPPER}}.elementor-testimonial--layout-image_stacked.elementor-testimonial--align-left .elementor-testimonial__content:after,
|
||||
{{WRAPPER}}.elementor-testimonial--layout-image_inline.elementor-testimonial--align-left .elementor-testimonial__content:after' => 'left: calc( {{text_padding.LEFT}}{{text_padding.UNIT}} + ({{SIZE}}{{UNIT}} / 2) - 8px ); right:auto;',
|
||||
|
||||
'body.rtl {{WRAPPER}}.elementor-testimonial--layout-image_stacked:not(.elementor-testimonial--align-center):not(.elementor-testimonial--align-left) .elementor-testimonial__content:after,
|
||||
body.rtl {{WRAPPER}}.elementor-testimonial--layout-image_inline:not(.elementor-testimonial--align-center):not(.elementor-testimonial--align-left) .elementor-testimonial__content:after,
|
||||
{{WRAPPER}}.elementor-testimonial--layout-image_stacked.elementor-testimonial--align-right .elementor-testimonial__content:after,
|
||||
{{WRAPPER}}.elementor-testimonial--layout-image_inline.elementor-testimonial--align-right .elementor-testimonial__content:after' => 'right: calc( {{text_padding.RIGHT}}{{text_padding.UNIT}} + ({{SIZE}}{{UNIT}} / 2) - 8px ); left:auto;',
|
||||
|
||||
'body:not(.rtl) {{WRAPPER}}.elementor-testimonial--layout-image_above:not(.elementor-testimonial--align-center):not(.elementor-testimonial--align-right) .elementor-testimonial__content:after,
|
||||
{{WRAPPER}}.elementor-testimonial--layout-image_above.elementor-testimonial--align-left .elementor-testimonial__content:after' => 'left: calc( {{text_padding.LEFT}}{{text_padding.UNIT}} + ({{SIZE}}{{UNIT}} / 2) - 8px ); right:auto;',
|
||||
|
||||
'body.rtl {{WRAPPER}}.elementor-testimonial--layout-image_above:not(.elementor-testimonial--align-center):not(.elementor-testimonial--align-left) .elementor-testimonial__content:after,
|
||||
{{WRAPPER}}.elementor-testimonial--layout-image_above.elementor-testimonial--align-right .elementor-testimonial__content:after' => 'right: calc( {{text_padding.RIGHT}}{{text_padding.UNIT}} + ({{SIZE}}{{UNIT}} / 2) - 8px ); left:auto;',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'image_gap',
|
||||
[
|
||||
'label' => esc_html__( 'Gap', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 100,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 10,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 10,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'body.rtl {{WRAPPER}}.elementor-testimonial--layout-image_inline.elementor-testimonial--align-left .elementor-testimonial__image + cite,
|
||||
body.rtl {{WRAPPER}}.elementor-testimonial--layout-image_above.elementor-testimonial--align-left .elementor-testimonial__image + cite,
|
||||
body:not(.rtl) {{WRAPPER}}.elementor-testimonial--layout-image_inline .elementor-testimonial__image + cite,
|
||||
body:not(.rtl) {{WRAPPER}}.elementor-testimonial--layout-image_above .elementor-testimonial__image + cite' => 'margin-left: {{SIZE}}{{UNIT}}; margin-right: 0;',
|
||||
|
||||
'body:not(.rtl) {{WRAPPER}}.elementor-testimonial--layout-image_inline.elementor-testimonial--align-right .elementor-testimonial__image + cite,
|
||||
body:not(.rtl) {{WRAPPER}}.elementor-testimonial--layout-image_above.elementor-testimonial--align-right .elementor-testimonial__image + cite,
|
||||
body.rtl {{WRAPPER}}.elementor-testimonial--layout-image_inline .elementor-testimonial__image + cite,
|
||||
body.rtl {{WRAPPER}}.elementor-testimonial--layout-image_above .elementor-testimonial__image + cite' => 'margin-right: {{SIZE}}{{UNIT}}; margin-left:0;',
|
||||
|
||||
'{{WRAPPER}}.elementor-testimonial--layout-image_stacked .elementor-testimonial__image + cite,
|
||||
{{WRAPPER}}.elementor-testimonial--layout-image_left .elementor-testimonial__image + cite,
|
||||
{{WRAPPER}}.elementor-testimonial--layout-image_right .elementor-testimonial__image + cite' => 'margin-top: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'image_border',
|
||||
[
|
||||
'label' => esc_html__( 'Border', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__image img' => 'border-style: solid',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'image_border_color',
|
||||
[
|
||||
'label' => esc_html__( 'Border Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'default' => '#000',
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__image img' => 'border-color: {{VALUE}}',
|
||||
],
|
||||
'condition' => [
|
||||
'image_border' => 'yes',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'image_border_width',
|
||||
[
|
||||
'label' => esc_html__( 'Border Width', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 20,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 2,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 2,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__image img' => 'border-width: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
'condition' => [
|
||||
'image_border' => 'yes',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'image_border_radius',
|
||||
[
|
||||
'label' => esc_html__( 'Border Radius', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-testimonial__image img' => 'border-radius: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->end_injection();
|
||||
|
||||
$this->update_responsive_control(
|
||||
'width',
|
||||
[
|
||||
'selectors' => [
|
||||
'{{WRAPPER}}.elementor-arrows-yes .elementor-main-swiper' => 'width: calc( {{SIZE}}{{UNIT}} - 40px )',
|
||||
'{{WRAPPER}} .elementor-main-swiper' => 'width: {{SIZE}}{{UNIT}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->update_responsive_control(
|
||||
'slides_per_view',
|
||||
[
|
||||
'condition' => null,
|
||||
]
|
||||
);
|
||||
|
||||
$this->update_responsive_control(
|
||||
'slides_to_scroll',
|
||||
[
|
||||
'condition' => null,
|
||||
]
|
||||
);
|
||||
|
||||
$this->remove_control( 'effect' );
|
||||
$this->remove_responsive_control( 'height' );
|
||||
$this->remove_control( 'pagination_position' );
|
||||
}
|
||||
|
||||
protected function add_repeater_controls( Repeater $repeater ) {
|
||||
$repeater->add_control(
|
||||
'content',
|
||||
[
|
||||
'label' => esc_html__( 'Content', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXTAREA,
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$repeater->add_control(
|
||||
'image',
|
||||
[
|
||||
'label' => esc_html__( 'Image', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::MEDIA,
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$repeater->add_control(
|
||||
'name',
|
||||
[
|
||||
'label' => esc_html__( 'Name', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXT,
|
||||
'default' => esc_html__( 'John Doe', 'elementor-pro' ),
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
'ai' => [
|
||||
'active' => false,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$repeater->add_control(
|
||||
'title',
|
||||
[
|
||||
'label' => esc_html__( 'Title', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXT,
|
||||
'default' => esc_html__( 'CEO', 'elementor-pro' ),
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
'ai' => [
|
||||
'active' => false,
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
protected function get_repeater_defaults() {
|
||||
$placeholder_image_src = Utils::get_placeholder_image_src();
|
||||
|
||||
return [
|
||||
[
|
||||
'content' => esc_html__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.', 'elementor-pro' ),
|
||||
'name' => esc_html__( 'John Doe', 'elementor-pro' ),
|
||||
'title' => esc_html__( 'CEO', 'elementor-pro' ),
|
||||
'image' => [
|
||||
'url' => $placeholder_image_src,
|
||||
],
|
||||
],
|
||||
[
|
||||
'content' => esc_html__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.', 'elementor-pro' ),
|
||||
'name' => esc_html__( 'John Doe', 'elementor-pro' ),
|
||||
'title' => esc_html__( 'CEO', 'elementor-pro' ),
|
||||
'image' => [
|
||||
'url' => $placeholder_image_src,
|
||||
],
|
||||
],
|
||||
[
|
||||
'content' => esc_html__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.', 'elementor-pro' ),
|
||||
'name' => esc_html__( 'John Doe', 'elementor-pro' ),
|
||||
'title' => esc_html__( 'CEO', 'elementor-pro' ),
|
||||
'image' => [
|
||||
'url' => $placeholder_image_src,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function print_cite( $slide, $location ) {
|
||||
if ( empty( $slide['name'] ) && empty( $slide['title'] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$skin = $this->get_settings( 'skin' );
|
||||
$layout = 'bubble' === $skin ? 'image_inline' : $this->get_settings( 'layout' );
|
||||
$locations_outside = [ 'image_above', 'image_right', 'image_left' ];
|
||||
$locations_inside = [ 'image_inline', 'image_stacked' ];
|
||||
|
||||
$print_outside = ( 'outside' === $location && in_array( $layout, $locations_outside ) );
|
||||
$print_inside = ( 'inside' === $location && in_array( $layout, $locations_inside ) );
|
||||
|
||||
$html = '';
|
||||
if ( $print_outside || $print_inside ) {
|
||||
$html = '<cite class="elementor-testimonial__cite">';
|
||||
if ( ! empty( $slide['name'] ) ) {
|
||||
$html .= '<span class="elementor-testimonial__name">' . $slide['name'] . '</span>';
|
||||
}
|
||||
if ( ! empty( $slide['title'] ) ) {
|
||||
$html .= '<span class="elementor-testimonial__title">' . $slide['title'] . '</span>';
|
||||
}
|
||||
$html .= '</cite>';
|
||||
}
|
||||
|
||||
// PHPCS - the main text of a widget should not be escaped.
|
||||
echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
protected function print_slide( array $slide, array $settings, $element_key ) {
|
||||
$lazyload = 'yes' === $this->get_settings( 'lazyload' );
|
||||
|
||||
$this->add_render_attribute( $element_key . '-testimonial', [
|
||||
'class' => 'elementor-testimonial',
|
||||
] );
|
||||
|
||||
if ( ! empty( $slide['image']['url'] ) ) {
|
||||
$img_src = $this->get_slide_image_url( $slide, $settings );
|
||||
|
||||
if ( $lazyload ) {
|
||||
$img_attribute['class'] = 'swiper-lazy';
|
||||
$img_attribute['data-src'] = $img_src;
|
||||
} else {
|
||||
$img_attribute['src'] = $img_src;
|
||||
}
|
||||
|
||||
$img_attribute['alt'] = ! empty( $slide['image']['alt'] ) ? $slide['image']['alt'] : $slide['name'];
|
||||
|
||||
$this->add_render_attribute( $element_key . '-image', $img_attribute );
|
||||
}
|
||||
|
||||
?>
|
||||
<div <?php $this->print_render_attribute_string( $element_key . '-testimonial' ); ?>>
|
||||
<?php if ( $slide['content'] ) : ?>
|
||||
<div class="elementor-testimonial__content">
|
||||
<div class="elementor-testimonial__text">
|
||||
<?php // PHPCS - the main text of a widget should not be escaped.
|
||||
echo $slide['content']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
<?php $this->print_cite( $slide, 'outside' ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="elementor-testimonial__footer">
|
||||
<?php if ( $slide['image']['url'] ) : ?>
|
||||
<div class="elementor-testimonial__image">
|
||||
<img <?php $this->print_render_attribute_string( $element_key . '-image' ); ?>>
|
||||
<?php if ( $lazyload ) : ?>
|
||||
<div class="swiper-lazy-preloader"></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php $this->print_cite( $slide, 'inside' ); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function render() {
|
||||
$this->print_slider();
|
||||
}
|
||||
|
||||
public function get_group_name() {
|
||||
return 'carousel';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\CodeHighlight;
|
||||
|
||||
use ElementorPro\Base\Module_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends Module_Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'code-highlight';
|
||||
}
|
||||
|
||||
public function get_widgets() {
|
||||
return [
|
||||
'Code_Highlight',
|
||||
];
|
||||
}
|
||||
|
||||
public function register_frontend_scripts() {
|
||||
$base_url = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.23.0';
|
||||
wp_register_script( 'prismjs_core', $base_url . '/components/prism-core.min.js', [], '1.23.0', true );
|
||||
wp_register_script( 'prismjs_loader', $base_url . '/plugins/autoloader/prism-autoloader.min.js', [ 'prismjs_core' ], '1.23.0', true );
|
||||
wp_register_script( 'prismjs_normalize', $base_url . '/plugins/normalize-whitespace/prism-normalize-whitespace.min.js', [ 'prismjs_core' ], '1.23.0', true );
|
||||
wp_register_script( 'prismjs_line_numbers', $base_url . '/plugins/line-numbers/prism-line-numbers.min.js', [ 'prismjs_normalize' ], '1.23.0', true );
|
||||
wp_register_script( 'prismjs_line_highlight', $base_url . '/plugins/line-highlight/prism-line-highlight.min.js', [ 'prismjs_normalize' ], '1.23.0', true );
|
||||
wp_register_script( 'prismjs_toolbar', $base_url . '/plugins/toolbar/prism-toolbar.min.js', [ 'prismjs_normalize' ], '1.23.0', true );
|
||||
wp_register_script( 'prismjs_copy_to_clipboard', $base_url . '/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js', [ 'prismjs_toolbar' ], '1.23.0', true );
|
||||
|
||||
wp_register_style( 'prismjs_style', ELEMENTOR_PRO_URL . 'assets/css/modules/code-highlight.min.css', [], '1.23.0', false );
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_action( 'elementor/frontend/before_register_scripts', [ $this, 'register_frontend_scripts' ] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\CodeHighlight\Widgets;
|
||||
|
||||
use Elementor\Modules\DynamicTags\Module as TagsModule;
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Plugin;
|
||||
use ElementorPro\Base\Base_Widget;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Code_Highlight extends Base_Widget {
|
||||
|
||||
public function get_name() {
|
||||
return 'code-highlight';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'Code Highlight', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_icon() {
|
||||
return 'eicon-code-highlight';
|
||||
}
|
||||
|
||||
public function get_keywords() {
|
||||
return [ 'code', 'highlight', 'syntax', 'highlighter', 'javascript', 'css', 'php', 'html', 'java', 'js' ];
|
||||
}
|
||||
|
||||
public function get_style_depends() {
|
||||
return [ 'prismjs_style' ];
|
||||
}
|
||||
|
||||
public function get_script_depends() {
|
||||
$depends = [
|
||||
'prismjs_core' => true,
|
||||
'prismjs_loader' => true,
|
||||
'prismjs_normalize' => true,
|
||||
'highlight_handler' => true,
|
||||
'prismjs_line_numbers' => true,
|
||||
'prismjs_line_highlight' => true,
|
||||
'prismjs_copy_to_clipboard' => true,
|
||||
];
|
||||
|
||||
if ( ! Plugin::elementor()->preview->is_preview_mode() ) {
|
||||
$settings = $this->get_settings_for_display();
|
||||
|
||||
if ( ! $settings['line_numbers'] ) {
|
||||
unset( $depends['prismjs_line_numbers'] );
|
||||
}
|
||||
|
||||
if ( ! $settings['highlight_lines'] ) {
|
||||
unset( $depends['prismjs_line_highlight'] );
|
||||
}
|
||||
|
||||
if ( ! $settings['copy_to_clipboard'] ) {
|
||||
unset( $depends['prismjs_copy_to_clipboard'] );
|
||||
}
|
||||
}
|
||||
|
||||
return array_keys( $depends );
|
||||
}
|
||||
|
||||
public function get_css_config() {
|
||||
// This widget is loading its own CSS using get_style_depends.
|
||||
return [
|
||||
'key' => $this->get_group_name(),
|
||||
'version' => ELEMENTOR_PRO_VERSION,
|
||||
'file_path' => '',
|
||||
'data' => [],
|
||||
];
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
$this->start_controls_section(
|
||||
'section_content',
|
||||
[
|
||||
'label' => esc_html__( 'Code Highlight', 'elementor-pro' ),
|
||||
]
|
||||
);
|
||||
|
||||
$language_option = [
|
||||
'markup' => 'Markup',
|
||||
'html' => 'HTML',
|
||||
'css' => 'CSS',
|
||||
'sass' => 'Sass (Sass)',
|
||||
'scss' => 'Sass (Scss)',
|
||||
'less' => 'Less',
|
||||
'javascript' => 'JavaScript',
|
||||
'typescript' => 'TypeScript',
|
||||
'jsx' => 'React JSX',
|
||||
'tsx' => 'React TSX',
|
||||
'php' => 'PHP',
|
||||
'ruby' => 'Ruby',
|
||||
'json' => 'JSON + Web App Manifest',
|
||||
'http' => 'HTTP',
|
||||
'xml' => 'XML',
|
||||
'svg' => 'SVG',
|
||||
'rust' => 'Rust',
|
||||
'csharp' => 'C#',
|
||||
'dart' => 'Dart',
|
||||
'git' => 'Git',
|
||||
'java' => 'Java',
|
||||
'sql' => 'SQL',
|
||||
'go' => 'Go',
|
||||
'kotlin' => 'Kotlin + Kotlin Script',
|
||||
'julia' => 'Julia',
|
||||
'python' => 'Python',
|
||||
'swift' => 'Swift',
|
||||
'bash' => 'Bash + Shell',
|
||||
'scala' => 'Scala',
|
||||
'haskell' => 'Haskell',
|
||||
'perl' => 'Perl',
|
||||
'objectivec' => 'Objective-C',
|
||||
'visual-basic,' => 'Visual Basic + VBA',
|
||||
'r' => 'R',
|
||||
'c' => 'C',
|
||||
'cpp' => 'C++',
|
||||
'aspnet' => 'ASP.NET (C#)',
|
||||
];
|
||||
|
||||
/**
|
||||
* Code highlight languages.
|
||||
*
|
||||
* Filters the available programming languages in the code highlight.
|
||||
*
|
||||
* By default supports a code list of programming languages. This hook
|
||||
* allows developers to add or remove languages.
|
||||
*
|
||||
* @param array $language_option An array of languages.
|
||||
*/
|
||||
$language_option = apply_filters( 'elementor_pro/code_highlight/languages', $language_option );
|
||||
|
||||
$this->add_control(
|
||||
'language',
|
||||
[
|
||||
'label' => esc_html__( 'Language', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT2,
|
||||
'multiple' => false,
|
||||
'options' => $language_option,
|
||||
'default' => 'javascript',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'code',
|
||||
[
|
||||
'label' => esc_html__( 'Code', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::CODE,
|
||||
'default' => 'console.log( \'Code is Poetry\' );',
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
'categories' => [
|
||||
TagsModule::TEXT_CATEGORY,
|
||||
],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'line_numbers',
|
||||
[
|
||||
'label' => esc_html__( 'Line Numbers', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'return_value' => 'line-numbers',
|
||||
'default' => 'line-numbers',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'copy_to_clipboard',
|
||||
[
|
||||
'label' => esc_html__( 'Copy to Clipboard', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'label_on' => esc_html__( 'On', 'elementor-pro' ),
|
||||
'label_off' => esc_html__( 'Off', 'elementor-pro' ),
|
||||
'return_value' => 'copy-to-clipboard',
|
||||
'default' => 'copy-to-clipboard',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'highlight_lines',
|
||||
[
|
||||
'label' => esc_html__( 'Highlight Lines', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXT,
|
||||
'default' => '',
|
||||
'placeholder' => '1, 3-6',
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'word_wrap',
|
||||
[
|
||||
'label' => esc_html__( 'Word Wrap', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'label_on' => esc_html__( 'On', 'elementor-pro' ),
|
||||
'label_off' => esc_html__( 'Off', 'elementor-pro' ),
|
||||
'return_value' => 'word-wrap',
|
||||
'default' => '',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'theme',
|
||||
[
|
||||
'label' => esc_html__( 'Theme', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => 'default',
|
||||
'options' => [
|
||||
'default' => 'Solid',
|
||||
'dark' => 'Dark',
|
||||
'okaidia' => 'Okaidia',
|
||||
'solarizedlight' => 'Solarizedlight',
|
||||
'tomorrow' => 'Tomorrow',
|
||||
'twilight' => 'Twilight',
|
||||
],
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'height',
|
||||
[
|
||||
'label' => esc_html__( 'Height', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'vh', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'min' => 115,
|
||||
'max' => 1000,
|
||||
],
|
||||
'em' => [
|
||||
'min' => 6,
|
||||
'max' => 50,
|
||||
],
|
||||
'rem' => [
|
||||
'min' => 6,
|
||||
'max' => 50,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .highlight-height' => 'height: {{SIZE}}{{UNIT}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'font_size',
|
||||
[
|
||||
'label' => esc_html__( 'Font Size', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'vw', 'custom' ],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'min' => 1,
|
||||
'max' => 200,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 20,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 20,
|
||||
],
|
||||
'vw' => [
|
||||
'min' => 0.1,
|
||||
'max' => 10,
|
||||
'step' => 0.1,
|
||||
],
|
||||
],
|
||||
'responsive' => true,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} pre, {{WRAPPER}} code, {{WRAPPER}} .line-numbers .line-numbers-rows' => 'font-size: {{SIZE}}{{UNIT}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
}
|
||||
|
||||
protected function render() {
|
||||
$settings = $this->get_settings_for_display();
|
||||
|
||||
if ( empty( $settings['code'] ) ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<div class="<?php echo 'prismjs-' . esc_attr( $settings['theme'] ); ?> <?php echo esc_attr( $settings['copy_to_clipboard'] ); ?> <?php echo esc_attr( $settings['word_wrap'] ); ?>">
|
||||
<pre data-line="<?php echo esc_attr( $settings['highlight_lines'] ); ?>" class="highlight-height language-<?php echo esc_attr( $settings['language'] ); ?> <?php echo esc_attr( $settings['line_numbers'] ); ?>">
|
||||
<code readonly="true" class="language-<?php echo esc_attr( $settings['language'] ); ?>">
|
||||
<xmp><?php $this->print_unescaped_setting( 'code' ); ?></xmp>
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function content_template() {
|
||||
?>
|
||||
<#
|
||||
if ( '' === settings.code ) {
|
||||
return;
|
||||
}
|
||||
#>
|
||||
<div class="prismjs-{{ settings.theme }} {{ settings.copy_to_clipboard }} {{ settings.word_wrap }}">
|
||||
<pre data-line="{{ settings.highlight_lines }}" class="highlight-height language-{{ settings.language }} {{ settings.line_numbers }}">
|
||||
<code readonly="true" class="language-{{ settings.language }}">
|
||||
<xmp>{{{ settings.code }}}</xmp>
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\CompatibilityTag;
|
||||
|
||||
use Elementor\Modules\CompatibilityTag\Base_Module as Compatibility_Tag_Base_Module;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Compatibility_Tag_Component extends Compatibility_Tag_Base_Module {
|
||||
/**
|
||||
* This is the header used by extensions to show testing.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PLUGIN_VERSION_TESTED_HEADER = 'Elementor Pro tested up to';
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function get_plugin_header() {
|
||||
return self::PLUGIN_VERSION_TESTED_HEADER;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function get_plugin_label() {
|
||||
return esc_html__( 'Elementor Pro', 'elementor-pro' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function get_plugin_name() {
|
||||
return ELEMENTOR_PRO_PLUGIN_BASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function get_plugin_version() {
|
||||
return ELEMENTOR_PRO_VERSION;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\CompatibilityTag;
|
||||
|
||||
use ElementorPro\Base\Module_Base;
|
||||
use Elementor\Modules\CompatibilityTag\Base_Module as Compatibility_Tag_Base_Module;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Module extends Module_Base {
|
||||
const MODULE_NAME = 'compatibility-tag-pro';
|
||||
|
||||
/**
|
||||
* Checks if elementor core compatibility module is exists before
|
||||
* activate this module
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_active() {
|
||||
return class_exists( Compatibility_Tag_Base_Module::class );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return self::MODULE_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Module constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->add_component( 'compatibility-tag-pro-handler', new Compatibility_Tag_Component() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\Countdown;
|
||||
|
||||
use ElementorPro\Base\Module_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends Module_Base {
|
||||
|
||||
public function get_widgets() {
|
||||
return [
|
||||
'Countdown',
|
||||
];
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'countdown';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,766 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\Countdown\Widgets;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use Elementor\Core\Kits\Documents\Tabs\Global_Colors;
|
||||
use Elementor\Core\Kits\Documents\Tabs\Global_Typography;
|
||||
use Elementor\Group_Control_Border;
|
||||
use Elementor\Group_Control_Typography;
|
||||
use Elementor\Group_Control_Text_Stroke;
|
||||
use Elementor\Utils;
|
||||
use ElementorPro\Base\Base_Widget;
|
||||
use ElementorPro\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Countdown extends Base_Widget {
|
||||
|
||||
public function get_name() {
|
||||
return 'countdown';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'Countdown', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_icon() {
|
||||
return 'eicon-countdown';
|
||||
}
|
||||
|
||||
public function get_keywords() {
|
||||
return [ 'countdown', 'number', 'timer', 'time', 'date', 'evergreen' ];
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
$this->start_controls_section(
|
||||
'section_countdown',
|
||||
[
|
||||
'label' => esc_html__( 'Countdown', 'elementor-pro' ),
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'countdown_type',
|
||||
[
|
||||
'label' => esc_html__( 'Type', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => [
|
||||
'due_date' => esc_html__( 'Due Date', 'elementor-pro' ),
|
||||
'evergreen' => esc_html__( 'Evergreen Timer', 'elementor-pro' ),
|
||||
],
|
||||
'default' => 'due_date',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'due_date',
|
||||
[
|
||||
'label' => esc_html__( 'Due Date', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::DATE_TIME,
|
||||
'default' => gmdate( 'Y-m-d H:i', strtotime( '+1 month' ) + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ),
|
||||
/* translators: %s: Time zone. */
|
||||
'description' => sprintf( esc_html__( 'Date set according to your timezone: %s.', 'elementor-pro' ), Utils::get_timezone_string() ),
|
||||
'condition' => [
|
||||
'countdown_type' => 'due_date',
|
||||
],
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'evergreen_counter_hours',
|
||||
[
|
||||
'label' => esc_html__( 'Hours', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::NUMBER,
|
||||
'default' => 47,
|
||||
'placeholder' => esc_html__( 'Hours', 'elementor-pro' ),
|
||||
'condition' => [
|
||||
'countdown_type' => 'evergreen',
|
||||
],
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'evergreen_counter_minutes',
|
||||
[
|
||||
'label' => esc_html__( 'Minutes', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::NUMBER,
|
||||
'default' => 59,
|
||||
'placeholder' => esc_html__( 'Minutes', 'elementor-pro' ),
|
||||
'condition' => [
|
||||
'countdown_type' => 'evergreen',
|
||||
],
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'label_display',
|
||||
[
|
||||
'label' => esc_html__( 'View', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => [
|
||||
'block' => esc_html__( 'Block', 'elementor-pro' ),
|
||||
'inline' => esc_html__( 'Inline', 'elementor-pro' ),
|
||||
],
|
||||
'default' => 'block',
|
||||
'prefix_class' => 'elementor-countdown--label-',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'show_days',
|
||||
[
|
||||
'label' => esc_html__( 'Days', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'label_on' => esc_html__( 'Show', 'elementor-pro' ),
|
||||
'label_off' => esc_html__( 'Hide', 'elementor-pro' ),
|
||||
'default' => 'yes',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'show_hours',
|
||||
[
|
||||
'label' => esc_html__( 'Hours', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'label_on' => esc_html__( 'Show', 'elementor-pro' ),
|
||||
'label_off' => esc_html__( 'Hide', 'elementor-pro' ),
|
||||
'default' => 'yes',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'show_minutes',
|
||||
[
|
||||
'label' => esc_html__( 'Minutes', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'label_on' => esc_html__( 'Show', 'elementor-pro' ),
|
||||
'label_off' => esc_html__( 'Hide', 'elementor-pro' ),
|
||||
'default' => 'yes',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'show_seconds',
|
||||
[
|
||||
'label' => esc_html__( 'Seconds', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'label_on' => esc_html__( 'Show', 'elementor-pro' ),
|
||||
'label_off' => esc_html__( 'Hide', 'elementor-pro' ),
|
||||
'default' => 'yes',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'show_labels',
|
||||
[
|
||||
'label' => esc_html__( 'Show Label', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'label_on' => esc_html__( 'Show', 'elementor-pro' ),
|
||||
'label_off' => esc_html__( 'Hide', 'elementor-pro' ),
|
||||
'default' => 'yes',
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'custom_labels',
|
||||
[
|
||||
'label' => esc_html__( 'Custom Label', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'condition' => [
|
||||
'show_labels!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'label_days',
|
||||
[
|
||||
'label' => esc_html__( 'Days', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXT,
|
||||
'default' => esc_html__( 'Days', 'elementor-pro' ),
|
||||
'placeholder' => esc_html__( 'Days', 'elementor-pro' ),
|
||||
'condition' => [
|
||||
'show_labels!' => '',
|
||||
'custom_labels!' => '',
|
||||
'show_days' => 'yes',
|
||||
],
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
'ai' => [
|
||||
'active' => false,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'label_hours',
|
||||
[
|
||||
'label' => esc_html__( 'Hours', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXT,
|
||||
'default' => esc_html__( 'Hours', 'elementor-pro' ),
|
||||
'placeholder' => esc_html__( 'Hours', 'elementor-pro' ),
|
||||
'condition' => [
|
||||
'show_labels!' => '',
|
||||
'custom_labels!' => '',
|
||||
'show_hours' => 'yes',
|
||||
],
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
'ai' => [
|
||||
'active' => false,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'label_minutes',
|
||||
[
|
||||
'label' => esc_html__( 'Minutes', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXT,
|
||||
'default' => esc_html__( 'Minutes', 'elementor-pro' ),
|
||||
'placeholder' => esc_html__( 'Minutes', 'elementor-pro' ),
|
||||
'condition' => [
|
||||
'show_labels!' => '',
|
||||
'custom_labels!' => '',
|
||||
'show_minutes' => 'yes',
|
||||
],
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
'ai' => [
|
||||
'active' => false,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'label_seconds',
|
||||
[
|
||||
'label' => esc_html__( 'Seconds', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXT,
|
||||
'default' => esc_html__( 'Seconds', 'elementor-pro' ),
|
||||
'placeholder' => esc_html__( 'Seconds', 'elementor-pro' ),
|
||||
'condition' => [
|
||||
'show_labels!' => '',
|
||||
'custom_labels!' => '',
|
||||
'show_seconds' => 'yes',
|
||||
],
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
'ai' => [
|
||||
'active' => false,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'expire_actions',
|
||||
[
|
||||
'label' => esc_html__( 'Actions After Expire', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT2,
|
||||
'options' => [
|
||||
'redirect' => esc_html__( 'Redirect', 'elementor-pro' ),
|
||||
'hide' => esc_html__( 'Hide', 'elementor-pro' ),
|
||||
'message' => esc_html__( 'Show Message', 'elementor-pro' ),
|
||||
],
|
||||
'label_block' => true,
|
||||
'separator' => 'before',
|
||||
'render_type' => 'none',
|
||||
'multiple' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'message_after_expire',
|
||||
[
|
||||
'label' => esc_html__( 'Message', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXTAREA,
|
||||
'separator' => 'before',
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
'condition' => [
|
||||
'expire_actions' => 'message',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'expire_redirect_url',
|
||||
[
|
||||
'label' => esc_html__( 'Redirect URL', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::URL,
|
||||
'separator' => 'before',
|
||||
'options' => false,
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
'condition' => [
|
||||
'expire_actions' => 'redirect',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_box_style',
|
||||
[
|
||||
'label' => esc_html__( 'Boxes', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'container_width',
|
||||
[
|
||||
'label' => esc_html__( 'Container Width', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
|
||||
'default' => [
|
||||
'unit' => '%',
|
||||
'size' => 100,
|
||||
],
|
||||
'tablet_default' => [
|
||||
'unit' => '%',
|
||||
],
|
||||
'mobile_default' => [
|
||||
'unit' => '%',
|
||||
],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 2000,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 200,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 200,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-countdown-wrapper' => 'max-width: {{SIZE}}{{UNIT}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'box_background_color',
|
||||
[
|
||||
'label' => esc_html__( 'Background Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'global' => [
|
||||
'default' => Global_Colors::COLOR_PRIMARY,
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-countdown-item' => 'background-color: {{VALUE}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Border::get_type(),
|
||||
[
|
||||
'name' => 'box_border',
|
||||
'selector' => '{{WRAPPER}} .elementor-countdown-item',
|
||||
'separator' => 'before',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'box_border_radius',
|
||||
[
|
||||
'label' => esc_html__( 'Border Radius', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::DIMENSIONS,
|
||||
'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-countdown-item' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'box_spacing',
|
||||
[
|
||||
'label' => esc_html__( 'Space Between', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SLIDER,
|
||||
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
|
||||
'default' => [
|
||||
'size' => 10,
|
||||
],
|
||||
'range' => [
|
||||
'px' => [
|
||||
'max' => 100,
|
||||
],
|
||||
'em' => [
|
||||
'max' => 10,
|
||||
],
|
||||
'rem' => [
|
||||
'max' => 10,
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'body:not(.rtl) {{WRAPPER}} .elementor-countdown-item:not(:first-of-type)' => 'margin-left: calc( {{SIZE}}{{UNIT}}/2 );',
|
||||
'body:not(.rtl) {{WRAPPER}} .elementor-countdown-item:not(:last-of-type)' => 'margin-right: calc( {{SIZE}}{{UNIT}}/2 );',
|
||||
'body.rtl {{WRAPPER}} .elementor-countdown-item:not(:first-of-type)' => 'margin-right: calc( {{SIZE}}{{UNIT}}/2 );',
|
||||
'body.rtl {{WRAPPER}} .elementor-countdown-item:not(:last-of-type)' => 'margin-left: calc( {{SIZE}}{{UNIT}}/2 );',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'box_padding',
|
||||
[
|
||||
'label' => esc_html__( 'Padding', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::DIMENSIONS,
|
||||
'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-countdown-item' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_content_style',
|
||||
[
|
||||
'label' => esc_html__( 'Content', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'heading_digits',
|
||||
[
|
||||
'label' => esc_html__( 'Digits', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::HEADING,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'digits_color',
|
||||
[
|
||||
'label' => esc_html__( 'Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-countdown-digits' => 'color: {{VALUE}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Typography::get_type(),
|
||||
[
|
||||
'name' => 'digits_typography',
|
||||
'selector' => '{{WRAPPER}} .elementor-countdown-digits',
|
||||
'global' => [
|
||||
'default' => Global_Typography::TYPOGRAPHY_TEXT,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'heading_label',
|
||||
[
|
||||
'label' => esc_html__( 'Label', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::HEADING,
|
||||
'separator' => 'before',
|
||||
'condition' => [
|
||||
'show_labels!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'label_color',
|
||||
[
|
||||
'label' => esc_html__( 'Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-countdown-label' => 'color: {{VALUE}};',
|
||||
],
|
||||
'condition' => [
|
||||
'show_labels!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Typography::get_type(),
|
||||
[
|
||||
'name' => 'label_typography',
|
||||
'selector' => '{{WRAPPER}} .elementor-countdown-label',
|
||||
'global' => [
|
||||
'default' => Global_Typography::TYPOGRAPHY_SECONDARY,
|
||||
],
|
||||
'condition' => [
|
||||
'show_labels!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Text_Stroke::get_type(),
|
||||
[
|
||||
'name' => 'text_stroke',
|
||||
'selector' => '{{WRAPPER}} .elementor-countdown-label',
|
||||
'condition' => [
|
||||
'show_labels!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_expire_message_style',
|
||||
[
|
||||
'label' => esc_html__( 'Message', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
'condition' => [
|
||||
'expire_actions' => 'message',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'align',
|
||||
[
|
||||
'label' => esc_html__( 'Alignment', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::CHOOSE,
|
||||
'options' => [
|
||||
'left' => [
|
||||
'title' => esc_html__( 'Left', 'elementor-pro' ),
|
||||
'icon' => 'eicon-text-align-left',
|
||||
],
|
||||
'center' => [
|
||||
'title' => esc_html__( 'Center', 'elementor-pro' ),
|
||||
'icon' => 'eicon-text-align-center',
|
||||
],
|
||||
'right' => [
|
||||
'title' => esc_html__( 'Right', 'elementor-pro' ),
|
||||
'icon' => 'eicon-text-align-right',
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-countdown-expire--message' => 'text-align: {{VALUE}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'text_color',
|
||||
[
|
||||
'label' => esc_html__( 'Text Color', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'default' => '',
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-countdown-expire--message' => 'color: {{VALUE}};',
|
||||
],
|
||||
'global' => [
|
||||
'default' => Global_Colors::COLOR_TEXT,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_group_control(
|
||||
Group_Control_Typography::get_type(),
|
||||
[
|
||||
'name' => 'typography',
|
||||
'global' => [
|
||||
'default' => Global_Typography::TYPOGRAPHY_TEXT,
|
||||
],
|
||||
'selector' => '{{WRAPPER}} .elementor-countdown-expire--message',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_responsive_control(
|
||||
'message_padding',
|
||||
[
|
||||
'label' => esc_html__( 'Padding', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::DIMENSIONS,
|
||||
'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-countdown-expire--message' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
}
|
||||
|
||||
private function get_strftime( $instance ) {
|
||||
$string = '';
|
||||
if ( $instance['show_days'] ) {
|
||||
$string .= $this->render_countdown_item( $instance, 'label_days', 'elementor-countdown-days' );
|
||||
}
|
||||
if ( $instance['show_hours'] ) {
|
||||
$string .= $this->render_countdown_item( $instance, 'label_hours', 'elementor-countdown-hours' );
|
||||
}
|
||||
if ( $instance['show_minutes'] ) {
|
||||
$string .= $this->render_countdown_item( $instance, 'label_minutes', 'elementor-countdown-minutes' );
|
||||
}
|
||||
if ( $instance['show_seconds'] ) {
|
||||
$string .= $this->render_countdown_item( $instance, 'label_seconds', 'elementor-countdown-seconds' );
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
private $_default_countdown_labels;
|
||||
|
||||
private function init_default_countdown_labels() {
|
||||
$this->_default_countdown_labels = [
|
||||
'label_months' => esc_html__( 'Months', 'elementor-pro' ),
|
||||
'label_weeks' => esc_html__( 'Weeks', 'elementor-pro' ),
|
||||
'label_days' => esc_html__( 'Days', 'elementor-pro' ),
|
||||
'label_hours' => esc_html__( 'Hours', 'elementor-pro' ),
|
||||
'label_minutes' => esc_html__( 'Minutes', 'elementor-pro' ),
|
||||
'label_seconds' => esc_html__( 'Seconds', 'elementor-pro' ),
|
||||
];
|
||||
}
|
||||
|
||||
public function get_default_countdown_labels() {
|
||||
if ( ! $this->_default_countdown_labels ) {
|
||||
$this->init_default_countdown_labels();
|
||||
}
|
||||
|
||||
return $this->_default_countdown_labels;
|
||||
}
|
||||
|
||||
private function render_countdown_item( $instance, $label, $part_class ) {
|
||||
$string = '<div class="elementor-countdown-item"><span class="elementor-countdown-digits ' . $part_class . '"></span>';
|
||||
|
||||
if ( $instance['show_labels'] ) {
|
||||
$default_labels = $this->get_default_countdown_labels();
|
||||
$label = ( $instance['custom_labels'] ) ? $instance[ $label ] : $default_labels[ $label ];
|
||||
$string .= ' <span class="elementor-countdown-label">' . $label . '</span>';
|
||||
}
|
||||
|
||||
$string .= '</div>';
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
private function get_evergreen_interval( $instance ) {
|
||||
$hours = empty( $instance['evergreen_counter_hours'] ) ? 0 : ( $instance['evergreen_counter_hours'] * HOUR_IN_SECONDS );
|
||||
$minutes = empty( $instance['evergreen_counter_minutes'] ) ? 0 : ( $instance['evergreen_counter_minutes'] * MINUTE_IN_SECONDS );
|
||||
$evergreen_interval = $hours + $minutes;
|
||||
|
||||
return $evergreen_interval;
|
||||
}
|
||||
|
||||
private function get_actions( $settings ) {
|
||||
if ( empty( $settings['expire_actions'] ) || ! is_array( $settings['expire_actions'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$actions = [];
|
||||
|
||||
foreach ( $settings['expire_actions'] as $action ) {
|
||||
$action_to_run = [ 'type' => $action ];
|
||||
if ( 'redirect' === $action ) {
|
||||
if ( empty( $settings['expire_redirect_url']['url'] ) ) {
|
||||
continue;
|
||||
}
|
||||
$action_to_run['redirect_url'] = esc_url( $settings['expire_redirect_url']['url'] );
|
||||
}
|
||||
$actions[] = $action_to_run;
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
private function is_valid_url( $url ) {
|
||||
return ! preg_match( '/\bjavascript\b/i', $url ) && filter_var( $url, FILTER_VALIDATE_URL );
|
||||
}
|
||||
|
||||
private function sanitize_action( $key, $value ) {
|
||||
if ( 'redirect_url' === $key && is_string( $value ) ) {
|
||||
return $this->is_valid_url( $value ) ? esc_url( $value ) : null;
|
||||
}
|
||||
|
||||
return esc_html( $value );
|
||||
}
|
||||
|
||||
private function map_sanitized_action( $action ) {
|
||||
$sanitized_action = [];
|
||||
|
||||
foreach ( $action as $key => $value ) {
|
||||
$sanitized_action[ $key ] = $this->sanitize_action( $key, $value );
|
||||
}
|
||||
|
||||
return $sanitized_action;
|
||||
}
|
||||
|
||||
private function sanitize_redirect_url( $actions ) {
|
||||
return array_map( function ( $action ) {
|
||||
return $this->map_sanitized_action( $action );
|
||||
}, $actions );
|
||||
}
|
||||
|
||||
|
||||
protected function render() {
|
||||
$instance = $this->get_settings_for_display();
|
||||
$due_date = $instance['due_date'];
|
||||
$string = $this->get_strftime( $instance );
|
||||
|
||||
if ( 'evergreen' === $instance['countdown_type'] ) {
|
||||
$this->add_render_attribute( 'div', 'data-evergreen-interval', $this->get_evergreen_interval( $instance ) );
|
||||
} else {
|
||||
$wp_timezone = new \DateTimeZone( wp_timezone_string() );
|
||||
$due_date = new \DateTime( $due_date, $wp_timezone );
|
||||
$due_date = $due_date->getTimestamp();
|
||||
}
|
||||
|
||||
$actions = false;
|
||||
|
||||
if ( ! Plugin::elementor()->editor->is_edit_mode() ) {
|
||||
$actions = $this->get_actions( $instance );
|
||||
}
|
||||
|
||||
if ( $actions ) {
|
||||
$sanitized_actions = $this->sanitize_redirect_url( $actions );
|
||||
|
||||
$this->add_render_attribute( 'div', 'data-expire-actions', wp_json_encode( $sanitized_actions ) );
|
||||
}
|
||||
|
||||
$this->add_render_attribute( 'div', [
|
||||
'class' => 'elementor-countdown-wrapper',
|
||||
'data-date' => $due_date,
|
||||
] );
|
||||
|
||||
?>
|
||||
<div <?php $this->print_render_attribute_string( 'div' ); ?>>
|
||||
<?php echo wp_kses_post( $string ); ?>
|
||||
</div>
|
||||
<?php
|
||||
if ( $actions && is_array( $actions ) ) {
|
||||
foreach ( $actions as $action ) {
|
||||
if ( 'message' !== $action['type'] ) {
|
||||
continue;
|
||||
} ?>
|
||||
<div class="elementor-countdown-expire--message">
|
||||
<?php echo esc_html( $instance['message_after_expire'] ); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\CustomAttributes;
|
||||
|
||||
use Elementor\Controls_Stack;
|
||||
use Elementor\Controls_Manager;
|
||||
use Elementor\Element_Base;
|
||||
use Elementor\Utils;
|
||||
use ElementorPro\Base\Module_Base;
|
||||
use ElementorPro\License\API;
|
||||
use ElementorPro\Modules\Tiers\Module as Tiers;
|
||||
use ElementorPro\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends Module_Base {
|
||||
|
||||
const LICENSE_FEATURE_NAME = 'custom-attributes';
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->add_actions();
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'custom-attributes';
|
||||
}
|
||||
|
||||
private function get_black_list_attributes() {
|
||||
static $black_list = null;
|
||||
|
||||
if ( null === $black_list ) {
|
||||
$black_list = [ 'id', 'class', 'data-id', 'data-settings', 'data-element_type', 'data-widget_type', 'data-model-cid' ];
|
||||
|
||||
/**
|
||||
* Elementor attributes black list.
|
||||
*
|
||||
* Filters the attributes that won't be rendered in the wrapper element.
|
||||
*
|
||||
* By default Elementor doesn't render some attributes to prevent things
|
||||
* from breaking down. This hook allows developers to alter this list of
|
||||
* attributes.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*
|
||||
* @param array $black_list A black list of attributes.
|
||||
*/
|
||||
$black_list = apply_filters( 'elementor_pro/element/attributes/black_list', $black_list );
|
||||
}
|
||||
|
||||
return $black_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Element_Base $element
|
||||
*/
|
||||
public function replace_go_pro_custom_attributes_controls( Element_Base $element ) {
|
||||
Plugin::elementor()->controls_manager->remove_control_from_stack( $element->get_unique_name(), [ 'section_custom_attributes_pro', 'custom_attributes_pro' ] );
|
||||
|
||||
$this->register_custom_attributes_controls( $element );
|
||||
}
|
||||
|
||||
public function register_custom_attributes_controls( Element_Base $element ) {
|
||||
$element_name = $element->get_name();
|
||||
|
||||
$element->start_controls_section(
|
||||
'_section_attributes',
|
||||
[
|
||||
'label' => esc_html__( 'Attributes', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_ADVANCED,
|
||||
]
|
||||
);
|
||||
|
||||
$element->add_control(
|
||||
'_attributes',
|
||||
[
|
||||
'label' => esc_html__( 'Custom Attributes', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXTAREA,
|
||||
'dynamic' => [
|
||||
'active' => true,
|
||||
],
|
||||
'ai' => [
|
||||
'active' => false,
|
||||
],
|
||||
'placeholder' => esc_html__( 'key|value', 'elementor-pro' ),
|
||||
'description' => sprintf(
|
||||
/* translators: %s: The `|` separate char. */
|
||||
esc_html__( 'Set custom attributes for the wrapper element. Each attribute in a separate line. Separate attribute key from the value using %s character.', 'elementor-pro' ),
|
||||
'<code>|</code>'
|
||||
),
|
||||
'classes' => 'elementor-control-direction-ltr',
|
||||
]
|
||||
);
|
||||
|
||||
$element->end_controls_section();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $element Controls_Stack
|
||||
* @param $section_id string
|
||||
*/
|
||||
public function register_controls( Controls_Stack $element, $section_id ) {
|
||||
if ( ! $element instanceof Element_Base ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove Custom CSS Banner (From free version)
|
||||
if ( 'section_custom_attributes_pro' !== $section_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! API::is_licence_has_feature( self::LICENSE_FEATURE_NAME, API::BC_VALIDATION_CALLBACK ) ) {
|
||||
$this->replace_controls_with_upgrade_promotion( $element );
|
||||
return;
|
||||
}
|
||||
|
||||
$this->replace_go_pro_custom_attributes_controls( $element );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $element Element_Base
|
||||
*/
|
||||
public function render_attributes( Element_Base $element ) {
|
||||
$settings = $element->get_settings_for_display();
|
||||
|
||||
if ( ! empty( $settings['_attributes'] ) ) {
|
||||
$attributes = Utils::parse_custom_attributes( $settings['_attributes'], "\n" );
|
||||
|
||||
$black_list = $this->get_black_list_attributes();
|
||||
|
||||
foreach ( $attributes as $attribute => $value ) {
|
||||
if ( ! in_array( $attribute, $black_list, true ) ) {
|
||||
$element->add_render_attribute( '_wrapper', $attribute, $value );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function add_actions() {
|
||||
add_action( 'elementor/element/after_section_end', [ $this, 'register_controls' ], 10, 2 );
|
||||
|
||||
if ( API::is_licence_has_feature( static::LICENSE_FEATURE_NAME, API::BC_VALIDATION_CALLBACK ) ) {
|
||||
add_action( 'elementor/element/after_add_attributes', [ $this, 'render_attributes' ] );
|
||||
}
|
||||
}
|
||||
|
||||
private function replace_controls_with_upgrade_promotion( Element_Base $element ) {
|
||||
Plugin::elementor()->controls_manager->remove_control_from_stack( $element->get_unique_name(), [ 'section_custom_attributes_pro', 'section_custom_attributes_pro' ] );
|
||||
|
||||
$element->start_controls_section(
|
||||
'section_custom_attributes_promotion',
|
||||
[
|
||||
'label' => esc_html__( 'Attributes', 'elementor-pro' ),
|
||||
'tab' => Controls_Manager::TAB_ADVANCED,
|
||||
]
|
||||
);
|
||||
|
||||
$element->add_control(
|
||||
'custom_attributes_promotion',
|
||||
[
|
||||
'type' => Controls_Manager::RAW_HTML,
|
||||
'raw' => Tiers::get_promotion_template( [
|
||||
'title' => esc_html__( 'Meet Our Attributes', 'elementor-pro' ),
|
||||
'messages' => [
|
||||
esc_html__( 'Add custom HTML attributes to any element.', 'elementor-pro' ),
|
||||
],
|
||||
'link' => 'https://go.elementor.com/go-pro-advanced-attributes/',
|
||||
] ),
|
||||
]
|
||||
);
|
||||
|
||||
$element->end_controls_section();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\CustomCode\AdminMenuItems;
|
||||
|
||||
use Elementor\Core\Admin\Menu\Interfaces\Admin_Menu_Item;
|
||||
use Elementor\Settings;
|
||||
use ElementorPro\Modules\CustomCode\Module as CustomCodeModule;
|
||||
use ElementorPro\License\API;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Custom_Code_Menu_Item implements Admin_Menu_Item {
|
||||
|
||||
const LICENSE_FEATURE_NAME = 'custom_code';
|
||||
|
||||
public function get_capability() {
|
||||
return CustomCodeModule::CAPABILITY;
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Custom Code', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_parent_slug() {
|
||||
return Settings::PAGE_ID;
|
||||
}
|
||||
|
||||
public function get_position() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function is_visible() {
|
||||
return API::is_licence_has_feature( static::LICENSE_FEATURE_NAME, API::BC_VALIDATION_CALLBACK );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\CustomCode\AdminMenuItems;
|
||||
|
||||
use ElementorPro\License\API;
|
||||
use ElementorPro\Modules\Tiers\AdminMenuItems\Base_Promotion_Template;
|
||||
use ElementorPro\Plugin;
|
||||
use ElementorPro\Modules\CustomCode\Module as Custom_Code_Module;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Custom_Code_Promotion_Menu_Item extends Base_Promotion_Template {
|
||||
public function get_name(): string {
|
||||
return 'custom-code-promotion';
|
||||
}
|
||||
|
||||
public function get_cta_url(): string {
|
||||
if ( ! API::active_licence_has_feature( Custom_Code_Module::MODULE_NAME ) ) {
|
||||
$upgrade_url = 'https://go.elementor.com/go-pro-advanced-custom-code/';
|
||||
|
||||
return $upgrade_url;
|
||||
}
|
||||
|
||||
$connect_url = Plugin::instance()->license_admin->get_connect_url( [
|
||||
'utm_source' => 'custom-code',
|
||||
'utm_medium' => 'wp-dash',
|
||||
'utm_campaign' => 'connect-and-activate-license',
|
||||
] );
|
||||
|
||||
$renew_url = 'https://go.elementor.com/renew-custom-code/';
|
||||
|
||||
return API::is_license_expired()
|
||||
? $renew_url
|
||||
: $connect_url;
|
||||
}
|
||||
|
||||
public function get_cta_text() {
|
||||
if ( ! API::active_licence_has_feature( Custom_Code_Module::MODULE_NAME ) ) {
|
||||
return esc_html__( 'Upgrade Now', 'elementor-pro' );
|
||||
}
|
||||
|
||||
return API::is_license_expired()
|
||||
? esc_html__( 'Renew now', 'elementor-pro' )
|
||||
: esc_html__( 'Connect & Activate', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return $this->get_page_title();
|
||||
}
|
||||
|
||||
public function get_page_title() {
|
||||
return esc_html__( 'Custom Code', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_promotion_title(): string {
|
||||
return sprintf( esc_html__( 'Enjoy Creative Freedom %s with Custom Code', 'elementor-pro' ), '<br />' );
|
||||
}
|
||||
|
||||
public function get_video_url(): string {
|
||||
return 'https://www.youtube-nocookie.com/embed/IOovQd1hJUg?si=JLHk3UAexnvTfU1a';
|
||||
}
|
||||
|
||||
public function get_promotion_description() {
|
||||
return esc_html__(
|
||||
'Add Custom Code snippets to your website.',
|
||||
'elementor-pro'
|
||||
);
|
||||
}
|
||||
|
||||
public function get_side_note(): string {
|
||||
return esc_html__( '* Requires an Advanced subscription or higher', 'elementor-pro' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use get_promotion_description instead
|
||||
* @return void
|
||||
*/
|
||||
public function render_promotion_description() {
|
||||
echo $this->get_promotion_description(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
protected function get_content_lines(): array {
|
||||
return [
|
||||
esc_html__( 'Add Custom Code snippets anywhere on your website, including the header or footer to measure your page’s performance*', 'elementor-pro' ),
|
||||
esc_html__( 'Use Custom Code to create sophisticated custom interactions to engage visitors', 'elementor-pro' ),
|
||||
esc_html__( 'Leverage Elementor AI to instantly generate Custom Code for Elementor', 'elementor-pro' ),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\CustomCode;
|
||||
|
||||
use Elementor\Utils;
|
||||
use ElementorPro\Modules\AssetsManager\Classes\Assets_Base;
|
||||
use ElementorPro\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Custom_Code_Metabox extends Assets_Base {
|
||||
const FIELD_LOCATION = 'location';
|
||||
const FIELD_PRIORITY = 'priority';
|
||||
const FILED_EXTRA_OPTIONS = 'extra_options';
|
||||
const FIELD_CODE = 'code';
|
||||
|
||||
const OPTION_LOCATION_HEAD = 'elementor_head';
|
||||
const OPTION_LOCATION_BODY_START = 'elementor_body_start';
|
||||
const OPTION_LOCATION_BODY_END = 'elementor_body_end';
|
||||
|
||||
const OPTION_PRIORITY_LENGTH = 10;
|
||||
|
||||
const INPUT_OPTION_ENSURE_JQUERY = 'ensure_jquery';
|
||||
|
||||
const INPUT_FIELDS = [
|
||||
self::FIELD_LOCATION,
|
||||
self::FIELD_PRIORITY,
|
||||
self::FIELD_CODE,
|
||||
self::FILED_EXTRA_OPTIONS,
|
||||
];
|
||||
|
||||
const INPUT_OPTIONS = [
|
||||
self::INPUT_OPTION_ENSURE_JQUERY,
|
||||
];
|
||||
|
||||
public function get_name() {
|
||||
return Module::MODULE_NAME;
|
||||
}
|
||||
|
||||
public function get_type() {
|
||||
return Module::CPT;
|
||||
}
|
||||
|
||||
public function get_field_label( $field ) {
|
||||
$label = parent::get_field_label( $field );
|
||||
|
||||
if ( ! empty( $field['info'] ) ) {
|
||||
$label = '<p class="elementor-field-label"><i data-info="' . $field['info'] . '" class="eicon-info-circle"></i>' . $label . '</p>';
|
||||
}
|
||||
|
||||
return $label;
|
||||
}
|
||||
|
||||
public function get_location_labels() {
|
||||
return [
|
||||
self::OPTION_LOCATION_HEAD => esc_html__( 'Head', 'elementor-pro' ),
|
||||
self::OPTION_LOCATION_BODY_START => esc_html__( 'Body Start', 'elementor-pro' ),
|
||||
self::OPTION_LOCATION_BODY_END => esc_html__( 'Body End', 'elementor-pro' ),
|
||||
];
|
||||
}
|
||||
|
||||
public function get_location_options() {
|
||||
return [
|
||||
self::OPTION_LOCATION_HEAD => '<head>',
|
||||
self::OPTION_LOCATION_BODY_START => sprintf(
|
||||
/* translators: %s: Body opening tag. */
|
||||
esc_html__( '%s - Start', 'elementor-pro' ),
|
||||
'<body>'
|
||||
),
|
||||
self::OPTION_LOCATION_BODY_END => sprintf(
|
||||
/* translators: %s: Body closing tag. */
|
||||
esc_html__( '%s - End', 'elementor-pro' ),
|
||||
'</body>'
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
public function get_priority_options() {
|
||||
$start = 1;
|
||||
$result = range( $start, self::OPTION_PRIORITY_LENGTH );
|
||||
|
||||
$result = array_combine( $result, $result );
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add script integrity.
|
||||
*
|
||||
* This is method is public, since its has to remove its own filter.
|
||||
*
|
||||
* @param string $html
|
||||
* @param mixed $handle
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function add_script_integrity( $html, $handle ) {
|
||||
if ( 'jshint' === $handle ) {
|
||||
$html = str_replace( '></script>', ' integrity="sha512-qcoitUjhkmNyPmbIOlUV/zd8MJvrVcKrNqnveMWS3C6MYOl5+HLwliRKUm/Ae/dfIok6+E54hjgVrAeS+sBAGA==" crossorigin="anonymous"></script>', $html );
|
||||
|
||||
remove_filter( 'script_loader_tag', [ $this, 'add_script_integrity' ] );
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
protected function actions() {
|
||||
add_action( 'add_meta_boxes_' . Module::CPT, function () {
|
||||
$this->add_meta_boxes();
|
||||
} );
|
||||
|
||||
add_action( 'save_post_' . Module::CPT, function( $post_id, $post, $update ) {
|
||||
return $this->save_post_meta( $post_id, $post );
|
||||
}, 10, 3 );
|
||||
|
||||
add_action('post_submitbox_misc_actions', function ( $post ) {
|
||||
$this->add_meta_publish_options( $post );
|
||||
} );
|
||||
}
|
||||
|
||||
private function get_fields() {
|
||||
return [
|
||||
[
|
||||
'id' => 'open-div-meta-box',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'attributes' => [
|
||||
'class' => 'elementor-custom-code-meta-box',
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => 'open-div-panel',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'attributes' => [
|
||||
'class' => 'elementor-custom-code-panel',
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => 'open-div-placement',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'attributes' => [
|
||||
'class' => 'elementor-custom-code-panel-placement',
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => self::FIELD_LOCATION,
|
||||
'field_type' => 'select',
|
||||
'label' => esc_html__( 'Location', 'elementor-pro' ) . ':',
|
||||
'options' => $this->get_location_options(),
|
||||
'info' => esc_html__( 'Define where the Custom Code will appear', 'elementor-pro' ),
|
||||
],
|
||||
[
|
||||
'id' => 'open-div-placement',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'attributes' => [
|
||||
'class' => 'elementor-custom-code-options-placement',
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => self::FILED_EXTRA_OPTIONS,
|
||||
'field_type' => 'checkbox',
|
||||
'options' => [
|
||||
self::INPUT_OPTION_ENSURE_JQUERY => esc_html__( 'Always load jQuery', 'elementor-pro' ),
|
||||
],
|
||||
'info' => esc_html__( 'If your snippet includes jQuery, this will ensure it will work for all visitors. It may have a minor impact on loading speed.', 'elementor-pro' ),
|
||||
],
|
||||
[
|
||||
'id' => 'close-div-placement',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'close' => true,
|
||||
],
|
||||
[
|
||||
'id' => self::FIELD_PRIORITY,
|
||||
'field_type' => 'select',
|
||||
'label' => esc_html__( 'Priority', 'elementor-pro' ) . ':',
|
||||
'options' => $this->get_priority_options(),
|
||||
'info' => esc_html__( 'Define in which order the Custom Code will appear', 'elementor-pro' ),
|
||||
],
|
||||
[
|
||||
'id' => 'close-div-placement',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'close' => true,
|
||||
],
|
||||
[
|
||||
'id' => 'close-div-panel',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'close' => true,
|
||||
],
|
||||
[
|
||||
'id' => 'close-div-meta-box',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'close' => true,
|
||||
],
|
||||
[
|
||||
'id' => 'open-div-code-mirror-holder',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'attributes' => [
|
||||
'class' => 'elementor-custom-code-codemirror-holder',
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => 'open-div-code-mirror',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'attributes' => [
|
||||
'class' => 'elementor-custom-code-codemirror',
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => self::FIELD_CODE,
|
||||
'field_type' => 'textarea',
|
||||
'label' => '',
|
||||
'extra_attributes' => [
|
||||
'class' => 'hidden',
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => 'close-div-code-mirror',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'close' => true,
|
||||
],
|
||||
[
|
||||
'id' => 'close-div-code-mirror-holder',
|
||||
'field_type' => 'html_tag',
|
||||
'label' => false,
|
||||
'tag' => 'div',
|
||||
'close' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function get_code_editor_settings() {
|
||||
// TODO: Handle `enqueue_code_editor_scripts` to work with `lint => 'true'`.
|
||||
return [
|
||||
'type' => 'text/html',
|
||||
'codemirror' => [
|
||||
'indentUnit' => 2,
|
||||
'tabSize' => 2,
|
||||
'gutters' => [ 'CodeMirror-lint-markers' ],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function enqueue_code_editor_scripts( $field_code_id ) {
|
||||
// Add integrity attribute to jshint.
|
||||
add_filter( 'script_loader_tag', [ $this, 'add_script_integrity' ], 10, 2 );
|
||||
|
||||
wp_enqueue_script( 'htmlhint' );
|
||||
wp_enqueue_script( 'csslint' );
|
||||
|
||||
wp_deregister_script( 'jshint' );
|
||||
|
||||
wp_enqueue_script( 'jshint',
|
||||
'https://cdnjs.cloudflare.com/ajax/libs/jshint/2.12.0/jshint.min.js',
|
||||
[],
|
||||
'2.12.0'
|
||||
);
|
||||
|
||||
/**
|
||||
* Some of the plugins may load 'code-editor' for their needs and change the default behavior, so it should
|
||||
* re-initialize the code editor with 'custom code' settings.
|
||||
*/
|
||||
if ( wp_script_is( 'code-editor' ) ) {
|
||||
wp_add_inline_script( 'custom-code-metabox', sprintf( 'wp.codeEditor.initialize( jQuery( "#%s"), %s );', $field_code_id, wp_json_encode( wp_get_code_editor_settings( $this->get_code_editor_settings() ) ) ) );
|
||||
} else {
|
||||
wp_enqueue_code_editor( $this->get_code_editor_settings() );
|
||||
|
||||
wp_add_inline_script( 'code-editor', sprintf( 'wp.codeEditor.initialize( jQuery( "#%s") );', $field_code_id ) );
|
||||
}
|
||||
}
|
||||
|
||||
private function render_meta_box() {
|
||||
$fields = $this->get_fields();
|
||||
|
||||
if ( ! empty( $_REQUEST['action'] ) && 'edit' == $_REQUEST['action'] ) {
|
||||
$post = get_post( \ElementorPro\Core\Utils::_unstable_get_super_global_value( $_REQUEST, 'post' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here.
|
||||
foreach ( self::INPUT_FIELDS as $input_field ) {
|
||||
$field_meta = get_post_meta( $post->ID, "_elementor_$input_field", true );
|
||||
|
||||
if ( ! empty( $field_meta ) ) {
|
||||
$key = array_search( $input_field, array_column( $fields, 'id' ) );
|
||||
if ( false !== $key ) {
|
||||
$fields[ $key ]['saved'] = $field_meta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The method, support fields only.
|
||||
$this->print_metabox( $fields );
|
||||
|
||||
/**
|
||||
* Elementor metabox render.
|
||||
*
|
||||
* Fires before custom scripts are enqueued, since enqueue depends on
|
||||
* render handlers.
|
||||
*
|
||||
* @param Custom_Code_Metabox $this An instance of custom code metabox.
|
||||
* @param int|false $id The ID of the current WordPress post.
|
||||
* False if post is not set.
|
||||
*/
|
||||
do_action( 'elementor-pro/metabox/render', $this, get_the_ID() );
|
||||
|
||||
// Init codemirror.
|
||||
$this->enqueue_code_editor_scripts( self::FIELD_CODE );
|
||||
}
|
||||
|
||||
private function save_post_meta( $post_id, $post ) {
|
||||
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
// Check the user's permissions.
|
||||
if ( ! current_user_can( 'edit_post', $post_id ) ) {
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
if ( get_post_status( $post->ID ) === 'auto-draft' ) {
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
// PHPCS - Should not validate for nonce (already done in WordPress save_post).
|
||||
$post_data = $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
|
||||
foreach ( self::INPUT_FIELDS as $field ) {
|
||||
if ( isset( $post_data[ $field ] ) && ! Utils::is_empty( $post_data[ $field ] ) ) {
|
||||
if ( self::FIELD_CODE === $field ) {
|
||||
$post_meta = $post_data[ $field ];
|
||||
} else {
|
||||
$post_meta = sanitize_text_field( $post_data[ $field ] );
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'unfiltered_html' ) ) {
|
||||
$post_meta = wp_kses_post( $post_meta );
|
||||
}
|
||||
update_post_meta( $post->ID, "_elementor_$field", $post_meta );
|
||||
|
||||
/** @var \ElementorPro\Modules\ThemeBuilder\Module $theme_builder */
|
||||
$theme_builder = Plugin::instance()->modules_manager->get_modules( 'theme-builder' );
|
||||
$theme_builder->get_conditions_manager()->get_cache()->regenerate();
|
||||
} elseif ( self::FILED_EXTRA_OPTIONS === $field ) {
|
||||
$input_options = [];
|
||||
|
||||
foreach ( self::INPUT_OPTIONS as $input_option ) {
|
||||
$key = self::FILED_EXTRA_OPTIONS . '_' . $input_option;
|
||||
$input_option_value = \ElementorPro\Core\Utils::_unstable_get_super_global_value( $post_data, $key );
|
||||
|
||||
if ( 'on' === $input_option_value ) {
|
||||
$input_options [] = $input_option;
|
||||
}
|
||||
}
|
||||
|
||||
update_post_meta( $post->ID, "_elementor_$field", $input_options );
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary workaround for applying conditions for draft custom code post.
|
||||
if ( ! empty( $post_data['_conditions'] ) ) {
|
||||
$conditions = (array) json_decode( wp_unslash( $post_data['_conditions'] ) );
|
||||
|
||||
foreach ( $conditions as $key => $item ) {
|
||||
$item_assoc_array = (array) $item;
|
||||
|
||||
$conditions[ $key ] = [
|
||||
$item_assoc_array['type'],
|
||||
$item_assoc_array['name'],
|
||||
$item_assoc_array['sub'],
|
||||
$item_assoc_array['subId'],
|
||||
];
|
||||
}
|
||||
|
||||
/** @var \ElementorPro\Modules\ThemeBuilder\Module $theme_builder */
|
||||
$theme_builder = Plugin::instance()->modules_manager->get_modules( 'theme-builder' );
|
||||
|
||||
$theme_builder->get_conditions_manager()->save_conditions( $post_id, $conditions );
|
||||
}
|
||||
}
|
||||
|
||||
private function add_meta_boxes() {
|
||||
add_meta_box(
|
||||
'elementor-custom-code',
|
||||
__( 'Custom code', 'elementor-pro' ),
|
||||
function() {
|
||||
$this->render_meta_box();
|
||||
},
|
||||
module::CPT,
|
||||
'normal',
|
||||
'default'
|
||||
);
|
||||
}
|
||||
|
||||
private function add_meta_publish_options( $post ) {
|
||||
if ( Module::CPT === $post->post_type ) {
|
||||
?>
|
||||
<div class="misc-pub-section misc-pub-post-conditions">
|
||||
<i class="dashicons dashicons-networking" aria-hidden="true"></i>
|
||||
<?php echo esc_html__( 'Conditions:', 'elementor-pro' ); ?>
|
||||
<span class="post-conditions"></span>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\CustomCode;
|
||||
|
||||
use ElementorPro\Modules\ThemeBuilder\Documents\Theme_Document;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Document extends Theme_Document {
|
||||
private static $applied_options = [];
|
||||
|
||||
public static function get_properties() {
|
||||
$properties = parent::get_properties();
|
||||
$properties['cpt'] = [ Module::CPT ];
|
||||
|
||||
$properties['admin_tab_group'] = '';
|
||||
$properties['show_in_library'] = false;
|
||||
$properties['support_site_editor'] = false;
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
public static function get_title() {
|
||||
return esc_html__( 'Custom Code', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public static function get_type() {
|
||||
return Module::DOCUMENT_TYPE;
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return Module::DOCUMENT_TYPE;
|
||||
}
|
||||
|
||||
public function print_content() {
|
||||
$content = get_post_meta( $this->post->ID, '_elementor_' . Custom_Code_Metabox::FIELD_CODE, true ) . PHP_EOL;
|
||||
$user_has_permission = current_user_can( Module::CAPABILITY );
|
||||
|
||||
$this->apply_snippet_options( get_post_meta( $this->get_id(), '_elementor_' . Custom_Code_Metabox::FILED_EXTRA_OPTIONS, true ) );
|
||||
|
||||
if ( $user_has_permission ) {
|
||||
$this->print_snippet_with_elementor_comment( $content );
|
||||
} else {
|
||||
// PHPCS - the main content of custom code
|
||||
echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
|
||||
public static function get_create_url() {
|
||||
$query_args = [
|
||||
'post_type' => Module::CPT,
|
||||
];
|
||||
|
||||
return add_query_arg( $query_args, admin_url( 'post-new.php' ) );
|
||||
}
|
||||
|
||||
private function print_snippet_with_elementor_comment( $content ) {
|
||||
echo implode( PHP_EOL, [
|
||||
'',
|
||||
'<!--',
|
||||
'Title: ' . esc_html( $this->post->post_title ),
|
||||
'Type: ' . Module::CPT, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
'Author: ' . esc_html( get_the_author_meta( 'display_name', $this->post->post_author ) ),
|
||||
'Last edited: ' . esc_html( $this->post->post_modified ),
|
||||
'--- The comment is visible only for administrators ---',
|
||||
'-->',
|
||||
'',
|
||||
] );
|
||||
|
||||
// PHPCS - the main content of custom code
|
||||
echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
|
||||
echo PHP_EOL . '<!-- End of snippet -->' . PHP_EOL;
|
||||
}
|
||||
|
||||
private function apply_snippet_options( $options ) {
|
||||
if ( ! is_array( $options ) || ! count( $options ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $options as $option ) {
|
||||
if ( ! empty( self::$applied_options[ $option ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ( $option ) {
|
||||
case Custom_Code_Metabox::INPUT_OPTION_ENSURE_JQUERY:
|
||||
wp_enqueue_script( 'jquery' );
|
||||
|
||||
// Ensure jQuery will be first in order.
|
||||
if ( 'wp_footer' === current_filter() ) {
|
||||
wp_print_footer_scripts();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
self::$applied_options[ $option ] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
449
wp-content/plugins/elementor-pro/modules/custom-code/module.php
Normal file
449
wp-content/plugins/elementor-pro/modules/custom-code/module.php
Normal file
@@ -0,0 +1,449 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\CustomCode;
|
||||
|
||||
use Elementor\Core\Admin\Menu\Admin_Menu_Manager;
|
||||
use Elementor\Core\Documents_Manager;
|
||||
use Elementor\Icons_Manager;
|
||||
use Elementor\Settings;
|
||||
use Elementor\TemplateLibrary\Source_Local;
|
||||
use Elementor\Utils;
|
||||
use ElementorPro\Base\Module_Base;
|
||||
use ElementorPro\License\API;
|
||||
use ElementorPro\Modules\CustomCode\AdminMenuItems\Custom_Code_Menu_Item;
|
||||
use ElementorPro\Modules\CustomCode\AdminMenuItems\Custom_Code_Promotion_Menu_Item;
|
||||
use ElementorPro\Modules\ThemeBuilder\Classes\Conditions_Manager;
|
||||
use ElementorPro\Modules\ThemeBuilder\Classes\Locations_Manager;
|
||||
use ElementorPro\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends Module_Base {
|
||||
const CAPABILITY = 'manage_options';
|
||||
const CPT = 'elementor_snippet';
|
||||
const MODULE_NAME = 'custom_code';
|
||||
const DOCUMENT_TYPE = 'code_snippet';
|
||||
|
||||
const ADDITIONAL_COLUMN_INSTANCES = 'instances';
|
||||
|
||||
const MENU_SLUG = 'edit.php?post_type=' . self::CPT;
|
||||
const PROMOTION_MENU_SLUG = 'e-custom-code';
|
||||
|
||||
/**
|
||||
* @var \ElementorPro\Modules\CustomCode\Custom_Code_Metabox
|
||||
*/
|
||||
public $meta_box;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->meta_box = new Custom_Code_Metabox();
|
||||
|
||||
$this->actions();
|
||||
|
||||
if ( $this->can_use_custom_code() ) {
|
||||
$this->register_custom_post_type();
|
||||
$this->register_metabox();
|
||||
}
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'custom-code';
|
||||
}
|
||||
|
||||
private function actions() {
|
||||
if ( $this->can_use_custom_code() ) {
|
||||
add_action( 'elementor/documents/register', function ( $documents_manager ) {
|
||||
return $this->register_documents( $documents_manager );
|
||||
} );
|
||||
|
||||
add_action( 'elementor/theme/register_locations', function ( $location_manager ) {
|
||||
return $this->register_location( $location_manager );
|
||||
} );
|
||||
}
|
||||
|
||||
add_action( 'elementor/admin/menu/register', function ( Admin_Menu_Manager $admin_menu_manager ) {
|
||||
$this->add_admin_menu( $admin_menu_manager );
|
||||
} );
|
||||
|
||||
// TODO: BC - Remove after `Admin_Menu_Manager` will be the standard.
|
||||
add_action( 'admin_menu', function () {
|
||||
if ( did_action( 'elementor/admin/menu/register' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$menu_title = esc_html__( 'Custom Code', 'elementor-pro' );
|
||||
add_submenu_page(
|
||||
Settings::PAGE_ID,
|
||||
$menu_title,
|
||||
$menu_title,
|
||||
self::CAPABILITY,
|
||||
static::MENU_SLUG
|
||||
);
|
||||
}, /* After custom icons */ 51 );
|
||||
|
||||
add_action( 'current_screen', function () {
|
||||
if ( ! is_admin() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$current_screen = get_current_screen();
|
||||
|
||||
if ( 'edit-' . self::CPT === $current_screen->id ) {
|
||||
$this->admin_ui_actions();
|
||||
} elseif ( self::CPT === $current_screen->id ) {
|
||||
// Enqueue assets.
|
||||
add_action( 'admin_enqueue_scripts', function () {
|
||||
$this->enqueue_assets();
|
||||
}, 0 /* elementor-app-base styles should be loaded in early stages */ );
|
||||
}
|
||||
} );
|
||||
|
||||
$this->frontend_actions();
|
||||
}
|
||||
|
||||
private function admin_ui_actions() {
|
||||
// Show blank 'custom code' snippets list.
|
||||
add_action( 'manage_posts_extra_tablenav', function ( $which ) {
|
||||
return $this->maybe_render_blank_state( $which );
|
||||
} );
|
||||
|
||||
// Mange post columns.
|
||||
add_filter( 'manage_posts_columns', function ( $columns ) {
|
||||
return $this->manage_posts_columns( $columns );
|
||||
} );
|
||||
|
||||
add_action( 'manage_posts_custom_column', function ( $column_name, $post_id ) {
|
||||
return $this->manage_posts_custom_column( $column_name, $post_id );
|
||||
}, 10, 2 );
|
||||
}
|
||||
|
||||
private function frontend_actions() {
|
||||
// Print snippets.
|
||||
add_action( 'wp_head', function () {
|
||||
$this->print_snippets( Custom_Code_Metabox::OPTION_LOCATION_HEAD );
|
||||
} );
|
||||
|
||||
add_action( 'wp_body_open', function () {
|
||||
$this->print_snippets( Custom_Code_Metabox::OPTION_LOCATION_BODY_START );
|
||||
} );
|
||||
|
||||
add_action( 'wp_footer', function () {
|
||||
$this->print_snippets( Custom_Code_Metabox::OPTION_LOCATION_BODY_END );
|
||||
}, 21 /* After 'wp_print_footer_scripts' */ );
|
||||
}
|
||||
|
||||
private function register_custom_post_type() {
|
||||
$labels = [
|
||||
'name' => esc_html__( 'Custom Code', 'elementor-pro' ),
|
||||
'singular_name' => esc_html__( 'Custom Code', 'elementor-pro' ),
|
||||
'add_new' => esc_html__( 'Add new', 'elementor-pro' ),
|
||||
'add_new_item' => esc_html__( 'New code', 'elementor-pro' ),
|
||||
'edit_item' => esc_html__( 'Edit code', 'elementor-pro' ),
|
||||
];
|
||||
|
||||
register_post_type( self::CPT, [
|
||||
'labels' => $labels,
|
||||
'public' => false,
|
||||
'rewrite' => false,
|
||||
'show_ui' => true,
|
||||
'show_in_menu' => false,
|
||||
'show_in_nav_menus' => false,
|
||||
'exclude_from_search' => true,
|
||||
'capability_type' => 'post',
|
||||
'hierarchical' => false,
|
||||
'supports' => [ 'title', 'author' ],
|
||||
'capabilities' => [
|
||||
'publish_posts' => 'manage_options',
|
||||
'edit_posts' => 'manage_options',
|
||||
'edit_others_posts' => 'manage_options',
|
||||
'delete_posts' => 'manage_options',
|
||||
'delete_others_posts' => 'manage_options',
|
||||
'read_private_posts' => 'manage_options',
|
||||
'edit_post' => 'manage_options',
|
||||
'delete_post' => 'manage_options',
|
||||
'read_post' => 'manage_options',
|
||||
],
|
||||
] );
|
||||
|
||||
// Handling custom post type messages.
|
||||
add_filter( 'post_updated_messages', function( $messages ) {
|
||||
if ( self::CPT === get_post_type() ) {
|
||||
$post = get_post();
|
||||
|
||||
// Thanks 'WooCommerce' for the example.
|
||||
$messages[ self::CPT ] = [
|
||||
'', // Not in use.
|
||||
__( 'Custom code updated.', 'elementor-pro' ),
|
||||
__( 'Custom field updated.', 'elementor-pro' ),
|
||||
__( 'Custom field deleted.', 'elementor-pro' ),
|
||||
__( 'Custom code updated.', 'elementor-pro' ),
|
||||
__( 'Revision restored.', 'elementor-pro' ),
|
||||
__( 'Custom code published.', 'elementor-pro' ),
|
||||
__( 'Custom code saved.', 'elementor-pro' ),
|
||||
__( 'Custom code submitted.', 'elementor-pro' ),
|
||||
sprintf(
|
||||
/* translators: %s: The scheduled date. */
|
||||
__( 'Custom code scheduled for %s.', 'elementor-pro' ),
|
||||
'<strong>' . date_i18n( esc_html__( 'M j, Y @ G:i', 'elementor-pro' ), strtotime( $post->post_date ) ) . '</strong>'
|
||||
),
|
||||
__( 'Custom code draft updated.', 'elementor-pro' ),
|
||||
];
|
||||
}
|
||||
|
||||
return $messages;
|
||||
} );
|
||||
|
||||
add_filter( 'bulk_post_updated_messages', function ( $messages, $counters ) {
|
||||
$current_screen = get_current_screen();
|
||||
|
||||
if ( $current_screen && self::CPT === $current_screen->post_type ) {
|
||||
$messages[ self::CPT ] = [
|
||||
'updated' => _n( '%s custom code updated.', '%s custom codes updated.', $counters['updated'], 'elementor-pro' ),
|
||||
'locked' => _n( '%s custom code cannot be not updated, someone else is editing it.', '%s custom codes cannot be not updated, someone else is editing them.', $counters['locked'], 'elementor-pro' ),
|
||||
'deleted' => _n( '%s custom code permanently deleted.', '%s custom codes permanently deleted.', $counters['deleted'], 'elementor-pro' ),
|
||||
'trashed' => _n( '%s custom code moved to trash.', '%s custom codes moved to trash.', $counters['trashed'], 'elementor-pro' ),
|
||||
'untrashed' => _n( '%s custom code restored.', '%s custom code restored.', $counters['untrashed'], 'elementor-pro' ),
|
||||
];
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}, 10, 12 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Function register metabox.
|
||||
*
|
||||
* Add meta box for custom-code post.
|
||||
*/
|
||||
private function register_metabox() {
|
||||
if ( ! is_admin() ) {
|
||||
return;
|
||||
}
|
||||
// Remove 'author' meta_box from 'add-new.php', 'author' is required only in list ( enabled via 'supports' arg ).
|
||||
add_action( 'add_meta_boxes_' . self::CPT, function () {
|
||||
remove_meta_box( 'authordiv', self::CPT, 'normal' );
|
||||
} );
|
||||
}
|
||||
|
||||
private function enqueue_assets() {
|
||||
wp_enqueue_style( 'elementor-app-base', $this->get_css_assets_url( 'app-base', null, 'default', true ), [
|
||||
'elementor-icons',
|
||||
'select2',
|
||||
], ELEMENTOR_VERSION );
|
||||
|
||||
wp_register_style(
|
||||
'select2',
|
||||
$this->get_css_assets_url( 'e-select2', 'assets/lib/e-select2/css/' ),
|
||||
[],
|
||||
'4.0.6-rc.1'
|
||||
);
|
||||
|
||||
wp_register_script(
|
||||
'select2',
|
||||
$this->get_js_assets_url( 'e-select2.full', 'assets/lib/e-select2/js/' ),
|
||||
[
|
||||
'jquery',
|
||||
],
|
||||
'4.0.6-rc.1',
|
||||
true
|
||||
);
|
||||
|
||||
wp_register_style(
|
||||
'elementor-icons',
|
||||
$this->get_css_assets_url( 'elementor-icons', 'assets/lib/eicons/css/' ),
|
||||
[],
|
||||
Icons_Manager::ELEMENTOR_ICONS_VERSION
|
||||
);
|
||||
|
||||
wp_enqueue_script( 'react' );
|
||||
wp_enqueue_script( 'react-dom' );
|
||||
|
||||
wp_enqueue_script(
|
||||
'elementor-app-packages',
|
||||
$this->get_js_assets_url( 'app-packages' ),
|
||||
[
|
||||
'wp-i18n',
|
||||
'react',
|
||||
],
|
||||
ELEMENTOR_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
add_action( 'elementor-pro/metabox/render', function ( $metabox, $post_id ) {
|
||||
$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
|
||||
);
|
||||
|
||||
$direction_suffix = is_rtl() ? '-rtl' : '';
|
||||
wp_enqueue_style(
|
||||
'custom-code',
|
||||
ELEMENTOR_PRO_ASSETS_URL . 'css/modules/custom-code' . $direction_suffix . $min_suffix . '.css',
|
||||
[
|
||||
'elementor-app-base',
|
||||
],
|
||||
ELEMENTOR_PRO_VERSION
|
||||
);
|
||||
|
||||
// Load 'admin.js` module JS entry.
|
||||
wp_enqueue_script(
|
||||
'custom-code-metabox',
|
||||
ELEMENTOR_PRO_ASSETS_URL . 'js/custom-code' . $min_suffix . '.js',
|
||||
[
|
||||
'elementor-v2-ui',
|
||||
'elementor-v2-icons',
|
||||
'react',
|
||||
'select2',
|
||||
// Temporary dependency until we will have a better way to load AI app in the admin.
|
||||
'elementor-ai-admin',
|
||||
],
|
||||
ELEMENTOR_PRO_VERSION
|
||||
);
|
||||
|
||||
$post = [
|
||||
'ID' => $post_id,
|
||||
'post_status' => get_post_status( $post_id ),
|
||||
];
|
||||
|
||||
wp_add_inline_script( 'custom-code-metabox', sprintf( 'elementorProAdmin.customCode.post = %s;', wp_json_encode( $post ) ) );
|
||||
}, 10, 2 );
|
||||
}
|
||||
|
||||
private function add_admin_menu( Admin_Menu_Manager $admin_menu_manager ) {
|
||||
if ( $this->can_use_custom_code() ) {
|
||||
$admin_menu_manager->register( static::MENU_SLUG, new Custom_Code_Menu_Item() );
|
||||
} else {
|
||||
$admin_menu_manager->register( static::PROMOTION_MENU_SLUG, new Custom_Code_Promotion_Menu_Item() );
|
||||
}
|
||||
}
|
||||
|
||||
private function can_use_custom_code() {
|
||||
return ( API::is_license_active() && API::is_licence_has_feature( static::MODULE_NAME, API::BC_VALIDATION_CALLBACK ) || $this->has_custom_code_snippets() );
|
||||
}
|
||||
|
||||
private function has_custom_code_snippets() {
|
||||
$existing_snippets = get_posts( [
|
||||
'posts_per_page' => 1, // Avoid fetching too much data
|
||||
'post_type' => static::CPT,
|
||||
] );
|
||||
|
||||
return ! empty( $existing_snippets );
|
||||
}
|
||||
|
||||
private function register_documents( Documents_Manager $documents_manager ) {
|
||||
$documents_manager->register_document_type( self::DOCUMENT_TYPE, Document::get_class_full_name() );
|
||||
}
|
||||
|
||||
private function register_location( Locations_Manager $location_manager ) {
|
||||
foreach ( array_keys( $this->meta_box->get_location_options() ) as $location ) {
|
||||
$location_manager->register_location( $location, [
|
||||
'multiple' => true,
|
||||
'public' => false,
|
||||
'edit_in_content' => false,
|
||||
] );
|
||||
}
|
||||
}
|
||||
|
||||
private function maybe_render_blank_state( $which ) {
|
||||
$counts = (array) wp_count_posts( self::CPT );
|
||||
unset( $counts['auto-draft'] );
|
||||
|
||||
if ( ! array_sum( $counts ) ) {
|
||||
/** @var Source_Local $source */
|
||||
$source = Plugin::elementor()->templates_manager->get_source( 'local' );
|
||||
|
||||
$source->maybe_render_blank_state( $which, [
|
||||
'post_type' => self::DOCUMENT_TYPE,
|
||||
'cpt' => self::CPT,
|
||||
'description' => esc_html__( 'Add pixels, meta tags and any other scripts to your site.', 'elementor-pro' ) . sprintf( '<br><a target="_blank" href="https://go.elementor.com/wp-dash-custom-code">%s</a>', esc_html__( 'Learn more about adding custom code', 'elementor-pro' ) ),
|
||||
'href' => esc_url( admin_url( '/post-new.php?post_type=' . self::CPT ) ),
|
||||
] );
|
||||
}
|
||||
}
|
||||
|
||||
private function manage_posts_columns( $columns ) {
|
||||
$new = [
|
||||
self::ADDITIONAL_COLUMN_INSTANCES => esc_html__( 'Instances', 'elementor-pro' ),
|
||||
Custom_Code_Metabox::FIELD_LOCATION => esc_html__( 'Location', 'elementor-pro' ),
|
||||
Custom_Code_Metabox::FIELD_PRIORITY => esc_html__( 'Priority', 'elementor-pro' ),
|
||||
];
|
||||
|
||||
// Insert after 'author'.
|
||||
$keys = array_keys( $columns );
|
||||
$pos = array_search( 'author', $keys ) + 1;
|
||||
$columns = array_merge( array_slice( $columns, 0, $pos ), $new, array_slice( $columns, $pos ) );
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
private function manage_posts_custom_column( $column_name, $post_id ) {
|
||||
if ( in_array( $column_name, Custom_Code_Metabox::INPUT_FIELDS ) ) {
|
||||
$value = get_post_meta( $post_id, '_elementor_' . $column_name, true );
|
||||
|
||||
if ( Custom_Code_Metabox::FIELD_LOCATION === $column_name ) {
|
||||
$location_labels = $this->meta_box->get_location_labels();
|
||||
|
||||
if ( isset( $location_labels[ $value ] ) ) {
|
||||
$value = $location_labels[ $value ];
|
||||
}
|
||||
}
|
||||
|
||||
echo esc_html( $value );
|
||||
} elseif ( self::ADDITIONAL_COLUMN_INSTANCES === $column_name ) {
|
||||
/** @var Conditions_Manager $conditions_manager */
|
||||
$conditions_manager = Plugin::instance()->modules_manager->get_modules( 'theme-builder' )->get_conditions_manager();
|
||||
|
||||
echo esc_html( implode( ', ', $conditions_manager->get_document_instances( $post_id ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
private function get_snippets_by_location( $location ) {
|
||||
return get_posts( [
|
||||
'numberposts' => -1,
|
||||
'post_type' => self::CPT,
|
||||
'meta_query' => [
|
||||
[
|
||||
'key' => '_elementor_' . Custom_Code_Metabox::FIELD_LOCATION,
|
||||
'value' => $location,
|
||||
],
|
||||
],
|
||||
// Order.
|
||||
'order' => 'ASC',
|
||||
'orderby' => 'meta_value_num',
|
||||
'meta_key' => '_elementor_' . Custom_Code_Metabox::FIELD_PRIORITY,
|
||||
] );
|
||||
}
|
||||
|
||||
private function print_snippets( $location ) {
|
||||
// Do not print snippets on safe mode.
|
||||
if ( isset( $_REQUEST['elementor-mode'] ) && 'safe' === $_REQUEST['elementor-mode'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$snippets = $this->get_snippets_by_location( $location );
|
||||
|
||||
/** @var \ElementorPro\Modules\ThemeBuilder\Module $theme_builder */
|
||||
$theme_builder = Plugin::instance()->modules_manager->get_modules( 'theme-builder' );
|
||||
$documents_by_conditions = $theme_builder->get_conditions_manager()->get_documents_for_location( $location );
|
||||
$location_manager = $theme_builder->get_locations_manager();
|
||||
|
||||
foreach ( $snippets as $snippet ) {
|
||||
// Add snippet to location.
|
||||
// Also handling situation without conditions, bind current snippet id with current location.
|
||||
if ( isset( $documents_by_conditions[ $snippet->ID ] ) || ! get_post_meta( $snippet->ID, '_elementor_conditions', true ) ) {
|
||||
$location_manager->add_doc_to_location( $location, $snippet->ID );
|
||||
}
|
||||
}
|
||||
|
||||
elementor_theme_do_location( $location );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\CustomCss\AdminMenuItems;
|
||||
|
||||
use Elementor\Core\Kits\Documents\Tabs\Settings_Custom_CSS;
|
||||
use ElementorPro\Modules\CustomCss\Module as Custom_Css;
|
||||
use ElementorPro\Modules\Tiers\Module as Tiers;
|
||||
|
||||
class Settings_Custom_CSS_Pro extends Settings_Custom_CSS {
|
||||
protected function register_tab_controls() {
|
||||
$template = Tiers::get_promotion_template( [
|
||||
'title' => esc_html__( 'Meet Our Custom CSS', 'elementor-pro' ),
|
||||
'messages' => [
|
||||
esc_html__( 'Apply CSS globally across your site to elevate your designs.', 'elementor-pro' ),
|
||||
],
|
||||
'link' => 'https://go.elementor.com/go-pro-advanced-global-css/',
|
||||
] );
|
||||
|
||||
Custom_Css::instance()->replace_controls_with_upgrade_promotion( $this->parent, $this->get_id(), $template );
|
||||
}
|
||||
}
|
||||
189
wp-content/plugins/elementor-pro/modules/custom-css/module.php
Normal file
189
wp-content/plugins/elementor-pro/modules/custom-css/module.php
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\CustomCss;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use Elementor\Controls_Stack;
|
||||
use Elementor\Core\DynamicTags\Dynamic_CSS;
|
||||
use Elementor\Core\Files\CSS\Post;
|
||||
use Elementor\Core\Kits\Documents\Kit;
|
||||
use Elementor\Element_Base;
|
||||
use ElementorPro\Base\Module_Base;
|
||||
use ElementorPro\Modules\CustomCss\AdminMenuItems\Settings_Custom_CSS_Pro;
|
||||
use ElementorPro\Plugin;
|
||||
use ElementorPro\License\API;
|
||||
use ElementorPro\Modules\Tiers\Module as Tiers;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends Module_Base {
|
||||
|
||||
const LICENSE_FEATURE_NAME = 'custom-css';
|
||||
const LICENSE_FEATURE_NAME_GLOBAL = 'global-css';
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->add_actions();
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'custom-css';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $element Controls_Stack
|
||||
* @param $section_id string
|
||||
*/
|
||||
public function register_controls( Controls_Stack $element, $section_id ) {
|
||||
// Remove Custom CSS Banner (From free version)
|
||||
if ( 'section_custom_css_pro' !== $section_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! API::is_licence_has_feature( static::LICENSE_FEATURE_NAME, API::BC_VALIDATION_CALLBACK ) ) {
|
||||
$template = Tiers::get_promotion_template( [
|
||||
'title' => esc_html__( 'Meet Our Custom CSS', 'elementor-pro' ),
|
||||
'messages' => [
|
||||
esc_html__( 'Apply CSS to any widget and elevate any element with Custom CSS.', 'elementor-pro' ),
|
||||
],
|
||||
'link' => 'https://go.elementor.com/go-pro-advanced-custom-css/',
|
||||
] );
|
||||
|
||||
$this->replace_controls_with_upgrade_promotion( $element, Controls_Manager::TAB_ADVANCED, $template );
|
||||
return;
|
||||
}
|
||||
|
||||
$this->replace_go_pro_custom_css_controls( $element );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $post_css Post
|
||||
* @param $element Element_Base
|
||||
*/
|
||||
public function add_post_css( $post_css, $element ) {
|
||||
if ( $post_css instanceof Dynamic_CSS ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$element_settings = $element->get_settings();
|
||||
|
||||
if ( empty( $element_settings['custom_css'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$css = trim( $element_settings['custom_css'] );
|
||||
|
||||
if ( empty( $css ) ) {
|
||||
return;
|
||||
}
|
||||
$css = str_replace( 'selector', $post_css->get_element_unique_selector( $element ), $css );
|
||||
|
||||
// Add a css comment
|
||||
$css = sprintf( '/* Start custom CSS for %s, class: %s */', $element->get_name(), $element->get_unique_selector() ) . $css . '/* End custom CSS */';
|
||||
|
||||
$post_css->get_stylesheet()->add_raw_css( $css );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $post_css Post
|
||||
*/
|
||||
public function add_page_settings_css( $post_css ) {
|
||||
$document = Plugin::elementor()->documents->get( $post_css->get_post_id() );
|
||||
$custom_css = $document->get_settings( 'custom_css' ) ?? '';
|
||||
|
||||
$custom_css = trim( $custom_css );
|
||||
|
||||
if ( empty( $custom_css ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$custom_css = str_replace( 'selector', $document->get_css_wrapper_selector(), $custom_css );
|
||||
|
||||
// Add a css comment
|
||||
$custom_css = '/* Start custom CSS */' . $custom_css . '/* End custom CSS */';
|
||||
|
||||
$post_css->get_stylesheet()->add_raw_css( $custom_css );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Controls_Stack $controls_stack
|
||||
*/
|
||||
public function replace_go_pro_custom_css_controls( $controls_stack ) {
|
||||
$old_section = Plugin::elementor()->controls_manager->get_control_from_stack( $controls_stack->get_unique_name(), 'section_custom_css_pro' );
|
||||
|
||||
Plugin::elementor()->controls_manager->remove_control_from_stack( $controls_stack->get_unique_name(), [ 'section_custom_css_pro', 'custom_css_pro' ] );
|
||||
|
||||
$controls_stack->start_controls_section(
|
||||
'section_custom_css',
|
||||
[
|
||||
'label' => esc_html__( 'Custom CSS', 'elementor-pro' ),
|
||||
'tab' => $old_section['tab'],
|
||||
]
|
||||
);
|
||||
|
||||
$controls_stack->add_control(
|
||||
'custom_css',
|
||||
[
|
||||
'label' => esc_html__( 'Add your own custom CSS', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::CODE,
|
||||
'description' => sprintf(
|
||||
/* translators: 1: Link opening tag, 2: Link opening tag, 3: Link closing tag. */
|
||||
esc_html__( 'Use %1$scustom CSS%3$s to style your content or add %2$sthe "selector" prefix%3$s to target specific elements.', 'elementor-pro' ),
|
||||
'<a href="https://go.elementor.com/learn-more-panel-custom-css/" target="_blank">',
|
||||
'<a href="https://go.elementor.com/learn-more-panel-custom-css-selectors/" target="_blank">',
|
||||
'</a>'
|
||||
),
|
||||
'language' => 'css',
|
||||
'render_type' => 'ui',
|
||||
]
|
||||
);
|
||||
|
||||
$controls_stack->end_controls_section();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.1.0
|
||||
*/
|
||||
public function localize_settings() {
|
||||
Plugin::elementor()->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.1.0' );
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
protected function add_actions() {
|
||||
add_action( 'elementor/element/after_section_end', [ $this, 'register_controls' ], 10, 2 );
|
||||
add_action( 'elementor/element/parse_css', [ $this, 'add_post_css' ], 10, 2 );
|
||||
add_action( 'elementor/css-file/post/parse', [ $this, 'add_page_settings_css' ] );
|
||||
|
||||
// Check license for site settings tabs
|
||||
if ( ! API::is_licence_has_feature( static::LICENSE_FEATURE_NAME_GLOBAL, API::BC_VALIDATION_CALLBACK ) ) {
|
||||
add_action( 'elementor/kit/register_tabs', function ( Kit $kit ) {
|
||||
$kit->register_tab( 'settings-custom-css', Settings_Custom_CSS_Pro::class );
|
||||
}, 100 );
|
||||
}
|
||||
}
|
||||
|
||||
public function replace_controls_with_upgrade_promotion( Controls_Stack $controls_stack, $tab, $template ) {
|
||||
Plugin::elementor()->controls_manager->remove_control_from_stack( $controls_stack->get_unique_name(), [ 'section_custom_css_pro', 'custom_css_pro' ] );
|
||||
|
||||
$controls_stack->start_controls_section(
|
||||
'section_custom_css_promotion',
|
||||
[
|
||||
'label' => esc_html__( 'Custom CSS', 'elementor-pro' ),
|
||||
'tab' => $tab,
|
||||
]
|
||||
);
|
||||
|
||||
$controls_stack->add_control(
|
||||
'custom_css_promotion',
|
||||
[
|
||||
'type' => Controls_Manager::RAW_HTML,
|
||||
'raw' => $template,
|
||||
]
|
||||
);
|
||||
|
||||
$controls_stack->end_controls_section();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Classes;
|
||||
|
||||
class And_Condition {
|
||||
/**
|
||||
* @var $conditions_manager Object
|
||||
*/
|
||||
private $conditions_manager;
|
||||
|
||||
/**
|
||||
* @var $conditions array
|
||||
*/
|
||||
private $conditions;
|
||||
|
||||
public function __construct( $conditions_manager, $conditions ) {
|
||||
$this->conditions_manager = $conditions_manager;
|
||||
$this->conditions = $conditions;
|
||||
}
|
||||
|
||||
public function check() {
|
||||
foreach ( $this->conditions as $condition_options ) {
|
||||
$condition_result = $this->is_condition_passing_check( $condition_options );
|
||||
|
||||
if ( ! $condition_result ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function is_condition_passing_check( $condition_options ) {
|
||||
$condition_instance = $this->get_condition_instance( $condition_options );
|
||||
|
||||
return $condition_instance
|
||||
? $condition_instance->check( $condition_options )
|
||||
: true;
|
||||
}
|
||||
|
||||
private function get_condition_instance( $condition ) {
|
||||
if ( ! isset( $condition['condition'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->conditions_manager->get_condition( $condition['condition'] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Classes;
|
||||
|
||||
use Elementor\Core\Editor\Editor;
|
||||
|
||||
class Cache_Notice {
|
||||
const OPTION_NAME_DC_CACHE_NOTICE_DISMISSED = 'elementor_pro_dc_cache_notice_dismissed';
|
||||
const NOTICE_STATUS_YES = 'yes';
|
||||
|
||||
public function should_show_notice() : bool {
|
||||
return self::NOTICE_STATUS_YES !== get_option( self::OPTION_NAME_DC_CACHE_NOTICE_DISMISSED );
|
||||
}
|
||||
|
||||
public function set_notice_status() : bool {
|
||||
if ( ! current_user_can( Editor::EDITING_CAPABILITY ) ) {
|
||||
throw new \Exception( 'Access denied.' );
|
||||
}
|
||||
|
||||
return add_option( self::OPTION_NAME_DC_CACHE_NOTICE_DISMISSED, self::NOTICE_STATUS_YES, '', 'no' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Classes;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Comparator_Provider {
|
||||
|
||||
private static array $comparators = [];
|
||||
|
||||
public const COMPARATOR_IS = 'is';
|
||||
public const COMPARATOR_IS_NOT = 'is_not';
|
||||
public const COMPARATOR_IS_ONE_OF = 'is_one_of';
|
||||
public const COMPARATOR_IS_NONE_OF = 'is_none_of';
|
||||
public const COMPARATOR_CONTAINS = 'contains';
|
||||
public const COMPARATOR_NOT_CONTAIN = 'not_contain';
|
||||
|
||||
public const COMPARATOR_IS_BEFORE = 'is_before';
|
||||
public const COMPARATOR_IS_AFTER = 'is_after';
|
||||
public const COMPARATOR_IS_LESS_THAN_INCLUSIVE = 'is_less_than_inclusive';
|
||||
public const COMPARATOR_IS_GREATER_THAN_INCLUSIVE = 'is_greater_than_inclusive';
|
||||
public const COMPARATOR_IS_BEFORE_INCLUSIVE = 'is_before_inclusive';
|
||||
public const COMPARATOR_IS_AFTER_INCLUSIVE = 'is_after_inclusive';
|
||||
public const COMPARATOR_IS_EMPTY = 'is_empty';
|
||||
public const COMPARATOR_IS_NOT_EMPTY = 'is_not_empty';
|
||||
|
||||
public static function get_comparators( array $comparators ): array {
|
||||
self::init_comparators_array_if_empty();
|
||||
|
||||
return array_intersect_key( self::$comparators, array_flip( $comparators ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private static function init_comparators_array_if_empty(): void {
|
||||
if ( ! empty( self::$comparators ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$comparators[ static::COMPARATOR_IS ] = esc_html__( 'Is', 'elementor-pro' );
|
||||
self::$comparators[ static::COMPARATOR_IS_NOT ] = esc_html__( 'Is Not', 'elementor-pro' );
|
||||
self::$comparators[ static::COMPARATOR_IS_ONE_OF ] = esc_html__( 'Is', 'elementor-pro' );
|
||||
self::$comparators[ static::COMPARATOR_IS_NONE_OF ] = esc_html__( 'Is Not', 'elementor-pro' );
|
||||
self::$comparators[ static::COMPARATOR_CONTAINS ] = esc_html__( 'Contains', 'elementor-pro' );
|
||||
self::$comparators[ static::COMPARATOR_NOT_CONTAIN ] = esc_html__( 'Does not contain', 'elementor-pro' );
|
||||
self::$comparators[ static::COMPARATOR_IS_BEFORE ] = esc_html__( 'Is Before', 'elementor-pro' );
|
||||
self::$comparators[ static::COMPARATOR_IS_AFTER ] = esc_html__( 'Is After', 'elementor-pro' );
|
||||
self::$comparators[ static::COMPARATOR_IS_LESS_THAN_INCLUSIVE ] = esc_html__( 'Less than or equal', 'elementor-pro' );
|
||||
self::$comparators[ static::COMPARATOR_IS_GREATER_THAN_INCLUSIVE ] = esc_html__( 'Greater than or equal', 'elementor-pro' );
|
||||
self::$comparators[ static::COMPARATOR_IS_BEFORE_INCLUSIVE ] = esc_html__( 'Is on or before', 'elementor-pro' );
|
||||
self::$comparators[ static::COMPARATOR_IS_AFTER_INCLUSIVE ] = esc_html__( 'Is on or after', 'elementor-pro' );
|
||||
self::$comparators[ static::COMPARATOR_IS_EMPTY ] = esc_html__( 'Is Empty', 'elementor-pro' );
|
||||
self::$comparators[ static::COMPARATOR_IS_NOT_EMPTY ] = esc_html__( 'Is not Empty', 'elementor-pro' );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Classes;
|
||||
|
||||
use DateTime;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Comparators_Checker {
|
||||
|
||||
/**
|
||||
* @param string $comparator
|
||||
* @param string|DateTime $value_to_check
|
||||
* @param string|DateTime $set_value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function check_date_time( string $comparator, $value_to_check, $set_value ): bool {
|
||||
switch ( $comparator ) {
|
||||
case Comparator_Provider::COMPARATOR_IS:
|
||||
return $set_value == $value_to_check;
|
||||
case Comparator_Provider::COMPARATOR_IS_NOT:
|
||||
return $set_value != $value_to_check;
|
||||
case Comparator_Provider::COMPARATOR_IS_AFTER:
|
||||
return $set_value < $value_to_check;
|
||||
case Comparator_Provider::COMPARATOR_IS_BEFORE:
|
||||
return $set_value > $value_to_check;
|
||||
case Comparator_Provider::COMPARATOR_IS_AFTER_INCLUSIVE:
|
||||
return $set_value <= $value_to_check;
|
||||
case Comparator_Provider::COMPARATOR_IS_BEFORE_INCLUSIVE:
|
||||
return $set_value >= $value_to_check;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function check_array_contains( string $comparator, array $expected_values, array $array_of_values ): bool {
|
||||
$is_contained = ! empty( array_intersect( $expected_values, $array_of_values ) );
|
||||
switch ( $comparator ) {
|
||||
case Comparator_Provider::COMPARATOR_IS:
|
||||
case Comparator_Provider::COMPARATOR_IS_ONE_OF:
|
||||
return $is_contained;
|
||||
|
||||
case Comparator_Provider::COMPARATOR_IS_NOT:
|
||||
case Comparator_Provider::COMPARATOR_IS_NONE_OF:
|
||||
return ! $is_contained;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function check_string_contains( string $comparator, string $expected_value, string $actual_value ): bool {
|
||||
$expected_value = strtolower( $expected_value );
|
||||
$actual_value = strtolower( $actual_value );
|
||||
|
||||
switch ( $comparator ) {
|
||||
case Comparator_Provider::COMPARATOR_IS:
|
||||
return $expected_value === $actual_value;
|
||||
|
||||
case Comparator_Provider::COMPARATOR_IS_NOT:
|
||||
return $expected_value !== $actual_value;
|
||||
|
||||
case Comparator_Provider::COMPARATOR_CONTAINS:
|
||||
return str_contains( $actual_value, $expected_value );
|
||||
|
||||
case Comparator_Provider::COMPARATOR_NOT_CONTAIN:
|
||||
return ! str_contains( $actual_value, $expected_value );
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function check_string_contains_and_empty( string $comparator, string $expected_value, string $actual_value ): bool {
|
||||
if ( self::check_string_contains( $comparator, $expected_value, $actual_value ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch ( $comparator ) {
|
||||
case Comparator_Provider::COMPARATOR_IS_EMPTY:
|
||||
return empty( $actual_value );
|
||||
|
||||
case Comparator_Provider::COMPARATOR_IS_NOT_EMPTY:
|
||||
return ! empty( $actual_value );
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function check_equality( string $comparator, string $value, string $compare_to ): bool {
|
||||
switch ( $comparator ) {
|
||||
case Comparator_Provider::COMPARATOR_IS:
|
||||
return $value === $compare_to;
|
||||
|
||||
case Comparator_Provider::COMPARATOR_IS_NOT:
|
||||
return $value !== $compare_to;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $comparator
|
||||
* @param int $value
|
||||
* @param int $compare_to
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function check_numeric_constraints( string $comparator, int $value, int $compare_to ): bool {
|
||||
switch ( $comparator ) {
|
||||
case Comparator_Provider::COMPARATOR_IS:
|
||||
return $compare_to === $value;
|
||||
case Comparator_Provider::COMPARATOR_IS_NOT:
|
||||
return $compare_to !== $value;
|
||||
case Comparator_Provider::COMPARATOR_IS_LESS_THAN_INCLUSIVE:
|
||||
return $compare_to <= $value;
|
||||
case Comparator_Provider::COMPARATOR_IS_GREATER_THAN_INCLUSIVE:
|
||||
return $compare_to >= $value;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Classes;
|
||||
|
||||
use ElementorPro\Core\Isolation\Wordpress_Adapter;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Condition_Base;
|
||||
use ElementorPro\Modules\DisplayConditions\Module;
|
||||
use ElementorPro\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Conditions_Manager {
|
||||
/**
|
||||
* @var Condition_Base[]
|
||||
*/
|
||||
private $conditions = [];
|
||||
|
||||
private $groups;
|
||||
|
||||
private const CONDITIONS = [
|
||||
// Page
|
||||
'Page_Title_Condition',
|
||||
'Page_Parent_Condition',
|
||||
'Page_Author_Condition',
|
||||
|
||||
// Post
|
||||
'Post_Title_Condition',
|
||||
'In_Categories_Condition',
|
||||
'In_Tags_Condition',
|
||||
'Date_Of_Modification_Condition',
|
||||
'Date_Of_Publish_Condition',
|
||||
'Post_Author_Condition',
|
||||
'Post_Number_Of_Comments_Condition',
|
||||
'Featured_Image_Condition',
|
||||
|
||||
// User
|
||||
'Login_Status_Condition',
|
||||
'User_Role_Condition',
|
||||
'User_Registration_Date_Condition',
|
||||
|
||||
// Date and time
|
||||
'Day_Of_The_Week_Condition',
|
||||
'Time_Of_The_Day_Condition',
|
||||
'Current_Date_Condition',
|
||||
|
||||
// Archive
|
||||
'Archive_Of_Category_Condition',
|
||||
'Archive_Of_Tag_Condition',
|
||||
'Archive_Of_Author_Condition',
|
||||
|
||||
// Other
|
||||
'From_URL_Condition',
|
||||
'Dynamic_Tags_Condition',
|
||||
];
|
||||
|
||||
private Module $display_conditions_module;
|
||||
|
||||
public function __construct( $display_conditions_module ) {
|
||||
$this->display_conditions_module = $display_conditions_module;
|
||||
$this->register_conditions();
|
||||
}
|
||||
|
||||
private function init_groups() {
|
||||
$this->groups = [
|
||||
'page' => [
|
||||
'label' => esc_html__( 'Page', 'elementor-pro' ),
|
||||
],
|
||||
'post' => [
|
||||
'label' => esc_html__( 'Post', 'elementor-pro' ),
|
||||
],
|
||||
'user' => [
|
||||
'label' => esc_html__( 'User', 'elementor-pro' ),
|
||||
],
|
||||
'date' => [
|
||||
'label' => esc_html__( 'Date and Time', 'elementor-pro' ),
|
||||
],
|
||||
'archive' => [
|
||||
'label' => esc_html__( 'Archive', 'elementor-pro' ),
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Registration of a group for the display conditions.
|
||||
*
|
||||
* Fires when a new display condition groups is registered. This hook allows developers
|
||||
* to register new display conditions groups using add_group().
|
||||
*
|
||||
* @param Conditions_Manager $this An instance of conditions manager.
|
||||
*/
|
||||
do_action( 'elementor/display_conditions/register_groups', $this );
|
||||
|
||||
$this->groups['other'] = [ 'label' => esc_html__( 'Other', 'elementor-pro' ) ];
|
||||
}
|
||||
|
||||
private function register_condition( $id, $args = [] ) {
|
||||
if ( isset( $this->conditions[ $id ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$args[] = new Wordpress_Adapter();
|
||||
$class_name = '\\ElementorPro\\Modules\\DisplayConditions\\Conditions\\' . $id;
|
||||
|
||||
/** @var Condition_Base $condition */
|
||||
$condition = new $class_name( $args );
|
||||
|
||||
$this->register_condition_instance( $condition );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Condition_Base $instance
|
||||
* @return false|void
|
||||
*/
|
||||
public function register_condition_instance( Condition_Base $instance ) {
|
||||
$id = $instance->get_name();
|
||||
$is_exist = $this->get_condition( $id );
|
||||
|
||||
if ( false !== $is_exist ) {
|
||||
return false; // Already registered.
|
||||
}
|
||||
|
||||
$this->conditions[ $id ] = $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add condition group.
|
||||
*
|
||||
* Register new group for the condition.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $group_name Group name.
|
||||
* @param array $group_properties Group properties.
|
||||
*/
|
||||
public function add_group( $group_name, $group_properties ) {
|
||||
if ( null === $this->groups ) {
|
||||
$this->get_groups();
|
||||
}
|
||||
|
||||
if ( ! isset( $this->groups[ $group_name ] ) ) {
|
||||
$this->groups[ $group_name ] = $group_properties;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get condition groups.
|
||||
*
|
||||
* Retrieve the list of groups for the conditions.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @return array Condition groups.
|
||||
*/
|
||||
private function get_groups() {
|
||||
if ( null === $this->groups ) {
|
||||
$this->init_groups();
|
||||
}
|
||||
|
||||
return $this->groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
*
|
||||
* @return Condition_Base|bool
|
||||
*/
|
||||
public function get_condition( $id ) {
|
||||
return isset( $this->conditions[ $id ] ) ? $this->conditions[ $id ] : false;
|
||||
}
|
||||
|
||||
public function get_conditions_config() {
|
||||
$config = [];
|
||||
|
||||
$config['conditions'] = [];
|
||||
|
||||
foreach ( $this->conditions as $condition ) {
|
||||
$config['conditions'][ $condition->get_name() ] = $condition->get_config();
|
||||
}
|
||||
|
||||
$config['groups'] = $this->get_groups();
|
||||
$config['show_cache_notice'] = $this->display_conditions_module->get_component( 'cache_notice' )->should_show_notice();
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function register_conditions() {
|
||||
$conditions = self::CONDITIONS;
|
||||
|
||||
foreach ( $conditions as $condition ) {
|
||||
$this->register_condition( $condition );
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor display conditions registration.
|
||||
*
|
||||
* Fires when a new display condition is registered. This hook allows developers
|
||||
* to register new display conditions using register_condition_instance().
|
||||
*
|
||||
* @param Conditions_Manager $this An instance of conditions manager.
|
||||
*/
|
||||
do_action( 'elementor/display_conditions/register', $this );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Classes\DynamicTags;
|
||||
|
||||
class Custom_Fields_Data_Provider implements Data_Provider {
|
||||
|
||||
const CUSTOM_FIELDS_META_LIMIT = 50;
|
||||
|
||||
/**
|
||||
* Build the custom fields options for the control. Add the groups and the items.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_control_options(): array {
|
||||
global $wpdb;
|
||||
|
||||
$keys = $wpdb->get_col(
|
||||
$wpdb->prepare(
|
||||
"SELECT DISTINCT meta_key
|
||||
FROM $wpdb->postmeta
|
||||
WHERE meta_key NOT BETWEEN '_' AND '_z'
|
||||
HAVING meta_key NOT LIKE %s
|
||||
ORDER BY meta_key
|
||||
LIMIT %d",
|
||||
$wpdb->esc_like( '_' ) . '%',
|
||||
apply_filters( 'elementor_pro/display_conditions/dynamic_tags/custom_fields_meta_limit', static::CUSTOM_FIELDS_META_LIMIT )
|
||||
)
|
||||
);
|
||||
|
||||
if ( empty( $keys ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->get_control_groups() + array_combine( $keys, $keys );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $args
|
||||
*
|
||||
* @return string | bool
|
||||
*/
|
||||
public function get_value( array $args ) {
|
||||
if ( ! metadata_exists( 'post', get_the_ID(), $args['dynamic_tag'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return get_post_meta( get_the_ID(), $args['dynamic_tag'], true );
|
||||
}
|
||||
|
||||
private function get_control_groups(): array {
|
||||
return [
|
||||
'custom_field' => [
|
||||
'label' => esc_html__( 'Custom Field', 'elementor-pro' ),
|
||||
'type' => 'group',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Classes\DynamicTags;
|
||||
|
||||
interface Data_Provider {
|
||||
|
||||
/**
|
||||
* @param array $args
|
||||
* @return string | bool
|
||||
*/
|
||||
public function get_value( array $args );
|
||||
|
||||
public function get_control_options(): array;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Classes\DynamicTags;
|
||||
|
||||
use ElementorPro\Plugin;
|
||||
|
||||
class Dynamic_Tags_Data_Provider implements Data_Provider {
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $dynamic_tags_options = [];
|
||||
|
||||
/**
|
||||
* Build the dynamic tags options for the control. Add the groups and the items.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_control_options(): array {
|
||||
$result = [];
|
||||
$dynamic_tags_options = $this->get_dynamic_tags_options();
|
||||
|
||||
foreach ( $this->get_control_groups() as $group_key => $group_name ) {
|
||||
$result[ $group_key ] = [
|
||||
'label' => $group_name,
|
||||
'type' => 'group',
|
||||
];
|
||||
|
||||
$group_items = array_filter( $dynamic_tags_options, function( $item ) use ( $group_key ) {
|
||||
return $group_key === $item['group'];
|
||||
} );
|
||||
|
||||
$group_items = array_map( function( $item ) {
|
||||
return $item['label'];
|
||||
}, $group_items );
|
||||
|
||||
$result = $result + $group_items;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function get_default_control_option(): string {
|
||||
return array_key_first( $this->get_dynamic_tags_options() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return array
|
||||
*/
|
||||
public function get_dynamic_tag_options( string $key ): array {
|
||||
$dt_config = $this->get_dynamic_tags_options();
|
||||
|
||||
return ! empty( $dt_config[ $key ] ) ? $dt_config[ $key ] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_dynamic_tags_options(): array {
|
||||
if ( ! empty( $this->dynamic_tags_options ) ) {
|
||||
return $this->dynamic_tags_options;
|
||||
}
|
||||
|
||||
$dynamic_tags_config = Plugin::elementor()->dynamic_tags->get_config();
|
||||
|
||||
foreach ( $dynamic_tags_config['tags'] as $dynamic_tag_config ) {
|
||||
if ( empty( $dynamic_tag_config['display_conditions'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$new_options = array_map( function( $item ) use ( $dynamic_tag_config ) {
|
||||
return $item + [ 'dynamic_tag_name' => $dynamic_tag_config['name'] ];
|
||||
}, $dynamic_tag_config['display_conditions'] );
|
||||
|
||||
$this->dynamic_tags_options = $this->dynamic_tags_options + $new_options;
|
||||
}
|
||||
|
||||
return $this->dynamic_tags_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $args
|
||||
* @return string | bool
|
||||
*/
|
||||
public function get_value( array $args ) {
|
||||
$dt_options = $this->get_dynamic_tag_options( $args['dynamic_tag'] );
|
||||
|
||||
if ( empty( $dt_options ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Plugin::elementor()->dynamic_tags->get_tag_data_content( null, $dt_options['dynamic_tag_name'], $dt_options['settings'] ) ?? false;
|
||||
}
|
||||
|
||||
private function get_control_groups(): array {
|
||||
return [
|
||||
'archive' => esc_html__( 'Archive', 'elementor-pro' ),
|
||||
'featured_image' => esc_html__( 'Featured Image', 'elementor-pro' ),
|
||||
'author' => esc_html__( 'Author', 'elementor-pro' ),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Classes;
|
||||
|
||||
use Elementor\Core\Experiments\Manager;
|
||||
use ElementorPro\Plugin;
|
||||
use ElementorPro\Modules\DisplayConditions\Module as Display_Conditions_Module;
|
||||
|
||||
class Experiments {
|
||||
public static function register_dc_experiment() {
|
||||
Plugin::elementor()->experiments->add_feature( [
|
||||
'name' => Display_Conditions_Module::LICENSE_FEATURE_NAME,
|
||||
'title' => esc_html__( 'Display Conditions', 'elementor-pro' ),
|
||||
'description' => sprintf(
|
||||
/* translators: 1: opening link tag, 2: closing link tag, 3: line break, 4: opening span tag, 5: closing span tag. */
|
||||
esc_html__( 'Define one or multiple conditions per widget, controlling when they\'re visible. Widgets will only appear on the front end if these conditions are met. It\'s ideal for showing content to specific audiences based on time, date, user role, and more. %1$sLearn More%2$s%3$s%4$sRequires: Elementor version 3.19%5$s', 'elementor-pro' ),
|
||||
'<a href="https://go.elementor.com/wp-dash-display-conditions/" target="_blank">',
|
||||
'</a>',
|
||||
'<br>',
|
||||
'<span style="display: block; font-weight: 700; color: #21759b; font-style: italic; line-height: 18px; padding-block-start: 10px; margin-block-end: -5px;">',
|
||||
'</span>',
|
||||
),
|
||||
'release_status' => Manager::RELEASE_STATUS_BETA,
|
||||
'default' => Manager::STATE_INACTIVE,
|
||||
'new_site' => [
|
||||
'default_active' => true,
|
||||
'minimum_installation_version' => '3.20',
|
||||
],
|
||||
] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Classes;
|
||||
|
||||
class Or_Condition {
|
||||
/**
|
||||
* @var $conditions_manager Object
|
||||
*/
|
||||
private $conditions_manager;
|
||||
|
||||
/**
|
||||
* @var $and_conditions And_Condition[]
|
||||
*/
|
||||
private $and_conditions;
|
||||
|
||||
public function __construct( $conditions_manager, $sets ) {
|
||||
$this->conditions_manager = $conditions_manager;
|
||||
$this->set_and_conditions( $sets );
|
||||
}
|
||||
|
||||
public function check() {
|
||||
if ( empty( $this->and_conditions ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ( $this->and_conditions as $condition ) {
|
||||
if ( $condition->check() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function set_and_conditions( $groups ) {
|
||||
$this->and_conditions = array_map( function ( $condition ) {
|
||||
return new And_Condition( $this->conditions_manager, $condition );
|
||||
}, $groups );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Condition_Base;
|
||||
use ElementorPro\Modules\QueryControl\Module as QueryControlModule;
|
||||
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Archive_Of_Author_Condition extends Condition_Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'archive_of_authors';
|
||||
}
|
||||
|
||||
public function get_label(): string {
|
||||
return esc_html__( 'Of Authors', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return 'archive';
|
||||
}
|
||||
|
||||
public function check( $args ) : bool {
|
||||
if ( empty( $args['authors'] ) ) {
|
||||
return parent::check( $args );
|
||||
}
|
||||
|
||||
$author_ids = array_column( $args['authors'], 'id' );
|
||||
|
||||
switch ( $args['comparator'] ) {
|
||||
case Comparator_Provider::COMPARATOR_IS:
|
||||
return $this->wordpress_adapter->is_author( $author_ids );
|
||||
|
||||
case Comparator_Provider::COMPARATOR_IS_NOT:
|
||||
return ! $this->wordpress_adapter->is_author( $author_ids );
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function get_options() {
|
||||
$comparators = Comparator_Provider::get_comparators( [
|
||||
Comparator_Provider::COMPARATOR_IS,
|
||||
Comparator_Provider::COMPARATOR_IS_NOT,
|
||||
] );
|
||||
|
||||
$this->add_control(
|
||||
'comparator',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => $comparators,
|
||||
'default' => Comparator_Provider::COMPARATOR_IS,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'authors',
|
||||
[
|
||||
'type' => QueryControlModule::QUERY_CONTROL_ID,
|
||||
'autocomplete' => [
|
||||
'object' => QueryControlModule::QUERY_OBJECT_AUTHOR,
|
||||
],
|
||||
'multiple' => true,
|
||||
'required' => true,
|
||||
'placeholder' => esc_html__( 'Type to search', 'elementor-pro' ),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Archive_Condition_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Archive_Of_Category_Condition extends Archive_Condition_Base {
|
||||
public function __construct() {
|
||||
parent::__construct( 'categories' );
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'archive_of_categories';
|
||||
}
|
||||
|
||||
public function get_label(): string {
|
||||
return esc_html__( 'Of Categories', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function check( $args ): bool {
|
||||
return parent::check_is_of_taxonomy( $args );
|
||||
}
|
||||
|
||||
protected function is_of_taxonomy( $args ): bool {
|
||||
return is_category( array_column( $args['categories'], 'id' ) );
|
||||
}
|
||||
|
||||
protected function get_taxonomy() {
|
||||
return 'category';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Archive_Condition_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Archive_Of_Tag_Condition extends Archive_Condition_Base {
|
||||
public function __construct() {
|
||||
parent::__construct( 'tags' );
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'archive_of_tags';
|
||||
}
|
||||
|
||||
public function get_label(): string {
|
||||
return esc_html__( 'Of Tags', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function check( $args ): bool {
|
||||
return parent::check_is_of_taxonomy( $args );
|
||||
}
|
||||
|
||||
protected function is_of_taxonomy( $args ): bool {
|
||||
return is_tag( array_column( $args['tags'], 'id' ) );
|
||||
}
|
||||
|
||||
protected function get_taxonomy() {
|
||||
return 'post_tag';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions\Base;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\QueryControl\Module as QueryControlModule;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
abstract class Archive_Condition_Base extends Condition_Base {
|
||||
|
||||
private string $condition_key;
|
||||
|
||||
public function __construct( $condition_key ) {
|
||||
$this->condition_key = $condition_key;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
abstract public function get_name();
|
||||
|
||||
abstract public function get_label();
|
||||
|
||||
abstract protected function get_taxonomy();
|
||||
|
||||
public function get_group(): string {
|
||||
return 'archive';
|
||||
}
|
||||
|
||||
abstract protected function is_of_taxonomy( $args ): bool;
|
||||
|
||||
protected function check_is_of_taxonomy( $args ) {
|
||||
switch ( $args['comparator'] ) {
|
||||
case Comparator_Provider::COMPARATOR_IS:
|
||||
return $this->is_of_taxonomy( $args );
|
||||
case Comparator_Provider::COMPARATOR_IS_NOT:
|
||||
return ! $this->is_of_taxonomy( $args );
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function get_options() {
|
||||
$comparators = Comparator_Provider::get_comparators( [
|
||||
Comparator_Provider::COMPARATOR_IS,
|
||||
Comparator_Provider::COMPARATOR_IS_NOT,
|
||||
] );
|
||||
$taxonomy = $this->get_taxonomy();
|
||||
|
||||
$this->add_control(
|
||||
'comparator',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => $comparators,
|
||||
'default' => Comparator_Provider::COMPARATOR_IS,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
$this->condition_key,
|
||||
[
|
||||
'type' => QueryControlModule::QUERY_CONTROL_ID,
|
||||
'autocomplete' => [
|
||||
'object' => QueryControlModule::QUERY_OBJECT_TAX,
|
||||
'query' => [
|
||||
'taxonomy' => $taxonomy,
|
||||
],
|
||||
],
|
||||
'multiple' => true,
|
||||
'required' => true,
|
||||
'placeholder' => esc_html__( 'Type to search', 'elementor-pro' ),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions\Base;
|
||||
|
||||
use Elementor\Controls_Stack;
|
||||
use ElementorPro\Core\Isolation\Wordpress_Adapter_Interface;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
abstract class Condition_Base extends Controls_Stack {
|
||||
|
||||
/**
|
||||
* @var Wordpress_Adapter_Interface
|
||||
*/
|
||||
protected $wordpress_adapter;
|
||||
|
||||
public function __construct( array $data = [] ) {
|
||||
$this->wordpress_adapter = array_pop( $data );
|
||||
parent::__construct( $data );
|
||||
}
|
||||
|
||||
abstract public function get_label();
|
||||
|
||||
abstract public function get_options();
|
||||
|
||||
public function get_group() {
|
||||
return 'other';
|
||||
}
|
||||
|
||||
public function check( $args ) : bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
$this->start_controls_section(
|
||||
'__settings'
|
||||
);
|
||||
|
||||
$this->get_options();
|
||||
|
||||
$this->end_controls_section();
|
||||
}
|
||||
|
||||
protected function get_initial_config() {
|
||||
$config = parent::get_initial_config();
|
||||
|
||||
$config['label'] = $this->get_label();
|
||||
$config['group'] = $this->get_group();
|
||||
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions\Base;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparators_Checker;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
abstract class Date_Condition_Base extends Condition_Base {
|
||||
private $condition_key;
|
||||
private $group_key;
|
||||
|
||||
const COMPARATOR_KEY = 'comparator';
|
||||
const OPTION_KEY = 'date_type';
|
||||
|
||||
const DATE_FORMAT = 'm-d-Y';
|
||||
const OPTION_SERVER = 'server';
|
||||
const OPTION_CLIENT = 'client';
|
||||
|
||||
public function __construct( $condition_key, $group_key ) {
|
||||
$this->condition_key = $condition_key;
|
||||
$this->group_key = $group_key;
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return $this->group_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function get_time_options(): array {
|
||||
return [
|
||||
self::OPTION_SERVER => esc_html__( 'Server Time', 'elementor-pro' ),
|
||||
self::OPTION_CLIENT => esc_html__( 'Visitor Time', 'elementor-pro' ),
|
||||
];
|
||||
}
|
||||
|
||||
protected function check_date( $args, $date_to_check ): bool {
|
||||
$comparator = $args[ self::COMPARATOR_KEY ];
|
||||
$date_string = $args[ $this->condition_key ];
|
||||
$set_date = date_create_from_format( self::DATE_FORMAT, $date_string );
|
||||
|
||||
if ( ! $set_date || ! $date_to_check || ! $comparator || $set_date->format( self::DATE_FORMAT ) !== $date_string ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Comparators_Checker::check_date_time( $comparator, $date_to_check, $set_date );
|
||||
}
|
||||
|
||||
public function get_options() {
|
||||
$this->add_control(
|
||||
self::COMPARATOR_KEY,
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => Comparator_Provider::get_comparators(
|
||||
[
|
||||
Comparator_Provider::COMPARATOR_IS,
|
||||
Comparator_Provider::COMPARATOR_IS_NOT,
|
||||
Comparator_Provider::COMPARATOR_IS_BEFORE,
|
||||
Comparator_Provider::COMPARATOR_IS_AFTER,
|
||||
Comparator_Provider::COMPARATOR_IS_BEFORE_INCLUSIVE,
|
||||
Comparator_Provider::COMPARATOR_IS_AFTER_INCLUSIVE,
|
||||
]
|
||||
),
|
||||
'default' => Comparator_Provider::COMPARATOR_IS,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
$this->condition_key,
|
||||
[
|
||||
'type' => Controls_Manager::DATE_TIME,
|
||||
'label' => $this::get_label(),
|
||||
'variant' => 'date',
|
||||
'required' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
self::OPTION_KEY,
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => self::get_time_options(),
|
||||
'default' => self::OPTION_SERVER,
|
||||
'disabled_options' => [ self::OPTION_CLIENT ],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions\Base;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparators_Checker;
|
||||
use ElementorPro\Modules\QueryControl\Module as QueryControlModule;
|
||||
|
||||
abstract class Title_Condition_Base extends Condition_Base {
|
||||
abstract protected function get_query();
|
||||
|
||||
public function check( $args ) : bool {
|
||||
$titles = array_column( $args['titles'], 'text' );
|
||||
$title = get_the_title();
|
||||
$comparator = $args['comparator'];
|
||||
|
||||
return Comparators_Checker::check_array_contains( $comparator, [ $title ], $titles );
|
||||
}
|
||||
|
||||
public function get_options() {
|
||||
$comparators = Comparator_Provider::get_comparators(
|
||||
[
|
||||
Comparator_Provider::COMPARATOR_IS,
|
||||
Comparator_Provider::COMPARATOR_IS_NOT,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'comparator',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => $comparators,
|
||||
'default' => Comparator_Provider::COMPARATOR_IS,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'titles',
|
||||
[
|
||||
'type' => QueryControlModule::QUERY_CONTROL_ID,
|
||||
'autocomplete' => [
|
||||
'object' => QueryControlModule::QUERY_OBJECT_POST,
|
||||
'query' => $this->get_query(),
|
||||
],
|
||||
'multiple' => true,
|
||||
'placeholder' => esc_html__( 'Type to search', 'elementor-pro' ),
|
||||
'required' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Date_Condition_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Current_Date_Condition extends Date_Condition_Base {
|
||||
const CONDITION_KEY = 'date';
|
||||
const GROUP_KEY = 'date';
|
||||
|
||||
public function get_name() {
|
||||
return 'current_date';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Current Date', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct( self::CONDITION_KEY, self::GROUP_KEY );
|
||||
}
|
||||
|
||||
public function check( $args ) : bool {
|
||||
return parent::check_date( $args, $this->get_current_date() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DateTime|false
|
||||
*/
|
||||
private function get_current_date() {
|
||||
return date_create_from_format( self::DATE_FORMAT, gmdate( self::DATE_FORMAT ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Date_Condition_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Date_Of_Modification_Condition extends Date_Condition_Base {
|
||||
const CONDITION_KEY = 'date';
|
||||
const GROUP_KEY = 'date';
|
||||
|
||||
public function get_name() {
|
||||
return 'date_of_modification';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Date Modified', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return 'post';
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct( self::CONDITION_KEY, self::GROUP_KEY );
|
||||
}
|
||||
|
||||
public function check( $args ): bool {
|
||||
return parent::check_date( $args, $this->get_modification_date() );
|
||||
}
|
||||
|
||||
private function get_modification_date() {
|
||||
return date_create_from_format(
|
||||
self::DATE_FORMAT,
|
||||
get_the_modified_date( self::DATE_FORMAT, get_the_ID() )
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Date_Condition_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Date_Of_Publish_Condition extends Date_Condition_Base {
|
||||
const CONDITION_KEY = 'date';
|
||||
const GROUP_KEY = 'date';
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct( self::CONDITION_KEY, self::GROUP_KEY );
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'date_of_publish';
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return 'post';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Date of Publish', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function check( $args ): bool {
|
||||
return parent::check_date( $args, $this->get_post_date() );
|
||||
}
|
||||
|
||||
private function get_post_date() {
|
||||
return date_create_from_format(
|
||||
self::DATE_FORMAT,
|
||||
get_the_date( self::DATE_FORMAT, get_the_ID() )
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparators_Checker;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Condition_Base;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Date_Condition_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Day_Of_The_Week_Condition extends Condition_Base {
|
||||
const CONDITION_KEY = 'days';
|
||||
|
||||
public function get_name() {
|
||||
return 'day_of_the_week';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Day of the week', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return 'date';
|
||||
}
|
||||
|
||||
public function check( $args ) : bool {
|
||||
return Comparators_Checker::check_array_contains( $args['comparator'], [ strtolower( gmdate( 'l' ) ) ], $args['days'] );
|
||||
}
|
||||
|
||||
public function get_options() {
|
||||
$comparators = Comparator_Provider::get_comparators(
|
||||
[
|
||||
Comparator_Provider::COMPARATOR_IS_ONE_OF,
|
||||
Comparator_Provider::COMPARATOR_IS_NONE_OF,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'comparator',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => $comparators,
|
||||
'default' => Comparator_Provider::COMPARATOR_IS_ONE_OF,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
self::CONDITION_KEY,
|
||||
[
|
||||
'type' => Controls_Manager::SELECT2,
|
||||
'options' => [
|
||||
'monday' => esc_html__( 'Monday', 'elementor-pro' ),
|
||||
'tuesday' => esc_html__( 'Tuesday', 'elementor-pro' ),
|
||||
'wednesday' => esc_html__( 'Wednesday', 'elementor-pro' ),
|
||||
'thursday' => esc_html__( 'Thursday', 'elementor-pro' ),
|
||||
'friday' => esc_html__( 'Friday', 'elementor-pro' ),
|
||||
'saturday' => esc_html__( 'Saturday', 'elementor-pro' ),
|
||||
'sunday' => esc_html__( 'Sunday', 'elementor-pro' ),
|
||||
],
|
||||
'multiple' => true,
|
||||
'required' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'time_type',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => Date_Condition_Base::get_time_options(),
|
||||
'default' => Date_Condition_Base::OPTION_SERVER,
|
||||
'disabled_options' => [ Date_Condition_Base::OPTION_CLIENT ],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparators_Checker;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\DynamicTags\Custom_Fields_Data_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\DynamicTags\Dynamic_Tags_Data_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Condition_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Dynamic_Tags_Condition extends Condition_Base {
|
||||
|
||||
/**
|
||||
* @var Dynamic_Tags_Data_Provider
|
||||
*/
|
||||
private $dynamic_tags_data_provider;
|
||||
|
||||
/**
|
||||
* @var Custom_Fields_Data_Provider
|
||||
*/
|
||||
private $custom_fields_data_provider;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->dynamic_tags_data_provider = new Dynamic_Tags_Data_Provider();
|
||||
$this->custom_fields_data_provider = new Custom_Fields_Data_Provider();
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'dynamic_tags';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Dynamic Tags', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return 'other';
|
||||
}
|
||||
|
||||
public function check( $args ) : bool {
|
||||
$value = $this->get_condition_value( $args );
|
||||
|
||||
if ( false === $value ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Comparators_Checker::check_string_contains_and_empty( $args['comparator'], $args['dynamic_tag_value'], $value );
|
||||
}
|
||||
|
||||
public function get_options() {
|
||||
$this->add_control(
|
||||
'dynamic_tag',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => $this->dynamic_tags_data_provider->get_control_options() + $this->custom_fields_data_provider->get_control_options(),
|
||||
'default' => $this->dynamic_tags_data_provider->get_default_control_option(),
|
||||
'disabled_options' => ! current_user_can( 'manage_options' ) ? [ 'author_info_email' ] : [],
|
||||
'disabled_type' => 'hidden',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'comparator',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => Comparator_Provider::get_comparators(
|
||||
[
|
||||
Comparator_Provider::COMPARATOR_IS,
|
||||
Comparator_Provider::COMPARATOR_IS_NOT,
|
||||
Comparator_Provider::COMPARATOR_CONTAINS,
|
||||
Comparator_Provider::COMPARATOR_NOT_CONTAIN,
|
||||
Comparator_Provider::COMPARATOR_IS_EMPTY,
|
||||
Comparator_Provider::COMPARATOR_IS_NOT_EMPTY,
|
||||
]
|
||||
),
|
||||
'default' => Comparator_Provider::COMPARATOR_IS,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'dynamic_tag_value',
|
||||
[
|
||||
'placeholder' => esc_html__( 'Type a value', 'elementor-pro' ),
|
||||
'required' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditionally retrieve the value of a dynamic tag or custom field.
|
||||
*
|
||||
* @return string | bool
|
||||
*/
|
||||
private function get_condition_value( array $args ) {
|
||||
$dt_value = $this->dynamic_tags_data_provider->get_value( $args );
|
||||
|
||||
if ( $dt_value ) {
|
||||
return $dt_value;
|
||||
}
|
||||
|
||||
return $this->custom_fields_data_provider->get_value( $args );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparators_Checker;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Condition_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Featured_Image_Condition extends Condition_Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'featured_image';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Featured Image', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return 'post';
|
||||
}
|
||||
|
||||
public function check( $args ) : bool {
|
||||
return Comparators_Checker::check_equality(
|
||||
$args['comparator'],
|
||||
'set' === $args['status'],
|
||||
$this->wordpress_adapter->has_post_thumbnail()
|
||||
);
|
||||
}
|
||||
|
||||
public function get_options() {
|
||||
$comparators = Comparator_Provider::get_comparators(
|
||||
[
|
||||
Comparator_Provider::COMPARATOR_IS,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'comparator',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => $comparators,
|
||||
'default' => Comparator_Provider::COMPARATOR_IS,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'status',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => [
|
||||
'set' => esc_html__( 'Set', 'elementor-pro' ),
|
||||
'not_set' => esc_html__( 'Not Set', 'elementor-pro' ),
|
||||
],
|
||||
'default' => 'set',
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparators_Checker;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Condition_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class From_URL_Condition extends Condition_Base {
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'From URL', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_options() {
|
||||
$comparators = Comparator_Provider::get_comparators(
|
||||
[
|
||||
Comparator_Provider::COMPARATOR_IS,
|
||||
Comparator_Provider::COMPARATOR_IS_NOT,
|
||||
Comparator_Provider::COMPARATOR_CONTAINS,
|
||||
Comparator_Provider::COMPARATOR_NOT_CONTAIN,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'comparator',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => $comparators,
|
||||
'default' => Comparator_Provider::COMPARATOR_IS,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'from_url',
|
||||
[
|
||||
'label' => esc_html__( 'URL', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::TEXT,
|
||||
'placeholder' => esc_html__( 'URL', 'elementor-pro' ),
|
||||
'required' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'from_url';
|
||||
}
|
||||
|
||||
public function wp_get_referer() {
|
||||
return wp_get_raw_referer();
|
||||
}
|
||||
|
||||
public function check( $args ) : bool {
|
||||
$referrer = $this->wp_get_referer();
|
||||
|
||||
return Comparators_Checker::check_string_contains( $args['comparator'], $args['from_url'], $referrer );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparators_Checker;
|
||||
use ElementorPro\Modules\QueryControl\Module as QueryControlModule;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Condition_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class In_Categories_Condition extends Condition_Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'in_categories';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'In Categories', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return 'post';
|
||||
}
|
||||
|
||||
public function check( $args ): bool {
|
||||
if ( empty( $args['categories'] ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$post_categories = wp_get_post_categories( get_the_ID(), [ 'fields' => 'ids' ] ) ?? [];
|
||||
|
||||
if ( empty( $post_categories ) ) {
|
||||
return ! ( Comparator_Provider::COMPARATOR_IS === $args['comparator'] );
|
||||
}
|
||||
|
||||
$category_ids = array_column( $args['categories'], 'id' );
|
||||
|
||||
return Comparators_Checker::check_array_contains( $args['comparator'], $category_ids, $post_categories );
|
||||
}
|
||||
|
||||
public function get_options() {
|
||||
$comparators = Comparator_Provider::get_comparators(
|
||||
[
|
||||
Comparator_Provider::COMPARATOR_IS,
|
||||
Comparator_Provider::COMPARATOR_IS_NOT,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'comparator',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => $comparators,
|
||||
'default' => Comparator_Provider::COMPARATOR_IS,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'categories',
|
||||
[
|
||||
'type' => QueryControlModule::QUERY_CONTROL_ID,
|
||||
'autocomplete' => [
|
||||
'object' => QueryControlModule::QUERY_OBJECT_TAX,
|
||||
'query' => [
|
||||
'taxonomy' => 'category',
|
||||
],
|
||||
],
|
||||
'multiple' => true,
|
||||
'placeholder' => esc_html__( 'Type to search', 'elementor-pro' ),
|
||||
'required' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparators_Checker;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Condition_Base;
|
||||
use ElementorPro\Modules\QueryControl\Module as QueryControlModule;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class In_Tags_Condition extends Condition_Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'in_tags';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'In Tags', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return 'post';
|
||||
}
|
||||
|
||||
public function check( $args ) : bool {
|
||||
if ( empty( $args['tags'] ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$post_tags = wp_get_post_tags( get_the_ID(), [ 'fields' => 'ids' ] ) ?? [];
|
||||
|
||||
$tag_ids = array_column( $args['tags'], 'id' );
|
||||
|
||||
return Comparators_Checker::check_array_contains( $args['comparator'], $tag_ids, $post_tags );
|
||||
}
|
||||
|
||||
public function get_options() {
|
||||
$comparators = Comparator_Provider::get_comparators(
|
||||
[
|
||||
Comparator_Provider::COMPARATOR_IS,
|
||||
Comparator_Provider::COMPARATOR_IS_NOT,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'comparator',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => $comparators,
|
||||
'default' => Comparator_Provider::COMPARATOR_IS,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'tags',
|
||||
[
|
||||
'type' => QueryControlModule::QUERY_CONTROL_ID,
|
||||
'autocomplete' => [
|
||||
'object' => QueryControlModule::QUERY_OBJECT_TAX,
|
||||
'query' => [
|
||||
'taxonomy' => 'post_tag',
|
||||
],
|
||||
],
|
||||
'multiple' => true,
|
||||
'placeholder' => esc_html__( 'Type to search', 'elementor-pro' ),
|
||||
'required' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparators_Checker;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Condition_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Login_Status_Condition extends Condition_Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'login_status';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Login Status', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return 'user';
|
||||
}
|
||||
|
||||
public function check( $args ) : bool {
|
||||
return Comparators_Checker::check_equality( $args['comparator'], 'logged_in' === $args['status'], is_user_logged_in() );
|
||||
}
|
||||
|
||||
public function get_options() {
|
||||
$comparators = Comparator_Provider::get_comparators(
|
||||
[
|
||||
Comparator_Provider::COMPARATOR_IS,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'comparator',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => $comparators,
|
||||
'default' => Comparator_Provider::COMPARATOR_IS,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'status',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => [
|
||||
'logged_in' => esc_html__( 'Logged In', 'elementor-pro' ),
|
||||
'logged_out' => esc_html__( 'Logged Out', 'elementor-pro' ),
|
||||
],
|
||||
'default' => 'logged_in',
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparators_Checker;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Condition_Base;
|
||||
use ElementorPro\Modules\QueryControl\Module as QueryControlModule;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Page_Author_Condition extends Condition_Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'page_author';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Author', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return 'page';
|
||||
}
|
||||
|
||||
public function check( $args ) : bool {
|
||||
if ( empty( $args['authors'] ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$current_post = get_post();
|
||||
|
||||
if ( ! $current_post ) {
|
||||
return parent::check( $args );
|
||||
}
|
||||
|
||||
$author_ids = array_column( $args['authors'], 'id' );
|
||||
|
||||
return Comparators_Checker::check_array_contains( $args['comparator'], [ $current_post->post_author ], $author_ids );
|
||||
|
||||
}
|
||||
|
||||
public function get_options() {
|
||||
$comparators = Comparator_Provider::get_comparators(
|
||||
[
|
||||
Comparator_Provider::COMPARATOR_IS,
|
||||
Comparator_Provider::COMPARATOR_IS_NOT,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'comparator',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => $comparators,
|
||||
'default' => Comparator_Provider::COMPARATOR_IS,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'authors',
|
||||
[
|
||||
'label' => esc_html__( 'Author', 'elementor-pro' ),
|
||||
'type' => QueryControlModule::QUERY_CONTROL_ID,
|
||||
'autocomplete' => [
|
||||
'object' => QueryControlModule::QUERY_OBJECT_AUTHOR,
|
||||
],
|
||||
'multiple' => true,
|
||||
'placeholder' => esc_html__( 'Type to search', 'elementor-pro' ),
|
||||
'required' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparators_Checker;
|
||||
use ElementorPro\Modules\QueryControl\Module as QueryControlModule;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Condition_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Page_Parent_Condition extends Condition_Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'page_parent';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Page Parent', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return 'page';
|
||||
}
|
||||
|
||||
public function check( $args ) : bool {
|
||||
if ( empty( $args['pages'] ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$current_post = get_post();
|
||||
|
||||
$parent_page_ids = array_column( $args['pages'], 'id' );
|
||||
|
||||
return Comparators_Checker::check_array_contains( $args['comparator'], [ $current_post->post_parent ], $parent_page_ids );
|
||||
}
|
||||
|
||||
public function get_options() {
|
||||
$comparators = Comparator_Provider::get_comparators(
|
||||
[
|
||||
Comparator_Provider::COMPARATOR_IS_ONE_OF,
|
||||
Comparator_Provider::COMPARATOR_IS_NONE_OF,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'comparator',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => $comparators,
|
||||
'default' => Comparator_Provider::COMPARATOR_IS_ONE_OF,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pages',
|
||||
[
|
||||
'type' => QueryControlModule::QUERY_CONTROL_ID,
|
||||
'autocomplete' => [
|
||||
'object' => QueryControlModule::QUERY_OBJECT_POST,
|
||||
'query' => [
|
||||
'post_status' => 'publish',
|
||||
'post_type' => 'page',
|
||||
],
|
||||
],
|
||||
'multiple' => true,
|
||||
'placeholder' => esc_html__( 'Type to search', 'elementor-pro' ),
|
||||
'required' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Title_Condition_Base;
|
||||
|
||||
class Page_Title_Condition extends Title_Condition_Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'page_title';
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return 'page';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Page Title', 'elementor-pro' );
|
||||
}
|
||||
|
||||
protected function get_query() {
|
||||
return [
|
||||
'post_status' => 'publish',
|
||||
'post_type' => 'page',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
class Post_Author_Condition extends Page_Author_Condition {
|
||||
|
||||
public function get_name() {
|
||||
return 'post_author';
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return 'post';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparators_Checker;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Condition_Base;
|
||||
|
||||
class Post_Number_Of_Comments_Condition extends Condition_Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'number_of_comments';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Number of Comments', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return esc_html__( 'post', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function check( $args ): bool {
|
||||
$actual_number_of_comments = $this->wordpress_adapter->get_comments_number();
|
||||
|
||||
return Comparators_Checker::check_numeric_constraints( $args['comparator'], (int) $args['number_of_comments'], (int) $actual_number_of_comments );
|
||||
}
|
||||
|
||||
public function get_options() {
|
||||
$comparators = Comparator_Provider::get_comparators(
|
||||
[
|
||||
Comparator_Provider::COMPARATOR_IS_GREATER_THAN_INCLUSIVE,
|
||||
Comparator_Provider::COMPARATOR_IS_LESS_THAN_INCLUSIVE,
|
||||
Comparator_Provider::COMPARATOR_IS,
|
||||
Comparator_Provider::COMPARATOR_IS_NOT,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'comparator',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => $comparators,
|
||||
'default' => Comparator_Provider::COMPARATOR_IS,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'number_of_comments',
|
||||
[
|
||||
'type' => Controls_Manager::TEXT,
|
||||
'input_type' => 'number',
|
||||
'variant' => 'number',
|
||||
'placeholder' => 'Type a number...',
|
||||
'step' => 1,
|
||||
'min' => 0,
|
||||
'default' => 1,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Title_Condition_Base;
|
||||
|
||||
class Post_Title_Condition extends Title_Condition_Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'post_title';
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return 'post';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Post Title', 'elementor-pro' );
|
||||
}
|
||||
|
||||
protected function get_query() {
|
||||
return [
|
||||
'post_status' => 'publish',
|
||||
'post_type' => 'post',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use DateTime;
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparators_Checker;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Condition_Base;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Date_Condition_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Time_Of_The_Day_Condition extends Condition_Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'time_of_the_day';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Time of the day', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return 'date';
|
||||
}
|
||||
|
||||
public function get_gm_date() {
|
||||
return gmdate( 'H:i' );
|
||||
}
|
||||
|
||||
public function check( $args ) : bool {
|
||||
if ( empty( $args['time'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$time_now = $this->get_gm_date();
|
||||
$expected_time = $this->convert_date_time_to_24_hour_format( $args['time'] );
|
||||
|
||||
return Comparators_Checker::check_date_time( $args['comparator'], $time_now, $expected_time );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $date_time_string
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function convert_date_time_to_24_hour_format( $date_time_string ): string {
|
||||
|
||||
if ( ! $this->is_valid_date_time_string( $date_time_string ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$date_time = DateTime::createFromFormat( 'm-d-Y H:i', $date_time_string );
|
||||
|
||||
return $date_time->format( 'H:i' );
|
||||
}
|
||||
|
||||
private function is_valid_date_time_string( $date_time_string ): bool {
|
||||
$date_time = DateTime::createFromFormat( 'm-d-Y H:i', $date_time_string );
|
||||
|
||||
if ( ! $date_time || $date_time->format( 'm-d-Y H:i' ) !== $date_time_string ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_options() {
|
||||
$comparators = Comparator_Provider::get_comparators(
|
||||
[
|
||||
Comparator_Provider::COMPARATOR_IS,
|
||||
Comparator_Provider::COMPARATOR_IS_NOT,
|
||||
Comparator_Provider::COMPARATOR_IS_BEFORE,
|
||||
Comparator_Provider::COMPARATOR_IS_AFTER,
|
||||
Comparator_Provider::COMPARATOR_IS_BEFORE_INCLUSIVE,
|
||||
Comparator_Provider::COMPARATOR_IS_AFTER_INCLUSIVE,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'comparator',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => $comparators,
|
||||
'default' => Comparator_Provider::COMPARATOR_IS,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'time',
|
||||
[
|
||||
'type' => Controls_Manager::DATE_TIME,
|
||||
'variant' => 'time',
|
||||
'required' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'time_type',
|
||||
[
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => Date_Condition_Base::get_time_options(),
|
||||
'default' => Date_Condition_Base::OPTION_SERVER,
|
||||
'disabled_options' => Date_Condition_Base::OPTION_CLIENT,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparators_Checker;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Date_Condition_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class User_Registration_Date_Condition extends Date_Condition_Base {
|
||||
const CONDITION_KEY = 'date';
|
||||
const GROUP_KEY = 'user';
|
||||
|
||||
public function get_name() {
|
||||
return 'user_registration_date';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Registration Date', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct( self::CONDITION_KEY, self::GROUP_KEY );
|
||||
}
|
||||
|
||||
public function check( $args ) : bool {
|
||||
return parent::check_date( $args, $this->get_user_registration_date() );
|
||||
}
|
||||
|
||||
private function get_user_registration_date() {
|
||||
$registration_date = date_create( wp_get_current_user()->user_registered )->format( self::DATE_FORMAT );
|
||||
$registration_date = date_create_from_format( self::DATE_FORMAT, $registration_date );
|
||||
|
||||
return $registration_date;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions\Conditions;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparator_Provider;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Comparators_Checker;
|
||||
use ElementorPro\Modules\DisplayConditions\Conditions\Base\Condition_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class User_Role_Condition extends Condition_Base {
|
||||
const CONDITION_KEY = 'roles';
|
||||
|
||||
public function get_name() {
|
||||
return 'user_role';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return esc_html__( 'Role', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return 'user';
|
||||
}
|
||||
|
||||
public function check( $args ) : bool {
|
||||
$current_user = wp_get_current_user();
|
||||
$current_user_roles = $current_user ? $current_user->roles : [];
|
||||
|
||||
return Comparators_Checker::check_array_contains( $args['comparator'], $current_user_roles, $args['roles'] );
|
||||
}
|
||||
|
||||
public function get_options() {
|
||||
$user_roles = $this->get_available_roles();
|
||||
|
||||
$comparators = Comparator_Provider::get_comparators(
|
||||
[
|
||||
Comparator_Provider::COMPARATOR_IS_ONE_OF,
|
||||
Comparator_Provider::COMPARATOR_IS_NONE_OF,
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control( 'comparator', [
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => $comparators,
|
||||
'default' => Comparator_Provider::COMPARATOR_IS_ONE_OF,
|
||||
] );
|
||||
|
||||
$this->add_control( self::CONDITION_KEY, [
|
||||
'type' => Controls_Manager::SELECT2,
|
||||
'options' => $user_roles,
|
||||
'multiple' => true,
|
||||
'required' => true,
|
||||
'default' => [],
|
||||
] );
|
||||
}
|
||||
|
||||
private function get_available_roles(): array {
|
||||
$user_roles = [];
|
||||
|
||||
foreach ( get_editable_roles() as $role_slug => $role_data ) {
|
||||
$role = $role_data['name'];
|
||||
$user_roles[ $role_slug ] = esc_html( $role );
|
||||
}
|
||||
|
||||
return $user_roles;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DisplayConditions;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use Elementor\Utils;
|
||||
use ElementorPro\Base\Module_Base;
|
||||
use ElementorPro\License\API;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Experiments;
|
||||
use ElementorPro\Modules\DisplayConditions\Classes\Or_Condition;
|
||||
use ElementorPro\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends Module_Base {
|
||||
|
||||
private $hidden_elements_ids = array();
|
||||
|
||||
const LICENSE_FEATURE_NAME = 'display-conditions';
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
if ( ! self::can_use_display_conditions() ) {
|
||||
$this->add_common_actions();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->register_display_conditions_experiments();
|
||||
$this->maybe_add_actions_and_components();
|
||||
}
|
||||
|
||||
public static function is_experiment_active(): bool {
|
||||
return Plugin::elementor()::$instance->experiments->is_feature_active( self::LICENSE_FEATURE_NAME );
|
||||
}
|
||||
|
||||
public static function should_show_promo(): bool {
|
||||
return ! self::can_use_display_conditions();
|
||||
}
|
||||
|
||||
private function add_actions() {
|
||||
$this->add_render_actions();
|
||||
|
||||
add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_actions' ] );
|
||||
}
|
||||
|
||||
private function add_components() {
|
||||
$this->add_component( 'conditions', new Classes\Conditions_Manager( $this ) );
|
||||
$this->add_component( 'cache_notice', new Classes\Cache_Notice() );
|
||||
}
|
||||
|
||||
private function add_common_actions() {
|
||||
$this->add_advanced_tab_actions();
|
||||
|
||||
add_action( 'elementor/editor/before_enqueue_scripts', function() {
|
||||
$this->enqueue_main_script();
|
||||
} );
|
||||
}
|
||||
|
||||
private function enqueue_main_script() {
|
||||
$min_suffix = Utils::is_script_debug() ? '' : '.min';
|
||||
|
||||
wp_enqueue_script(
|
||||
'e-display-conditions',
|
||||
ELEMENTOR_PRO_ASSETS_URL . 'js/display-conditions' . $min_suffix . '.js',
|
||||
[
|
||||
'react',
|
||||
'react-dom',
|
||||
'backbone-marionette',
|
||||
'elementor-web-cli',
|
||||
'wp-date',
|
||||
'elementor-common',
|
||||
'elementor-editor-modules',
|
||||
'elementor-editor-document',
|
||||
'elementor-v2-ui',
|
||||
'elementor-v2-icons',
|
||||
],
|
||||
ELEMENTOR_PRO_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
wp_set_script_translations( 'e-display-conditions', 'elementor-pro' );
|
||||
}
|
||||
|
||||
private function add_advanced_tab_actions() {
|
||||
$hooks = array(
|
||||
'elementor/element/section/section_advanced/after_section_end' => 'css_classes', // Sections
|
||||
'elementor/element/column/section_advanced/after_section_end' => 'css_classes', // Columns
|
||||
'elementor/element/common/_section_style/after_section_end' => '_css_classes', // Widgets
|
||||
'elementor/element/container/section_layout/after_section_end' => 'css_classes', // Containers
|
||||
);
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function add_render_actions() {
|
||||
$element_types = array(
|
||||
'section',
|
||||
'column',
|
||||
'widget',
|
||||
'container',
|
||||
);
|
||||
|
||||
foreach ( $element_types as $el ) {
|
||||
add_action( 'elementor/frontend/' . $el . '/before_render', array( $this, 'before_element_render' ) );
|
||||
add_action( 'elementor/frontend/' . $el . '/after_render', array( $this, 'after_element_render' ) );
|
||||
}
|
||||
}
|
||||
|
||||
private function add_control_to_advanced_tab( $element, $args, $injection_position ) {
|
||||
$element->start_injection(
|
||||
array(
|
||||
'of' => $injection_position,
|
||||
)
|
||||
);
|
||||
|
||||
$element->add_control(
|
||||
'e_display_conditions_trigger',
|
||||
array(
|
||||
'type' => Controls_Manager::RAW_HTML,
|
||||
'separator' => 'before',
|
||||
'raw' => $this->get_display_conditions_control_template(),
|
||||
)
|
||||
);
|
||||
|
||||
$element->add_control(
|
||||
'e_display_conditions',
|
||||
array(
|
||||
'type' => Controls_Manager::HIDDEN,
|
||||
)
|
||||
);
|
||||
|
||||
$element->end_injection();
|
||||
}
|
||||
|
||||
private function get_display_conditions_control_template() {
|
||||
$icon_class = 'e-control-display-conditions';
|
||||
$show_promo = self::should_show_promo();
|
||||
|
||||
if ( $show_promo ) {
|
||||
$icon_class .= '-promo';
|
||||
}
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="e-control-display-conditions__wrapper">
|
||||
<span class="e-control-display-conditions__desc">
|
||||
<?php echo esc_html__( 'Display Conditions', 'elementor-pro' ); ?>
|
||||
<?php if ( $show_promo ) : ?>
|
||||
<i class="eicon-lock"></i>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
<i class="eicon-flow <?php echo esc_attr( $icon_class ); ?>"></i>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
protected function get_saved_conditions( $settings ) {
|
||||
$conditions_json = ! empty( $settings['e_display_conditions'] ) ? $settings['e_display_conditions'] : [];
|
||||
|
||||
return ! empty( $conditions_json ) && ! empty( $conditions_json[0] )
|
||||
? json_decode( $conditions_json[0], true )
|
||||
: [];
|
||||
}
|
||||
|
||||
public function before_element_render( $element ) {
|
||||
$settings = $element->get_settings_for_display();
|
||||
$is_visible = true;
|
||||
$saved_conditions = $this->get_saved_conditions( $settings );
|
||||
|
||||
if ( empty( $settings['e_display_conditions'] ) || Plugin::elementor()->editor->is_edit_mode() || empty( $saved_conditions ) ) {
|
||||
return $is_visible;
|
||||
}
|
||||
|
||||
$saved_conditions = $this->get_converted_conditions( $saved_conditions );
|
||||
$saved_conditions = new Or_Condition( $this->get_conditions_manager(), $saved_conditions );
|
||||
$is_visible = $saved_conditions->check();
|
||||
|
||||
if ( ! $is_visible ) {
|
||||
add_filter( 'elementor/element/get_child_type', '__return_false' ); // Prevent getting content of inner elements.
|
||||
add_filter( 'elementor/frontend/' . $element->get_type() . '/should_render', '__return_false' );
|
||||
|
||||
$this->hidden_elements_ids[] = $element->get_id();
|
||||
}
|
||||
}
|
||||
|
||||
public function after_element_render( $element ) {
|
||||
if ( ! in_array( $element->get_id(), $this->hidden_elements_ids, true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
remove_filter( 'elementor/element/get_child_type', '__return_false' );
|
||||
remove_filter( 'elementor/frontend/' . $element->get_type() . '/should_render', '__return_false' );
|
||||
}
|
||||
|
||||
public function register_display_conditions_experiments() {
|
||||
if ( ! self::can_use_display_conditions() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Experiments::register_dc_experiment();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return static::LICENSE_FEATURE_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Classes\Conditions_Manager
|
||||
*/
|
||||
public function get_conditions_manager() {
|
||||
return $this->get_component( 'conditions' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ajax $ajax_manager
|
||||
*/
|
||||
public function register_ajax_actions( $ajax_manager ) {
|
||||
$ajax_manager->register_ajax_action( 'display_conditions_set_cache_notice_status', [ $this->get_component( 'cache_notice' ), 'set_notice_status' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function can_use_display_conditions(): bool {
|
||||
return API::is_license_active() && API::is_licence_has_feature( self::LICENSE_FEATURE_NAME, API::BC_VALIDATION_CALLBACK );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private function maybe_add_actions_and_components(): void {
|
||||
if ( self::is_experiment_active() ) {
|
||||
$this->add_common_actions();
|
||||
$this->add_actions();
|
||||
$this->add_components();
|
||||
}
|
||||
}
|
||||
|
||||
private function get_converted_conditions( $conditions ) {
|
||||
foreach ( $conditions as $condition ) {
|
||||
if ( ! isset( $condition['condition'] ) ) {
|
||||
return $conditions;
|
||||
}
|
||||
}
|
||||
return count( $conditions )
|
||||
? [ $conditions ]
|
||||
: [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DynamicTags\ACF;
|
||||
|
||||
use ElementorPro\Modules\LoopBuilder\Providers\Taxonomy_Loop_Provider;
|
||||
use ElementorPro\Plugin;
|
||||
use ElementorPro\Modules\LoopBuilder\Module as LoopBuilderModule;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Dynamic_Value_Provider {
|
||||
|
||||
public function get_value( $key ) {
|
||||
if ( empty( $key ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
[ $field_key, $meta_key ] = explode( ':', $key );
|
||||
|
||||
if ( Taxonomy_Loop_Provider::is_loop_taxonomy() ) {
|
||||
return $this->get_taxonomy_field_data( $field_key, $meta_key );
|
||||
}
|
||||
|
||||
$document = Plugin::elementor()->documents->get_current();
|
||||
|
||||
if ( 'options' === $field_key ) {
|
||||
$field = $this->get_field_object( $meta_key, $field_key );
|
||||
} elseif ( ! empty( $document ) && LoopBuilderModule::TEMPLATE_LIBRARY_TYPE_SLUG === $document::get_type() ) {
|
||||
$field = $this->get_field_object( $field_key, get_the_ID() );
|
||||
} else {
|
||||
$field = $this->get_field_object( $field_key, get_queried_object() );
|
||||
}
|
||||
|
||||
return [ $field, $meta_key ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the custom field value from `ACF` plugin.
|
||||
* Used for testing.
|
||||
*
|
||||
* @param $selector
|
||||
* @param $post_id
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
protected function get_field_object( $selector, $post_id ) {
|
||||
return get_field_object( $selector, $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the field data needed when rendering a dynamic tag for a taxonomy object.
|
||||
* @param $field_key
|
||||
* @param $meta_key
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_taxonomy_field_data( $field_key, $meta_key ) {
|
||||
global $wp_query;
|
||||
$field = $this->get_field_object( $field_key, $wp_query->loop_term );
|
||||
return [ $field, $meta_key ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DynamicTags\ACF;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use Elementor\Core\Base\Document;
|
||||
use Elementor\Core\DynamicTags\Base_Tag;
|
||||
use Elementor\Modules\DynamicTags;
|
||||
use ElementorPro\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends DynamicTags\Module {
|
||||
|
||||
const ACF_GROUP = 'acf';
|
||||
|
||||
// TODO: Remove when Core 3.10.0 is released.
|
||||
const DATETIME_CATEGORY = 'datetime';
|
||||
|
||||
/**
|
||||
* @var Dynamic_Value_Provider
|
||||
*/
|
||||
private static $dynamic_value_provider;
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_control_options( $types ) {
|
||||
// ACF >= 5.0.0
|
||||
if ( function_exists( 'acf_get_field_groups' ) ) {
|
||||
$acf_groups = acf_get_field_groups();
|
||||
} else {
|
||||
$acf_groups = apply_filters( 'acf/get_field_groups', [] );
|
||||
}
|
||||
|
||||
$groups = [];
|
||||
|
||||
$options_page_groups_ids = [];
|
||||
|
||||
if ( function_exists( 'acf_options_page' ) ) {
|
||||
$pages = acf_options_page()->get_pages();
|
||||
foreach ( $pages as $slug => $page ) {
|
||||
$options_page_groups = acf_get_field_groups( [
|
||||
'options_page' => $slug,
|
||||
] );
|
||||
|
||||
foreach ( $options_page_groups as $options_page_group ) {
|
||||
$options_page_groups_ids[] = $options_page_group['ID'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $acf_groups as $acf_group ) {
|
||||
// ACF >= 5.0.0
|
||||
if ( function_exists( 'acf_get_fields' ) ) {
|
||||
if ( isset( $acf_group['ID'] ) && ! empty( $acf_group['ID'] ) ) {
|
||||
$fields = acf_get_fields( $acf_group['ID'] );
|
||||
} else {
|
||||
$fields = acf_get_fields( $acf_group );
|
||||
}
|
||||
} else {
|
||||
$fields = apply_filters( 'acf/field_group/get_fields', [], $acf_group['id'] );
|
||||
}
|
||||
|
||||
$options = [];
|
||||
|
||||
if ( ! is_array( $fields ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$has_option_page_location = in_array( $acf_group['ID'], $options_page_groups_ids, true );
|
||||
$is_only_options_page = $has_option_page_location && 1 === count( $acf_group['location'] );
|
||||
|
||||
foreach ( $fields as $field ) {
|
||||
if ( ! in_array( $field['type'], $types, true ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use group ID for unique keys
|
||||
if ( $has_option_page_location ) {
|
||||
$key = 'options:' . $field['name'];
|
||||
$options[ $key ] = esc_html__( 'Options', 'elementor-pro' ) . ':' . $field['label'];
|
||||
if ( $is_only_options_page ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$key = $field['key'] . ':' . $field['name'];
|
||||
$options[ $key ] = $field['label'];
|
||||
}
|
||||
|
||||
if ( empty( $options ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( 1 === count( $options ) ) {
|
||||
$options = [ -1 => ' -- ' ] + $options;
|
||||
}
|
||||
|
||||
$groups[] = [
|
||||
'label' => $acf_group['title'],
|
||||
'options' => $options,
|
||||
];
|
||||
} // End foreach().
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
public static function add_key_control( Base_Tag $tag ) {
|
||||
$tag->add_control(
|
||||
'key',
|
||||
[
|
||||
'label' => esc_html__( 'Key', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'groups' => self::get_control_options( $tag->get_supported_fields() ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function get_tag_classes_names() {
|
||||
return [
|
||||
'ACF_Text',
|
||||
'ACF_Image',
|
||||
'ACF_URL',
|
||||
'ACF_Gallery',
|
||||
'ACF_File',
|
||||
'ACF_Number',
|
||||
'ACF_Color',
|
||||
'ACF_Date_Time',
|
||||
];
|
||||
}
|
||||
|
||||
// For use by ACF tags
|
||||
public static function get_tag_value_field( Base_Tag $tag ) {
|
||||
$key = $tag->get_settings( 'key' );
|
||||
|
||||
// TODO: The tags should use the `Dynamic_Value_Provider::get_value()` method, but it involves
|
||||
// heavily refactoring them, so currently this method is just a proxy and also kept for BC.
|
||||
|
||||
if ( ! static::$dynamic_value_provider ) {
|
||||
static::$dynamic_value_provider = new Dynamic_Value_Provider();
|
||||
}
|
||||
|
||||
return static::$dynamic_value_provider->get_value( $key );
|
||||
}
|
||||
|
||||
public function get_groups() {
|
||||
return [
|
||||
self::ACF_GROUP => [
|
||||
'title' => esc_html__( 'ACF', 'elementor-pro' ),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DynamicTags\ACF\Tags;
|
||||
|
||||
use ElementorPro\Modules\DynamicTags\Tags\Base\Data_Tag;
|
||||
use ElementorPro\Modules\DynamicTags\ACF\Module;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class ACF_COLOR extends Data_Tag {
|
||||
|
||||
public function get_name() {
|
||||
return 'acf-color';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'ACF', 'elementor-pro' ) . ' ' . esc_html__( 'Color Picker Field', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return Module::ACF_GROUP;
|
||||
}
|
||||
|
||||
public function get_categories() {
|
||||
return [ Module::COLOR_CATEGORY ];
|
||||
}
|
||||
|
||||
public function get_panel_template_setting_key() {
|
||||
return 'key';
|
||||
}
|
||||
|
||||
public function get_value( array $options = [] ) {
|
||||
list( $field, $meta_key ) = Module::get_tag_value_field( $this );
|
||||
|
||||
if ( $field ) {
|
||||
$value = $field['value'];
|
||||
} else {
|
||||
// Field settings has been deleted or not available.
|
||||
$value = get_field( $meta_key );
|
||||
}
|
||||
|
||||
if ( empty( $value ) && $this->get_settings( 'fallback' ) ) {
|
||||
$value = $this->get_settings( 'fallback' );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
Module::add_key_control( $this );
|
||||
}
|
||||
|
||||
public function get_supported_fields() {
|
||||
return [
|
||||
'color_picker',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DynamicTags\ACF\Tags;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DynamicTags\ACF\Dynamic_Value_Provider;
|
||||
use ElementorPro\Modules\DynamicTags\Tags\Base\Data_Tag;
|
||||
use ElementorPro\Modules\DynamicTags\ACF\Module;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class ACF_Date_Time extends Data_Tag {
|
||||
|
||||
/**
|
||||
* @var Dynamic_Value_Provider|mixed
|
||||
*/
|
||||
private $dynamic_value_provider;
|
||||
|
||||
public function get_name() {
|
||||
return 'acf-date-time';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'ACF', 'elementor-pro' ) . ' ' . esc_html__( 'Date Time Field', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return Module::ACF_GROUP;
|
||||
}
|
||||
|
||||
public function get_categories() {
|
||||
return [
|
||||
Module::DATETIME_CATEGORY,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* @return string - date time in format Y-m-d H:i:s
|
||||
*/
|
||||
public function get_value( array $options = [] ) {
|
||||
$field_settings = $this->dynamic_value_provider->get_value(
|
||||
$this->get_settings( 'key' )
|
||||
);
|
||||
|
||||
if ( empty( $field_settings ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$field = $field_settings[0];
|
||||
$value = '';
|
||||
|
||||
if ( $field ) {
|
||||
$date_time = \DateTime::createFromFormat( $field['return_format'], $field['value'] );
|
||||
|
||||
$value = $date_time instanceof \DateTime
|
||||
? $date_time->format( 'Y-m-d H:i:s' )
|
||||
: '';
|
||||
}
|
||||
|
||||
if ( empty( $value ) && $this->get_settings( 'fallback' ) ) {
|
||||
$value = $this->get_settings( 'fallback' );
|
||||
}
|
||||
|
||||
return wp_kses_post( $value );
|
||||
}
|
||||
|
||||
public function get_panel_template_setting_key() {
|
||||
return 'key';
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
Module::add_key_control( $this );
|
||||
|
||||
$this->add_control(
|
||||
'fallback',
|
||||
[
|
||||
'type' => Controls_Manager::DATE_TIME,
|
||||
'label' => esc_html__( 'Fallback', 'elementor-pro' ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function get_supported_fields() {
|
||||
return [
|
||||
'date_time_picker',
|
||||
];
|
||||
}
|
||||
|
||||
public function __construct( array $data = [], $dynamic_value_provider = null ) {
|
||||
parent::__construct( $data );
|
||||
|
||||
$this->dynamic_value_provider = $dynamic_value_provider ?? new Dynamic_Value_Provider();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DynamicTags\ACF\Tags;
|
||||
|
||||
use ElementorPro\Modules\DynamicTags\ACF\Module;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class ACF_File extends ACF_Image {
|
||||
|
||||
public function get_name() {
|
||||
return 'acf-file';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'ACF', 'elementor-pro' ) . ' ' . esc_html__( 'File Field', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_categories() {
|
||||
return [
|
||||
Module::MEDIA_CATEGORY,
|
||||
];
|
||||
}
|
||||
|
||||
public function get_supported_fields() {
|
||||
return [
|
||||
'file',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DynamicTags\ACF\Tags;
|
||||
|
||||
use ElementorPro\Modules\DynamicTags\Tags\Base\Data_Tag;
|
||||
use ElementorPro\Modules\DynamicTags\ACF\Module;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class ACF_Gallery extends Data_Tag {
|
||||
|
||||
public function get_name() {
|
||||
return 'acf-gallery';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'ACF', 'elementor-pro' ) . ' ' . esc_html__( 'Gallery Field', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_categories() {
|
||||
return [ Module::GALLERY_CATEGORY ];
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return Module::ACF_GROUP;
|
||||
}
|
||||
|
||||
public function get_panel_template_setting_key() {
|
||||
return 'key';
|
||||
}
|
||||
|
||||
public function get_value( array $options = [] ) {
|
||||
$images = [];
|
||||
|
||||
list( $field, $meta_key ) = Module::get_tag_value_field( $this );
|
||||
|
||||
if ( $field ) {
|
||||
$value = $field['value'];
|
||||
} else {
|
||||
// Field settings has been deleted or not available.
|
||||
$value = get_field( $meta_key );
|
||||
}
|
||||
|
||||
if ( is_array( $value ) && ! empty( $value ) ) {
|
||||
foreach ( $value as $image ) {
|
||||
$images[] = [
|
||||
'id' => $image['ID'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $images;
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
Module::add_key_control( $this );
|
||||
}
|
||||
|
||||
public function get_supported_fields() {
|
||||
return [
|
||||
'gallery',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DynamicTags\ACF\Tags;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DynamicTags\Tags\Base\Data_Tag;
|
||||
use ElementorPro\Modules\DynamicTags\ACF\Module;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class ACF_Image extends Data_Tag {
|
||||
|
||||
public function get_name() {
|
||||
return 'acf-image';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'ACF', 'elementor-pro' ) . ' ' . esc_html__( 'Image Field', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return Module::ACF_GROUP;
|
||||
}
|
||||
|
||||
public function get_categories() {
|
||||
return [ Module::IMAGE_CATEGORY ];
|
||||
}
|
||||
|
||||
public function get_panel_template_setting_key() {
|
||||
return 'key';
|
||||
}
|
||||
|
||||
public function get_value( array $options = [] ) {
|
||||
$image_data = [
|
||||
'id' => null,
|
||||
'url' => '',
|
||||
];
|
||||
|
||||
list( $field, $meta_key ) = Module::get_tag_value_field( $this );
|
||||
|
||||
if ( $field && is_array( $field ) ) {
|
||||
$field['return_format'] = isset( $field['save_format'] ) ? $field['save_format'] : $field['return_format'];
|
||||
switch ( $field['return_format'] ) {
|
||||
case 'object':
|
||||
case 'array':
|
||||
$value = $field['value'];
|
||||
break;
|
||||
case 'url':
|
||||
$value = [
|
||||
'id' => 0,
|
||||
'url' => $field['value'],
|
||||
];
|
||||
break;
|
||||
case 'id':
|
||||
$src = wp_get_attachment_image_src( $field['value'], $field['preview_size'] );
|
||||
$value = [
|
||||
'id' => $field['value'],
|
||||
'url' => $src[0],
|
||||
];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! isset( $value ) ) {
|
||||
// Field settings has been deleted or not available.
|
||||
$value = get_field( $meta_key );
|
||||
}
|
||||
|
||||
if ( empty( $value ) && $this->get_settings( 'fallback' ) ) {
|
||||
$value = $this->get_settings( 'fallback' );
|
||||
}
|
||||
|
||||
if ( ! empty( $value ) && is_array( $value ) ) {
|
||||
$image_data['id'] = $value['id'];
|
||||
$image_data['url'] = $value['url'];
|
||||
}
|
||||
|
||||
return $image_data;
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
Module::add_key_control( $this );
|
||||
|
||||
$this->add_control(
|
||||
'fallback',
|
||||
[
|
||||
'label' => esc_html__( 'Fallback', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::MEDIA,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function get_supported_fields() {
|
||||
return [
|
||||
'image',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DynamicTags\ACF\Tags;
|
||||
|
||||
use ElementorPro\Modules\DynamicTags\Tags\Base\Tag;
|
||||
use ElementorPro\Modules\DynamicTags\ACF\Module;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class ACF_Number extends Tag {
|
||||
|
||||
public function get_name() {
|
||||
return 'acf-number';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'ACF', 'elementor-pro' ) . ' ' . esc_html__( 'Number', 'elementor-pro' ) . ' ' . esc_html__( 'Field', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return Module::ACF_GROUP;
|
||||
}
|
||||
|
||||
public function get_categories() {
|
||||
return [
|
||||
Module::NUMBER_CATEGORY,
|
||||
Module::POST_META_CATEGORY,
|
||||
];
|
||||
}
|
||||
|
||||
public function render() {
|
||||
list( $field, $meta_key ) = Module::get_tag_value_field( $this );
|
||||
|
||||
if ( $field && ! empty( $field['type'] ) ) {
|
||||
$value = $field['value'];
|
||||
} else {
|
||||
// Field settings has been deleted or not available.
|
||||
$value = get_field( $meta_key );
|
||||
} // End if().
|
||||
|
||||
echo wp_kses_post( $value );
|
||||
}
|
||||
|
||||
public function get_panel_template_setting_key() {
|
||||
return 'key';
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
Module::add_key_control( $this );
|
||||
}
|
||||
|
||||
public function get_supported_fields() {
|
||||
return [
|
||||
'number',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DynamicTags\ACF\Tags;
|
||||
|
||||
use ElementorPro\Modules\DynamicTags\Tags\Base\Tag;
|
||||
use ElementorPro\Modules\DynamicTags\ACF\Module;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class ACF_Text extends Tag {
|
||||
|
||||
public function get_name() {
|
||||
return 'acf-text';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'ACF', 'elementor-pro' ) . ' ' . esc_html__( 'Field', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return Module::ACF_GROUP;
|
||||
}
|
||||
|
||||
public function get_categories() {
|
||||
return [
|
||||
Module::TEXT_CATEGORY,
|
||||
Module::POST_META_CATEGORY,
|
||||
];
|
||||
}
|
||||
|
||||
public function render() {
|
||||
list( $field, $meta_key ) = Module::get_tag_value_field( $this );
|
||||
|
||||
if ( $field && ! empty( $field['type'] ) ) {
|
||||
$value = $field['value'];
|
||||
|
||||
switch ( $field['type'] ) {
|
||||
case 'radio':
|
||||
if ( isset( $field['choices'][ $value ] ) ) {
|
||||
$value = $field['choices'][ $value ];
|
||||
}
|
||||
break;
|
||||
case 'select':
|
||||
// Use as array for `multiple=true` or `return_format=array`.
|
||||
$values = (array) $value;
|
||||
|
||||
foreach ( $values as $key => $item ) {
|
||||
if ( isset( $field['choices'][ $item ] ) ) {
|
||||
$values[ $key ] = $field['choices'][ $item ];
|
||||
}
|
||||
}
|
||||
|
||||
$value = implode( ', ', $values );
|
||||
|
||||
break;
|
||||
case 'checkbox':
|
||||
$value = (array) $value;
|
||||
$values = [];
|
||||
foreach ( $value as $item ) {
|
||||
if ( isset( $field['choices'][ $item ] ) ) {
|
||||
$values[] = $field['choices'][ $item ];
|
||||
} else {
|
||||
$values[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$value = implode( ', ', $values );
|
||||
|
||||
break;
|
||||
case 'oembed':
|
||||
// Get from db without formatting.
|
||||
$value = $this->get_queried_object_meta( $meta_key );
|
||||
break;
|
||||
case 'google_map':
|
||||
$meta = $this->get_queried_object_meta( $meta_key );
|
||||
$value = isset( $meta['address'] ) ? $meta['address'] : '';
|
||||
break;
|
||||
} // End switch().
|
||||
} else {
|
||||
// Field settings has been deleted or not available.
|
||||
$value = get_field( $meta_key );
|
||||
} // End if().
|
||||
|
||||
echo wp_kses_post( $value );
|
||||
}
|
||||
|
||||
public function get_panel_template_setting_key() {
|
||||
return 'key';
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
Module::add_key_control( $this );
|
||||
}
|
||||
|
||||
public function get_supported_fields() {
|
||||
return [
|
||||
'text',
|
||||
'textarea',
|
||||
'number',
|
||||
'email',
|
||||
'password',
|
||||
'wysiwyg',
|
||||
'select',
|
||||
'checkbox',
|
||||
'radio',
|
||||
'true_false',
|
||||
|
||||
// Pro
|
||||
'oembed',
|
||||
'google_map',
|
||||
'date_picker',
|
||||
'time_picker',
|
||||
'date_time_picker',
|
||||
'color_picker',
|
||||
];
|
||||
}
|
||||
|
||||
private function get_queried_object_meta( $meta_key ) {
|
||||
$value = '';
|
||||
if ( is_singular() ) {
|
||||
$value = get_post_meta( get_the_ID(), $meta_key, true );
|
||||
} elseif ( is_tax() || is_category() || is_tag() ) {
|
||||
$value = get_term_meta( get_queried_object_id(), $meta_key, true );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DynamicTags\ACF\Tags;
|
||||
|
||||
use ElementorPro\Modules\DynamicTags\Tags\Base\Data_Tag;
|
||||
use ElementorPro\Modules\DynamicTags\ACF\Module;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class ACF_URL extends Data_Tag {
|
||||
|
||||
public function get_name() {
|
||||
return 'acf-url';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'ACF', 'elementor-pro' ) . ' ' . esc_html__( 'URL Field', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return Module::ACF_GROUP;
|
||||
}
|
||||
|
||||
public function get_categories() {
|
||||
return [ Module::URL_CATEGORY ];
|
||||
}
|
||||
|
||||
public function get_panel_template_setting_key() {
|
||||
return 'key';
|
||||
}
|
||||
|
||||
public function get_value( array $options = [] ) {
|
||||
list( $field, $meta_key ) = Module::get_tag_value_field( $this );
|
||||
|
||||
if ( $field ) {
|
||||
$value = $field['value'];
|
||||
|
||||
if ( is_array( $value ) && isset( $value[0] ) ) {
|
||||
$value = $value[0];
|
||||
}
|
||||
|
||||
if ( $value ) {
|
||||
if ( ! isset( $field['return_format'] ) ) {
|
||||
$field['return_format'] = isset( $field['save_format'] ) ? $field['save_format'] : '';
|
||||
}
|
||||
|
||||
switch ( $field['type'] ) {
|
||||
case 'email':
|
||||
if ( $value ) {
|
||||
$value = 'mailto:' . $value;
|
||||
}
|
||||
break;
|
||||
case 'image':
|
||||
case 'file':
|
||||
switch ( $field['return_format'] ) {
|
||||
case 'array':
|
||||
case 'object':
|
||||
$value = $value['url'];
|
||||
break;
|
||||
case 'id':
|
||||
if ( 'image' === $field['type'] ) {
|
||||
$src = wp_get_attachment_image_src( $value, 'full' );
|
||||
$value = $src[0];
|
||||
} else {
|
||||
$value = wp_get_attachment_url( $value );
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'post_object':
|
||||
case 'relationship':
|
||||
$value = get_permalink( $value );
|
||||
break;
|
||||
case 'taxonomy':
|
||||
$value = get_term_link( $value, $field['taxonomy'] );
|
||||
break;
|
||||
} // End switch().
|
||||
}
|
||||
} else {
|
||||
// Field settings has been deleted or not available.
|
||||
$value = get_field( $meta_key );
|
||||
} // End if().
|
||||
|
||||
if ( empty( $value ) && $this->get_settings( 'fallback' ) ) {
|
||||
$value = $this->get_settings( 'fallback' );
|
||||
}
|
||||
|
||||
return wp_kses_post( $value );
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
Module::add_key_control( $this );
|
||||
|
||||
$this->add_control(
|
||||
'fallback',
|
||||
[
|
||||
'label' => esc_html__( 'Fallback', 'elementor-pro' ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function get_supported_fields() {
|
||||
return [
|
||||
'text',
|
||||
'email',
|
||||
'image',
|
||||
'file',
|
||||
'page_link',
|
||||
'post_object',
|
||||
'relationship',
|
||||
'taxonomy',
|
||||
'url',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace ElementorPro\Modules\DynamicTags\Components;
|
||||
|
||||
use ElementorPro\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Author_Meta_Filter {
|
||||
|
||||
const DYNAMIC_TAG_SHORTCODE_PATTERN = '/\[elementor-tag.*?name=.*?"(author-meta|author-info).*?".*?settings=.*?".*?(user_email|email).*?".*?\]/';
|
||||
|
||||
public function filter( $data, $document ) : array {
|
||||
if ( current_user_can( 'manage_options' ) || empty( $data['elements'] ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$dynamic_tag = $this->get_dynamic_tag( $data['elements'] );
|
||||
|
||||
if ( ! $dynamic_tag ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
if ( $this->is_dynamic_tag_authored_by_admin( $document, $dynamic_tag ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
return Plugin::elementor()->db->iterate_data( $data, function ( $element ) {
|
||||
if ( $this->is_dynamic_tag_to_escape( $element ) ) {
|
||||
$element['settings']['__dynamic__'] = [];
|
||||
}
|
||||
|
||||
return $element;
|
||||
});
|
||||
}
|
||||
|
||||
private function is_dynamic_tag_authored_by_admin( $document, string $needle_tag ): bool {
|
||||
global $post;
|
||||
|
||||
$post_author_id = $post->post_author ?? 0;
|
||||
$is_post_authored_by_admin = user_can( $post_author_id, 'manage_options' );
|
||||
|
||||
if ( ! $is_post_authored_by_admin ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$json = wp_json_encode( $document->get_elements_data() );
|
||||
|
||||
return false !== strpos( $json, $needle_tag );
|
||||
}
|
||||
|
||||
private function is_dynamic_tag_to_escape( array $element ): bool {
|
||||
if ( 'widget' !== $element['elType'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! empty( $element['settings']['__dynamic__'] ) && ! empty( preg_match( self::DYNAMIC_TAG_SHORTCODE_PATTERN, $element['settings']['__dynamic__']['title'] ) );
|
||||
}
|
||||
|
||||
private function get_dynamic_tag( array $elements ): ?string {
|
||||
$json = wp_json_encode( $elements );
|
||||
|
||||
preg_match( self::DYNAMIC_TAG_SHORTCODE_PATTERN, $json, $matches );
|
||||
|
||||
if ( empty( $matches ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $matches[0];
|
||||
}
|
||||
}
|
||||
164
wp-content/plugins/elementor-pro/modules/dynamic-tags/module.php
Normal file
164
wp-content/plugins/elementor-pro/modules/dynamic-tags/module.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DynamicTags;
|
||||
|
||||
use Elementor\Modules\DynamicTags\Module as TagsModule;
|
||||
use ElementorPro\Modules\DynamicTags\ACF;
|
||||
use ElementorPro\Modules\DynamicTags\Toolset;
|
||||
use ElementorPro\Modules\DynamicTags\Pods;
|
||||
use ElementorPro\Core\Utils;
|
||||
use ElementorPro\License\API;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends TagsModule {
|
||||
|
||||
const AUTHOR_GROUP = 'author';
|
||||
|
||||
const POST_GROUP = 'post';
|
||||
|
||||
const COMMENTS_GROUP = 'comments';
|
||||
|
||||
const SITE_GROUP = 'site';
|
||||
|
||||
const ARCHIVE_GROUP = 'archive';
|
||||
|
||||
const MEDIA_GROUP = 'media';
|
||||
|
||||
const ACTION_GROUP = 'action';
|
||||
|
||||
const WOOCOMMERCE_GROUP = 'woocommerce';
|
||||
|
||||
// TODO: Remove when Core 3.10.0 is released.
|
||||
const DATETIME_CATEGORY = 'datetime';
|
||||
|
||||
const LICENSE_FEATURE_ACF_NAME = 'dynamic-tags-acf';
|
||||
const LICENSE_FEATURE_PODS_NAME = 'dynamic-tags-pods';
|
||||
const LICENSE_FEATURE_TOOLSET_NAME = 'dynamic-tags-toolset';
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->add_component( 'author-meta-filter', new Components\Author_Meta_Filter() );
|
||||
|
||||
// ACF 5 and up
|
||||
if ( class_exists( '\acf' ) && function_exists( 'acf_get_field_groups' ) && API::is_licence_has_feature( self::LICENSE_FEATURE_ACF_NAME, API::BC_VALIDATION_CALLBACK ) ) {
|
||||
$this->add_component( 'acf', new ACF\Module() );
|
||||
}
|
||||
|
||||
if ( function_exists( 'wpcf_admin_fields_get_groups' ) && API::is_licence_has_feature( self::LICENSE_FEATURE_TOOLSET_NAME, API::BC_VALIDATION_CALLBACK ) ) {
|
||||
$this->add_component( 'toolset', new Toolset\Module() );
|
||||
}
|
||||
|
||||
if ( function_exists( 'pods' ) && API::is_licence_has_feature( self::LICENSE_FEATURE_PODS_NAME, API::BC_VALIDATION_CALLBACK ) ) {
|
||||
$this->add_component( 'pods', new Pods\Module() );
|
||||
}
|
||||
|
||||
/*
|
||||
* WooCommerce Add To Cart Dynamic Tag.
|
||||
*
|
||||
* The WC ATC Dynamic Tag returns a URL that adds items to a users cart
|
||||
* via the URL parameters `?add-to-cart=' . $product_id . '&quantity=' . $quantity`.
|
||||
* Normally this URL method redirects to the website's Home page after adding the items to
|
||||
* the cart.
|
||||
*
|
||||
* Since the behavior of the Tag should be identical to the "Add to Cart" widget, clicking an
|
||||
* element that is using the tag needs to redirect to the Single Product page for the added
|
||||
* product or the Cart page after this process if the user selected that setting in WooCommerce.
|
||||
*
|
||||
* To accomplish that, an extra parameter in the URL ('&e-redirect=') is used. When this
|
||||
* paramater is found, the WooCommerce Add to Cart Dynamic Tag will redirect to the
|
||||
* appropriate page.
|
||||
*/
|
||||
|
||||
//phpcs:ignore WordPress.Security.NonceVerification.Recommended -- The nonce is verified in the WC class.
|
||||
$add_to_cart = Utils::_unstable_get_super_global_value( $_REQUEST, 'add-to-cart' );
|
||||
//phpcs:ignore WordPress.Security.NonceVerification.Recommended -- The nonce is verified in the WC class.
|
||||
$redirect = Utils::_unstable_get_super_global_value( $_REQUEST, 'e-redirect' );
|
||||
|
||||
if ( $add_to_cart && $redirect ) {
|
||||
add_filter( 'woocommerce_add_to_cart_redirect', [ $this, 'filter_woocommerce_add_to_cart_redirect' ], 10, 1 );
|
||||
}
|
||||
|
||||
add_filter( 'elementor/document/save/data', [ $this->get_component( 'author-meta-filter' ), 'filter' ], 10, 2 );
|
||||
}
|
||||
|
||||
public function filter_woocommerce_add_to_cart_redirect( $wc_get_cart_url ) {
|
||||
//phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here.
|
||||
return esc_url( Utils::_unstable_get_super_global_value( $_REQUEST, 'e-redirect' ) );
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'tags';
|
||||
}
|
||||
|
||||
public function get_tag_classes_names() {
|
||||
return [
|
||||
'Archive_Description',
|
||||
'Archive_Meta',
|
||||
'Archive_Title',
|
||||
'Archive_URL',
|
||||
'Author_Info',
|
||||
'Author_Meta',
|
||||
'Author_Name',
|
||||
'Author_Profile_Picture',
|
||||
'Author_URL',
|
||||
'Comments_Number',
|
||||
'Comments_URL',
|
||||
'Page_Title',
|
||||
'Post_Custom_Field',
|
||||
'Post_Date',
|
||||
'Post_Excerpt',
|
||||
'Post_Featured_Image',
|
||||
'Post_Gallery',
|
||||
'Post_ID',
|
||||
'Post_Terms',
|
||||
'Post_Time',
|
||||
'Post_Title',
|
||||
'Post_URL',
|
||||
'Site_Logo',
|
||||
'Site_Tagline',
|
||||
'Site_Title',
|
||||
'Site_URL',
|
||||
'Internal_URL',
|
||||
'Current_Date_Time',
|
||||
'Request_Parameter',
|
||||
'Lightbox',
|
||||
'Featured_Image_Data',
|
||||
'Shortcode',
|
||||
'Contact_URL',
|
||||
'User_Info',
|
||||
'User_Profile_Picture',
|
||||
];
|
||||
}
|
||||
|
||||
public function get_groups() {
|
||||
return [
|
||||
self::POST_GROUP => [
|
||||
'title' => esc_html__( 'Post', 'elementor-pro' ),
|
||||
],
|
||||
self::ARCHIVE_GROUP => [
|
||||
'title' => esc_html__( 'Archive', 'elementor-pro' ),
|
||||
],
|
||||
self::SITE_GROUP => [
|
||||
'title' => esc_html__( 'Site', 'elementor-pro' ),
|
||||
],
|
||||
self::MEDIA_GROUP => [
|
||||
'title' => esc_html__( 'Media', 'elementor-pro' ),
|
||||
],
|
||||
self::ACTION_GROUP => [
|
||||
'title' => esc_html__( 'Actions', 'elementor-pro' ),
|
||||
],
|
||||
self::AUTHOR_GROUP => [
|
||||
'title' => esc_html__( 'Author', 'elementor-pro' ),
|
||||
],
|
||||
self::COMMENTS_GROUP => [
|
||||
'title' => esc_html__( 'Comments', 'elementor-pro' ),
|
||||
],
|
||||
self::WOOCOMMERCE_GROUP => [
|
||||
'title' => esc_html__( 'WooCommerce', 'elementor-pro' ),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DynamicTags\Pods;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Dynamic_Value_Provider {
|
||||
|
||||
// Copied from the Module with some modifications & improvements.
|
||||
// TODO: Refactor the Tags to use this class instead of the Module.
|
||||
public function get_value( $key ) {
|
||||
if ( ! $this->is_valid_field_key( $key ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
list( $pod_name, , $meta_key ) = explode( ':', $key );
|
||||
|
||||
$pod = $this->get_pods_value( $pod_name, get_the_ID() );
|
||||
|
||||
if ( false === $pod ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
'field' => $pod->fields[ $meta_key ],
|
||||
'value' => $pod->field( $meta_key ),
|
||||
'display' => $pod->display( $meta_key ),
|
||||
'pod' => $pod,
|
||||
'key' => $meta_key,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Pod value from `Pods` plugin.
|
||||
* Used for testing.
|
||||
*
|
||||
* @param $type
|
||||
* @param $id
|
||||
*
|
||||
* @return bool|\Pods
|
||||
*/
|
||||
protected function get_pods_value( $type, $id ) {
|
||||
return pods( $type, $id );
|
||||
}
|
||||
|
||||
private function is_valid_field_key( $key ) {
|
||||
$key = trim( $key );
|
||||
|
||||
if ( empty( $key ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$colon_count = substr_count( $key, ':' );
|
||||
|
||||
// Key structure looks like: `page:699:pods_date_time`.
|
||||
return ( 2 === $colon_count );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DynamicTags\Pods;
|
||||
|
||||
use Elementor\Modules\DynamicTags;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends DynamicTags\Module {
|
||||
|
||||
const PODS_GROUP = 'Pods';
|
||||
|
||||
// TODO: Remove when Core 3.10.0 is released.
|
||||
const DATETIME_CATEGORY = 'datetime';
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_control_options( $types ) {
|
||||
if ( ! function_exists( 'pods_api' ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$all_pods = pods_api()->load_pods( [
|
||||
'table_info' => true,
|
||||
'fields' => true,
|
||||
] );
|
||||
|
||||
$groups = [];
|
||||
|
||||
foreach ( $all_pods as $group ) {
|
||||
$options = [];
|
||||
|
||||
foreach ( $group['fields'] as $field ) {
|
||||
if ( ! self::valid_field_type( $types, $field ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use pods ID for unique keys
|
||||
$key = $group['name'] . ':' . $field['pod_id'] . ':' . $field['name'];
|
||||
$options[ $key ] = $field['label'];
|
||||
}
|
||||
|
||||
if ( empty( $options ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( 1 === count( $options ) ) {
|
||||
$options = [ -1 => ' -- ' ] + $options;
|
||||
}
|
||||
|
||||
$groups[] = [
|
||||
'label' => $group['name'],
|
||||
'options' => $options,
|
||||
];
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
public static function valid_field_type( $types, $field ) {
|
||||
// Only file field with single image value
|
||||
if ( in_array( 'pods_image', $types, true ) && self::pods_image_mapping( $field ) ) {
|
||||
return true;
|
||||
}
|
||||
if ( in_array( 'pods_url', $types, true ) && in_array( $field['type'], [ 'email', 'file', 'website', 'phone' ] ) ) {
|
||||
// Only file with single value allowed
|
||||
if ( 'file' === $field['type'] && ! self::pods_file_mapping( $field ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// Only file with multiple images allowed
|
||||
if ( in_array( 'pods_gallery', $types, true ) && self::pods_image_mapping( $field, false ) ) {
|
||||
return true;
|
||||
}
|
||||
// Any other type
|
||||
if ( in_array( $field['type'], $types, true ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function pods_file_mapping( $field, $single = true ) {
|
||||
if ( 'file' !== $field['type'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$limit = $single ? 'single' : 'multi';
|
||||
if ( $limit !== $field['options']['file_format_type'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function pods_image_mapping( $field, $single = true ) {
|
||||
if ( ! isset( $field['options'] ) || ! isset( $field['options']['file_type'] ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( 'images' !== $field['options']['file_type'] ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! self::pods_file_mapping( $field, $single ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_tag_classes_names() {
|
||||
return [
|
||||
'Pods_Text',
|
||||
'Pods_Date',
|
||||
'Pods_Date_Time',
|
||||
'Pods_Image',
|
||||
'Pods_Gallery',
|
||||
'Pods_URL',
|
||||
'Pods_Numeric',
|
||||
];
|
||||
}
|
||||
|
||||
public function get_groups() {
|
||||
return [
|
||||
self::PODS_GROUP => [
|
||||
'title' => esc_html__( 'Pods', 'elementor-pro' ),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DynamicTags\Pods\Tags;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DynamicTags\Tags\Base\Tag;
|
||||
use ElementorPro\Modules\DynamicTags\Pods\Module;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
abstract class Pods_Base extends Tag {
|
||||
|
||||
public function get_group() {
|
||||
return Module::PODS_GROUP;
|
||||
}
|
||||
|
||||
public function get_field() {
|
||||
$key = $this->get_settings( 'key' );
|
||||
if ( empty( $key ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
list( $pod_name, $pod_id, $meta_key ) = explode( ':', $key );
|
||||
/**
|
||||
* @var \Pods
|
||||
*/
|
||||
$pod = pods( $pod_name, get_the_ID() );
|
||||
|
||||
if ( false === $pod ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
'field' => $pod->fields[ $meta_key ],
|
||||
'value' => $pod->field( $meta_key ),
|
||||
'display' => $pod->display( $meta_key ),
|
||||
'pod' => $pod,
|
||||
'key' => $meta_key,
|
||||
];
|
||||
}
|
||||
|
||||
public function get_categories() {
|
||||
return [
|
||||
Module::TEXT_CATEGORY,
|
||||
Module::POST_META_CATEGORY,
|
||||
];
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
$this->add_control(
|
||||
'key',
|
||||
[
|
||||
'label' => esc_html__( 'Key', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'groups' => Module::get_control_options( $this->get_supported_fields() ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
protected function get_supported_fields() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DynamicTags\Pods\Tags;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use ElementorPro\Modules\DynamicTags\Pods\Dynamic_Value_Provider;
|
||||
use ElementorPro\Modules\DynamicTags\Pods\Module;
|
||||
use ElementorPro\Modules\DynamicTags\Tags\Base\Data_Tag;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Pods_Date_Time extends Data_Tag {
|
||||
|
||||
/**
|
||||
* @var Dynamic_Value_Provider
|
||||
*/
|
||||
private $dynamic_value_provider;
|
||||
|
||||
public function get_name() {
|
||||
return 'pods-date-time';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'Pods', 'elementor-pro' ) . ' ' . esc_html__( 'Date Time Field', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function get_group() {
|
||||
return Module::PODS_GROUP;
|
||||
}
|
||||
|
||||
public function get_categories() {
|
||||
return [
|
||||
Module::DATETIME_CATEGORY,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* @return string - date time in format Y-m-d H:i:s
|
||||
*/
|
||||
public function get_value( array $options = [] ) {
|
||||
$field = $this->dynamic_value_provider->get_value(
|
||||
$this->get_settings( 'key' )
|
||||
);
|
||||
|
||||
$value = $field['value'] ?? '';
|
||||
|
||||
if ( ! empty( $value ) ) {
|
||||
$value = gmdate( 'Y-m-d H:i:s', strtotime( $value ) );
|
||||
}
|
||||
|
||||
if ( empty( $value ) && $this->get_settings( 'fallback' ) ) {
|
||||
$value = $this->get_settings( 'fallback' );
|
||||
}
|
||||
|
||||
return wp_kses_post( $value );
|
||||
}
|
||||
|
||||
public function get_panel_template_setting_key() {
|
||||
return 'key';
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
$this->add_control(
|
||||
'key',
|
||||
[
|
||||
'label' => esc_html__( 'Key', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'groups' => Module::get_control_options( $this->get_supported_fields() ),
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'fallback',
|
||||
[
|
||||
'type' => Controls_Manager::DATE_TIME,
|
||||
'label' => esc_html__( 'Fallback', 'elementor-pro' ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
protected function get_supported_fields() {
|
||||
return [
|
||||
'datetime',
|
||||
];
|
||||
}
|
||||
|
||||
public function __construct( array $data = [], $dynamic_value_provider = null ) {
|
||||
parent::__construct( $data );
|
||||
|
||||
$this->dynamic_value_provider = $dynamic_value_provider ?? new Dynamic_Value_Provider();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
namespace ElementorPro\Modules\DynamicTags\Pods\Tags;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Pods_Date extends Pods_Base {
|
||||
|
||||
public function get_name() {
|
||||
return 'pods-date';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'Pods', 'elementor-pro' ) . ' ' . esc_html__( 'Date Field', 'elementor-pro' );
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$field_data = $this->get_field();
|
||||
$field = $field_data['field'];
|
||||
$value = empty( $field_data['value'] ) ? '' : $field_data['value'];
|
||||
|
||||
if ( $field && ! empty( $field['type'] ) && in_array( $field['type'], [ 'date', 'datetime' ] ) ) {
|
||||
|
||||
$format = $this->get_settings( 'format' );
|
||||
|
||||
$timestamp = strtotime( $value );
|
||||
|
||||
if ( 'human' === $format ) {
|
||||
$value = human_time_diff( $timestamp );
|
||||
} else {
|
||||
switch ( $format ) {
|
||||
case 'default':
|
||||
$date_format = get_option( 'date_format' );
|
||||
break;
|
||||
case 'custom':
|
||||
$date_format = $this->get_settings( 'custom_format' );
|
||||
break;
|
||||
default:
|
||||
$date_format = $format;
|
||||
break;
|
||||
}
|
||||
|
||||
$value = gmdate( $date_format, $timestamp );
|
||||
}
|
||||
}
|
||||
echo wp_kses_post( $value );
|
||||
}
|
||||
|
||||
public function get_panel_template_setting_key() {
|
||||
return 'key';
|
||||
}
|
||||
|
||||
protected function register_controls() {
|
||||
parent::register_controls();
|
||||
|
||||
$this->add_control(
|
||||
'format',
|
||||
[
|
||||
'label' => esc_html__( 'Format', 'elementor-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'options' => [
|
||||
'default' => esc_html__( 'Default', 'elementor-pro' ),
|
||||
'F j, Y' => gmdate( 'F j, Y' ),
|
||||
'Y-m-d' => gmdate( 'Y-m-d' ),
|
||||
'm/d/Y' => gmdate( 'm/d/Y' ),
|
||||
'd/m/Y' => gmdate( 'd/m/Y' ),
|
||||
'human' => esc_html__( 'Human Readable', 'elementor-pro' ),
|
||||
'custom' => esc_html__( 'Custom', 'elementor-pro' ),
|
||||
],
|
||||
'default' => 'default',
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'custom_format',
|
||||
[
|
||||
'label' => esc_html__( 'Custom Format', 'elementor-pro' ),
|
||||
'default' => '',
|
||||
'description' => sprintf( '<a href="https://go.elementor.com/wordpress-date-time/" target="_blank">%s</a>', esc_html__( 'Documentation on date and time formatting', 'elementor-pro' ) ),
|
||||
'condition' => [
|
||||
'format' => 'custom',
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
protected function get_supported_fields() {
|
||||
return [
|
||||
'datetime',
|
||||
'date',
|
||||
];
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user