frontend register styles. * * Fires after Elementor frontend styles are registered. * * @since 1.2.0 */ do_action( 'elementor/frontend/after_register_styles' ); } /** * Enqueue scripts. * * Enqueue all the frontend scripts. * * @since 1.0.0 * @access public */ public function enqueue_scripts() { /** * Before frontend enqueue scripts. * * Fires before Elementor frontend scripts are enqueued. * * @since 1.0.0 */ do_action( 'elementor/frontend/before_enqueue_scripts' ); wp_enqueue_script( 'elementor-frontend' ); if ( ! $this->is_improved_assets_loading() ) { wp_enqueue_script( 'preloaded-modules', $this->get_js_assets_url( 'preloaded-modules', 'assets/js/' ), [ 'elementor-frontend', ], ELEMENTOR_VERSION, true ); } $this->print_config(); $this->enqueue_conditional_assets(); /** * After frontend enqueue scripts. * * Fires after Elementor frontend scripts are enqueued. * * @since 1.0.0 */ do_action( 'elementor/frontend/after_enqueue_scripts' ); } /** * Enqueue styles. * * Enqueue all the frontend styles. * * Fired by `wp_enqueue_scripts` action. * * @since 1.0.0 * @access public */ public function enqueue_styles() { static $is_enqueue_styles_already_triggered; if ( ! $is_enqueue_styles_already_triggered ) { $is_enqueue_styles_already_triggered = true; /** * Before frontend styles enqueued. * * Fires before Elementor frontend styles are enqueued. * * @since 1.0.0 */ do_action( 'elementor/frontend/before_enqueue_styles' ); // The e-icons are needed in preview mode for the editor icons (plus-icon for new section, folder-icon for the templates library etc.). if ( ! Plugin::$instance->experiments->is_feature_active( 'e_font_icon_svg' ) || Plugin::$instance->preview->is_preview_mode() ) { wp_enqueue_style( 'elementor-icons' ); } wp_enqueue_style( 'elementor-frontend' ); /** * After frontend styles enqueued. * * Fires after Elementor frontend styles are enqueued. * * @since 1.0.0 */ do_action( 'elementor/frontend/after_enqueue_styles' ); if ( ! Plugin::$instance->preview->is_preview_mode() ) { $this->parse_global_css_code(); $post_id = get_the_ID(); // Check $post_id for virtual pages. check is singular because the $post_id is set to the first post on archive pages. if ( $post_id && is_singular() ) { $css_file = Post_CSS::create( get_the_ID() ); $css_file->enqueue(); } } } } /** * Get Frontend File URL * * Returns the URL for the CSS file to be loaded in the front end. If requested via the second parameter, a custom * file is generated based on a passed template file name. Otherwise, the URL for the default CSS file is returned. * * @since 3.4.5 * * @access public * * @param string $frontend_file_name * @param boolean $custom_file * * @return string frontend file URL */ public function get_frontend_file_url( $frontend_file_name, $custom_file ) { if ( $custom_file ) { $frontend_file = $this->get_frontend_file( $frontend_file_name ); $frontend_file_url = $frontend_file->get_url(); } else { $frontend_file_url = ELEMENTOR_ASSETS_URL . 'css/' . $frontend_file_name; } return $frontend_file_url; } /** * Get Frontend File Path * * Returns the path for the CSS file to be loaded in the front end. If requested via the second parameter, a custom * file is generated based on a passed template file name. Otherwise, the path for the default CSS file is returned. * * @since 3.5.0 * @access public * * @param string $frontend_file_name * @param boolean $custom_file * * @return string frontend file path */ public function get_frontend_file_path( $frontend_file_name, $custom_file ) { if ( $custom_file ) { $frontend_file = $this->get_frontend_file( $frontend_file_name ); $frontend_file_path = $frontend_file->get_path(); } else { $frontend_file_path = ELEMENTOR_ASSETS_PATH . 'css/' . $frontend_file_name; } return $frontend_file_path; } /** * Get Frontend File * * Returns a frontend file instance. * * @since 3.5.0 * @access public * * @param string $frontend_file_name * @param string $file_prefix * @param string $template_file_path * * @return FrontendFile */ public function get_frontend_file( $frontend_file_name, $file_prefix = 'custom-', $template_file_path = '' ) { static $cached_frontend_files = []; $file_name = $file_prefix . $frontend_file_name; if ( isset( $cached_frontend_files[ $file_name ] ) ) { return $cached_frontend_files[ $file_name ]; } if ( ! $template_file_path ) { $template_file_path = Breakpoints_Manager::get_stylesheet_templates_path() . $frontend_file_name; } $frontend_file = new FrontendFile( $file_name, $template_file_path ); $time = $frontend_file->get_meta( 'time' ); if ( ! $time ) { $frontend_file->update(); } $cached_frontend_files[ $file_name ] = $frontend_file; return $frontend_file; } /** * Enqueue assets conditionally. * * Enqueue all assets that were pre-enabled. * * @since 3.3.0 * @access private */ private function enqueue_conditional_assets() { Plugin::$instance->assets_loader->enqueue_assets(); } /** * Elementor footer scripts and styles. * * Handle styles and scripts that are not printed in the header. * * Fired by `wp_footer` action. * * @since 1.0.11 * @access public */ public function wp_footer() { if ( ! $this->_has_elementor_in_page ) { return; } $this->enqueue_styles(); $this->enqueue_scripts(); $this->print_fonts_links(); } /** * Print fonts links. * * Enqueue all the frontend fonts by url. * * Fired by `wp_head` action. * * @since 1.9.4 * @access public */ public function print_fonts_links() { $google_fonts = [ 'google' => [], 'early' => [], ]; foreach ( $this->fonts_to_enqueue as $key => $font ) { $font_type = Fonts::get_font_type( $font ); switch ( $font_type ) { case Fonts::GOOGLE: $google_fonts['google'][] = $font; break; case Fonts::EARLYACCESS: $google_fonts['early'][] = $font; break; case false: $this->maybe_enqueue_icon_font( $font ); break; default: /** * Print font links. * * Fires when Elementor frontend fonts are printed on the HEAD tag. * * The dynamic portion of the hook name, `$font_type`, refers to the font type. * * @since 2.0.0 * * @param string $font Font name. */ do_action( "elementor/fonts/print_font_links/{$font_type}", $font ); } } $this->fonts_to_enqueue = []; $this->enqueue_google_fonts( $google_fonts ); $this->enqueue_icon_fonts(); } private function maybe_enqueue_icon_font( $icon_font_type ) { if ( ! Icons_Manager::is_migration_allowed() ) { return; } $icons_types = Icons_Manager::get_icon_manager_tabs(); if ( ! isset( $icons_types[ $icon_font_type ] ) ) { return; } $icon_type = $icons_types[ $icon_font_type ]; if ( isset( $icon_type['url'] ) ) { $this->icon_fonts_to_enqueue[ $icon_font_type ] = [ $icon_type['url'] ]; } } private function enqueue_icon_fonts() { if ( empty( $this->icon_fonts_to_enqueue ) || ! Icons_Manager::is_migration_allowed() ) { return; } foreach ( $this->icon_fonts_to_enqueue as $icon_type => $css_url ) { wp_enqueue_style( 'elementor-icons-' . $icon_type ); $this->enqueued_icon_fonts[] = $css_url; } //clear enqueued icons $this->icon_fonts_to_enqueue = []; } /** * Print Google fonts. * * Enqueue all the frontend Google fonts. * * Fired by `wp_head` action. * * @since 1.0.0 * @access private * * @param array $google_fonts Optional. Google fonts to print in the frontend. * Default is an empty array. */ private function enqueue_google_fonts( $google_fonts = [] ) { static $google_fonts_index = 0; $print_google_fonts = true; /** * Print frontend google fonts. * * Filters whether to enqueue Google fonts in the frontend. * * @since 1.0.0 * * @param bool $print_google_fonts Whether to enqueue Google fonts. Default is true. */ $print_google_fonts = apply_filters( 'elementor/frontend/print_google_fonts', $print_google_fonts ); if ( ! $print_google_fonts ) { return; } // Print used fonts if ( ! empty( $google_fonts['google'] ) ) { $google_fonts_index++; foreach ( $google_fonts['google'] as &$font ) { $font = str_replace( ' ', '+', $font ) . ':100,100italic,200,200italic,300,300italic,400,400italic,500,500italic,600,600italic,700,700italic,800,800italic,900,900italic'; } // Defining a font-display type to google fonts. $font_display_url_str = '&display=' . Fonts::get_font_display_setting(); $fonts_url = sprintf( 'https://fonts.googleapis.com/css?family=%1$s%2$s', implode( rawurlencode( '|' ), $google_fonts['google'] ), $font_display_url_str ); $subsets = [ 'ru_RU' => 'cyrillic', 'bg_BG' => 'cyrillic', 'he_IL' => 'hebrew', 'el' => 'greek', 'vi' => 'vietnamese', 'uk' => 'cyrillic', 'cs_CZ' => 'latin-ext', 'ro_RO' => 'latin-ext', 'pl_PL' => 'latin-ext', 'hr_HR' => 'latin-ext', 'hu_HU' => 'latin-ext', 'sk_SK' => 'latin-ext', 'tr_TR' => 'latin-ext', 'lt_LT' => 'latin-ext', ]; /** * Google font subsets. * * Filters the list of Google font subsets from which locale will be enqueued in frontend. * * @since 1.0.0 * * @param array $subsets A list of font subsets. */ $subsets = apply_filters( 'elementor/frontend/google_font_subsets', $subsets ); $locale = get_locale(); if ( isset( $subsets[ $locale ] ) ) { $fonts_url .= '&subset=' . $subsets[ $locale ]; } wp_enqueue_style( 'google-fonts-' . $google_fonts_index, $fonts_url ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion } if ( ! empty( $google_fonts['early'] ) ) { foreach ( $google_fonts['early'] as $current_font ) { $google_fonts_index++; //printf( '', strtolower( str_replace( ' ', '', $current_font ) ) ); $font_url = sprintf( 'https://fonts.googleapis.com/earlyaccess/%s.css', strtolower( str_replace( ' ', '', $current_font ) ) ); wp_enqueue_style( 'google-earlyaccess-' . $google_fonts_index, $font_url ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion } } } /** * Enqueue fonts. * * Enqueue all the frontend fonts. * * @since 1.2.0 * @access public * * @param array $font Fonts to enqueue in the frontend. */ public function enqueue_font( $font ) { if ( in_array( $font, $this->registered_fonts ) ) { return; } $this->fonts_to_enqueue[] = $font; $this->registered_fonts[] = $font; } /** * Parse global CSS. * * Enqueue the global CSS file. * * @since 1.2.0 * @access protected */ protected function parse_global_css_code() { $scheme_css_file = Global_CSS::create( 'global.css' ); $scheme_css_file->enqueue(); } /** * Apply builder in content. * * Used to apply the Elementor page editor on the post content. * * @since 1.0.0 * @access public * * @param string $content The post content. * * @return string The post content. */ public function apply_builder_in_content( $content ) { $this->restore_content_filters(); if ( Plugin::$instance->preview->is_preview_mode() || $this->_is_excerpt ) { return $content; } // Remove the filter itself in order to allow other `the_content` in the elements $this->remove_content_filter(); $post_id = get_the_ID(); $builder_content = $this->get_builder_content( $post_id ); if ( ! empty( $builder_content ) ) { $content = $builder_content; $this->remove_content_filters(); } // Add the filter again for other `the_content` calls $this->add_content_filter(); return $content; } /** * Retrieve builder content. * * Used to render and return the post content with all the Elementor elements. * * Note that this method is an internal method, please use `get_builder_content_for_display()`. * * @since 1.0.0 * @access public * * @param int $post_id The post ID. * @param bool $with_css Optional. Whether to retrieve the content with CSS * or not. Default is false. * * @return string The post content. */ public function get_builder_content( $post_id, $with_css = false ) { if ( post_password_required( $post_id ) ) { return ''; } $document = Plugin::$instance->documents->get_doc_for_frontend( $post_id ); if ( ! $document || ! $document->is_built_with_elementor() ) { return ''; } // Change the current post, so widgets can use `documents->get_current`. Plugin::$instance->documents->switch_to_document( $document ); $data = $document->get_elements_data(); /** * Frontend builder content data. * * Filters the builder content in the frontend. * * @since 1.0.0 * * @param array $data The builder content. * @param int $post_id The post ID. */ $data = apply_filters( 'elementor/frontend/builder_content_data', $data, $post_id ); do_action( 'elementor/frontend/before_get_builder_content', $document, $this->_is_excerpt ); if ( empty( $data ) ) { Plugin::$instance->documents->restore_document(); return ''; } if ( ! $this->_is_excerpt ) { if ( $document->is_autosave() ) { $css_file = Post_Preview::create( $document->get_post()->ID ); } else { $css_file = Post_CSS::create( $post_id ); } $css_file->enqueue(); } ob_start(); // Handle JS and Customizer requests, with CSS inline. if ( is_customize_preview() || wp_doing_ajax() ) { $with_css = true; } if ( ! empty( $css_file ) && $with_css ) { $css_file->print_css(); } $document->print_elements_with_wrapper( $data ); $content = ob_get_clean(); $content = $this->process_more_tag( $content ); /** * Frontend content. * * Filters the content in the frontend. * * @since 1.0.0 * * @param string $content The content. */ $content = apply_filters( 'elementor/frontend/the_content', $content ); if ( ! empty( $content ) ) { $this->_has_elementor_in_page = true; } Plugin::$instance->documents->restore_document(); // BC // TODO: use Deprecation::do_deprecated_action() in 3.1.0 do_action( 'elementor/frontend/get_builder_content', $document, $this->_is_excerpt, $with_css ); return $content; } /** * Retrieve builder content for display. * * Used to render and return the post content with all the Elementor elements. * * @since 1.0.0 * @access public * * @param int $post_id The post ID. * * @param bool $with_css Optional. Whether to retrieve the content with CSS * or not. Default is false. * * @return string The post content. */ public function get_builder_content_for_display( $post_id, $with_css = false ) { if ( ! get_post( $post_id ) ) { return ''; } $editor = Plugin::$instance->editor; // Avoid recursion if ( get_the_ID() === (int) $post_id ) { $content = ''; if ( $editor->is_edit_mode() ) { $content = '