PluginProbe
Elementor Website Builder – more than just a page builder / 3.23.0-beta5
Elementor Website Builder – more than just a page builder v3.23.0-beta5
4.3.2 4.3.1 4.3.0 4.3.0-beta3 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 All 455 releases
elementor / modules / floating-buttons / module.php

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

527 lines 15.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\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 if ( ! ElementorUtils::has_pro() ) {
122 add_action( 'wp_footer', function () {
123 $this->render_floating_buttons();
124 } );
125 }
126
127 add_action( 'elementor/admin-top-bar/is-active', function ( $is_top_bar_active, $current_screen ) {
128
129 if ( strpos( $current_screen->id ?? '', static::CPT_FLOATING_BUTTONS ) !== false ) {
130 return true;
131 }
132
133 return $is_top_bar_active;
134 }, 10, 2 );
135
136 add_action( 'elementor/admin/menu/register', function( Admin_Menu_Manager $admin_menu ) {
137 $this->register_admin_menu_legacy( $admin_menu );
138 }, Source_Local::ADMIN_MENU_PRIORITY + 20 );
139
140 add_action( 'elementor/admin/localize_settings', function ( array $settings ) {
141 return $this->admin_localize_settings( $settings );
142 } );
143
144 add_action( 'elementor/editor/localize_settings', function ( $data ) {
145 return $this->editor_localize_settings( $data );
146 } );
147
148 add_filter( 'elementor/template_library/sources/local/register_taxonomy_cpts', function ( array $cpts ) {
149 $cpts[] = static::CPT_FLOATING_BUTTONS;
150
151 return $cpts;
152 } );
153
154 add_action( 'admin_init', function () {
155 $action = filter_input( INPUT_GET, 'action' );
156 $menu_args = $this->get_contact_menu_args();
157
158 switch ( $action ) {
159 case 'remove_from_entire_site':
160 $post = filter_input( INPUT_GET, 'post', FILTER_VALIDATE_INT );
161 check_admin_referer( 'remove_from_entire_site_' . $post );
162 delete_post_meta( $post, '_elementor_conditions' );
163 wp_redirect( $menu_args['menu_slug'] );
164 exit;
165 case 'set_as_entire_site':
166 $post = filter_input( INPUT_GET, 'post', FILTER_VALIDATE_INT );
167 check_admin_referer( 'set_as_entire_site_' . $post );
168
169 $posts = get_posts( [
170 'post_type' => static::CPT_FLOATING_BUTTONS,
171 'posts_per_page' => -1,
172 'post_status' => 'publish',
173 'fields' => 'ids',
174 'meta_key' => '_elementor_conditions',
175 'meta_compare' => 'EXISTS',
176 ] );
177
178 foreach ( $posts as $post_id ) {
179 delete_post_meta( $post_id, '_elementor_conditions' );
180 }
181
182 update_post_meta( $post, '_elementor_conditions', [ 'include/general' ] );
183
184 wp_redirect( $menu_args['menu_slug'] );
185 exit;
186 default:
187 break;
188 }
189 } );
190
191 add_action( 'manage_' . static::CPT_FLOATING_BUTTONS . '_posts_columns', function( $posts_columns ) {
192 $source_local = Plugin::$instance->templates_manager->get_source( 'local' );
193 unset( $posts_columns['date'] );
194 unset( $posts_columns['comments'] );
195 $posts_columns['click_tracking'] = esc_html__( 'Click Tracking', 'elementor' );
196
197 if ( ! ElementorUtils::has_pro() ) {
198 $posts_columns['instances'] = esc_html__( 'Instances', 'elementor' );
199 }
200
201 return $source_local->admin_columns_headers( $posts_columns );
202 } );
203
204 add_action(
205 'manage_' . static::CPT_FLOATING_BUTTONS . '_posts_custom_column',
206 [ $this, 'set_admin_columns_content' ],
207 10,
208 2
209 );
210
211 add_action( 'admin_bar_menu', function ( $admin_bar ) {
212
213 $this->override_admin_bar_add_contact( $admin_bar );
214 }, 100 );
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 update_post_meta( $post_id, static::META_CLICK_TRACKING, $clicks );
246 }
247
248 wp_send_json_success();
249 }
250
251 public function set_admin_columns_content( $column_name, $post_id ) {
252 $document = Plugin::$instance->documents->get( $post_id );
253
254 if ( method_exists( $document, 'admin_columns_content' ) ) {
255 $document->admin_columns_content( $column_name );
256 }
257
258 switch ( $column_name ) {
259 case 'click_tracking':
260 $click_tracking = get_post_meta( $post_id, static::META_CLICK_TRACKING, true );
261 echo esc_html( $click_tracking );
262 break;
263 case 'instances':
264 if ( ElementorUtils::has_pro() ) {
265 break;
266 }
267 $instances = get_post_meta( $post_id, '_elementor_conditions', true );
268 if ( $instances ) {
269 echo esc_html__( 'Entire Site', 'elementor' );
270 }
271 break;
272 default:
273 break;
274 }
275 }
276
277 public function flush_permalinks_on_save() {
278 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
279 return;
280 }
281
282 if ( get_option( static::ROUTER_OPTION_KEY ) !== static::ROUTER_VERSION ) {
283 flush_rewrite_rules();
284 update_option( static::ROUTER_OPTION_KEY, static::ROUTER_VERSION );
285 }
286 }
287
288 private function get_trashed_contact_posts(): array {
289 if ( $this->trashed_contact_pages ) {
290 return $this->trashed_contact_pages;
291 }
292
293 $this->trashed_contact_pages = $this->get_trashed_posts(
294 static::CPT_FLOATING_BUTTONS,
295 static::FLOATING_BUTTONS_DOCUMENT_TYPE
296 );
297
298 return $this->trashed_contact_pages;
299 }
300
301 private function get_trashed_posts( string $cpt, string $document_type ) {
302 $query = new \WP_Query( [
303 'no_found_rows' => true,
304 'post_type' => $cpt,
305 'post_status' => 'trash',
306 'posts_per_page' => 1,
307 'meta_key' => '_elementor_template_type',
308 'meta_value' => $document_type,
309 ] );
310
311 return $query->posts;
312 }
313
314 private function get_add_new_contact_page_url() {
315 if ( ElementorUtils::has_pro() ) {
316 return Plugin::$instance->documents->get_create_new_post_url(
317 static::CPT_FLOATING_BUTTONS,
318 static::FLOATING_BUTTONS_DOCUMENT_TYPE
319 );
320 }
321
322 return Plugin::$instance->documents->get_create_new_post_url(
323 static::CPT_FLOATING_BUTTONS,
324 static::FLOATING_BUTTONS_DOCUMENT_TYPE
325 ) . '#library';
326 }
327
328 public function print_empty_contact_pages_page() {
329 $template_sources = Plugin::$instance->templates_manager->get_registered_sources();
330 $source_local = $template_sources['local'];
331 $trashed_posts = $this->get_trashed_contact_posts();
332
333 ?>
334 <div class="e-landing-pages-empty">
335 <?php
336 /** @var Source_Local $source_local */
337 $source_local->print_blank_state_template(
338 esc_html__( 'Floating Button', 'elementor' ),
339 $this->get_add_new_contact_page_url(),
340 nl2br( esc_html__( 'Add a Floating button so your users can easily get in touch!', 'elementor' ) )
341 );
342
343 if ( ! empty( $trashed_posts ) ) : ?>
344 <div class="e-trashed-items">
345 <?php
346 printf(
347 /* translators: %1$s Link open tag, %2$s: Link close tag. */
348 esc_html__( 'Or view %1$sTrashed Items%1$s', 'elementor' ),
349 '<a href="' . esc_url( admin_url( 'edit.php?post_status=trash&post_type=' . self::CPT_FLOATING_BUTTONS ) ) . '">',
350 '</a>'
351 );
352 ?>
353 </div>
354 <?php endif; ?>
355 </div>
356 <?php
357 }
358
359 private function admin_localize_settings( $settings ) {
360 $contact_menu_slug = $this->get_contact_menu_args()['menu_slug'];
361
362 if ( static::CPT_FLOATING_BUTTONS === $contact_menu_slug ) {
363 $contact_menu_slug = 'admin.php?page=' . $contact_menu_slug;
364 }
365
366 $additional_settings = [
367 'urls' => [
368 'addNewLinkUrlContact' => $this->get_add_new_contact_page_url(),
369 'viewContactPageUrl' => $contact_menu_slug,
370 ],
371 'contactPages' => [
372 'hasPages' => $this->has_contact_pages(),
373 ],
374 ];
375
376 return array_replace_recursive( $settings, $additional_settings );
377 }
378
379 private function register_contact_pages_cpt() {
380 $this->register_post_type(
381 Floating_Buttons::get_labels(),
382 static::CPT_FLOATING_BUTTONS
383 );
384 }
385
386 private function is_editing_existing_floating_buttons_page() {
387 $action = ElementorUtils::get_super_global_value( $_GET, 'action' );
388 $post_id = ElementorUtils::get_super_global_value( $_GET, 'post' );
389
390 return 'elementor' === $action && $this->is_floating_buttons_type_meta_key( $post_id );
391 }
392
393 private function is_creating_floating_buttons_page() {
394 $action = ElementorUtils::get_super_global_value( $_POST, 'action' ); //phpcs:ignore WordPress.Security.NonceVerification.Missing
395 $post_id = ElementorUtils::get_super_global_value( $_POST, 'editor_post_id' ); //phpcs:ignore WordPress.Security.NonceVerification.Missing
396
397 return 'elementor_ajax' === $action && $this->is_floating_buttons_type_meta_key( $post_id );
398 }
399
400 private function is_floating_buttons_type_meta_key( $post_id ) {
401 return static::FLOATING_BUTTONS_DOCUMENT_TYPE === get_post_meta( $post_id, Document::TYPE_META_KEY, true );
402 }
403
404 private function register_post_type( array $labels, string $cpt ) {
405 $args = [
406 'labels' => $labels,
407 'public' => true,
408 'show_in_menu' => 'edit.php?post_type=elementor_library&tabs_group=library',
409 'capability_type' => 'page',
410 'taxonomies' => [ Source_Local::TAXONOMY_TYPE_SLUG ],
411 'supports' => [
412 'title',
413 'editor',
414 'comments',
415 'revisions',
416 'trackbacks',
417 'author',
418 'excerpt',
419 'page-attributes',
420 'thumbnail',
421 'custom-fields',
422 'post-formats',
423 'elementor',
424 ],
425 ];
426
427 register_post_type( $cpt, $args );
428 }
429
430 private function has_contact_pages(): bool {
431 if ( null !== $this->has_contact_pages ) {
432 return $this->has_contact_pages;
433 }
434
435 $this->has_contact_pages = $this->has_pages(
436 static::CPT_FLOATING_BUTTONS,
437 static::FLOATING_BUTTONS_DOCUMENT_TYPE
438 );
439
440 return $this->has_contact_pages;
441 }
442
443 private function has_pages( string $cpt, string $document_type ): bool {
444 $posts_query = new \WP_Query( [
445 'no_found_rows' => true,
446 'post_type' => $cpt,
447 'post_status' => 'any',
448 'posts_per_page' => 1,
449 'meta_key' => '_elementor_template_type',
450 'meta_value' => $document_type,
451 ] );
452
453 return $posts_query->post_count > 0;
454
455 }
456
457 private function get_contact_menu_args(): array {
458 if ( $this->has_contact_pages() ) {
459 $menu_slug = static::ADMIN_PAGE_SLUG_CONTACT;
460 $function = null;
461 } else {
462 $menu_slug = static::CPT_FLOATING_BUTTONS;
463 $function = [ $this, 'print_empty_contact_pages_page' ];
464 }
465
466 return [
467 'menu_slug' => $menu_slug,
468 'function' => $function,
469 ];
470 }
471
472 public function override_admin_bar_add_contact( $admin_bar ): void {
473 $new_contact_page_node = $admin_bar->get_node( 'new-e-floating-buttons' );
474
475 if ( $new_contact_page_node ) {
476 $new_contact_page_node->href = $this->get_add_new_contact_page_url();
477
478 $admin_bar->add_node( $new_contact_page_node );
479 }
480 }
481
482 private function editor_localize_settings( $data ) {
483 $data['admin_floating_button_admin_url'] = admin_url( $this->get_contact_menu_args()['menu_slug'] );
484 return $data;
485 }
486
487 private function render_floating_buttons(): void {
488 if ( Plugin::$instance->preview->is_preview_mode() ) {
489 $post_id = ElementorUtils::get_super_global_value( $_GET, 'elementor-preview' );
490 $document = Plugin::$instance->documents->get( $post_id );
491
492 if (
493 $document instanceof Document &&
494 $document->get_name() === static::FLOATING_BUTTONS_DOCUMENT_TYPE
495 ) {
496 return;
497 }
498 }
499
500 $query = new \WP_Query( [
501 'post_type' => static::CPT_FLOATING_BUTTONS,
502 'posts_per_page' => - 1,
503 'post_status' => 'publish',
504 'fields' => 'ids',
505 'meta_key' => '_elementor_conditions',
506 'meta_compare' => 'EXISTS',
507 ] );
508
509 if ( ! $query->have_posts() ) {
510 return;
511 }
512
513 foreach ( $query->posts as $post_id ) {
514 $conditions = get_post_meta( $post_id, '_elementor_conditions', true );
515 if ( ! $conditions ) {
516 continue;
517 }
518 if ( in_array( 'include/general', $conditions ) ) {
519 $document = Plugin::$instance->documents->get( $post_id );
520 $document->print_content();
521 break;
522 }
523 }
524 }
525
526 }
527