register_control_type( 'GeneratePress_Action_Button_Control' ); } $wp_customize->add_setting( 'generate_settings[css_print_method]', array( 'default' => $defaults['css_print_method'], 'type' => 'option', 'sanitize_callback' => 'generate_premium_sanitize_choices', ) ); $wp_customize->add_control( 'generate_settings[css_print_method]', array( 'type' => 'select', 'label' => __( 'Dynamic CSS Print Method', 'gp-premium' ), 'description' => __( 'Generating your dynamic CSS in an external file offers significant performance advantages.', 'gp-premium' ), 'section' => 'generate_general_section', 'choices' => array( 'inline' => __( 'Inline Embedding', 'gp-premium' ), 'file' => __( 'External File', 'gp-premium' ), ), 'settings' => 'generate_settings[css_print_method]', ) ); $wp_customize->add_control( new GeneratePress_Action_Button_Control( $wp_customize, 'generate_regenerate_external_css_file', array( 'section' => 'generate_general_section', 'data_type' => 'regenerate_external_css', 'nonce' => esc_html( wp_create_nonce( 'generatepress_regenerate_css_file' ) ), 'label' => __( 'Regenerate CSS File', 'gp-premium' ), 'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname', 'active_callback' => 'generate_is_using_external_css_file_callback', ) ) ); } /** * Set our CSS Print Method. * * @param string $method The existing method. */ public function set_print_method( $method ) { if ( ! function_exists( 'generate_get_option' ) ) { return $method; } return generate_get_option( 'css_print_method' ); } /** * Determine if we're using file mode or inline mode. */ public function mode() { $mode = generate_get_css_print_method(); if ( 'file' === $mode && $this->needs_update() ) { $data = get_option( 'generatepress_dynamic_css_data', array() ); if ( ! isset( $data['updated_time'] ) ) { // No time set, so set the current time minus 5 seconds so the file is still generated. $data['updated_time'] = time() - 5; update_option( 'generatepress_dynamic_css_data', $data ); } // Only allow processing 1 file every 5 seconds. $current_time = (int) time(); $last_time = (int) $data['updated_time']; if ( 5 <= ( $current_time - $last_time ) ) { // Attempt to write to the file. $mode = ( $this->can_write() && $this->make_css() ) ? 'file' : 'inline'; // Does again if the file exists. if ( 'file' === $mode ) { $mode = ( file_exists( $this->file( 'path' ) ) ) ? 'file' : 'inline'; } } } return $mode; } /** * Set things up. */ public function init() { if ( 'file' === $this->mode() ) { add_filter( 'generate_using_dynamic_css_external_file', '__return_true' ); add_filter( 'generate_dynamic_css_skip_cache', '__return_true', 20 ); // Remove inline CSS in GP < 3.0.0. if ( ! function_exists( 'generate_get_dynamic_css' ) && function_exists( 'generate_enqueue_dynamic_css' ) ) { remove_action( 'wp_enqueue_scripts', 'generate_enqueue_dynamic_css', 50 ); } } } /** * Enqueue the dynamic CSS. */ public function enqueue_dynamic_css() { if ( 'file' === $this->mode() ) { wp_enqueue_style( 'generatepress-dynamic', esc_url( $this->file( 'uri' ) ), array(), null ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion // Re-add no-cache CSS in GP < 3.0.0. if ( ! function_exists( 'generate_get_dynamic_css' ) && function_exists( 'generate_no_cache_dynamic_css' ) ) { $nocache_css = generate_no_cache_dynamic_css(); if ( function_exists( 'generate_do_icon_css' ) ) { $nocache_css .= generate_do_icon_css(); } wp_add_inline_style( 'generate-style', wp_strip_all_tags( $nocache_css ) ); } } } /** * Make our CSS. */ public function make_css() { $content = ''; if ( function_exists( 'generate_get_dynamic_css' ) ) { $content = generate_get_dynamic_css(); } elseif ( function_exists( 'generate_base_css' ) && function_exists( 'generate_font_css' ) && function_exists( 'generate_advanced_css' ) && function_exists( 'generate_spacing_css' ) ) { $content = generate_base_css() . generate_font_css() . generate_advanced_css() . generate_spacing_css(); } $content = apply_filters( 'generate_external_dynamic_css_output', $content ); if ( ! $content ) { return false; } global $wp_filesystem; // Initialize the WordPress filesystem. if ( empty( $wp_filesystem ) ) { require_once ABSPATH . '/wp-admin/includes/file.php'; WP_Filesystem(); } // Take care of domain mapping. if ( defined( 'DOMAIN_MAPPING' ) && DOMAIN_MAPPING ) { if ( function_exists( 'domain_mapping_siteurl' ) && function_exists( 'get_original_url' ) ) { $mapped_domain = domain_mapping_siteurl( false ); $mapped_domain = str_replace( 'https://', '//', $domain_mapping ); $mapped_domain = str_replace( 'http://', '//', $mapped_domain ); $original_domain = get_original_url( 'siteurl' ); $original_domain = str_replace( 'https://', '//', $original_domain ); $original_domain = str_replace( 'http://', '//', $original_domain ); $content = str_replace( $original_domain, $mapped_domain, $content ); } } // Strip protocols. $content = str_replace( 'https://', '//', $content ); $content = str_replace( 'http://', '//', $content ); if ( is_writable( $this->file( 'path' ) ) || ( ! file_exists( $this->file( 'path' ) ) && is_writable( dirname( $this->file( 'path' ) ) ) ) ) { if ( ! $wp_filesystem->put_contents( $this->file( 'path' ), wp_strip_all_tags( $content ), FS_CHMOD_FILE ) ) { // Fail! return false; } else { $this->update_saved_time(); // Success! return true; } } } /** * Determines if the CSS file is writable. */ public function can_write() { global $blog_id; // Get the upload directory for this site. $upload_dir = wp_upload_dir(); // If this is a multisite installation, append the blogid to the filename. $css_blog_id = ( is_multisite() && $blog_id > 1 ) ? '_blog-' . $blog_id : null; $file_name = '/style' . $css_blog_id . '.min.css'; $folder_path = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'generatepress'; // Does the folder exist? if ( file_exists( $folder_path ) ) { // Folder exists, but is the folder writable? if ( ! is_writable( $folder_path ) ) { // Folder is not writable. // Does the file exist? if ( ! file_exists( $folder_path . $file_name ) ) { // File does not exist, therefore it can't be created // since the parent folder is not writable. return false; } else { // File exists, but is it writable? if ( ! is_writable( $folder_path . $file_name ) ) { // Nope, it's not writable. return false; } } } else { // The folder is writable. // Does the file exist? if ( file_exists( $folder_path . $file_name ) ) { // File exists. // Is it writable? if ( ! is_writable( $folder_path . $file_name ) ) { // Nope, it's not writable. return false; } } } } else { // Can we create the folder? // returns true if yes and false if not. return wp_mkdir_p( $folder_path ); } // all is well! return true; } /** * Gets the css path or url to the stylesheet * * @param string $target path/url. */ public function file( $target = 'path' ) { global $blog_id; // Get the upload directory for this site. $upload_dir = wp_upload_dir(); // If this is a multisite installation, append the blogid to the filename. $css_blog_id = ( is_multisite() && $blog_id > 1 ) ? '_blog-' . $blog_id : null; $file_name = 'style' . $css_blog_id . '.min.css'; $folder_path = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'generatepress'; // The complete path to the file. $file_path = $folder_path . DIRECTORY_SEPARATOR . $file_name; // Get the URL directory of the stylesheet. $css_uri_folder = $upload_dir['baseurl']; $css_uri = trailingslashit( $css_uri_folder ) . 'generatepress/' . $file_name; // Take care of domain mapping. if ( defined( 'DOMAIN_MAPPING' ) && DOMAIN_MAPPING ) { if ( function_exists( 'domain_mapping_siteurl' ) && function_exists( 'get_original_url' ) ) { $mapped_domain = domain_mapping_siteurl( false ); $original_domain = get_original_url( 'siteurl' ); $css_uri = str_replace( $original_domain, $mapped_domain, $css_uri ); } } // Strip protocols. $css_uri = str_replace( 'https://', '//', $css_uri ); $css_uri = str_replace( 'http://', '//', $css_uri ); if ( 'path' === $target ) { return $file_path; } elseif ( 'url' === $target || 'uri' === $target ) { $timestamp = ( file_exists( $file_path ) ) ? '?ver=' . filemtime( $file_path ) : ''; return $css_uri . $timestamp; } } /** * Update the our updated file time. */ public function update_saved_time() { $data = get_option( 'generatepress_dynamic_css_data', array() ); $data['updated_time'] = time(); update_option( 'generatepress_dynamic_css_data', $data ); } /** * Delete the saved time. */ public function delete_saved_time() { $data = get_option( 'generatepress_dynamic_css_data', array() ); if ( isset( $data['updated_time'] ) ) { unset( $data['updated_time'] ); } update_option( 'generatepress_dynamic_css_data', $data ); } /** * Update our plugin/theme versions. */ public function update_versions() { $data = get_option( 'generatepress_dynamic_css_data', array() ); $data['theme_version'] = GENERATE_VERSION; $data['plugin_version'] = GP_PREMIUM_VERSION; update_option( 'generatepress_dynamic_css_data', $data ); } /** * Do we need to update the CSS file? */ public function needs_update() { $data = get_option( 'generatepress_dynamic_css_data', array() ); $update = false; // If there's no updated time, needs update. // The time is set in mode(). if ( ! isset( $data['updated_time'] ) ) { $update = true; } // If we haven't set our versions, do so now. if ( ! isset( $data['theme_version'] ) && ! isset( $data['plugin_version'] ) ) { $update = true; $this->update_versions(); // Bail early so we don't check undefined versions below. return $update; } // Version numbers have changed, needs update. if ( (string) GENERATE_VERSION !== (string) $data['theme_version'] || (string) GP_PREMIUM_VERSION !== (string) $data['plugin_version'] ) { $update = true; $this->update_versions(); } return $update; } /** * Regenerate the CSS file. */ public function regenerate_css_file() { check_ajax_referer( 'generatepress_regenerate_css_file', '_nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( __( 'Security check failed.', 'gp-premium' ) ); } $this->delete_saved_time(); wp_send_json_success(); } } GeneratePress_External_CSS_File::get_instance();