base_path = UAGB_UPLOAD_DIR . 'assets/'; $this->base_url = UAGB_UPLOAD_URL . 'assets/'; if ( empty( $_GET['page'] ) || 'spectra' !== $_GET['page'] || empty( $_GET['path'] ) || 'settings' !== $_GET['path'] || empty( $_GET['settings'] ) || 'fse-support' !== $_GET['settings'] ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended return; } $uagb_filesystem = uagb_filesystem(); $fonts_folder_path = get_stylesheet_directory() . '/assets/fonts/spectra'; if ( file_exists( $fonts_folder_path ) ) { $uagb_filesystem->delete( $fonts_folder_path, true, 'd' ); } self::delete_all_theme_font_family(); $load_fse_font_globally = UAGB_Admin_Helper::get_admin_settings_option( 'uag_load_fse_font_globally', 'disabled' ); if ( 'disabled' !== $load_fse_font_globally ) { add_action( 'admin_init', array( $this, 'save_google_fonts_to_theme' ) ); } } /** * Get, add and update font family in Spectra for ST. * * @param array $families font family. * @since 2.7.0 * @return void */ public function get_font_family_for_starter_template( $families ) { if ( UAGB_Admin_Helper::get_admin_settings_option( 'uag_load_fse_font_globally', 'disabled' ) ) { // if Load FSE Fonts Globaly is disabled then enabled it. UAGB_Admin_Helper::update_admin_settings_option( 'uag_load_fse_font_globally', 'enabled' ); } $new_font_families = array(); if ( empty( $families ) || ! is_array( $families ) ) { return; } foreach ( $families as $family ) { $font_name = ! empty( $family ) ? $family : ''; $font_name_string = explode( ',', $font_name ); $font_family = trim( $font_name_string[0], "'" ); $font_slug = $this->get_font_slug( $font_family ); $font_weight = 'Default'; $font_style = 'normal'; $final_font_files = $this->get_fonts_file_url( $font_family, $font_weight, $font_style ); $new_font_faces = array( array( 'fontFamily' => $font_family, 'fontStyle' => $font_style, 'fontWeight' => $font_weight, 'src' => $final_font_files, ), ); $this->add_or_update_theme_font_faces( $font_family, $font_slug, $new_font_faces ); } $theme_json_raw = json_decode( file_get_contents( get_stylesheet_directory() . '/theme.json' ), true ); $all_font_families = $theme_json_raw['settings']['typography']['fontFamilies']; if ( empty( $all_font_families ) || ! is_array( $all_font_families ) ) { return; } foreach ( $all_font_families as $font_families_item ) { $new_font_families_item = array( 'value' => $font_families_item['fontFamily'], 'label' => $font_families_item['fontFamily'], 'weights' => array( array( 'value' => 'Default', 'label' => __( 'Default', 'ultimate-addons-for-gutenberg' ), ), array( 'value' => '400', 'label' => __( '400', 'ultimate-addons-for-gutenberg' ), ), ), 'styles' => array( array( 'value' => 'normal', 'label' => __( 'normal', 'ultimate-addons-for-gutenberg' ), ), ), 'weight' => array( array( 'value' => '400', 'label' => __( '400', 'ultimate-addons-for-gutenberg' ), ), ), 'style' => array( array( 'value' => 'normal', 'label' => __( 'normal', 'ultimate-addons-for-gutenberg' ), ), ), ); $new_font_families[] = $new_font_families_item; } UAGB_Admin_Helper::update_admin_settings_option( 'spectra_global_fse_fonts', $new_font_families ); } /** * Save Google Fonts to the FSE Theme. * * @return void * @since 2.5.1 */ public function save_google_fonts_to_theme() { $spectra_global_fse_fonts = \UAGB_Admin_Helper::get_admin_settings_option( 'spectra_global_fse_fonts', array() ); if ( empty( $spectra_global_fse_fonts ) || ! is_array( $spectra_global_fse_fonts ) ) { return; } foreach ( $spectra_global_fse_fonts as $font ) { $font_family = ! empty( $font['value'] ) ? $font['value'] : ''; $font_slug = $this->get_font_slug( $font_family ); $new_font_faces = array(); foreach ( $font['weight'] as $weight ) { $font_weight = ! empty( $weight['value'] ) ? $weight['value'] : ''; foreach ( $font['style'] as $style ) { $font_style = ! empty( $style['value'] ) ? $style['value'] : ''; $final_font_files = $this->get_fonts_file_url( $font_family, $font_weight, $font_style ); // Add each variant as one font face. $new_font_faces[] = array( 'fontFamily' => $font_family, 'fontStyle' => $font_style, 'fontWeight' => $font_weight, 'src' => $final_font_files, ); } } $this->add_or_update_theme_font_faces( $font_family, $font_slug, $new_font_faces ); } } /** * Get Font Slug. * * @return string slug. * @param string $name Font Family. * @since 2.5.1 */ public function get_font_slug( $name ) { $slug = sanitize_title( $name ); $slug = preg_replace( '/\s+/', '', $slug ); // Remove spaces. return $slug; } /** * Get Font URl. * * @param string $font_family Font Family. * @param string $font_weight Font Weight. * @param string $font_style Font Style. * @return array final font files. * @since 2.5.1 */ public function get_fonts_file_url( $font_family, $font_weight, $font_style ) { $font_family_key = sanitize_key( strtolower( str_replace( ' ', '-', $font_family ) ) ); $fonts_attr = str_replace( ' ', '+', $font_family ); $fonts_file_name = $font_family_key; if ( ! empty( $font_weight ) ) { $fonts_attr .= ':' . $font_weight; $fonts_file_name .= '-' . $font_weight; if ( ! empty( $font_style ) ) { $fonts_attr .= ',' . $font_weight . $font_style; $fonts_file_name .= '-' . $font_style; } } $fonts_link = 'https://fonts.googleapis.com/css?family=' . esc_attr( $fonts_attr ); // Get the remote URL contents. $this->remote_styles = $this->get_remote_url_contents( $fonts_link ); $font_files = $this->get_remote_files_from_css(); $fonts_folder_path = get_stylesheet_directory() . '/assets/fonts/spectra/'; // If the fonts folder don't exist, create it. if ( ! file_exists( $fonts_folder_path ) ) { wp_mkdir_p( $fonts_folder_path ); if ( ! file_exists( $fonts_folder_path ) ) { $this->get_filesystem()->mkdir( $fonts_folder_path, FS_CHMOD_DIR ); } } $final_font_files = array(); if ( ! is_array( $font_files ) && empty( $font_files ) && empty( $font_family_key ) ) { return; } foreach ( $font_files[ $font_family_key ] as $key => $font_file ) { // require file.php if the download_url function doesn't exist. if ( ! function_exists( 'download_url' ) ) { require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/file.php' ); } // Download file to temporary location. $tmp_path = download_url( $font_file ); // Make sure there were no errors. if ( is_wp_error( $tmp_path ) ) { return array(); } $fonts_file_name_final = $fonts_file_name . $key . '.' . $this->font_format; // Move font asset to theme assets folder. rename( $tmp_path, get_stylesheet_directory() . '/assets/fonts/spectra/' . $fonts_file_name_final ); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.file_ops_rename $final_font_files[] = 'file:./assets/fonts/spectra/' . $fonts_file_name_final; } return $final_font_files; } /** * Get the filesystem. * * @access protected * @since 2.5.1 * @return WP_Filesystem */ protected function get_filesystem() { global $wp_filesystem; // If the filesystem has not been instantiated yet, do it here. if ( ! $wp_filesystem ) { if ( ! function_exists( 'WP_Filesystem' ) ) { require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/file.php' ); } WP_Filesystem(); } return $wp_filesystem; } /** * Get remote file contents. * * @access public * @param string $url URL. * @since 2.5.1 * @return string Returns the remote URL contents. */ public function get_remote_url_contents( $url ) { /** * The user-agent we want to use. * * The default user-agent is the only one compatible with woff (not woff2) * which also supports unicode ranges. */ $user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8'; // Switch to a user-agent supporting woff2 if we don't need to support IE. if ( 'woff2' === $this->font_format ) { $user_agent = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0'; } // Get the response. $response = wp_remote_get( $url, array( 'user-agent' => $user_agent ) ); // Early exit if there was an error. if ( is_wp_error( $response ) ) { return ''; } // Get the CSS from our response. $contents = wp_remote_retrieve_body( $response ); // Early exit if there was an error. if ( is_wp_error( $contents ) ) { return ''; } return $contents; } /** * Get font files from the CSS. * * @access public * @since 2.5.1 * @return array Returns an array of font-families and the font-files used. */ public function get_remote_files_from_css() { // Return early if remote styles is not a string, or is empty. if ( ! is_string( $this->remote_styles ) || empty( $this->remote_styles ) ) { return array(); } $font_faces = explode( '@font-face', $this->remote_styles ); // Return early if font faces is not an array, or is empty. if ( ! is_array( $font_faces ) || empty( $font_faces ) ) { return array(); } $result = array(); // Loop all our font-face declarations. foreach ( $font_faces as $font_face ) { // Continue the loop if the current font face is not a string, or is empty. if ( ! is_string( $font_face ) || empty( $font_face ) ) { continue; } // Get the styles based on the font face. $style_array = explode( '}', $font_face ); // Continue the loop if the current font face is not a string, or is empty. if ( ! is_string( $style_array[0] ) || empty( $style_array[0] ) ) { continue; } // Make sure we only process styles inside this declaration. $style = $style_array[0]; // Sanity check. if ( false === strpos( $style, 'font-family' ) ) { continue; } // Get an array of our font-families. preg_match_all( '/font-family.*?\;/', $style, $matched_font_families ); // Get an array of our font-files. preg_match_all( '/url\(.*?\)/i', $style, $matched_font_files ); // Get the font-family name. $font_family = 'unknown'; if ( isset( $matched_font_families[0] ) && isset( $matched_font_families[0][0] ) ) { $font_family = rtrim( ltrim( $matched_font_families[0][0], 'font-family:' ), ';' ); $font_family = trim( str_replace( array( "'", ';' ), '', $font_family ) ); $font_family = sanitize_key( strtolower( str_replace( ' ', '-', $font_family ) ) ); } // Make sure the font-family is set in our array. if ( ! isset( $result[ $font_family ] ) ) { $result[ $font_family ] = array(); } // Get files for this font-family and add them to the array. foreach ( $matched_font_files as $match ) { // Sanity check. if ( ! isset( $match[0] ) ) { continue; } // Add the file URL. $result[ $font_family ][] = rtrim( ltrim( $match[0], 'url(' ), ')' ); } // Make sure we have unique items. // We're using array_flip here instead of array_unique for improved performance. $result[ $font_family ] = array_flip( array_flip( $result[ $font_family ] ) ); } return $result; } /** * Get font files from the CSS. * * @access public * @param string $font_name Font Name. * @param string $font_slug Font Slug. * @param array $font_faces Font Faces. * @return void * @since 2.5.1 */ public function add_or_update_theme_font_faces( $font_name, $font_slug, $font_faces ) { // Get the current theme.json and fontFamilies defined (if any). $theme_json_raw = json_decode( file_get_contents( get_stylesheet_directory() . '/theme.json' ), true ); $theme_font_families = isset( $theme_json_raw['settings']['typography']['fontFamilies'] ) ? $theme_json_raw['settings']['typography']['fontFamilies'] : null; $existent_family = $theme_font_families ? array_values( array_filter( $theme_font_families, function ( $font_family ) use ( $font_slug ) { return $font_family['slug'] === $font_slug; } ) ) : null; // Add the new font faces. if ( empty( $existent_family ) ) { // If the new font family doesn't exist in the theme.json font families, add it to the exising font families. $theme_font_families[] = array( 'fontFamily' => $font_name, 'slug' => $font_slug, 'fontFace' => $font_faces, 'isSpectra' => true, ); } else { // If the new font family already exists in the theme.json font families, add the new font faces to the existing font family. $theme_font_families = array_values( array_filter( $theme_font_families, function ( $font_family ) use ( $font_slug ) { return $font_family['slug'] !== $font_slug; } ) ); $existent_family[0]['fontFace'] = $font_faces; $theme_font_families = array_merge( $theme_font_families, $existent_family ); } // Overwrite the previous fontFamilies with the new ones. $theme_json_raw['settings']['typography']['fontFamilies'] = $theme_font_families; $theme_json = wp_json_encode( $theme_json_raw, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); $theme_json_string = preg_replace( '~(?:^|\G)\h{4}~m', "\t", $theme_json ); // Write the new theme.json to the theme folder. file_put_contents( // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions get_stylesheet_directory() . '/theme.json', $theme_json_string ); } /** * Save setting - Sanitizes form inputs. * * @param array $input_settings setting data. * @return array The sanitized form inputs. * * @since 2.5.1 */ public static function sanitize_form_inputs( $input_settings = array() ) { $new_settings = array(); if ( ! empty( $input_settings ) ) { foreach ( $input_settings as $key => $value ) { $new_key = sanitize_text_field( $key ); if ( is_array( $value ) ) { $new_settings[ $new_key ] = self::sanitize_form_inputs( $value ); } else { $new_settings[ $new_key ] = sanitize_text_field( $value ); } } } return $new_settings; } /** * Delete all Spectra font files from the theme JSON. * * @return void * @since 2.5.1 */ public static function delete_all_theme_font_family() { // Construct updated theme.json. $theme_json_raw = json_decode( file_get_contents( get_stylesheet_directory() . '/theme.json' ), true ); if ( empty( $theme_json_raw['settings']['typography']['fontFamilies'] ) ) { // Added condition to resolve an issue of PHP Notice: Undefined index: fontFamilies. return; } // Overwrite the previous fontFamilies with the new ones. $font_families = $theme_json_raw['settings']['typography']['fontFamilies']; if ( ! empty( $font_families ) && is_array( $font_families ) ) { $font_families = array_values( array_filter( $font_families, function( $value ) { if ( ! empty( $value['isSpectra'] ) ) { return false; } return true; } ) ); } $theme_json_raw['settings']['typography']['fontFamilies'] = $font_families; $theme_json = wp_json_encode( $theme_json_raw, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); $theme_json_string = preg_replace( '~(?:^|\G)\h{4}~m', "\t", $theme_json ); // Write the new theme.json to the theme folder. file_put_contents( // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions get_stylesheet_directory() . '/theme.json', $theme_json_string ); } /** * Delete font files from the CSS. * * @return void * @param array $font Font Data. * @since 2.5.1 */ public static function delete_theme_font_family( $font ) { // Construct updated theme.json. $theme_json_raw = json_decode( file_get_contents( get_stylesheet_directory() . '/theme.json' ), true ); // Overwrite the previous fontFamilies with the new ones. $font_families = $theme_json_raw['settings']['typography']['fontFamilies']; if ( ! empty( $font_families ) && is_array( $font_families ) ) { foreach ( $font_families as $key => $value ) { if ( $font['fontFamily'] === $value['fontFamily'] && ! empty( $value['fontFace'] ) && is_array( $value['fontFace'] ) ) { unset( $font_families[ $key ] ); break; } } } $theme_json_raw['settings']['typography']['fontFamilies'] = $font_families; $theme_json = wp_json_encode( $theme_json_raw, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); $theme_json_string = preg_replace( '~(?:^|\G)\h{4}~m', "\t", $theme_json ); // Write the new theme.json to the theme folder. file_put_contents( // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions get_stylesheet_directory() . '/theme.json', $theme_json_string ); $spectra_global_fse_fonts = \UAGB_Admin_Helper::get_admin_settings_option( 'spectra_global_fse_fonts', array() ); if ( ! is_array( $spectra_global_fse_fonts ) ) { $response_data = array( 'messsage' => __( 'There was some error in deleting the font.', 'ultimate-addons-for-gutenberg' ), ); wp_send_json_error( $response_data ); } $spectra_global_fse_fonts = array_values( array_filter( $spectra_global_fse_fonts, function( $value ) use ( $font ) { if ( $font['fontFamily'] === $value['value'] ) { return false; } return true; } ) ); foreach ( $spectra_global_fse_fonts as $key => $value ) { if ( $font['fontFamily'] === $value['value'] ) { array_splice( $spectra_global_fse_fonts, $key, $key ); } } $spectra_global_fse_fonts = self::sanitize_form_inputs( $spectra_global_fse_fonts ); UAGB_Admin_Helper::update_admin_settings_option( 'spectra_global_fse_fonts', $spectra_global_fse_fonts ); $response_data = array( 'messsage' => __( 'Successfully deleted font.', 'ultimate-addons-for-gutenberg' ), ); wp_send_json_success( $response_data ); } } } UAGB_FSE_Fonts_Compatibility::get_instance();