haxorqt
Home
Console
Upload
information
Create File
Create Folder
About
:
/
home
/
sc1jaqa5103
/
prod.puv-editions.fr
/
wp-content
/
plugins
/
megamenu
/
classes
/
Filename :
style-manager.class.php
back
Copy
<?php if ( ! defined( 'ABSPATH' ) ) { exit; // disable direct access } if ( ! class_exists( 'Mega_Menu_Style_Manager' ) ) : /** * Manages the plugin's CSS generation, caching, and enqueueing, including * SCSS compilation and filesystem storage. WPML is handled in {@see Mega_Menu_Integration_Wpml}. Polylang is handled in {@see Mega_Menu_Integration_Polylang}. * * @since 1.0 * @package MegaMenu */ final class Mega_Menu_Style_Manager { /** * Saved plugin settings from the database. * * @var array */ public $settings = []; /** * When true, {@see delete_cache_after_nav_menu_locations_save} will run on shutdown. * * @var bool */ private $pending_delete_cache_after_nav_menu_locations = false; /** * Constructor. Loads settings from the database. * * @since 1.0 */ public function __construct() { $settings = get_option( 'megamenu_settings', [] ); $this->settings = is_array( $settings ) ? $settings : []; } /** * Register all WordPress actions and filters used by the style manager. * * @since 1.0 * @return void */ public function setup_actions() { add_action( 'megamenu_enqueue_scripts', [ $this, 'enqueue_scripts' ] ); add_action( 'megamenu_enqueue_styles', [ $this, 'enqueue_styles' ] ); add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_styles' ] ); add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_scripts' ], 999 ); add_action( 'wp_head', [ $this, 'head_css' ], 9999 ); add_action( 'megamenu_delete_cache', [ $this, 'delete_cache' ] ); add_action( 'after_switch_theme', [ $this, 'delete_cache' ] ); add_filter( 'pre_set_theme_mod_nav_menu_locations', [ $this, 'schedule_delete_cache_on_nav_menu_locations_change' ], 10, 2 ); add_action( 'megamenu_head_css', [ $this, 'head_css' ], 999 ); add_filter( 'megamenu_scripts_in_footer', [ $this, 'scripts_in_footer' ] ); add_filter( "filesystem_method", [ $this, "use_direct_filesystem_method" ], 10, 4 ); } /** * Always use the 'direct' filesystem method when writing the style.css file. * * @since 3.0.1 * @param string $method Filesystem access method. * @param mixed $args Optional arguments passed to the filesystem method. * @param string $context Full path to the directory that is tested for being writable. * @param bool $allow_relaxed_file_ownership Whether to allow group file ownership. * @return string 'direct' within the plugin's upload directory, otherwise unchanged method. */ public function use_direct_filesystem_method( $method, $args, $context, $allow_relaxed_file_ownership ) { if ( $method != 'direct' && str_contains( $context, "/maxmegamenu" ) ) { return 'direct'; } return $method; } /** * Determines whether to load JavaScript in the footer based on the configured option. * * @since 2.9 * @return bool True to load scripts in the footer, false to load in the head. */ public function scripts_in_footer() { return ( $this->settings['js'] ?? '' ) !== 'head'; } /** * When menu-location assignments change, invalidate CSS if Max Mega Menu is enabled for an affected location. * Defer to `shutdown` so `nav_menu_locations` is saved before regeneration (see `set_theme_mod`). * * @param array|false $new_value New location => menu ID map. * @param array|false $old_value Previous map or false. * @return array Map passed through unchanged. */ public function schedule_delete_cache_on_nav_menu_locations_change( $new_value, $old_value ) { if ( ! is_array( $new_value ) ) { $new_value = []; } if ( ! is_array( $old_value ) ) { $old_value = []; } $keys = array_unique( array_merge( array_keys( $old_value ), array_keys( $new_value ) ) ); foreach ( $keys as $location ) { $old_id = isset( $old_value[ $location ] ) ? (int) $old_value[ $location ] : 0; $new_id = isset( $new_value[ $location ] ) ? (int) $new_value[ $location ] : 0; if ( $old_id === $new_id ) { continue; } $mega = Mega_Menu_Location::find( $location ); if ( $mega && $mega->is_enabled() ) { if ( ! $this->pending_delete_cache_after_nav_menu_locations ) { $this->pending_delete_cache_after_nav_menu_locations = true; add_action( 'shutdown', [ $this, 'delete_cache_after_nav_menu_locations_save' ], 999 ); } break; } } return $new_value; } /** * Run after theme mods are persisted so `get_nav_menu_locations()` matches the new assignments. * * @return void */ public function delete_cache_after_nav_menu_locations_save() { if ( ! $this->pending_delete_cache_after_nav_menu_locations ) { return; } $this->pending_delete_cache_after_nav_menu_locations = false; do_action( 'megamenu_delete_cache' ); } /** * Clear external plugin caches when CSS is updated or menu settings are changed. * * @since 2.0 * @return void */ public function clear_external_caches() { // Breeze: https://wordpress.org/plugins/breeze/ do_action( 'breeze_clear_all_cache' ); } /** * Return the version of MMM that was used to generate the current CSS file. * * @since 1.0 * @return string|false Plugin version string, or false if not set. */ public static function get_css_version() { if ( $version = get_option('megamenu_css_version') ) { return $version; } return get_transient('megamenu_css_version'); } /** * Return the timestamp when the menu CSS was last generated. * * @since 1.0 * @return int|false Unix timestamp, or false if not set. */ public static function get_css_last_updated() { if ( $date = get_option('megamenu_css_last_updated') ) { return $date; } return get_transient('megamenu_css_last_updated'); } /** * Return the default menu theme settings array. * Delegates to Mega_Menu_Theme::get_default() for backward compatibility. * * @since 1.0 * @return array Default theme settings. */ public function get_default_theme() { return Mega_Menu_Theme::get_default()->settings; } /** * Return a filtered list of all themes (default + saved custom), fully merged. * Delegates to Mega_Menu_Theme::get_all() for backward compatibility. * * @since 1.0 * @return array Map of theme ID to settings array. */ public function get_themes() { $theme_objects = Mega_Menu_Theme::get_all(); $themes = []; foreach ( $theme_objects as $id => $theme ) { $themes[ $id ] = $theme->settings; } return $themes; } /** * Whether the plugin is running in debug mode. * * @since 1.3.1 * @return bool True if MEGAMENU_DEBUG is defined and true. */ private function is_debug_mode() { return ( defined( 'MEGAMENU_DEBUG' ) && MEGAMENU_DEBUG === true ); } /** * Return the menu CSS. Uses the transient cache when available. * * @since 1.3.1 * @return string Compiled CSS string. */ public function get_css() { if ( ( $css = $this->get_cached_css() ) && ! $this->is_debug_mode() ) { return $css; } else { return $this->generate_css(); } } /** * Compile CSS for all active menu locations (same rules as {@see generate_css()}). * * @since 3.9.3 * @param bool $fail_on_location_error When true, return a {@see WP_Error} if any location fails to compile. * When false, skip failed locations (legacy {@see generate_css()} behaviour). * @return string|WP_Error Full CSS string including filters and `.wp-block {}` hack, or {@see WP_Error}. * * The {@see 'megamenu_include_location_in_compiled_css'} filter controls whether each location is compiled (default true). */ private function compile_active_menu_css( $fail_on_location_error = false ) { if ( function_exists( 'wp_raise_memory_limit' ) ) { wp_raise_memory_limit(); } $settings = get_option( 'megamenu_settings', [] ); $this->settings = is_array( $settings ) ? $settings : []; if ( empty( $this->settings ) ) { if ( $fail_on_location_error ) { return new WP_Error( 'megamenu_no_settings', __( 'CSS generation failed: no menu settings found.', 'megamenu' ) ); } return '/** CSS Generation Failed. No menu settings found **/'; } $date = date( 'l jS F Y H:i:s e' ); $time = time(); $css = '@charset "UTF-8";' . "\n\n"; $css .= "/** THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MAKE MANUAL EDITS! **/\n"; $css .= "/** Custom CSS should be added to Mega Menu > Menu Themes > Custom Styling **/\n\n"; $css .= ".mega-menu-last-modified-{$time} { content: '{$date}'; }\n\n"; foreach ( Mega_Menu_Location::get_all() as $location ) { if ( $location->is_active() && apply_filters( 'megamenu_include_location_in_compiled_css', true, $location->id ) ) { $compiled_css = $location->generate_css(); if ( is_wp_error( $compiled_css ) ) { if ( $fail_on_location_error ) { return $compiled_css; } continue; } $css .= $compiled_css; } } if ( strlen( $css ) ) { $css = apply_filters( 'megamenu_compiled_css', $css ); $css .= ".wp-block {}"; // hack required for loading CSS in site editor https://github.com/WordPress/gutenberg/issues/40603#issuecomment-1112807162 } return $css; } /** * Generate and cache the CSS for all active menus. * CSS is compiled by scssphp using the file located in /css/megamenu.scss. * * @since 1.0 * @return string Compiled CSS string, or an error comment if generation failed. */ public function generate_css() { $css = $this->compile_active_menu_css( false ); if ( is_wp_error( $css ) ) { return ''; } if ( $this->settings && strlen( $css ) ) { $this->set_cached_css( $css ); $this->save_to_filesystem( $css ); } return $css; } /** * Saves the generated CSS to the uploads folder. * * @since 1.6.1 * @param string $css The compiled CSS to write. * @return void */ private function save_to_filesystem( $css ) { global $wp_filesystem; if ( ! $wp_filesystem ) { require_once( ABSPATH . 'wp-admin/includes/file.php' ); } $upload_dir = wp_upload_dir(); $filename = $this->get_css_filename(); $dir = trailingslashit( $upload_dir['basedir'] ) . 'maxmegamenu/'; delete_option( 'megamenu_failed_to_write_css_to_filesystem' ); WP_Filesystem(false, $dir); if ( ! $wp_filesystem->is_dir( $dir ) ) { $wp_filesystem->mkdir( $dir ); } if ( ! $wp_filesystem->put_contents( $dir . $filename, $css ) ) { // File write failed. // Update CSS output option to 'head' to stop us from attempting to regenerate the CSS on every request. $method = $this->get_css_output_method(); if ( in_array( $method, [ 'disabled' ] ) ) { return; } $this->settings['css'] = 'head'; update_option( 'megamenu_settings', $this->settings ); update_option( 'megamenu_failed_to_write_css_to_filesystem', 'true' ); } } /** * Before a theme is saved, attempt to compile it to verify it produces valid CSS. * Delegates to Mega_Menu_Theme for backward compatibility. * * @since 1.3 * @param array $theme Theme settings array to test. * @return string|WP_Error Compiled CSS on success, or WP_Error on failure. */ public function test_theme_compilation( $theme ) { return Mega_Menu_Theme::from_settings( $theme )->test_compilation(); } /** * Compiles raw SCSS into CSS for a particular menu location. * Delegates to Mega_Menu_Location::generate_css() for backward compatibility. * * @since 1.3 * @param string $location The menu location slug. * @param array $theme Theme settings array. * @param int $menu_id Menu term ID. * @return string|WP_Error Compiled CSS on success, or WP_Error on failure. */ public function generate_css_for_location( $location, $theme, $menu_id ) { $location_obj = Mega_Menu_Location::find( $location ); if ( ! $location_obj ) { $location_obj = new Mega_Menu_Location( $location, $location ); } return $location_obj->generate_css( Mega_Menu_Theme::from_settings( $theme ) ); } /** * Enqueue public CSS files required by Mega Menu. * * @since 1.0 * @return void */ public function enqueue_styles() { if ( ! ( defined( 'MEGAMENU_PREVIEW' ) && MEGAMENU_PREVIEW ) && 'fs' === $this->get_css_output_method() ) { $this->enqueue_fs_style(); } do_action( 'megamenu_enqueue_public_scripts' ); } /** * Enqueue public JavaScript files required by Mega Menu. * * @since 1.0 * @return void */ public function enqueue_scripts() { $js_path = MEGAMENU_BASE_URL . 'js/maxmegamenu.js'; $dependencies = apply_filters( 'megamenu_javascript_dependencies', [ 'jquery', 'hoverIntent' ] ); $scripts_in_footer = apply_filters( 'megamenu_scripts_in_footer', true ); if ( defined( 'MEGAMENU_SCRIPTS_IN_FOOTER' ) ) { $scripts_in_footer = MEGAMENU_SCRIPTS_IN_FOOTER; } $handle = apply_filters( 'megamenu_javascript_handle', 'megamenu' ); wp_enqueue_script( $handle, $js_path, $dependencies, MEGAMENU_VERSION, $scripts_in_footer ); $params = apply_filters( 'megamenu_javascript_localisation', [] ); if ( count( $params) ) { wp_localize_script( $handle, 'megamenu', $params ); } } /** * Enqueue the stylesheet saved to the uploads filesystem. * * @since 1.6.1 * @return void */ public function enqueue_fs_style() { $upload_dir = wp_upload_dir(); $filename = $this->get_css_filename(); $filepath = trailingslashit( $upload_dir['basedir'] ) . 'maxmegamenu/' . $filename; if ( ! is_file( $filepath ) || $this->is_debug_mode() ) { // regenerate the CSS and save to filesystem. $this->generate_css(); } // file should now exist. if ( is_file( $filepath ) ) { $css_url = trailingslashit( $upload_dir['baseurl'] ) . 'maxmegamenu/' . $filename; $protocol = is_ssl() ? 'https://' : 'http://'; // ensure we're using the correct protocol. $css_url = str_replace( [ 'http://', 'https://' ], $protocol, $css_url ); wp_enqueue_style( 'megamenu', $css_url, false, substr( md5( (string) filemtime( $filepath ) ), 0, 6 ) ); } } /** * Store compiled CSS in the transient cache and update version/timestamp options. * * @since 1.6.1 * @param string $css The compiled CSS to cache. * @return void */ private function set_cached_css( $css ) { // set a far expiration date to prevent transient from being autoloaded. $hundred_years_in_seconds = 3153600000; set_transient( $this->get_transient_key(), $css, $hundred_years_in_seconds ); update_option( 'megamenu_css_version', MEGAMENU_VERSION ); update_option( 'megamenu_css_last_updated', time() ); } /** * Return the cached CSS if it exists. * * @since 1.9 * @return string|false Cached CSS string, or false if the transient has expired. */ private function get_cached_css() { return get_transient( $this->get_transient_key() ); } /** * Regenerate CSS, flush the filesystem directory, and repopulate the cache. * * @return bool True on success, false if CSS compilation produced a WP_Error. */ public function delete_cache() { global $wp_filesystem; $css = $this->compile_active_menu_css( true ); if ( is_wp_error( $css ) ) { do_action( 'megamenu_delete_cache_failed', $css ); return false; } if ( ! $wp_filesystem ) { require_once( ABSPATH . 'wp-admin/includes/file.php' ); } $upload_dir = wp_upload_dir(); $dir = trailingslashit( $upload_dir['basedir'] ) . 'maxmegamenu/'; WP_Filesystem(false, $dir); $wp_filesystem->rmdir( $dir, true ); delete_transient( $this->get_transient_key() ); if ( strlen( $css ) ) { $this->set_cached_css( $css ); $this->save_to_filesystem( $css ); } $this->clear_external_caches(); do_action( 'megamenu_after_delete_cache' ); return true; } /** * Return the key to use for the CSS transient * * @since 1.9 * @return string */ private function get_transient_key() { return apply_filters( 'megamenu_css_transient_key', 'megamenu_css' ); } /** * Return the filename to use for the stylesheet. * The filename is filtered to be unique on multisite setups. * * @since 1.6.1 * @return string CSS filename with .css extension. */ public function get_css_filename() { return apply_filters( 'megamenu_css_filename', 'style' ) . '.css'; } /** * Return the configured CSS output method. * * @since 1.0 * @return string 'fs' (filesystem), 'head', or 'disabled'. */ private function get_css_output_method() { return $this->settings['css'] ?? 'fs'; } /** * Output the Mega Menu CSS inline in the <head>. * * @since 1.3.1 * @return void */ public function head_css() { if ( defined( 'MEGAMENU_PREVIEW' ) && MEGAMENU_PREVIEW ) { $css = $this->get_css(); echo '<style class="megamenu-css">' . str_replace( [ ' ', "\n" ], '', $css ) . "</style>\n"; return; } $method = $this->get_css_output_method(); // Filesystem and disabled modes use linked styles or no CSS — do not emit a // placeholder <style class="megamenu-css"> (breaks block editor iframe rules in WP 6.9+). if ( in_array( $method, [ 'disabled', 'fs' ], true ) ) { return; } $css = $this->get_css(); echo '<style class="megamenu-css">' . str_replace( [ ' ', "\n" ], '', $css ) . "</style>\n"; } } endif;