admin-templates
1 year ago
base
4 months ago
controls
4 months ago
editor-templates
2 months ago
elements
4 months ago
interfaces
1 year ago
libraries
1 year ago
managers
2 months ago
settings
2 months ago
template-library
2 months ago
widgets
2 months ago
api.php
8 months ago
autoloader.php
7 months ago
beta-testers.php
3 years ago
compatibility.php
1 year ago
conditions.php
3 years ago
db.php
4 months ago
editor-assets-api.php
2 months ago
embed.php
1 year ago
fonts.php
1 year ago
frontend.php
2 months ago
heartbeat.php
3 years ago
maintenance-mode.php
7 months ago
maintenance.php
1 year ago
plugin.php
3 months ago
preview.php
7 months ago
rollback.php
4 months ago
shapes.php
9 months ago
stylesheet.php
8 months ago
tracker.php
6 months ago
user-data.php
7 months ago
user.php
5 months ago
utils.php
2 months ago
compatibility.php
385 lines
| 1 | <?php |
| 2 | namespace Elementor; |
| 3 | |
| 4 | use Elementor\Core\Base\Document; |
| 5 | use Elementor\Core\DocumentTypes\PageBase; |
| 6 | use Elementor\TemplateLibrary\Source_Local; |
| 7 | use Elementor\Utils; |
| 8 | |
| 9 | if ( ! defined( 'ABSPATH' ) ) { |
| 10 | exit; // Exit if accessed directly. |
| 11 | } |
| 12 | |
| 13 | /** |
| 14 | * Elementor compatibility. |
| 15 | * |
| 16 | * Elementor compatibility handler class is responsible for compatibility with |
| 17 | * external plugins. The class resolves different issues with non-compatible |
| 18 | * plugins. |
| 19 | * |
| 20 | * @since 1.0.0 |
| 21 | */ |
| 22 | class Compatibility { |
| 23 | |
| 24 | /** |
| 25 | * Register actions. |
| 26 | * |
| 27 | * Run Elementor compatibility with external plugins using custom filters and |
| 28 | * actions. |
| 29 | * |
| 30 | * @since 1.0.0 |
| 31 | * @access public |
| 32 | * @static |
| 33 | */ |
| 34 | public static function register_actions() { |
| 35 | add_action( 'init', [ __CLASS__, 'init' ] ); |
| 36 | |
| 37 | self::polylang_compatibility(); |
| 38 | self::yoast_duplicate_post(); |
| 39 | |
| 40 | if ( is_admin() || defined( 'WP_LOAD_IMPORTERS' ) ) { |
| 41 | add_filter( 'wp_import_post_meta', [ __CLASS__, 'on_wp_import_post_meta' ] ); |
| 42 | add_filter( 'wxr_importer.pre_process.post_meta', [ __CLASS__, 'on_wxr_importer_pre_process_post_meta' ] ); |
| 43 | } |
| 44 | |
| 45 | add_action( 'elementor/maintenance_mode/mode_changed', [ __CLASS__, 'clear_3rd_party_cache' ] ); |
| 46 | |
| 47 | // Enable floating buttons and link in bio experiment for all. |
| 48 | // TODO Remove in version 3.26. |
| 49 | add_filter( 'pre_option_elementor_experiment-floating-buttons', [ __CLASS__, 'return_active' ] ); |
| 50 | add_filter( 'pre_option_elementor_experiment-link-in-bio', [ __CLASS__, 'return_active' ] ); |
| 51 | } |
| 52 | |
| 53 | public static function return_active() { |
| 54 | return 'active'; |
| 55 | } |
| 56 | |
| 57 | public static function clear_3rd_party_cache() { |
| 58 | // W3 Total Cache. |
| 59 | if ( function_exists( 'w3tc_flush_all' ) ) { |
| 60 | w3tc_flush_all(); |
| 61 | } |
| 62 | |
| 63 | // WP Fastest Cache. |
| 64 | if ( ! empty( $GLOBALS['wp_fastest_cache'] ) && method_exists( $GLOBALS['wp_fastest_cache'], 'deleteCache' ) ) { |
| 65 | $GLOBALS['wp_fastest_cache']->deleteCache(); |
| 66 | } |
| 67 | |
| 68 | // WP Super Cache. |
| 69 | if ( function_exists( 'wp_cache_clean_cache' ) ) { |
| 70 | global $file_prefix; |
| 71 | wp_cache_clean_cache( $file_prefix, true ); |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | /** |
| 76 | * Add new button to gutenberg. |
| 77 | * |
| 78 | * Insert new "Elementor" button to the gutenberg editor to create new post |
| 79 | * using Elementor page builder. |
| 80 | * |
| 81 | * @since 1.9.0 |
| 82 | * @access public |
| 83 | * @static |
| 84 | */ |
| 85 | public static function add_new_button_to_gutenberg() { |
| 86 | global $typenow; |
| 87 | if ( ! User::is_current_user_can_edit_post_type( $typenow ) ) { |
| 88 | return; |
| 89 | } |
| 90 | |
| 91 | // Introduced in WP 5.0. |
| 92 | if ( function_exists( 'use_block_editor_for_post' ) && ! use_block_editor_for_post( $typenow ) ) { |
| 93 | return; |
| 94 | } |
| 95 | |
| 96 | // Deprecated/removed in Gutenberg plugin v5.3.0. |
| 97 | if ( function_exists( 'gutenberg_can_edit_post_type' ) && ! gutenberg_can_edit_post_type( $typenow ) ) { |
| 98 | return; |
| 99 | } |
| 100 | |
| 101 | ?> |
| 102 | <script> |
| 103 | document.addEventListener( 'DOMContentLoaded', function() { |
| 104 | var dropdown = document.querySelector( '#split-page-title-action .dropdown' ); |
| 105 | |
| 106 | if ( ! dropdown ) { |
| 107 | return; |
| 108 | } |
| 109 | |
| 110 | var url = '<?php echo esc_url( Plugin::$instance->documents->get_create_new_post_url( $typenow ) ); ?>'; |
| 111 | |
| 112 | dropdown.insertAdjacentHTML( 'afterbegin', '<a href="' + url + '">Elementor</a>' ); |
| 113 | } ); |
| 114 | </script> |
| 115 | <?php |
| 116 | } |
| 117 | |
| 118 | /** |
| 119 | * Init. |
| 120 | * |
| 121 | * Initialize Elementor compatibility with external plugins. |
| 122 | * |
| 123 | * Fired by `init` action. |
| 124 | * |
| 125 | * @since 1.0.0 |
| 126 | * @access public |
| 127 | * @static |
| 128 | */ |
| 129 | public static function init() { |
| 130 | // Hotfix for NextGEN Gallery plugin. |
| 131 | if ( defined( 'NGG_PLUGIN_VERSION' ) ) { |
| 132 | add_filter( 'elementor/document/urls/edit', function( $edit_link ) { |
| 133 | return add_query_arg( 'display_gallery_iframe', '', $edit_link ); |
| 134 | } ); |
| 135 | } |
| 136 | |
| 137 | // Exclude our Library from Yoast SEO plugin. |
| 138 | add_filter( 'wpseo_sitemaps_supported_post_types', [ __CLASS__, 'filter_library_post_type' ] ); |
| 139 | add_filter( 'wpseo_accessible_post_types', [ __CLASS__, 'filter_library_post_type' ] ); |
| 140 | add_filter( 'wpseo_sitemap_exclude_post_type', function( $retval, $post_type ) { |
| 141 | if ( Source_Local::CPT === $post_type ) { |
| 142 | $retval = true; |
| 143 | } |
| 144 | |
| 145 | return $retval; |
| 146 | }, 10, 2 ); |
| 147 | |
| 148 | // Disable optimize files in Editor from Autoptimize plugin. |
| 149 | add_filter( 'autoptimize_filter_noptimize', function( $retval ) { |
| 150 | if ( Plugin::$instance->editor->is_edit_mode() ) { |
| 151 | $retval = true; |
| 152 | } |
| 153 | |
| 154 | return $retval; |
| 155 | } ); |
| 156 | |
| 157 | // Add the description (content) tab for a new product, so it can be edited with Elementor. |
| 158 | add_filter( 'woocommerce_product_tabs', function( $tabs ) { |
| 159 | if ( ! isset( $tabs['description'] ) && Plugin::$instance->preview->is_preview_mode() ) { |
| 160 | $post = get_post(); |
| 161 | if ( empty( $post->post_content ) ) { |
| 162 | $tabs['description'] = [ |
| 163 | 'title' => esc_html__( 'Description', 'elementor' ), |
| 164 | 'priority' => 10, |
| 165 | 'callback' => 'woocommerce_product_description_tab', |
| 166 | ]; |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | return $tabs; |
| 171 | } ); |
| 172 | |
| 173 | // Fix WC session not defined in editor. |
| 174 | if ( class_exists( 'woocommerce' ) ) { |
| 175 | add_action( 'elementor/editor/before_enqueue_scripts', function() { |
| 176 | remove_action( 'woocommerce_shortcode_before_product_cat_loop', 'wc_print_notices' ); |
| 177 | remove_action( 'woocommerce_before_shop_loop', 'wc_print_notices' ); |
| 178 | remove_action( 'woocommerce_before_single_product', 'wc_print_notices' ); |
| 179 | } ); |
| 180 | |
| 181 | add_filter( 'elementor/maintenance_mode/is_login_page', function( $value ) { |
| 182 | |
| 183 | // Support Woocommerce Account Page. |
| 184 | if ( is_account_page() && ! is_user_logged_in() ) { |
| 185 | $value = true; |
| 186 | } |
| 187 | return $value; |
| 188 | } ); |
| 189 | } |
| 190 | |
| 191 | // Fix Jetpack Contact Form in Editor Mode. |
| 192 | if ( class_exists( 'Grunion_Editor_View' ) ) { |
| 193 | add_action( 'elementor/editor/before_enqueue_scripts', function() { |
| 194 | remove_action( 'media_buttons', 'grunion_media_button', 999 ); |
| 195 | remove_action( 'admin_enqueue_scripts', 'grunion_enable_spam_recheck' ); |
| 196 | |
| 197 | remove_action( 'admin_notices', [ 'Grunion_Editor_View', 'handle_editor_view_js' ] ); |
| 198 | remove_action( 'admin_head', [ 'Grunion_Editor_View', 'admin_head' ] ); |
| 199 | } ); |
| 200 | } |
| 201 | |
| 202 | // Fix Popup Maker in Editor Mode. |
| 203 | if ( class_exists( 'PUM_Admin_Shortcode_UI' ) ) { |
| 204 | add_action( 'elementor/editor/before_enqueue_scripts', function() { |
| 205 | $pum_admin_instance = \PUM_Admin_Shortcode_UI::instance(); |
| 206 | |
| 207 | remove_action( 'print_media_templates', [ $pum_admin_instance, 'print_media_templates' ] ); |
| 208 | remove_action( 'admin_print_footer_scripts', [ $pum_admin_instance, 'admin_print_footer_scripts' ], 100 ); |
| 209 | remove_action( 'wp_ajax_pum_do_shortcode', [ $pum_admin_instance, 'wp_ajax_pum_do_shortcode' ] ); |
| 210 | |
| 211 | remove_action( 'admin_enqueue_scripts', [ $pum_admin_instance, 'admin_enqueue_scripts' ] ); |
| 212 | |
| 213 | remove_filter( 'pum_admin_var', [ $pum_admin_instance, 'pum_admin_var' ] ); |
| 214 | } ); |
| 215 | } |
| 216 | |
| 217 | // Fix Preview URL for https://github.com/wpmudev/domain-mapping plugin. |
| 218 | if ( class_exists( 'domain_map' ) ) { |
| 219 | add_filter( 'elementor/document/urls/preview', function( $preview_url ) { |
| 220 | if ( wp_parse_url( $preview_url, PHP_URL_HOST ) !== Utils::get_super_global_value( $_SERVER, 'HTTP_HOST' ) ) { |
| 221 | $preview_url = \domain_map::utils()->unswap_url( $preview_url ); |
| 222 | $preview_url = add_query_arg( [ |
| 223 | 'dm' => \Domainmap_Module_Mapping::BYPASS, |
| 224 | ], $preview_url ); |
| 225 | } |
| 226 | |
| 227 | return $preview_url; |
| 228 | } ); |
| 229 | } |
| 230 | |
| 231 | // Gutenberg. |
| 232 | if ( function_exists( 'gutenberg_init' ) ) { |
| 233 | add_action( 'admin_print_scripts-edit.php', [ __CLASS__, 'add_new_button_to_gutenberg' ], 11 ); |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | public static function filter_library_post_type( $post_types ) { |
| 238 | unset( $post_types[ Source_Local::CPT ] ); |
| 239 | |
| 240 | return $post_types; |
| 241 | } |
| 242 | |
| 243 | /** |
| 244 | * Polylang compatibility. |
| 245 | * |
| 246 | * Fix Polylang compatibility with Elementor. |
| 247 | * |
| 248 | * @since 2.0.0 |
| 249 | * @access private |
| 250 | * @static |
| 251 | */ |
| 252 | private static function polylang_compatibility() { |
| 253 | // Copy elementor data while polylang creates a translation copy. |
| 254 | add_filter( 'pll_copy_post_metas', [ __CLASS__, 'save_polylang_meta' ], 10, 4 ); |
| 255 | } |
| 256 | |
| 257 | /** |
| 258 | * Save polylang meta. |
| 259 | * |
| 260 | * Copy elementor data while polylang creates a translation copy. |
| 261 | * |
| 262 | * Fired by `pll_copy_post_metas` filter. |
| 263 | * |
| 264 | * @since 1.6.0 |
| 265 | * @access public |
| 266 | * @static |
| 267 | * |
| 268 | * @param array $keys List of custom fields names. |
| 269 | * @param bool $sync True if it is synchronization, false if it is a copy. |
| 270 | * @param int $from ID of the post from which we copy information. |
| 271 | * @param int $to ID of the post to which we paste information. |
| 272 | * |
| 273 | * @return array List of custom fields names. |
| 274 | */ |
| 275 | public static function save_polylang_meta( $keys, $sync, $from, $to ) { |
| 276 | // Copy only for a new post. |
| 277 | if ( ! $sync ) { |
| 278 | Plugin::$instance->db->copy_elementor_meta( $from, $to ); |
| 279 | } |
| 280 | |
| 281 | return $keys; |
| 282 | } |
| 283 | |
| 284 | private static function yoast_duplicate_post() { |
| 285 | add_filter( 'duplicate_post_excludelist_filter', function( $meta_excludelist ) { |
| 286 | $exclude_list = [ |
| 287 | Document::TYPE_META_KEY, |
| 288 | '_elementor_page_assets', |
| 289 | '_elementor_controls_usage', |
| 290 | '_elementor_css', |
| 291 | '_elementor_screenshot', |
| 292 | ]; |
| 293 | |
| 294 | return array_merge( $meta_excludelist, $exclude_list ); |
| 295 | } ); |
| 296 | |
| 297 | add_action( 'duplicate_post_post_copy', function( $new_post_id, $post ) { |
| 298 | $original_template_type = get_post_meta( $post->ID, Document::TYPE_META_KEY, true ); |
| 299 | if ( ! empty( $original_template_type ) ) { |
| 300 | update_post_meta( $new_post_id, Document::TYPE_META_KEY, $original_template_type ); |
| 301 | } |
| 302 | }, 10, 2 ); |
| 303 | } |
| 304 | |
| 305 | /** |
| 306 | * Process post meta before WP importer. |
| 307 | * |
| 308 | * Normalize Elementor post meta on import, We need the `wp_slash` in order |
| 309 | * to avoid the unslashing during the `add_post_meta`. |
| 310 | * |
| 311 | * Fired by `wp_import_post_meta` filter. |
| 312 | * |
| 313 | * @since 1.0.0 |
| 314 | * @access public |
| 315 | * @static |
| 316 | * |
| 317 | * @param array $post_meta Post meta. |
| 318 | * |
| 319 | * @return array Updated post meta. |
| 320 | */ |
| 321 | public static function on_wp_import_post_meta( $post_meta ) { |
| 322 | $is_wp_importer_before_0_7 = self::is_wp_importer_before_0_7(); |
| 323 | |
| 324 | if ( $is_wp_importer_before_0_7 ) { |
| 325 | foreach ( $post_meta as &$meta ) { |
| 326 | if ( '_elementor_data' === $meta['key'] ) { |
| 327 | $meta['value'] = wp_slash( $meta['value'] ); |
| 328 | break; |
| 329 | } |
| 330 | } |
| 331 | } |
| 332 | |
| 333 | return $post_meta; |
| 334 | } |
| 335 | |
| 336 | /** |
| 337 | * Is WP Importer Before 0.7 |
| 338 | * |
| 339 | * Checks if WP Importer is installed, and whether its version is older than 0.7. |
| 340 | * |
| 341 | * @return bool |
| 342 | */ |
| 343 | public static function is_wp_importer_before_0_7() { |
| 344 | $wp_importer = get_plugins( '/wordpress-importer' ); |
| 345 | |
| 346 | if ( ! empty( $wp_importer ) ) { |
| 347 | $wp_importer_version = $wp_importer['wordpress-importer.php']['Version']; |
| 348 | |
| 349 | if ( version_compare( $wp_importer_version, '0.7', '<' ) ) { |
| 350 | return true; |
| 351 | } |
| 352 | } |
| 353 | |
| 354 | return false; |
| 355 | } |
| 356 | |
| 357 | /** |
| 358 | * Process post meta before WXR importer. |
| 359 | * |
| 360 | * Normalize Elementor post meta on import with the new WP_importer, We need |
| 361 | * the `wp_slash` in order to avoid the unslashing during the `add_post_meta`. |
| 362 | * |
| 363 | * Fired by `wxr_importer.pre_process.post_meta` filter. |
| 364 | * |
| 365 | * @since 1.0.0 |
| 366 | * @access public |
| 367 | * @static |
| 368 | * |
| 369 | * @param array $post_meta Post meta. |
| 370 | * |
| 371 | * @return array Updated post meta. |
| 372 | */ |
| 373 | public static function on_wxr_importer_pre_process_post_meta( $post_meta ) { |
| 374 | $is_wp_importer_before_0_7 = self::is_wp_importer_before_0_7(); |
| 375 | |
| 376 | if ( $is_wp_importer_before_0_7 ) { |
| 377 | if ( '_elementor_data' === $post_meta['key'] ) { |
| 378 | $post_meta['value'] = wp_slash( $post_meta['value'] ); |
| 379 | } |
| 380 | } |
| 381 | |
| 382 | return $post_meta; |
| 383 | } |
| 384 | } |
| 385 |