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

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