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

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