admin-templates
1 year ago
base
1 year ago
container
1 year ago
controls
1 year ago
editor-templates
1 year ago
elements
1 year ago
interfaces
1 year ago
libraries
1 year ago
managers
1 year ago
settings
1 year ago
template-library
1 year ago
widgets
1 year ago
api.php
1 year ago
autoloader.php
1 year ago
beta-testers.php
3 years ago
compatibility.php
1 year ago
conditions.php
3 years ago
db.php
2 years ago
editor-assets-api.php
1 year ago
embed.php
1 year ago
fonts.php
1 year ago
frontend.php
1 year ago
heartbeat.php
3 years ago
maintenance-mode.php
2 years ago
maintenance.php
1 year ago
plugin.php
1 year ago
preview.php
1 year ago
rollback.php
3 years ago
shapes.php
1 year ago
stylesheet.php
1 year ago
tracker.php
1 year ago
user.php
2 years ago
utils.php
1 year ago
preview.php
359 lines
| 1 | <?php |
| 2 | namespace Elementor; |
| 3 | |
| 4 | use Elementor\Core\Base\App; |
| 5 | use Elementor\Core\Settings\Manager as SettingsManager; |
| 6 | |
| 7 | if ( ! defined( 'ABSPATH' ) ) { |
| 8 | exit; // Exit if accessed directly. |
| 9 | } |
| 10 | |
| 11 | /** |
| 12 | * Elementor preview. |
| 13 | * |
| 14 | * Elementor preview handler class is responsible for initializing Elementor in |
| 15 | * preview mode. |
| 16 | * |
| 17 | * @since 1.0.0 |
| 18 | */ |
| 19 | class Preview extends App { |
| 20 | |
| 21 | /** |
| 22 | * The priority of the preview enqueued styles. |
| 23 | */ |
| 24 | const ENQUEUED_STYLES_PRIORITY = 20; |
| 25 | |
| 26 | /** |
| 27 | * Is Preview. |
| 28 | * |
| 29 | * Holds a flag if current request is a preview. |
| 30 | * The flag is not related to a specific post or edit permissions. |
| 31 | * |
| 32 | * @since 2.9.5 |
| 33 | * @access private |
| 34 | * |
| 35 | * @var bool Is Preview. |
| 36 | */ |
| 37 | |
| 38 | private $is_preview; |
| 39 | |
| 40 | /** |
| 41 | * Post ID. |
| 42 | * |
| 43 | * Holds the ID of the current post being previewed. |
| 44 | * |
| 45 | * @since 1.0.0 |
| 46 | * @access private |
| 47 | * |
| 48 | * @var int Post ID. |
| 49 | */ |
| 50 | private $post_id; |
| 51 | |
| 52 | /** |
| 53 | * Get module name. |
| 54 | * |
| 55 | * Retrieve the module name. |
| 56 | * |
| 57 | * @since 3.0.0 |
| 58 | * @access public |
| 59 | * @abstract |
| 60 | * |
| 61 | * @return string Module name. |
| 62 | */ |
| 63 | public function get_name() { |
| 64 | return 'preview'; |
| 65 | } |
| 66 | |
| 67 | /** |
| 68 | * Init. |
| 69 | * |
| 70 | * Initialize Elementor preview mode. |
| 71 | * |
| 72 | * Fired by `template_redirect` action. |
| 73 | * |
| 74 | * @since 1.0.0 |
| 75 | * @access public |
| 76 | */ |
| 77 | public function init() { |
| 78 | if ( is_admin() || ! $this->is_preview_mode() ) { |
| 79 | return; |
| 80 | } |
| 81 | |
| 82 | if ( isset( $_GET['preview-debug'] ) ) { |
| 83 | register_shutdown_function( function () { |
| 84 | $e = error_get_last(); |
| 85 | if ( $e ) { |
| 86 | echo '<div id="elementor-preview-debug-error"><pre>'; |
| 87 | Utils::print_unescaped_internal_string( $e['message'] ); |
| 88 | echo '</pre></div>'; |
| 89 | } |
| 90 | } ); |
| 91 | } |
| 92 | |
| 93 | $this->post_id = get_the_ID(); |
| 94 | $this->is_preview = true; |
| 95 | |
| 96 | // Don't redirect to permalink. |
| 97 | remove_action( 'template_redirect', 'redirect_canonical' ); |
| 98 | |
| 99 | // Compatibility with Yoast SEO plugin when 'Removes unneeded query variables from the URL' enabled. |
| 100 | // TODO: Move this code to `includes/compatibility.php`. |
| 101 | if ( class_exists( 'WPSEO_Frontend' ) ) { |
| 102 | remove_action( 'template_redirect', [ \WPSEO_Frontend::get_instance(), 'clean_permalink' ], 1 ); |
| 103 | } |
| 104 | |
| 105 | // Disable the WP admin bar in preview mode. |
| 106 | add_filter( 'show_admin_bar', '__return_false' ); |
| 107 | |
| 108 | add_action( 'wp_enqueue_scripts', function() { |
| 109 | $this->enqueue_styles(); |
| 110 | $this->enqueue_scripts(); |
| 111 | }, self::ENQUEUED_STYLES_PRIORITY ); |
| 112 | |
| 113 | add_filter( 'the_content', [ $this, 'builder_wrapper' ], 999999 ); |
| 114 | |
| 115 | add_action( 'wp_footer', [ $this, 'wp_footer' ] ); |
| 116 | |
| 117 | // Avoid Cloudflare's Rocket Loader lazy load the editor iframe |
| 118 | add_filter( 'script_loader_tag', [ $this, 'rocket_loader_filter' ], 10, 3 ); |
| 119 | |
| 120 | // Tell to WP Cache plugins do not cache this request. |
| 121 | Utils::do_not_cache(); |
| 122 | |
| 123 | /** |
| 124 | * Preview init. |
| 125 | * |
| 126 | * Fires on Elementor preview init, after Elementor preview has finished |
| 127 | * loading but before any headers are sent. |
| 128 | * |
| 129 | * @since 1.0.0 |
| 130 | * |
| 131 | * @param Preview $this The current preview. |
| 132 | */ |
| 133 | do_action( 'elementor/preview/init', $this ); |
| 134 | } |
| 135 | |
| 136 | /** |
| 137 | * Retrieve post ID. |
| 138 | * |
| 139 | * Get the ID of the current post. |
| 140 | * |
| 141 | * @since 1.8.0 |
| 142 | * @access public |
| 143 | * |
| 144 | * @return int Post ID. |
| 145 | */ |
| 146 | public function get_post_id() { |
| 147 | return $this->post_id; |
| 148 | } |
| 149 | |
| 150 | /** |
| 151 | * Is Preview. |
| 152 | * |
| 153 | * Whether current request is the elementor preview iframe. |
| 154 | * The flag is not related to a specific post or edit permissions. |
| 155 | * |
| 156 | * @since 2.9.5 |
| 157 | * @access public |
| 158 | * |
| 159 | * @return bool |
| 160 | */ |
| 161 | public function is_preview() { |
| 162 | return $this->is_preview; |
| 163 | } |
| 164 | |
| 165 | /** |
| 166 | * Whether preview mode is active. |
| 167 | * |
| 168 | * Used to determine whether we are in the preview mode (iframe). |
| 169 | * |
| 170 | * @since 1.0.0 |
| 171 | * @access public |
| 172 | * |
| 173 | * @param int $post_id Optional. Post ID. Default is `0`. |
| 174 | * |
| 175 | * @return bool Whether preview mode is active. |
| 176 | */ |
| 177 | public function is_preview_mode( $post_id = 0 ) { |
| 178 | if ( ! isset( $_GET['elementor-preview'] ) ) { |
| 179 | return false; |
| 180 | } |
| 181 | |
| 182 | if ( empty( $post_id ) ) { |
| 183 | $post_id = get_the_ID(); |
| 184 | } |
| 185 | |
| 186 | if ( ! User::is_current_user_can_edit( $post_id ) ) { |
| 187 | return false; |
| 188 | } |
| 189 | |
| 190 | if ( $post_id !== (int) $_GET['elementor-preview'] ) { |
| 191 | return false; |
| 192 | } |
| 193 | |
| 194 | return true; |
| 195 | } |
| 196 | |
| 197 | /** |
| 198 | * Builder wrapper. |
| 199 | * |
| 200 | * Used to add an empty HTML wrapper for the builder, the javascript will add |
| 201 | * the content later. |
| 202 | * |
| 203 | * @since 1.0.0 |
| 204 | * @access public |
| 205 | * |
| 206 | * @param string $content The content of the builder. |
| 207 | * |
| 208 | * @return string HTML wrapper for the builder. |
| 209 | */ |
| 210 | public function builder_wrapper( $content ) { |
| 211 | if ( get_the_ID() === $this->post_id ) { |
| 212 | $document = Plugin::$instance->documents->get( $this->post_id ); |
| 213 | |
| 214 | $attributes = $document->get_container_attributes(); |
| 215 | |
| 216 | $content = '<div ' . Utils::render_html_attributes( $attributes ) . '></div>'; |
| 217 | } |
| 218 | |
| 219 | return $content; |
| 220 | } |
| 221 | |
| 222 | /** |
| 223 | * Enqueue preview styles. |
| 224 | * |
| 225 | * Registers all the preview styles and enqueues them. |
| 226 | * |
| 227 | * Fired by `wp_enqueue_scripts` action. |
| 228 | * |
| 229 | * @since 1.0.0 |
| 230 | * @access private |
| 231 | */ |
| 232 | private function enqueue_styles() { |
| 233 | // Hold-on all jQuery plugins after all HTML markup render. |
| 234 | wp_add_inline_script( 'jquery-migrate', 'jQuery.holdReady( true );' ); |
| 235 | |
| 236 | Plugin::$instance->frontend->enqueue_styles(); |
| 237 | |
| 238 | Plugin::$instance->elements_manager->enqueue_elements_styles(); |
| 239 | |
| 240 | Plugin::$instance->widgets_manager->enqueue_widgets_styles(); |
| 241 | |
| 242 | $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; |
| 243 | |
| 244 | $direction_suffix = is_rtl() ? '-rtl' : ''; |
| 245 | |
| 246 | wp_register_style( |
| 247 | 'elementor-select2', |
| 248 | ELEMENTOR_ASSETS_URL . 'lib/e-select2/css/e-select2' . $suffix . '.css', |
| 249 | [], |
| 250 | '4.0.6-rc.1' |
| 251 | ); |
| 252 | |
| 253 | wp_register_style( |
| 254 | 'editor-preview', |
| 255 | ELEMENTOR_ASSETS_URL . 'css/editor-preview' . $direction_suffix . $suffix . '.css', |
| 256 | [ |
| 257 | 'elementor-select2', |
| 258 | ], |
| 259 | ELEMENTOR_VERSION |
| 260 | ); |
| 261 | |
| 262 | wp_enqueue_style( |
| 263 | 'e-theme-ui-light', |
| 264 | $this->get_css_assets_url( 'theme-light' ), |
| 265 | [], |
| 266 | ELEMENTOR_VERSION |
| 267 | ); |
| 268 | |
| 269 | wp_enqueue_style( 'editor-preview' ); |
| 270 | |
| 271 | // Handle the 'wp audio' in editor preview. |
| 272 | wp_enqueue_style( 'wp-mediaelement' ); |
| 273 | |
| 274 | /** |
| 275 | * Preview enqueue styles. |
| 276 | * |
| 277 | * Fires after Elementor preview styles are enqueued. |
| 278 | * |
| 279 | * @since 1.0.0 |
| 280 | */ |
| 281 | do_action( 'elementor/preview/enqueue_styles' ); |
| 282 | } |
| 283 | |
| 284 | /** |
| 285 | * Enqueue preview scripts. |
| 286 | * |
| 287 | * Registers all the preview scripts and enqueues them. |
| 288 | * |
| 289 | * Fired by `wp_enqueue_scripts` action. |
| 290 | * |
| 291 | * @since 1.5.4 |
| 292 | * @access private |
| 293 | */ |
| 294 | private function enqueue_scripts() { |
| 295 | Plugin::$instance->frontend->register_scripts(); |
| 296 | |
| 297 | Plugin::$instance->widgets_manager->enqueue_widgets_scripts(); |
| 298 | |
| 299 | $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; |
| 300 | |
| 301 | wp_enqueue_script( |
| 302 | 'elementor-inline-editor', |
| 303 | ELEMENTOR_ASSETS_URL . 'lib/inline-editor/js/inline-editor' . $suffix . '.js', |
| 304 | [], |
| 305 | ELEMENTOR_VERSION, |
| 306 | true |
| 307 | ); |
| 308 | |
| 309 | // Handle the 'wp audio' in editor preview. |
| 310 | wp_enqueue_script( 'wp-mediaelement' ); |
| 311 | |
| 312 | /** |
| 313 | * Preview enqueue scripts. |
| 314 | * |
| 315 | * Fires after Elementor preview scripts are enqueued. |
| 316 | * |
| 317 | * @since 1.5.4 |
| 318 | */ |
| 319 | do_action( 'elementor/preview/enqueue_scripts' ); |
| 320 | } |
| 321 | |
| 322 | public function rocket_loader_filter( $tag, $handle, $src ) { |
| 323 | return str_replace( '<script', '<script data-cfasync="false"', $tag ); |
| 324 | } |
| 325 | |
| 326 | /** |
| 327 | * Elementor Preview footer scripts and styles. |
| 328 | * |
| 329 | * Handle styles and scripts from frontend. |
| 330 | * |
| 331 | * Fired by `wp_footer` action. |
| 332 | * |
| 333 | * @since 2.0.9 |
| 334 | * @access public |
| 335 | */ |
| 336 | public function wp_footer() { |
| 337 | $frontend = Plugin::$instance->frontend; |
| 338 | if ( $frontend->has_elementor_in_page() ) { |
| 339 | // Has header/footer/widget-template - enqueue all style/scripts/fonts. |
| 340 | $frontend->wp_footer(); |
| 341 | } else { |
| 342 | // Enqueue only scripts. |
| 343 | $frontend->enqueue_scripts(); |
| 344 | } |
| 345 | } |
| 346 | |
| 347 | /** |
| 348 | * Preview constructor. |
| 349 | * |
| 350 | * Initializing Elementor preview. |
| 351 | * |
| 352 | * @since 1.0.0 |
| 353 | * @access public |
| 354 | */ |
| 355 | public function __construct() { |
| 356 | add_action( 'template_redirect', [ $this, 'init' ], 0 ); |
| 357 | } |
| 358 | } |
| 359 |