PluginProbe
Elementor Website Builder – more than just a page builder / 3.35.9
Elementor Website Builder – more than just a page builder v3.35.9
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / modules / floating-buttons / module.php

module.php in Elementor Website Builder – more than just a page builder 3.35.9, at modules/floating-buttons/module.php

594 lines 18.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Elementor\Modules\FloatingButtons;
4
5 use Elementor\Controls_Manager;
6 use Elementor\Core\Admin\Menu\Admin_Menu_Manager;
7 use Elementor\Core\Base\Document;
8 use Elementor\Core\Base\Module as BaseModule;
9 use Elementor\Core\Documents_Manager;
10 use Elementor\Core\Experiments\Manager;
11 use Elementor\Modules\FloatingButtons\Base\Widget_Floating_Bars_Base;
12 use Elementor\Modules\FloatingButtons\AdminMenuItems\Floating_Buttons_Empty_View_Menu_Item;
13 use Elementor\Modules\FloatingButtons\AdminMenuItems\Floating_Buttons_Menu_Item;
14 use Elementor\Modules\FloatingButtons\Base\Widget_Contact_Button_Base;
15 use Elementor\Modules\FloatingButtons\Classes\Action\Action_Handler;
16 use Elementor\Modules\FloatingButtons\Control\Hover_Animation_Floating_Buttons;
17 use Elementor\Modules\FloatingButtons\Documents\Floating_Buttons;
18 use Elementor\Plugin;
19 use Elementor\TemplateLibrary\Source_Local;
20 use Elementor\Utils as ElementorUtils;
21 use Elementor\Modules\EditorOne\Classes\Menu_Data_Provider;
22 use Elementor\Modules\FloatingButtons\AdminMenuItems\Editor_One_Floating_Elements_Menu;
23
24 if ( ! defined( 'ABSPATH' ) ) {
25 exit; // Exit if accessed directly.
26 }
27
28 class Module extends BaseModule {
29
30 const FLOATING_ELEMENTS_TYPE_META_KEY = '_elementor_floating_elements_type';
31 const ROUTER_OPTION_KEY = 'elementor_floating_buttons_router_version';
32 const META_CLICK_TRACKING = '_elementor_click_tracking';
33 const CLICK_TRACKING_NONCE = 'elementor-conversion-center-click';
34 const FLOATING_BUTTONS_DOCUMENT_TYPE = 'floating-buttons';
35 const CPT_FLOATING_BUTTONS = 'e-floating-buttons';
36 const ADMIN_PAGE_SLUG_CONTACT = 'edit.php?post_type=e-floating-buttons';
37 const WIDGET_HAS_CUSTOM_BREAKPOINTS = true;
38
39 private $has_contact_pages = null;
40 private $trashed_contact_pages;
41
42 public static function is_active(): bool {
43 return Plugin::$instance->experiments->is_feature_active( 'container' );
44 }
45
46 public static function get_floating_elements_types() {
47 return [
48 'floating-buttons' => esc_html__( 'Floating Buttons', 'elementor' ),
49 'floating-bars' => esc_html__( 'Floating Bars', 'elementor' ),
50 ];
51 }
52
53 public function get_name(): string {
54 return 'floating-buttons';
55 }
56
57 public function get_widgets(): array {
58
59 return [
60 'Contact_Buttons',
61 'Floating_Bars_Var_1',
62 ];
63 }
64
65 private function register_admin_menu_legacy( Admin_Menu_Manager $admin_menu ) {
66 if ( ! $this->is_editor_one_active() ) {
67 $menu_args = $this->get_contact_menu_args();
68 $function = $menu_args['function'];
69 if ( is_callable( $function ) ) {
70 $admin_menu->register( $menu_args['menu_slug'], new Floating_Buttons_Empty_View_Menu_Item( $function ) );
71 } else {
72 $admin_menu->register( $menu_args['menu_slug'], new Floating_Buttons_Menu_Item() );
73 }
74 }
75 }
76
77 private function register_editor_one_menu( Menu_Data_Provider $menu_data_provider ) {
78 $menu_data_provider->register_menu( new Editor_One_Floating_Elements_Menu() );
79 }
80
81 private function is_editor_one_active(): bool {
82 return (bool) Plugin::instance()->modules_manager->get_modules( 'editor-one' );
83 }
84
85 public function __construct() {
86 parent::__construct();
87
88 if ( Floating_Buttons::is_creating_floating_buttons_page() || Floating_Buttons::is_editing_existing_floating_buttons_page() ) {
89 Controls_Manager::add_tab(
90 Widget_Contact_Button_Base::TAB_ADVANCED,
91 esc_html__( 'Advanced', 'elementor' )
92 );
93
94 Controls_Manager::add_tab(
95 Widget_Floating_Bars_Base::TAB_ADVANCED,
96 esc_html__( 'Advanced', 'elementor' )
97 );
98 }
99
100 $this->register_contact_pages_cpt();
101
102 add_action( 'elementor/documents/register', function ( Documents_Manager $documents_manager ) {
103 $documents_manager->register_document_type(
104 static::FLOATING_BUTTONS_DOCUMENT_TYPE,
105 Floating_Buttons::get_class_full_name()
106 );
107 } );
108
109 add_action( 'current_screen', function() {
110 $screen = get_current_screen();
111 if ( $screen && 'edit-e-floating-buttons' === $screen->id ) {
112 $this->flush_permalinks_on_elementor_version_change();
113 }
114 });
115
116 add_filter( 'elementor/editor-one/menu/elementor_post_types', function ( array $elementor_post_types ): array {
117 $elementor_post_types[ static::CPT_FLOATING_BUTTONS ] = [
118 'menu_slug' => 'elementor-editor-templates',
119 'child_slug' => 'edit.php?post_type=e-floating-buttons',
120 ];
121 return $elementor_post_types;
122 } );
123
124 add_action( 'wp_ajax_elementor_send_clicks', [ $this, 'handle_click_tracking' ] );
125 add_action( 'wp_ajax_nopriv_elementor_send_clicks', [ $this, 'handle_click_tracking' ] );
126
127 add_action( 'elementor/frontend/after_register_styles', [ $this, 'register_styles' ] );
128
129 add_action( 'elementor/controls/register', function ( Controls_Manager $controls_manager ) {
130 $controls_manager->register( new Hover_Animation_Floating_Buttons() );
131 });
132
133 add_filter( 'elementor/widget/common/register_css_attributes_control', function ( $common_controls ) {
134 if ( Floating_Buttons::is_creating_floating_buttons_page() || Floating_Buttons::is_editing_existing_floating_buttons_page() ) {
135 return false;
136 }
137
138 return $common_controls;
139 } );
140
141 add_filter( 'elementor/settings/controls/checkbox_list_cpt/post_type_objects', function ( $post_types ) {
142 unset( $post_types[ static::CPT_FLOATING_BUTTONS ] );
143
144 return $post_types;
145 } );
146
147 add_filter(
148 'elementor/template_library/sources/local/is_valid_template_type',
149 function ( $is_valid_template_type, $cpt ) {
150
151 if ( in_array( static::CPT_FLOATING_BUTTONS, $cpt, true ) ) {
152 return true;
153 }
154
155 return $is_valid_template_type;
156 },
157 10,
158 2
159 );
160
161 if ( ! ElementorUtils::has_pro() ) {
162 add_action( 'wp_footer', function () {
163 $this->render_floating_buttons();
164 } );
165 }
166
167 add_action( 'elementor/admin-top-bar/is-active', function ( $is_top_bar_active, $current_screen ) {
168
169 if ( strpos( $current_screen->id ?? '', static::CPT_FLOATING_BUTTONS ) !== false ) {
170 return true;
171 }
172
173 return $is_top_bar_active;
174 }, 10, 2 );
175
176 add_action( 'elementor/admin/menu/register', function( Admin_Menu_Manager $admin_menu ) {
177 $this->register_admin_menu_legacy( $admin_menu );
178 }, Source_Local::ADMIN_MENU_PRIORITY + 20 );
179
180 add_action( 'elementor/editor-one/menu/register', function ( Menu_Data_Provider $menu_data_provider ) {
181 $this->register_editor_one_menu( $menu_data_provider );
182 } );
183
184 add_action( 'elementor/admin/localize_settings', function ( array $settings ) {
185 return $this->admin_localize_settings( $settings );
186 } );
187
188 add_action( 'elementor/editor/localize_settings', function ( $data ) {
189 return $this->editor_localize_settings( $data );
190 } );
191
192 add_filter( 'elementor/template_library/sources/local/register_taxonomy_cpts', function ( array $cpts ) {
193 $cpts[] = static::CPT_FLOATING_BUTTONS;
194
195 return $cpts;
196 } );
197
198 add_action( 'admin_init', function () {
199 $action = sanitize_text_field( filter_input( INPUT_GET, 'action' ) );
200
201 if ( $action ) {
202 $menu_args = $this->get_contact_menu_args();
203 $action_handler = new Action_Handler( $action, $menu_args );
204 $action_handler->process_action();
205 }
206 } );
207
208 add_action( 'manage_' . static::CPT_FLOATING_BUTTONS . '_posts_columns', function( $posts_columns ) {
209 $source_local = Plugin::$instance->templates_manager->get_source( 'local' );
210 unset( $posts_columns['date'] );
211 unset( $posts_columns['comments'] );
212 $posts_columns['click_tracking'] = esc_html__( 'Click Tracking', 'elementor' );
213
214 if ( ! ElementorUtils::has_pro() ) {
215 $posts_columns['instances'] = esc_html__( 'Instances', 'elementor' );
216 }
217
218 return $source_local->admin_columns_headers( $posts_columns );
219 } );
220
221 add_action(
222 'manage_' . static::CPT_FLOATING_BUTTONS . '_posts_custom_column',
223 [ $this, 'set_admin_columns_content' ],
224 10,
225 2
226 );
227
228 add_action( 'admin_bar_menu', function ( $admin_bar ) {
229
230 $this->override_admin_bar_add_contact( $admin_bar );
231 }, 100 );
232 }
233
234 public function is_preview_for_document( $post_id ) {
235 $preview_id = ElementorUtils::get_super_global_value( $_GET, 'preview_id' );
236 $preview = ElementorUtils::get_super_global_value( $_GET, 'preview' );
237
238 return 'true' === $preview && (int) $post_id === (int) $preview_id;
239 }
240
241 public function handle_click_tracking() {
242 $data = filter_input_array( INPUT_POST, [
243 'clicks' => [
244 'filter' => FILTER_VALIDATE_INT,
245 'flags' => FILTER_REQUIRE_ARRAY,
246 ],
247 '_nonce' => FILTER_UNSAFE_RAW,
248 ] );
249
250 if ( ! wp_verify_nonce( $data['_nonce'], static::CLICK_TRACKING_NONCE ) ) {
251 wp_send_json_error( [ 'message' => 'Invalid nonce' ] );
252 }
253
254 if ( ! check_ajax_referer( static::CLICK_TRACKING_NONCE, '_nonce', false ) ) {
255 wp_send_json_error( [ 'message' => 'Invalid referrer' ] );
256 }
257
258 $posts_to_update = [];
259
260 foreach ( $data['clicks'] as $post_id ) {
261 if ( ! isset( $posts_to_update[ $post_id ] ) ) {
262 $starting_clicks = (int) get_post_meta( $post_id, static::META_CLICK_TRACKING, true );
263 $posts_to_update[ $post_id ] = $starting_clicks ? $starting_clicks : 0;
264 }
265 ++$posts_to_update[ $post_id ];
266 }
267
268 foreach ( $posts_to_update as $post_id => $clicks ) {
269 if ( self::CPT_FLOATING_BUTTONS !== get_post_type( $post_id ) ) {
270 continue;
271 }
272
273 if ( 'publish' !== get_post_status( $post_id ) ) {
274 continue;
275 }
276
277 update_post_meta( $post_id, static::META_CLICK_TRACKING, $clicks );
278 }
279
280 wp_send_json_success();
281 }
282
283 public function set_admin_columns_content( $column_name, $post_id ) {
284 $document = Plugin::$instance->documents->get( $post_id );
285
286 if ( method_exists( $document, 'admin_columns_content' ) ) {
287 $document->admin_columns_content( $column_name );
288 }
289
290 switch ( $column_name ) {
291 case 'click_tracking':
292 $click_tracking = get_post_meta( $post_id, static::META_CLICK_TRACKING, true );
293 echo esc_html( $click_tracking );
294 break;
295 case 'instances':
296 if ( ElementorUtils::has_pro() ) {
297 break;
298 }
299 $instances = get_post_meta( $post_id, '_elementor_conditions', true );
300 if ( $instances ) {
301 echo esc_html__( 'Entire Site', 'elementor' );
302 }
303 break;
304 default:
305 break;
306 }
307 }
308
309 public function flush_permalinks_on_elementor_version_change() {
310 if ( get_option( static::ROUTER_OPTION_KEY ) !== ELEMENTOR_VERSION ) {
311 flush_rewrite_rules();
312 update_option( static::ROUTER_OPTION_KEY, ELEMENTOR_VERSION );
313 }
314 }
315
316 private function get_trashed_contact_posts(): array {
317 if ( $this->trashed_contact_pages ) {
318 return $this->trashed_contact_pages;
319 }
320
321 $this->trashed_contact_pages = $this->get_trashed_posts(
322 static::CPT_FLOATING_BUTTONS,
323 static::FLOATING_BUTTONS_DOCUMENT_TYPE
324 );
325
326 return $this->trashed_contact_pages;
327 }
328
329 private function get_trashed_posts( string $cpt, string $document_type ) {
330 $query = new \WP_Query( [
331 'no_found_rows' => true,
332 'post_type' => $cpt,
333 'post_status' => 'trash',
334 'posts_per_page' => 1,
335 'meta_key' => '_elementor_template_type',
336 'meta_value' => $document_type,
337 ] );
338
339 return $query->posts;
340 }
341
342 private function get_add_new_contact_page_url() {
343 if ( ElementorUtils::has_pro() ) {
344 return Plugin::$instance->documents->get_create_new_post_url(
345 static::CPT_FLOATING_BUTTONS,
346 static::FLOATING_BUTTONS_DOCUMENT_TYPE
347 );
348 }
349
350 return Plugin::$instance->documents->get_create_new_post_url(
351 static::CPT_FLOATING_BUTTONS,
352 static::FLOATING_BUTTONS_DOCUMENT_TYPE
353 ) . '#library';
354 }
355
356 public function print_empty_contact_pages_page() {
357 $template_sources = Plugin::$instance->templates_manager->get_registered_sources();
358 $source_local = $template_sources['local'];
359 $trashed_posts = $this->get_trashed_contact_posts();
360
361 ?>
362 <div class="e-landing-pages-empty">
363 <?php
364 /** @var Source_Local $source_local */
365 $source_local->print_blank_state_template(
366 esc_html__( 'Floating Element', 'elementor' ),
367 $this->get_add_new_contact_page_url(),
368 nl2br( esc_html__( 'Add a Floating element so your users can easily get in touch!', 'elementor' ) )
369 );
370
371 if ( ! empty( $trashed_posts ) ) : ?>
372 <div class="e-trashed-items">
373 <?php
374 printf(
375 /* translators: %1$s Link open tag, %2$s: Link close tag. */
376 esc_html__( 'Or view %1$sTrashed Items%2$s', 'elementor' ),
377 '<a href="' . esc_url( admin_url( 'edit.php?post_status=trash&post_type=' . self::CPT_FLOATING_BUTTONS ) ) . '">',
378 '</a>'
379 );
380 ?>
381 </div>
382 <?php endif; ?>
383 </div>
384 <?php
385 }
386
387 private function admin_localize_settings( $settings ) {
388 $contact_menu_slug = $this->get_contact_menu_args()['menu_slug'];
389
390 if ( static::CPT_FLOATING_BUTTONS === $contact_menu_slug ) {
391 $contact_menu_slug = 'admin.php?page=' . $contact_menu_slug;
392 }
393
394 $additional_settings = [
395 'urls' => [
396 'addNewLinkUrlContact' => $this->get_add_new_contact_page_url(),
397 'viewContactPageUrl' => $contact_menu_slug,
398 ],
399 'contactPages' => [
400 'hasPages' => $this->has_contact_pages(),
401 ],
402 ];
403
404 return array_replace_recursive( $settings, $additional_settings );
405 }
406
407 private function register_contact_pages_cpt() {
408 $this->register_post_type(
409 Floating_Buttons::get_labels(),
410 static::CPT_FLOATING_BUTTONS
411 );
412 }
413
414 private function register_post_type( array $labels, string $cpt ) {
415 $args = [
416 'labels' => $labels,
417 'public' => true,
418 'show_in_menu' => 'edit.php?post_type=elementor_library&tabs_group=library',
419 'show_in_nav_menus' => false,
420 'capabilities' => [
421 'edit_post' => 'manage_options',
422 'read_post' => 'manage_options',
423 'delete_post' => 'manage_options',
424 'edit_posts' => 'manage_options',
425 'edit_others_posts' => 'manage_options',
426 'publish_posts' => 'manage_options',
427 'read_private_posts' => 'manage_options',
428 'create_posts' => 'manage_options',
429 ],
430 'taxonomies' => [ Source_Local::TAXONOMY_TYPE_SLUG ],
431 'show_in_rest' => true,
432 'supports' => [
433 'title',
434 'editor',
435 'comments',
436 'revisions',
437 'trackbacks',
438 'author',
439 'excerpt',
440 'page-attributes',
441 'thumbnail',
442 'custom-fields',
443 'post-formats',
444 'elementor',
445 ],
446 ];
447
448 register_post_type( $cpt, $args );
449 }
450
451 private function has_contact_pages(): bool {
452 if ( null !== $this->has_contact_pages ) {
453 return $this->has_contact_pages;
454 }
455
456 $this->has_contact_pages = $this->has_pages(
457 static::CPT_FLOATING_BUTTONS,
458 static::FLOATING_BUTTONS_DOCUMENT_TYPE
459 );
460
461 return $this->has_contact_pages;
462 }
463
464 private function has_pages( string $cpt, string $document_type ): bool {
465 $posts_query = new \WP_Query( [
466 'no_found_rows' => true,
467 'post_type' => $cpt,
468 'post_status' => 'any',
469 'posts_per_page' => 1,
470 'meta_key' => '_elementor_template_type',
471 'meta_value' => $document_type,
472 ] );
473
474 return $posts_query->post_count > 0;
475 }
476
477 private function get_contact_menu_args(): array {
478 if ( $this->has_contact_pages() ) {
479 $menu_slug = static::ADMIN_PAGE_SLUG_CONTACT;
480 $function = null;
481 } else {
482 $menu_slug = static::CPT_FLOATING_BUTTONS;
483 $function = [ $this, 'print_empty_contact_pages_page' ];
484 }
485
486 return [
487 'menu_slug' => $menu_slug,
488 'function' => $function,
489 ];
490 }
491
492 public function override_admin_bar_add_contact( $admin_bar ): void {
493 $new_contact_page_node = $admin_bar->get_node( 'new-e-floating-buttons' );
494
495 if ( $new_contact_page_node ) {
496 $new_contact_page_node->href = $this->get_add_new_contact_page_url();
497
498 $admin_bar->add_node( $new_contact_page_node );
499 }
500 }
501
502 private function editor_localize_settings( $data ) {
503 $data['admin_floating_button_admin_url'] = admin_url( $this->get_contact_menu_args()['menu_slug'] );
504 return $data;
505 }
506
507 private function render_floating_buttons(): void {
508 if ( Plugin::$instance->preview->is_preview_mode() ) {
509 $post_id = ElementorUtils::get_super_global_value( $_GET, 'elementor-preview' );
510 $document = Plugin::$instance->documents->get( $post_id );
511
512 if (
513 $document instanceof Document &&
514 $document->get_name() === static::FLOATING_BUTTONS_DOCUMENT_TYPE
515 ) {
516 return;
517 }
518 }
519
520 $query = new \WP_Query( [
521 'post_type' => static::CPT_FLOATING_BUTTONS,
522 'posts_per_page' => - 1,
523 'post_status' => 'publish',
524 'fields' => 'ids',
525 'meta_key' => '_elementor_conditions',
526 'meta_compare' => 'EXISTS',
527 ] );
528
529 if ( ! $query->have_posts() ) {
530 return;
531 }
532
533 foreach ( $query->posts as $post_id ) {
534 $conditions = get_post_meta( $post_id, '_elementor_conditions', true );
535
536 if ( ! $conditions ) {
537 continue;
538 }
539
540 if (
541 in_array( 'include/general', $conditions ) &&
542 ! $this->is_preview_for_document( $post_id ) &&
543 get_the_ID() !== $post_id
544 ) {
545 $document = Plugin::$instance->documents->get( $post_id );
546 $document->print_content();
547 }
548 }
549 }
550
551 /**
552 * Register styles.
553 *
554 * At build time, Elementor compiles `/modules/floating-buttons/assets/scss/widgets/*.scss`
555 * to `/assets/css/widget-*.min.css`.
556 *
557 * @return void
558 */
559 public function register_styles() {
560 $direction_suffix = is_rtl() ? '-rtl' : '';
561 $widget_styles = $this->get_widgets_style_list();
562 $has_custom_breakpoints = Plugin::$instance->breakpoints->has_custom_breakpoints();
563
564 foreach ( $widget_styles as $widget_style_name => $widget_has_responsive_style ) {
565 $should_load_responsive_css = $widget_has_responsive_style ? $has_custom_breakpoints : false;
566
567 wp_register_style(
568 $widget_style_name,
569 $this->get_frontend_file_url( "{$widget_style_name}{$direction_suffix}.min.css", $should_load_responsive_css ),
570 [ 'elementor-frontend', 'elementor-icons' ],
571 $should_load_responsive_css ? null : ELEMENTOR_VERSION
572 );
573 }
574 }
575
576 private function get_widgets_style_list(): array {
577 return [
578 'widget-floating-buttons' => self::WIDGET_HAS_CUSTOM_BREAKPOINTS, // TODO: Remove in v3.27.0 [ED-15717]
579 'widget-floating-bars-base' => self::WIDGET_HAS_CUSTOM_BREAKPOINTS,
580 'widget-floating-bars-var-2' => ! self::WIDGET_HAS_CUSTOM_BREAKPOINTS,
581 'widget-floating-bars-var-3' => self::WIDGET_HAS_CUSTOM_BREAKPOINTS,
582 'widget-contact-buttons-base' => self::WIDGET_HAS_CUSTOM_BREAKPOINTS,
583 'widget-contact-buttons-var-1' => ! self::WIDGET_HAS_CUSTOM_BREAKPOINTS,
584 'widget-contact-buttons-var-3' => ! self::WIDGET_HAS_CUSTOM_BREAKPOINTS,
585 'widget-contact-buttons-var-4' => ! self::WIDGET_HAS_CUSTOM_BREAKPOINTS,
586 'widget-contact-buttons-var-6' => ! self::WIDGET_HAS_CUSTOM_BREAKPOINTS,
587 'widget-contact-buttons-var-7' => self::WIDGET_HAS_CUSTOM_BREAKPOINTS,
588 'widget-contact-buttons-var-8' => ! self::WIDGET_HAS_CUSTOM_BREAKPOINTS,
589 'widget-contact-buttons-var-9' => self::WIDGET_HAS_CUSTOM_BREAKPOINTS,
590 'widget-contact-buttons-var-10' => self::WIDGET_HAS_CUSTOM_BREAKPOINTS,
591 ];
592 }
593 }
594