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

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