PluginProbe
Elementor Website Builder – more than just a page builder / 4.2.2
Elementor Website Builder – more than just a page builder v4.2.2
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 4.2.2, at modules/floating-buttons/module.php

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