/var/www/html_us/wp-content/plugins/elementor/modules/landing-pages/module.php


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
<?php
namespace Elementor\Modules\LandingPages;

use 
Elementor\Core\Admin\Menu\Admin_Menu_Manager;
use 
Elementor\Core\Admin\Menu\Main as MainMenu;
use 
Elementor\Core\Base\Module as BaseModule;
use 
Elementor\Core\Documents_Manager;
use 
Elementor\Core\Experiments\Manager as Experiments_Manager;
use 
Elementor\Modules\LandingPages\Documents\Landing_Page;
use 
Elementor\Modules\LandingPages\AdminMenuItems\Landing_Pages_Menu_Item;
use 
Elementor\Modules\LandingPages\AdminMenuItems\Landing_Pages_Empty_View_Menu_Item;
use 
Elementor\Modules\LandingPages\Module as Landing_Pages_Module;
use 
Elementor\Plugin;
use 
Elementor\TemplateLibrary\Source_Local;

if ( ! 
defined'ABSPATH' ) ) {
    exit; 
// Exit if accessed directly.
}

class 
Module extends BaseModule {

    const 
DOCUMENT_TYPE 'landing-page';
    const 
CPT 'e-landing-page';
    const 
ADMIN_PAGE_SLUG 'edit.php?post_type=' self::CPT;

    private 
$has_pages null;
    private 
$trashed_posts;
    private 
$new_lp_url;
    private 
$permalink_structure;

    public function 
get_name() {
        return 
'landing-pages';
    }

    
/**
     * Get Experimental Data
     *
     * Implementation of this method makes the module an experiment.
     *
     * @since 3.1.0
     *
     * @return array
     */
    
public static function get_experimental_data() {
        return [
            
'name' => 'landing-pages',
            
'title' => esc_html__'Landing Pages''elementor' ),
            
'description' => esc_html__'Adds a new Elementor content type that allows creating beautiful landing pages instantly in a streamlined workflow.''elementor' ),
            
'release_status' => Experiments_Manager::RELEASE_STATUS_BETA,
            
'default' => Experiments_Manager::STATE_ACTIVE,
            
'new_site' => [
                
'default_inactive' => true,
                
'minimum_installation_version' => '3.22.0',
            ],
            
'deprecated' => true,
        ];
    }

    
/**
     * Get Trashed Landing Pages Posts
     *
     * Returns the posts property of a WP_Query run for Landing Pages with post_status of 'trash'.
     *
     * @since 3.1.0
     *
     * @return array trashed posts
     */
    
private function get_trashed_landing_page_posts() {
        if ( 
$this->trashed_posts ) {
            return 
$this->trashed_posts;
        }

        
// `'posts_per_page' => 1` is because this is only used as an indicator to whether there are any trashed landing pages.
        
$trashed_posts_query = new \WP_Query( [
            
'no_found_rows' => true,
            
'post_type' => self::CPT,
            
'post_status' => 'trash',
            
'posts_per_page' => 1,
            
'meta_key' => '_elementor_template_type',
            
'meta_value' => self::DOCUMENT_TYPE,
        ] );

        
$this->trashed_posts $trashed_posts_query->posts;

        return 
$this->trashed_posts;
    }

    private function 
has_landing_pages() {
        if ( 
null !== $this->has_pages ) {
            return 
$this->has_pages;
        }

        
$posts_query = new \WP_Query( [
            
'no_found_rows' => true,
            
'post_type' => self::CPT,
            
'post_status' => 'any',
            
'posts_per_page' => 1,
            
'meta_key' => '_elementor_template_type',
            
'meta_value' => self::DOCUMENT_TYPE,
        ] );

        
$this->has_pages $posts_query->post_count 0;

        return 
$this->has_pages;
    }

    
/**
     * Is Elementor Landing Page.
     *
     * Check whether the post is an Elementor Landing Page.
     *
     * @since 3.1.0
     * @access public
     *
     * @param \WP_Post $post Post Object
     *
     * @return bool Whether the post was built with Elementor.
     */
    
public function is_elementor_landing_page$post ) {
        return 
self::CPT === $post->post_type;
    }

    private function 
get_menu_args() {
        if ( 
$this->has_landing_pages() ) {
            
$menu_slug self::ADMIN_PAGE_SLUG;
            
$function null;
        } else {
            
$menu_slug self::CPT;
            
$function = [ $this'print_empty_landing_pages_page' ];
        }

        return [
            
'menu_slug' => $menu_slug,
            
'function' => $function,
        ];
    }

    private function 
register_admin_menuMainMenu $menu ) {
        
$landing_pages_title esc_html__'Landing Pages''elementor' );

        
$menu_args array_merge$this->get_menu_args(), [
            
'page_title' => $landing_pages_title,
            
'menu_title' => $landing_pages_title,
            
'index' => 20,
        ] );

        
$menu->add_submenu$menu_args );
    }

    
/**
     * Add Submenu Page
     *
     * Adds the 'Landing Pages' submenu item to the 'Templates' menu item.
     *
     * @since 3.1.0
     */
    
private function register_admin_menu_legacyAdmin_Menu_Manager $admin_menu ) {
        
$menu_args $this->get_menu_args();

        
$slug $menu_args['menu_slug'];
        
$function $menu_args['function'];

        if ( 
is_callable$function ) ) {
            
$admin_menu->register$slug, new Landing_Pages_Empty_View_Menu_Item$function ) );
        } else {
            
$admin_menu->register$slug, new Landing_Pages_Menu_Item() );
        }
    }

    
/**
     * Get 'Add New' Landing Page URL
     *
     * Retrieves the custom URL for the admin dashboard's 'Add New' button in the Landing Pages admin screen. This URL
     * creates a new Landing Pages and directly opens the Elementor Editor with the Template Library modal open on the
     * Landing Pages tab.
     *
     * @since 3.1.0
     *
     * @return string
     */
    
private function get_add_new_landing_page_url() {
        if ( ! 
$this->new_lp_url ) {
            
$this->new_lp_url Plugin::$instance->documents->get_create_new_post_urlself::CPTself::DOCUMENT_TYPE ) . '#library';
        }
        return 
$this->new_lp_url;
    }

    
/**
     * Get Empty Landing Pages Page
     *
     * Prints the HTML content of the page that is displayed when there are no existing landing pages in the DB.
     * Added as the callback to add_submenu_page.
     *
     * @since 3.1.0
     */
    
public function print_empty_landing_pages_page() {
        
$template_sources Plugin::$instance->templates_manager->get_registered_sources();
        
$source_local $template_sources['local'];
        
$trashed_posts $this->get_trashed_landing_page_posts();

        
?>
        <div class="e-landing-pages-empty">
        <?php
        
/** @var Source_Local $source_local */
        
$source_local->print_blank_state_templateesc_html__'Landing Page''elementor' ), $this->get_add_new_landing_page_url(), esc_html__'Build Effective Landing Pages for your business\' marketing campaigns.''elementor' ) );

        if ( ! empty( 
$trashed_posts ) ) : ?>
            <div class="e-trashed-items">
                <?php
                    printf
(
                        
/* translators: %1$s Link open tag, %2$s: Link close tag. */
                        
esc_html__'Or view %1$sTrashed Items%1$s''elementor' ),
                        
'<a href="' esc_urladmin_url'edit.php?post_status=trash&post_type=' self::CPT ) ) . '">',
                        
'</a>'
                    
);
                
?>
            </div>
        <?php endif; ?>
        </div>
        <?php
    
}

    
/**
     * Is Current Admin Page Edit LP
     *
     * Checks whether the current page is a native WordPress edit page for a landing page.
     */
    
private function is_landing_page_admin_edit() {
        
$screen get_current_screen();

        if ( 
'post' === $screen->base ) {
            return 
$this->is_elementor_landing_pageget_post() );
        }

        return 
false;
    }

    
/**
     * Admin Localize Settings
     *
     * Enables adding properties to the globally available elementorAdmin.config JS object in the Admin Dashboard.
     * Runs on the 'elementor/admin/localize_settings' filter.
     *
     * @since 3.1.0
     *
     * @param $settings
     * @return array|null
     */
    
private function admin_localize_settings$settings ) {
        
$additional_settings = [
            
'urls' => [
                
'addNewLandingPageUrl' => $this->get_add_new_landing_page_url(),
            ],
            
'landingPages' => [
                
'landingPagesHasPages' => $this->has_landing_pages(),
                
'isLandingPageAdminEdit' => $this->is_landing_page_admin_edit(),
            ],
        ];

        return 
array_replace_recursive$settings$additional_settings );
    }

    
/**
     * Register Landing Pages CPT
     *
     * @since 3.1.0
     */
    
private function register_landing_page_cpt() {
        
$labels = [
            
'name' => esc_html__'Landing Pages''elementor' ),
            
'singular_name' => esc_html__'Landing Page''elementor' ),
            
'add_new' => esc_html__'Add New''elementor' ),
            
'add_new_item' => esc_html__'Add New Landing Page''elementor' ),
            
'edit_item' => esc_html__'Edit Landing Page''elementor' ),
            
'new_item' => esc_html__'New Landing Page''elementor' ),
            
'all_items' => esc_html__'All Landing Pages''elementor' ),
            
'view_item' => esc_html__'View Landing Page''elementor' ),
            
'search_items' => esc_html__'Search Landing Pages''elementor' ),
            
'not_found' => esc_html__'No landing pages found''elementor' ),
            
'not_found_in_trash' => esc_html__'No landing pages found in trash''elementor' ),
            
'parent_item_colon' => '',
            
'menu_name' => esc_html__'Landing Pages''elementor' ),
        ];

        
$args = [
            
'labels' => $labels,
            
'public' => true,
            
'show_in_menu' => 'edit.php?post_type=elementor_library&tabs_group=library',
            
'capability_type' => 'page',
            
'taxonomies' => [ Source_Local::TAXONOMY_TYPE_SLUG ],
            
'supports' => [ 'title''editor''comments''revisions''trackbacks''author''excerpt''page-attributes''thumbnail''custom-fields''post-formats''elementor' ],
        ];

        
register_post_typeself::CPT$args );
    }

    
/**
     * Remove Post Type Slug
     *
     * Landing Pages are supposed to act exactly like pages. This includes their URLs being directly under the site's
     * domain name. Since "Landing Pages" is a CPT, WordPress automatically adds the landing page slug as a prefix to
     * it's posts' permalinks. This method checks if the post's post type is Landing Pages, and if it is, it removes
     * the CPT slug from the requested post URL.
     *
     * Runs on the 'post_type_link' filter.
     *
     * @since 3.1.0
     *
     * @param $post_link
     * @param $post
     * @param $leavename
     * @return string|string[]
     */
    
private function remove_post_type_slug$post_link$post$leavename ) {
        
// Only try to modify the permalink if the post is a Landing Page.
        
if ( self::CPT !== $post->post_type || 'publish' !== $post->post_status ) {
            return 
$post_link;
        }

        
// Any slug prefixes need to be removed from the post link.
        
return trailingslashitget_home_url() ) . trailingslashit$post->post_name );
    }

    
/**
     * Adjust Landing Page Query
     *
     * Since Landing Pages are a CPT but should act like pages, the WP_Query that is used to fetch the page from the
     * database needs to be adjusted. This method adds the Landing Pages CPT to the list of queried post types, to
     * make sure the database query finds the correct Landing Page to display.
     * Runs on the 'pre_get_posts' action.
     *
     * @since 3.1.0
     *
     * @param \WP_Query $query
     */
    
private function adjust_landing_page_query\WP_Query $query ) {
        
// Only handle actual pages.
        
if (
            ! 
$query->is_main_query()
            
// If the query is not for a page.
            
|| ! isset( $query->query['page'] )
            
// If the query is for a static home/blog page.
            
|| is_home()
            
// If the post type comes already set, the main query is probably a custom one made by another plugin.
            // In this case we do not want to intervene in order to not cause a conflict.
            
|| isset( $query->query['post_type'] )
        ) {
            return;
        }

        
// Create the post types property as an array and include the landing pages CPT in it.
        
$query_post_types = [ 'post''page'self::CPT ];

        
// Since WordPress determined this is supposed to be a page, we'll pre-set the post_type query arg to make sure
        // it includes the Landing Page CPT, so when the query is parsed, our CPT will be a legitimate match to the
        // Landing Page's permalink (that is directly under the domain, without a CPT slug prefix). In some cases,
        // The 'name' property will be set, and in others it is the 'pagename', so we have to cover both cases.
        
if ( ! empty( $query->query['name'] ) ) {
            
$query->set'post_type'$query_post_types );
        } elseif ( ! empty( 
$query->query['pagename'] ) && false === strpos$query->query['pagename'], '/' ) ) {
            
$query->set'post_type'$query_post_types );

            
// We also need to set the name query var since redirect_guess_404_permalink() relies on it.
            
add_filter'pre_redirect_guess_404_permalink', function( $value ) use ( $query ) {
                
set_query_var'name'$query->query['pagename'] );

                return 
$value;
            } );
        }
    }

    
/**
     * Handle 404
     *
     * This method runs after a page is not found in the database, but before a page is returned as a 404.
     * These cases are handled in this filter callback, that runs on the 'pre_handle_404' filter.
     *
     * In some cases (such as when a site uses custom permalink structures), WordPress's WP_Query does not identify a
     * Landing Page's URL as a post belonging to the Landing Page CPT. Some cases are handled successfully by the
     * adjust_landing_page_query() method, but some are not and still trigger a 404 process. This method handles such
     * cases by overriding the $wp_query global to fetch the correct landing page post entry.
     *
     * For example, since Landing Pages slugs come directly after the site domain name, WP_Query might parse the post
     * as a category page. Since there is no category matching the slug, it triggers a 404 process. In this case, we
     * run a query for a Landing Page post with the passed slug ($query->query['category_name']. If a Landing Page
     * with the passed slug is found, we override the global $wp_query with the new, correct query.
     *
     * @param $current_value
     * @param $query
     * @return false
     */
    
private function handle_404$current_value$query ) {
        global 
$wp_query;

        
// If another plugin/theme already used this filter, exit here to avoid conflicts.
        
if ( $current_value ) {
            return 
$current_value;
        }

        if (
            
// Make sure we only intervene in the main query.
            
$query->is_main_query()
            
// If a post was found, this is not a 404 case, so do not intervene.
            
|| ! empty( $query->posts )
            
// This filter is only meant to deal with wrong queries where the only query var is 'category_name'.
            // If there is no 'category_name' query var, do not intervene.
            
|| empty( $query->query['category_name'] )
            
// If the query is for a real taxonomy (determined by it including a table to search in, such as the
            // wp_term_relationships table), do not intervene.
            
|| ! empty( $query->tax_query->table_aliases )
        ) {
            return 
false;
        }

        
// Search for a Landing Page with the same name passed as the 'category name'.
        
$possible_new_query = new \WP_Query( [
            
'no_found_rows' => true,
            
'post_type' => self::CPT,
            
'name' => $query->query['category_name'],
        ] );

        
// Only if such a Landing Page is found, override the query to fetch the correct page.
        
if ( ! empty( $possible_new_query->posts ) ) {
            
$wp_query $possible_new_query//phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
        
}

        return 
false;
    }

    public function 
__construct() {
        
$this->permalink_structure get_option'permalink_structure' );

        
$this->register_landing_page_cpt();

        
// If there is a permalink structure set to the site, run the hooks that modify the Landing Pages permalinks to
        // match WordPress' native 'Pages' post type.
        
if ( '' !== $this->permalink_structure ) {
            
// Landing Pages' post link needs to be modified to be identical to the pages permalink structure. This
            // needs to happen in both the admin and the front end, since post links are also used in the admin pages.
            
add_filter'post_type_link', function( $post_link$post$leavename ) {
                return 
$this->remove_post_type_slug$post_link$post$leavename );
            }, 
10);

            
// The query itself only has to be manipulated when pages are viewed in the front end.
            
if ( ! is_admin() || wp_doing_ajax() ) {
                
add_action'pre_get_posts', function ( $query ) {
                    
$this->adjust_landing_page_query$query );
                } );

                
// Handle cases where visiting a Landing Page's URL returns 404.
                
add_filter'pre_handle_404', function ( $value$query ) {
                    return 
$this->handle_404$value$query );
                }, 
10);
            }
        }

        
add_action'elementor/documents/register', function( Documents_Manager $documents_manager ) {
            
$documents_manager->register_document_typeself::DOCUMENT_TYPELanding_Page::get_class_full_name() );
        } );

        
add_action'elementor/admin/menu/register', function( Admin_Menu_Manager $admin_menu ) {
            
$this->register_admin_menu_legacy$admin_menu );
        }, 
Source_Local::ADMIN_MENU_PRIORITY 20 );

        
// Add the custom 'Add New' link for Landing Pages into Elementor's admin config.
        
add_action'elementor/admin/localize_settings', function( array $settings ) {
            return 
$this->admin_localize_settings$settings );
        } );

        
add_filter'elementor/template_library/sources/local/register_taxonomy_cpts', function( array $cpts ) {
            
$cpts[] = self::CPT;

            return 
$cpts;
        } );

        
// In the Landing Pages Admin Table page - Overwrite Template type column header title.
        
add_action'manage_' Landing_Pages_Module::CPT '_posts_columns', function( $posts_columns ) {
            
/** @var Source_Local $source_local */
            
$source_local Plugin::$instance->templates_manager->get_source'local' );

            return 
$source_local->admin_columns_headers$posts_columns );
        } );

        
// In the Landing Pages Admin Table page - Overwrite Template type column row values.
        
add_action'manage_' Landing_Pages_Module::CPT '_posts_custom_column', function( $column_name$post_id ) {
            
/** @var Landing_Page $document */
            
$document Plugin::$instance->documents->get$post_id );

            
$document->admin_columns_content$column_name );
        }, 
10);

        
// Overwrite the Admin Bar's 'New +' Landing Page URL with the link that creates the new LP in Elementor
        // with the Template Library modal open.
        
add_action'admin_bar_menu', function( $admin_bar ) {
            
// Get the Landing Page menu node.
            
$new_landing_page_node $admin_bar->get_node'new-e-landing-page' );

            if ( 
$new_landing_page_node ) {
                
$new_landing_page_node->href $this->get_add_new_landing_page_url();

                
$admin_bar->add_node$new_landing_page_node );
            }
        }, 
100 );
    }
}