文件操作 - AssetManager.php
返回文件管理
返回主菜单
删除本文件
文件: /storage/v12552/creatormedianetwork/public_html/wp-content/plugins/embedpress/Core/AssetManager.php
编辑文件内容
<?php namespace EmbedPress\Core; // Include LocalizationManager // require_once __DIR__ . '/LocalizationManager.php'; use Embedpress\Core\LocalizationManager; use EmbedPress\Includes\Classes\Helper; /** * EmbedPress Asset Manager * * Centralized asset management for JS/CSS files across blocks, Elementor, admin, and frontend * Handles new build files from Vite build system */ class AssetManager { /** * Track which handles should be treated as ES modules */ private static $module_handles = []; /** * Track if the global module filter has been added */ private static $module_filter_added = false; /** * Cache for content detection to avoid multiple checks */ private static $has_embedpress_content = null; /** * Cache for custom player detection */ private static $custom_player_enabled = null; /** * Cache for detected embed types on current page */ private static $detected_embed_types = null; /** * Asset definitions with context-based loading */ private static $assets = [ // 🔧 Scripts (Ordered by Priority) // ---------------------------------- // Vendor assets (copied to assets folder for consistency) // Priority 1-5: Core vendor libraries 'plyr-css' => [ 'file' => 'css/plyr.css', 'deps' => [], 'contexts' => ['frontend', 'elementor', 'editor'], 'type' => 'style', 'handle' => 'embedpress-plyr-css', 'priority' => 1, 'condition' => 'custom_player', // Only load if custom player is enabled 'providers' => ['youtube', 'vimeo', 'video', 'audio'], // Only for these providers ], 'carousel-vendor-css' => [ 'file' => 'css/carousel.min.css', 'deps' => [], 'contexts' => ['frontend', 'elementor'], 'type' => 'style', 'handle' => 'embedpress-carousel-vendor-css', 'priority' => 1, 'condition' => 'has_content', // Load whenever EmbedPress content is present since front.js depends on it ], 'glider-css' => [ 'file' => 'css/glider.min.css', 'deps' => [], 'contexts' => ['frontend', 'elementor'], 'type' => 'style', 'handle' => 'embedpress-glider-css', 'priority' => 1, 'providers' => ['youtube-channel', 'youtube-live', 'instagram', 'opensea'], // Only for carousel-based embeds ], 'plyr-js' => [ 'file' => 'js/vendor/plyr.js', 'deps' => ['jquery'], 'contexts' => ['frontend', 'elementor', 'editor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-plyr', 'priority' => 2, 'condition' => 'custom_player', // Only load if custom player is enabled 'providers' => ['youtube', 'vimeo', 'video', 'audio'], // Only for these providers ], 'carousel-vendor-js' => [ 'file' => 'js/vendor/carousel.min.js', 'deps' => ['jquery'], 'contexts' => ['frontend', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-carousel-vendor', 'priority' => 2, 'condition' => 'has_content', // Load whenever EmbedPress content is present since front.js depends on it ], 'glider-js' => [ 'file' => 'js/vendor/glider.min.js', 'deps' => ['jquery'], 'contexts' => ['frontend', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-glider', 'priority' => 2, 'providers' => ['youtube-channel', 'youtube-live', 'instagram', 'opensea'], // Only for carousel-based embeds ], 'pdfobject-js' => [ 'file' => 'js/vendor/pdfobject.js', 'deps' => [], 'contexts' => ['frontend', 'elementor', 'editor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-pdfobject', 'priority' => 2, 'providers' => ['pdf', 'document'], // Only for PDF/document embeds ], 'vimeo-player-js' => [ 'file' => 'js/vendor/vimeo-player.js', 'deps' => [], 'contexts' => ['frontend', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-vimeo-player', 'priority' => 2, 'providers' => ['vimeo'], // Only for Vimeo embeds ], 'ytiframeapi-js' => [ 'file' => 'js/vendor/ytiframeapi.js', 'deps' => [], 'contexts' => ['frontend', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-ytiframeapi', 'priority' => 2, 'providers' => ['youtube', 'youtube-channel', 'youtube-live', 'youtube-shorts'], // Only for YouTube embeds ], // Priority 5-6: Main application build assets 'admin-js' => [ 'file' => 'js/admin.build.js', 'deps' => [], 'contexts' => ['admin'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-admin', 'priority' => 5, 'page' => 'embedpress' ], 'onboarding-js' => [ 'file' => 'js/onboarding.build.js', 'deps' => ['wp-i18n'], 'contexts' => ['admin'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-onboarding', 'priority' => 5, 'page' => 'embedpress-onboarding' ], 'custom-player-js' => [ 'file' => 'js/custom-player.build.js', 'deps' => ['wp-i18n'], 'contexts' => ['admin'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-custom-player', 'priority' => 5, 'page' => 'embedpress-player-engagement' ], 'google-reviews-js' => [ 'file' => 'js/google-reviews.build.js', 'deps' => [], 'contexts' => ['admin'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-google-reviews-admin', 'priority' => 5, 'page' => 'embedpress-google-reviews' ], 'google-reviews-css' => [ 'file' => 'css/google-reviews.build.css', 'deps' => [], 'contexts' => ['admin'], 'type' => 'style', 'handle' => 'embedpress-google-reviews-admin-css', 'priority' => 5, 'page' => 'embedpress-google-reviews' ], // GR FRONTEND assets (the block/shortcode render CSS + read-more JS). // Registered at priority 1 (register_all_assets) so the handle // `embedpress-google-reviews` ALWAYS exists early — Pro's // `embedpress-google-reviews-pro` style declares it as a dependency on // `wp_enqueue_scripts`, which fires before the block renders. Previously // this was registered lazily inside GoogleReviewsRenderer at render time, // so Pro's dependency was "not registered" on the frontend → WP 6.9.1 // "dependencies that are not registered" notice. `has_content` keeps the // actual ENQUEUE gated to pages that have a GR block/shortcode. 'google-reviews-frontend-css' => [ 'file' => 'css/google-reviews.css', 'deps' => [], 'contexts' => ['frontend', 'editor', 'elementor'], 'type' => 'style', 'handle' => 'embedpress-google-reviews', 'priority' => 1, 'condition' => 'has_content', ], 'google-reviews-frontend-js' => [ 'file' => 'js/google-reviews.js', 'deps' => [], 'contexts' => ['frontend', 'editor', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-google-reviews', 'priority' => 1, 'condition' => 'has_content', ], // Priority 7-10: Blocks 'blocks-js' => [ 'file' => 'js/blocks.build.js', // wp-hooks is required: blocks call wp.hooks.applyFilters() to expose // Pro extension slots (e.g. Google Reviews Pro controls). Without it, // load order isn't guaranteed and Pro's addFilter() can register after // the block first renders, leaving the free upsell placeholder showing. 'deps' => ['wp-blocks', 'wp-i18n', 'wp-element', 'wp-api-fetch', 'wp-is-shallow-equal', 'wp-editor', 'wp-components', 'wp-hooks'], 'contexts' => ['editor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-blocks-editor', 'priority' => 10, ], 'blocks-editor-style' => [ 'file' => 'css/blocks.build.css', 'deps' => [], 'contexts' => ['editor'], 'type' => 'style', 'handle' => 'embedpress-blocks-editor-style', 'priority' => 10, ], 'blocks-style' => [ 'file' => 'css/blocks.build.css', 'deps' => [], 'contexts' => ['frontend', 'editor'], 'type' => 'style', 'handle' => 'embedpress-blocks-style', 'priority' => 10, ], 'lazy-load-css' => [ 'file' => 'css/lazy-load.css', 'deps' => [], 'contexts' => ['frontend', 'elementor'], 'type' => 'style', 'handle' => 'embedpress-lazy-load-css', 'priority' => 10, 'condition' => 'lazy_load', ], // Priority 15-20: Legacy JS files 'admin-legacy-js' => [ 'file' => 'js/admin.js', 'deps' => ['jquery'], 'contexts' => ['admin'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-admin-legacy', 'priority' => 15, 'page' => 'embedpress' ], 'ads-js' => [ 'file' => 'js/sponsored.js', 'deps' => ['jquery', 'embedpress-front'], 'contexts' => ['editor', 'frontend', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-ads', 'priority' => 16, 'condition' => 'has_content', // Load for any EmbedPress content (ads can be on any embed) ], 'lazy-load-js' => [ 'file' => 'js/lazy-load.js', 'deps' => [], 'contexts' => ['frontend', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-lazy-load', 'priority' => 16, 'condition' => 'lazy_load', ], 'analytics-tracker-js' => [ 'file' => 'js/analytics-tracker.js', 'deps' => ['jquery'], 'contexts' => ['frontend', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-analytics-tracker', 'priority' => 15, 'condition' => 'analytics_enabled', // Only when the analytics tracking toggle is on AND EmbedPress content exists ], 'carousel-js' => [ 'file' => 'js/carousel.js', 'deps' => ['jquery', 'embedpress-carousel-vendor'], 'contexts' => ['frontend', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-carousel', 'priority' => 15, 'providers' => ['youtube-channel', 'youtube-live', 'instagram', 'opensea'], // Only for carousel-based embeds ], 'documents-viewer-js' => [ 'file' => 'js/documents-viewer-script.js', 'deps' => ['jquery'], 'contexts' => ['frontend', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-documents-viewer', 'priority' => 15, 'providers' => ['document', 'google-docs', 'google-sheets', 'google-slides'], // Only for document embeds ], 'front-js' => [ 'file' => 'js/front.js', 'deps' => ['jquery', 'embedpress-carousel-vendor'], 'contexts' => ['frontend', 'editor', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-front', 'priority' => 15, 'condition' => 'has_content', // Core script - load for any EmbedPress content ], 'yt-queue-js' => [ 'file' => 'js/ep-yt-queue.js', 'deps' => [], 'contexts' => ['frontend', 'editor', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-yt-queue', 'priority' => 15, 'condition' => 'has_content', // Lightweight; loads with any EmbedPress content ], 'gallery-justify-js' => [ 'file' => 'js/gallery-justify.js', 'deps' => ['jquery'], 'contexts' => ['editor', 'frontend', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-gallery-justify', 'priority' => 15, 'providers' => ['google-photos'], ], 'pdf-gallery-js' => [ 'file' => 'js/pdf-gallery.js', 'deps' => ['jquery'], 'contexts' => ['frontend', 'elementor', 'elementor-editor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-pdf-gallery', 'priority' => 15, 'providers' => ['pdf-gallery'], ], 'pdf-lightbox-js' => [ 'file' => 'js/ep-pdf-lightbox.js', 'deps' => [], 'contexts' => ['frontend', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-pdf-lightbox', 'priority' => 15, 'providers' => ['pdf'], ], 'meetup-timezone-js' => [ 'file' => 'js/meetup-timezone.js', 'deps' => [], 'contexts' => ['frontend', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-meetup-timezone', 'priority' => 15, 'providers' => ['meetup'], // Only for Meetup embeds ], 'gutenberg-script-js' => [ 'file' => 'js/gutneberg-script.js', 'deps' => ['wp-blocks', 'wp-element'], 'contexts' => ['editor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-gutenberg-script', 'priority' => 15, ], 'init-plyr-js' => [ 'file' => 'js/initplyr.js', 'deps' => ['jquery', 'embedpress-plyr'], 'contexts' => ['editor', 'frontend', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-init-plyr', 'priority' => 15, 'condition' => 'custom_player', // Only load if custom player is enabled 'providers' => ['youtube', 'vimeo', 'video', 'audio'], // Only for these providers ], 'instafeed-js' => [ 'file' => 'js/instafeed.js', 'deps' => ['jquery'], 'contexts' => ['frontend', 'elementor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-instafeed', 'priority' => 15, 'providers' => ['instagram'], // Only for Instagram embeds ], 'license-js' => [ 'file' => 'js/license.js', 'deps' => ['jquery', 'wp-url'], 'contexts' => ['admin'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-license', 'priority' => 15, 'page' => 'embedpress' ], 'feature-notices-js' => [ 'file' => 'js/feature-notices.js', 'deps' => ['jquery'], 'contexts' => ['admin'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-feature-notices', 'priority' => 15, // 'page' => 'embedpress' ], 'preview-js' => [ 'file' => 'js/preview.js', 'deps' => ['jquery'], 'contexts' => ['classic_editor'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-preview', 'priority' => 15, ], 'settings-js' => [ 'file' => 'js/settings.js', 'deps' => ['jquery', 'wp-color-picker'], 'contexts' => ['admin'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-settings', 'priority' => 15, 'page' => 'embedpress' ], 'instagram-shortcode-generator-js' => [ 'file' => 'js/instagram-shortcode-generator.js', 'deps' => [], 'contexts' => ['admin'], 'type' => 'script', 'footer' => true, 'handle' => 'embedpress-instagram-shortcode-generator', 'priority' => 15, 'page' => 'embedpress' ], // 🎨 Styles (Ordered by Priority) // ---------------------------------- // Build CSS files (analytics.build.css is handled by Analytics.php) // Legacy CSS files 'admin-notices-css' => [ 'file' => 'css/admin-notices.css', 'deps' => [], 'contexts' => ['admin'], 'type' => 'style', 'handle' => 'embedpress-admin-notices', 'priority' => 5, // 'page' => 'embedpress' ], 'feature-notices-css' => [ 'file' => 'css/feature-notices.css', 'deps' => [], 'contexts' => ['admin'], 'type' => 'style', 'handle' => 'embedpress-feature-notices', 'priority' => 5, ], 'el-icon-css' => [ 'file' => 'css/el-icon.css', 'deps' => [], 'contexts' => ['elementor-editor'], 'type' => 'style', 'handle' => 'embedpress-el-icon', 'priority' => 5, ], 'embedpress-elementor-css' => [ 'file' => 'css/embedpress-elementor.css', 'deps' => [], 'contexts' => ['elementor'], 'type' => 'style', 'handle' => 'embedpress-elementor-css', 'priority' => 5, ], 'embedpress-css' => [ 'file' => 'css/embedpress.css', 'deps' => [], 'contexts' => ['editor', 'frontend', 'elementor'], 'type' => 'style', 'handle' => 'embedpress-css', 'priority' => 5, ], 'pdf-gallery-css' => [ 'file' => 'css/pdf-gallery.css', 'deps' => ['embedpress-css'], 'contexts' => ['frontend', 'elementor', 'editor', 'elementor-editor'], 'type' => 'style', 'handle' => 'embedpress-pdf-gallery-css', 'priority' => 6, 'providers' => ['pdf-gallery'], ], 'pdf-lightbox-css' => [ 'file' => 'css/ep-pdf-lightbox.css', 'deps' => ['embedpress-css'], 'contexts' => ['frontend', 'elementor'], 'type' => 'style', 'handle' => 'embedpress-pdf-lightbox-css', 'priority' => 6, 'providers' => ['pdf'], ], 'modal-css' => [ 'file' => 'css/modal.css', 'deps' => [], 'contexts' => ['editor', 'classic_editor'], 'type' => 'style', 'handle' => 'embedpress-classic-editor-modal', 'priority' => 6, ], 'meetup-events-css' => [ 'file' => 'css/meetup-events.css', 'deps' => ['embedpress-css'], 'contexts' => ['frontend', 'editor', 'elementor'], 'type' => 'style', 'handle' => 'embedpress-meetup-events', 'providers' => ['meetup'], // Only for Meetup embeds 'priority' => 6, ], 'settings-icons-css' => [ 'file' => 'css/settings-icons.css', 'deps' => [], 'contexts' => ['admin'], 'type' => 'style', 'handle' => 'embedpress-settings-icons', 'priority' => 5, 'page' => 'embedpress' ], 'settings-css' => [ 'file' => 'css/settings.css', 'deps' => [], 'contexts' => ['admin'], 'type' => 'style', 'handle' => 'embedpress-settings-css', 'priority' => 5, 'page' => 'embedpress' ], 'instagram-shortcode-generator-css' => [ 'file' => 'css/instagram-shortcode-generator.css', 'deps' => [], 'contexts' => ['admin'], 'type' => 'style', 'handle' => 'embedpress-instagram-shortcode-generator', 'priority' => 6, 'page' => 'embedpress' ], 'admin-css' => [ 'file' => 'css/admin.css', 'deps' => [], 'contexts' => ['admin'], 'type' => 'style', 'handle' => 'embedpress-admin-css', 'priority' => 5, 'page' => 'embedpress' ], 'admin-build-css' => [ 'file' => 'css/admin.build.css', 'deps' => [], 'contexts' => ['admin'], 'type' => 'style', 'handle' => 'embedpress-admin-build-css', 'priority' => 6, 'page' => 'embedpress' ], 'onboarding-build-css' => [ 'file' => 'css/onboarding.build.css', 'deps' => [], 'contexts' => ['admin'], 'type' => 'style', 'handle' => 'embedpress-onboarding-build-css', 'priority' => 6, 'page' => 'embedpress-onboarding' ], 'custom-player-build-css' => [ 'file' => 'css/custom-player.build.css', 'deps' => [], 'contexts' => ['admin'], 'type' => 'style', 'handle' => 'embedpress-custom-player-css', 'priority' => 6, 'page' => 'embedpress-player-engagement' ], ]; /** * Initialize asset manager */ public static function init() { // Register all assets early so they're available as dependencies for Elementor and other plugins add_action('wp_enqueue_scripts', [__CLASS__, 'register_all_assets'], 1); add_action('admin_enqueue_scripts', [__CLASS__, 'register_all_assets'], 1); // Use proper priorities to ensure correct load order add_action('wp_enqueue_scripts', [__CLASS__, 'enqueue_frontend_assets'], 5); add_action('admin_enqueue_scripts', [__CLASS__, 'enqueue_admin_assets'], 5); add_action('admin_enqueue_scripts', [__CLASS__, 'enqueue_classic_editor_assets'], 5); add_action('enqueue_block_assets', [__CLASS__, 'enqueue_block_assets'], 5); add_action('enqueue_block_editor_assets', [__CLASS__, 'enqueue_editor_assets'], 5); // Elementor preview (frontend iframe) - enqueue after scripts are enqueued add_action('elementor/frontend/after_enqueue_scripts', [__CLASS__, 'enqueue_elementor_assets'], 5); // In Elementor editor, WP_Scripts registry is reset; re-register our assets before enqueuing add_action('elementor/editor/before_enqueue_scripts', [__CLASS__, 'register_all_assets'], 1); // Elementor editor panel (admin) - enqueue after editor scripts are enqueued add_action('elementor/editor/after_enqueue_scripts', [__CLASS__, 'enqueue_elementor_editor_assets'], 5); } /** * Register all assets early so they're available as dependencies * This is crucial for Elementor widgets that declare script/style dependencies */ public static function register_all_assets() { foreach (self::$assets as $key => $asset) { $file_url = EMBEDPRESS_PLUGIN_DIR_URL . 'assets/' . $asset['file']; $file_path = EMBEDPRESS_PLUGIN_DIR_PATH . '/assets/' . $asset['file']; if (!file_exists($file_path)) { continue; } $version = filemtime($file_path); // Register (not enqueue) all assets if ($asset['type'] === 'script') { wp_register_script( $asset['handle'], $file_url, $asset['deps'], $version, !empty($asset['footer']) ); // Wire up JS translations via the `embedpress` textdomain so // `__('Foo','embedpress')` calls inside React build files // resolve against wp-content/languages/plugins/embedpress-{locale}-{handle}.json. // Applies to every script we register, since the textdomain is shared. if (function_exists('wp_set_script_translations')) { wp_set_script_translations( $asset['handle'], 'embedpress', defined('EMBEDPRESS_PATH_BASE') ? EMBEDPRESS_PATH_BASE . 'languages' : false ); } // Add module attribute for ES modules (only build files) if (strpos($asset['file'], '.build.js') !== false) { // Track this handle as a module self::$module_handles[] = $asset['handle']; // Add the global filter only once if (!self::$module_filter_added) { self::$module_filter_added = true; add_filter('script_loader_tag', [__CLASS__, 'add_module_attribute'], 10, 2); } } } elseif ($asset['type'] === 'style') { wp_register_style( $asset['handle'], $file_url, $asset['deps'], $version, $asset['media'] ?? 'all' ); } } } /** * Enqueue frontend assets */ public static function enqueue_frontend_assets() { self::enqueue_assets_for_context('frontend'); // Setup frontend localization LocalizationManager::setup_frontend_localization(); } /** * Enqueue admin assets */ public static function enqueue_admin_assets($hook = '') { self::enqueue_assets_for_context('admin', $hook); // Load settings assets only on EmbedPress settings pages (not onboarding) $current_page = isset($_GET['page']) ? $_GET['page'] : ''; if (strpos($hook, 'embedpress') !== false && $current_page !== 'embedpress-onboarding' && $current_page !== 'embedpress-player-engagement') { self::enqueue_assets_for_context('settings', $hook); // Ensure wp-color-picker is loaded for settings page wp_enqueue_style('wp-color-picker'); // Ensure media scripts are loaded if (!did_action('wp_enqueue_media')) { wp_enqueue_media(); } } // Setup admin localization LocalizationManager::setup_admin_localization($hook); } /** * Enqueue block assets (both editor and frontend) */ public static function enqueue_block_assets() { // This runs on both frontend and editor for blocks // For frontend, we don't need the editor scripts if (is_admin()) { self::enqueue_assets_for_context('editor'); } } /** * Enqueue editor-only assets */ public static function enqueue_editor_assets() { // Ensure editor assets are loaded self::enqueue_assets_for_context('editor'); // Setup editor localization LocalizationManager::setup_editor_localization(); } public static function enqueue_classic_editor_assets() { // Ensure editor assets are loaded self::enqueue_assets_for_context('classic_editor'); // Setup editor localization LocalizationManager::setup_editor_localization(); } /** * Enqueue Elementor frontend assets */ public static function enqueue_elementor_assets() { self::enqueue_assets_for_context('elementor'); // Setup Elementor localization LocalizationManager::setup_elementor_localization(); } /** * Enqueue Elementor editor assets */ public static function enqueue_elementor_editor_assets() { // In Elementor editor, load only elementor and elementor-editor contexts // Do NOT load 'editor' context - that's for Gutenberg only self::enqueue_assets_for_context('elementor'); self::enqueue_assets_for_context('elementor-editor'); // Setup Elementor editor localization LocalizationManager::setup_elementor_localization(); } /** * Enqueue assets for a specific context */ private static function enqueue_assets_for_context($context, $hook = '') { $assets_to_enqueue = []; // Collect assets for this context foreach (self::$assets as $key => $asset) { if (in_array($context, $asset['contexts'])) { // Check if asset has page restriction if (isset($asset['page']) && !empty($asset['page'])) { // Only enqueue if we're on the specified page if (strpos($hook, $asset['page']) !== false) { $assets_to_enqueue[] = array_merge($asset, ['key' => $key]); } // If page doesn't match, don't enqueue this asset } else { // No page restriction, enqueue normally $assets_to_enqueue[] = array_merge($asset, ['key' => $key]); } } } // Sort by priority usort($assets_to_enqueue, function ($a, $b) { return $a['priority'] - $b['priority']; }); // Enqueue assets foreach ($assets_to_enqueue as $asset) { self::enqueue_single_asset($asset); } } /** * Enqueue a single asset (assumes asset is already registered) */ private static function enqueue_single_asset($asset) { $file_path = EMBEDPRESS_PLUGIN_DIR_PATH . '/assets/' . $asset['file']; if (! file_exists($file_path)) { return; } // Check if we should load this asset based on current context if (!self::should_load_asset($asset)) { return; } // Enqueue the already-registered asset if ($asset['type'] === 'script') { wp_enqueue_script($asset['handle']); } elseif ($asset['type'] === 'style') { wp_enqueue_style($asset['handle']); } } /** * Determine if an asset should be loaded based on current context */ private static function should_load_asset($asset) { // Check conditional loading requirements first if (isset($asset['condition'])) { if (!self::check_asset_condition($asset['condition'])) { return false; } // When a condition like 'custom_player' already passed, skip the // provider check — the condition itself proves these scripts are // needed. Provider detection is fragile (missing URL attrs, // widget-name typos, etc.) and should not block explicitly-enabled // features. if ($asset['condition'] === 'custom_player') { // Provider check not needed; fall through to context check } elseif (isset($asset['providers']) && !empty($asset['providers'])) { if (!self::check_provider_match($asset['providers'])) { return false; } } } elseif (isset($asset['providers']) && !empty($asset['providers'])) { // No condition set — still check providers if (!self::check_provider_match($asset['providers'])) { return false; } } // Get current environment state $is_admin = is_admin(); $is_elementor_editor = false; $is_elementor_preview = false; $is_gutenberg_editor = false; // Check Elementor states if (class_exists('\Elementor\Plugin')) { $elementor = \Elementor\Plugin::$instance; if (isset($elementor->editor)) { $is_elementor_editor = $elementor->editor->is_edit_mode(); } if (isset($elementor->preview)) { $is_elementor_preview = $elementor->preview->is_preview_mode(); } } // Check if we're in Gutenberg editor if ($is_admin) { global $pagenow; $is_gutenberg_editor = ( $pagenow === 'post.php' || $pagenow === 'post-new.php' || $pagenow === 'site-editor.php' ) && function_exists('use_block_editor_for_post_type'); // Check if we're in classic editor (not Gutenberg) $is_classic_editor = false; if ($pagenow === 'post.php' || $pagenow === 'post-new.php') { // Check if classic editor is being used if ( isset($_GET['classic-editor']) || (function_exists('use_block_editor_for_post_type') && isset($_GET['post']) && !use_block_editor_for_post_type(get_post_type($_GET['post']))) ) { $is_classic_editor = true; } // Also check if Classic Editor plugin is active and set to classic mode if ( class_exists('Classic_Editor') && get_option('classic-editor-replace') === 'classic' ) { $is_classic_editor = true; } } } // Asset loading logic based on contexts foreach ($asset['contexts'] as $context) { switch ($context) { case 'frontend': // Load on frontend (not in any editor or admin) if (!$is_admin && !$is_elementor_editor && !$is_elementor_preview) { return true; } break; case 'admin': // Load in WordPress admin (but not in Elementor editor) if ($is_admin && !$is_elementor_editor && !$is_elementor_preview) { // Check if asset has page restriction if (isset($asset['page'])) { return self::is_embedpress_admin_page($asset['page']); } return true; } break; case 'editor': // Load ONLY in Gutenberg editor (not in Elementor editor or other admin pages) if ($is_gutenberg_editor && !$is_elementor_editor) { return true; } break; case 'classic_editor': // Load only in classic editor (TinyMCE) if ($is_classic_editor) { return true; } break; case 'elementor': // Load in Elementor editor, preview, or frontend when Elementor is rendering if ($is_elementor_editor || $is_elementor_preview) { return true; } // Also load on frontend if Elementor content is present if (!$is_admin && self::has_elementor_content()) { return true; } break; case 'elementor-editor': // Load only in Elementor editor (not preview or frontend) if ($is_elementor_editor) { return true; } break; case 'settings': // Load only on EmbedPress settings pages if ($is_admin && !$is_elementor_editor && !$is_elementor_preview) { return true; } break; } } // Check if this is an individual block script and if it should be loaded if (strpos($asset['handle'], 'embedpress-block-') === 0) { return self::should_load_individual_block($asset['handle']); } return false; } /** * Check if we're on an EmbedPress admin page */ private static function is_embedpress_admin_page($page_type) { global $pagenow; // Get current page $current_page = isset($_GET['page']) ? $_GET['page'] : ''; switch ($page_type) { case 'embedpress': // Check if we're on any EmbedPress admin page (except onboarding which has its own assets) return ( $current_page === 'embedpress' || (strpos($current_page, 'embedpress') !== false && $current_page !== 'embedpress-onboarding') ); case 'embedpress-analytics': return $current_page === 'embedpress-analytics'; case 'embedpress-onboarding': return $current_page === 'embedpress-onboarding'; case 'embedpress-player-engagement': return $current_page === 'embedpress-player-engagement'; case 'embedpress-google-reviews': return $current_page === 'embedpress-google-reviews'; default: return false; } } /** * Check if individual block should be loaded based on active blocks */ private static function should_load_individual_block($handle) { // Get active blocks from settings $elements = (array) get_option(EMBEDPRESS_PLG_NAME . ":elements", []); $active_blocks = isset($elements['gutenberg']) ? (array) $elements['gutenberg'] : []; // Map handles to block names $block_map = [ 'embedpress-block-embedpress' => 'embedpress', 'embedpress-block-document' => 'document', 'embedpress-block-pdf' => 'embedpress-pdf', 'embedpress-block-calendar' => 'embedpress-calendar', 'embedpress-block-google-docs' => 'google-docs', 'embedpress-block-google-drawings' => 'google-drawings', 'embedpress-block-google-forms' => 'google-forms', 'embedpress-block-google-maps' => 'google-maps', 'embedpress-block-google-sheets' => 'google-sheets', 'embedpress-block-google-slides' => 'google-slides', 'embedpress-block-twitch' => 'twitch', 'embedpress-block-wistia' => 'wistia', 'embedpress-block-youtube' => 'youtube' ]; $block_name = isset($block_map[$handle]) ? $block_map[$handle] : ''; // If no block name found or no active blocks set, load all blocks (default behavior) if (empty($block_name) || empty($active_blocks)) { return true; } // Check if this specific block is active return in_array($block_name, $active_blocks); } /** * Check if current page has Elementor content */ private static function has_elementor_content() { if (! class_exists('\Elementor\Plugin')) { return false; } if (is_singular()) { $post_id = get_the_ID(); if (empty($post_id) || ! is_numeric($post_id)) { return false; } $document = \Elementor\Plugin::$instance->documents->get($post_id); if ($document && method_exists($document, 'is_built_with_elementor')) { return (bool) $document->is_built_with_elementor(); } } return false; } /** * Get asset URL */ public static function get_asset_url($file) { return EMBEDPRESS_PLUGIN_DIR_URL . 'assets/' . $file; } /** * Add module attribute to script tags for ES modules */ public static function add_module_attribute($tag, $handle) { if (in_array($handle, self::$module_handles)) { // Only add type="module" if it doesn't already exist if (strpos($tag, 'type="module"') === false) { return str_replace('<script ', '<script type="module" ', $tag); } } return $tag; } /** * Check if asset exists */ public static function asset_exists($file) { $plugin_path = dirname(dirname(dirname(__DIR__))); return file_exists($plugin_path . '/assets/' . $file); } /** * Check if an asset condition is met * * @param string $condition The condition to check * @return bool */ private static function check_asset_condition($condition) { switch ($condition) { case 'custom_player': return self::is_custom_player_enabled(); case 'has_content': // In Elementor editor, always load core scripts with has_content condition // because we can't detect unsaved content if (class_exists('\Elementor\Plugin')) { $elementor = \Elementor\Plugin::$instance; if (isset($elementor->editor) && $elementor->editor->is_edit_mode()) { return true; } } return self::has_embedpress_content(); case 'lazy_load': // In Elementor editor, always load lazy load scripts // because we can't detect unsaved content if (class_exists('\Elementor\Plugin')) { $elementor = \Elementor\Plugin::$instance; if (isset($elementor->editor) && $elementor->editor->is_edit_mode()) { return true; } } return self::has_lazy_load_enabled(); case 'analytics_enabled': // Gate on both the tracking toggle and the presence of EmbedPress content, // so disabling analytics short-circuits the script (and the JS cookie writer) // entirely instead of relying on a runtime flag. if (!get_option('embedpress_analytics_tracking_enabled', true)) { return false; } return self::has_embedpress_content(); case 'always': default: return true; } } /** * Check if custom player is enabled on the current page * * @return bool */ private static function is_custom_player_enabled() { // Cache the result to avoid multiple checks if (self::$custom_player_enabled !== null) { return self::$custom_player_enabled; } // In the Gutenberg block editor and Elementor editor, always load // custom-player scripts so live preview keeps working as the user // toggles options — the saved post content doesn't yet reflect // unsaved inspector / widget changes, so the per-post detection // below would return false and Plyr would never get enqueued. if (is_admin() && function_exists('get_current_screen')) { $screen = get_current_screen(); if ($screen && method_exists($screen, 'is_block_editor') && $screen->is_block_editor()) { self::$custom_player_enabled = true; return true; } } if (class_exists('\Elementor\Plugin')) { $elementor = \Elementor\Plugin::$instance; if (isset($elementor->editor) && $elementor->editor->is_edit_mode()) { self::$custom_player_enabled = true; return true; } } global $post; if (!$post) { self::$custom_player_enabled = false; return false; } $content = $post->post_content; // Check for custom player in Gutenberg blocks if (function_exists('has_blocks') && has_blocks($content)) { $blocks = parse_blocks($content); if (self::has_custom_player_in_blocks($blocks)) { self::$custom_player_enabled = true; return true; } } // Check for custom player in Elementor if (class_exists('\Elementor\Plugin')) { $document = \Elementor\Plugin::$instance->documents->get($post->ID); if ($document && method_exists($document, 'is_built_with_elementor') && $document->is_built_with_elementor()) { // Check Elementor meta for custom player settings $elementor_data = get_post_meta($post->ID, '_elementor_data', true); if ($elementor_data && is_string($elementor_data) && (strpos($elementor_data, 'emberpress_custom_player') !== false || strpos($elementor_data, '"customPlayer":true') !== false)) { self::$custom_player_enabled = true; return true; } } } // Check for custom player in shortcodes (look for customPlayer attribute) if (has_shortcode($content, 'embedpress')) { if (is_string($content) && (strpos($content, 'customPlayer') !== false || strpos($content, 'custom_player') !== false)) { self::$custom_player_enabled = true; return true; } } self::$custom_player_enabled = false; return false; } /** * Check if blocks contain custom player settings * * @param array $blocks * @return bool */ private static function has_custom_player_in_blocks($blocks) { foreach ($blocks as $block) { // Check if this is an EmbedPress block with custom player enabled $block_name = $block['blockName'] ?? ''; if ($block_name && strpos($block_name, 'embedpress/') === 0) { if (isset($block['attrs']['customPlayer']) && $block['attrs']['customPlayer']) { return true; } } // Recursively check inner blocks if (!empty($block['innerBlocks'])) { if (self::has_custom_player_in_blocks($block['innerBlocks'])) { return true; } } } return false; } /** * Check if lazy loading is enabled in any embed on the page * * @return bool */ private static function has_lazy_load_enabled() { // Check global lazy load setting first - if enabled globally, // load lazy-load assets whenever EmbedPress content is present $g_settings = get_option(EMBEDPRESS_PLG_NAME, []); if (isset($g_settings['g_lazyload']) && $g_settings['g_lazyload'] == 1) { return self::has_embedpress_content(); } global $post; if (!$post) { return false; } $content = $post->post_content; // Check if post content contains lazy load attributes in blocks if (function_exists('has_blocks') && has_blocks($content)) { $blocks = parse_blocks($content); if (self::has_lazy_load_in_blocks($blocks)) { return true; } } // Check for Elementor meta (if Elementor is active) if (class_exists('\Elementor\Plugin')) { $document = \Elementor\Plugin::$instance->documents->get($post->ID); if ($document && method_exists($document, 'is_built_with_elementor') && $document->is_built_with_elementor()) { $elementor_data = get_post_meta($post->ID, '_elementor_data', true); if ($elementor_data && is_string($elementor_data) && strpos($elementor_data, '"enable_lazy_load":"yes"') !== false) { return true; } } } return false; } /** * Check if blocks contain lazy load settings * * @param array $blocks * @return bool */ private static function has_lazy_load_in_blocks($blocks) { foreach ($blocks as $block) { // Check if this is an EmbedPress block with lazy load enabled $block_name = $block['blockName'] ?? ''; if ($block_name && strpos($block_name, 'embedpress/') === 0) { if (isset($block['attrs']['enableLazyLoad']) && $block['attrs']['enableLazyLoad']) { return true; } } // Recursively check inner blocks if (!empty($block['innerBlocks'])) { if (self::has_lazy_load_in_blocks($block['innerBlocks'])) { return true; } } } return false; } /** * Check if current page has EmbedPress content * * @return bool */ private static function has_embedpress_content() { // Cache the result to avoid multiple checks if (self::$has_embedpress_content !== null) { return self::$has_embedpress_content; } global $post; if (!$post) { self::$has_embedpress_content = false; return false; } $content = $post->post_content; // Check for EmbedPress shortcodes if (has_shortcode($content, 'embedpress') || has_shortcode($content, 'embedpress_pdf_gallery')) { self::$has_embedpress_content = true; return true; } // Check for EmbedPress Gutenberg blocks $embedpress_blocks = [ 'embedpress/embedpress', 'embedpress/google-docs-block', 'embedpress/google-sheets-block', 'embedpress/google-slides-block', 'embedpress/google-forms-block', 'embedpress/google-drawings-block', 'embedpress/google-maps-block', 'embedpress/youtube-block', 'embedpress/vimeo-block', 'embedpress/wistia-block', 'embedpress/twitch-block', 'embedpress/embedpress-pdf', 'embedpress/pdf-gallery', 'embedpress/document', 'embedpress/embedpress-calendar', 'embedpress/google-reviews' ]; foreach ($embedpress_blocks as $block_name) { if (has_block($block_name, $post)) { self::$has_embedpress_content = true; return true; } } // Check for Elementor EmbedPress widgets if (class_exists('\Elementor\Plugin')) { $document = \Elementor\Plugin::$instance->documents->get($post->ID); if ($document && method_exists($document, 'is_built_with_elementor') && $document->is_built_with_elementor()) { $elementor_data = get_post_meta($post->ID, '_elementor_data', true); if ($elementor_data && is_string($elementor_data) && (strpos($elementor_data, 'embedpress') !== false || strpos($elementor_data, 'Embedpress') !== false)) { self::$has_embedpress_content = true; return true; } } } self::$has_embedpress_content = false; return false; } /** * Check if any of the required providers match the detected embed types * * @param array $required_providers List of providers this asset needs * @return bool */ private static function check_provider_match($required_providers) { // In Elementor editor or preview, always load provider scripts to allow live preview // because we can't detect unsaved widgets from _elementor_data if (class_exists('\Elementor\Plugin')) { $elementor = \Elementor\Plugin::$instance; if (isset($elementor->editor) && $elementor->editor->is_edit_mode()) { return true; } if (isset($elementor->preview) && $elementor->preview->is_preview_mode()) { return true; } } // In Gutenberg editor, always load provider assets to allow live preview // because we can't detect unsaved blocks from post_content if (function_exists('get_current_screen')) { $screen = get_current_screen(); if ($screen && $screen->is_block_editor()) { return true; } } $detected_types = self::detect_embed_types(); // If no embeds detected, don't load if (empty($detected_types)) { return false; } // Check if any required provider matches detected types foreach ($required_providers as $provider) { if (in_array($provider, $detected_types)) { return true; } } return false; } /** * Detect all embed types on the current page * * @return array List of detected embed types */ private static function detect_embed_types() { // Cache the result to avoid multiple checks if (self::$detected_embed_types !== null) { return self::$detected_embed_types; } self::$detected_embed_types = []; global $post; if (!$post) { return self::$detected_embed_types; } $content = $post->post_content; // Detect from Gutenberg blocks if (function_exists('has_blocks') && has_blocks($content)) { $blocks = parse_blocks($content); self::$detected_embed_types = array_merge( self::$detected_embed_types, self::detect_types_from_blocks($blocks) ); } // Detect from shortcodes self::$detected_embed_types = array_merge( self::$detected_embed_types, self::detect_types_from_shortcodes($content) ); // Detect from Elementor if (class_exists('\Elementor\Plugin')) { $document = \Elementor\Plugin::$instance->documents->get($post->ID); if ($document && method_exists($document, 'is_built_with_elementor') && $document->is_built_with_elementor()) { self::$detected_embed_types = array_merge( self::$detected_embed_types, self::detect_types_from_elementor($post->ID) ); } } // Remove duplicates self::$detected_embed_types = array_unique(self::$detected_embed_types); return self::$detected_embed_types; } /** * Detect embed types from Gutenberg blocks * * @param array $blocks * @return array */ private static function detect_types_from_blocks($blocks) { $types = []; foreach ($blocks as $block) { // Map block names to embed types $block_name = $block['blockName'] ?? ''; if ($block_name && strpos($block_name, 'embedpress/') === 0) { // Extract type from block name if ($block_name === 'embedpress/embedpress') { // Generic block - detect from URL $url = $block['attrs']['url'] ?? ''; $types = array_merge($types, self::detect_type_from_url($url)); } elseif ($block_name === 'embedpress/embedpress-pdf') { $types[] = 'pdf'; } elseif ($block_name === 'embedpress/pdf-gallery') { $types[] = 'pdf-gallery'; $types[] = 'pdf'; } elseif ($block_name === 'embedpress/document') { $types[] = 'document'; } elseif ($block_name === 'embedpress/youtube-block') { $types[] = 'youtube'; } elseif ($block_name === 'embedpress/vimeo-block') { $types[] = 'vimeo'; } elseif ($block_name === 'embedpress/google-docs-block') { $types[] = 'google-docs'; } elseif ($block_name === 'embedpress/google-sheets-block') { $types[] = 'google-sheets'; } elseif ($block_name === 'embedpress/google-slides-block') { $types[] = 'google-slides'; } elseif ($block_name === 'embedpress/wistia-block') { $types[] = 'wistia'; } elseif ($block_name === 'embedpress/twitch-block') { $types[] = 'twitch'; } } // Recursively check inner blocks if (!empty($block['innerBlocks'])) { $types = array_merge($types, self::detect_types_from_blocks($block['innerBlocks'])); } } return $types; } /** * Detect embed types from shortcodes * * @param string $content * @return array */ private static function detect_types_from_shortcodes($content) { $types = []; if (!is_string($content)) { return $types; } // Find all embedpress shortcodes with URL attribute (with or without quotes) // Matches: [embedpress url="..."], [embedpress url='...'], [embedpress url=...] if (preg_match_all('/\[embedpress[^\]]*url=["\']?([^"\'\s\]]+)["\']?[^\]]*\]/i', $content, $matches)) { foreach ($matches[1] as $url) { $types = array_merge($types, self::detect_type_from_url($url)); } } // Detect PDF gallery shortcode if (has_shortcode($content, 'embedpress_pdf_gallery')) { $types[] = 'pdf-gallery'; $types[] = 'pdf'; } // Find embedpress shortcodes with URL between tags // Matches: [embedpress]URL[/embedpress] if (preg_match_all('/\[embedpress[^\]]*\]([^\[]+)\[\/embedpress\]/i', $content, $matches)) { foreach ($matches[1] as $url) { $url = trim($url); if (!empty($url)) { $types = array_merge($types, self::detect_type_from_url($url)); } } } return $types; } /** * Detect embed types from Elementor * * @param int $post_id * @return array */ private static function detect_types_from_elementor($post_id) { $types = []; $elementor_data = get_post_meta($post_id, '_elementor_data', true); if (!$elementor_data || !is_string($elementor_data)) { return $types; } // Decode JSON data $data = json_decode($elementor_data, true); if (!$data || !is_array($data)) { return $types; } // Recursively search for EmbedPress widgets $types = self::detect_types_from_elementor_data($data); return $types; } /** * Recursively detect types from Elementor data * * @param array $data * @return array */ private static function detect_types_from_elementor_data($data) { $types = []; if (!is_array($data)) { return $types; } foreach ($data as $element) { if (!is_array($element)) { continue; } // Check if this is an EmbedPress widget // Note: widget name is 'embedpres_elementor' (legacy typo without double 's') $widget_type = $element['widgetType'] ?? ''; if ($widget_type && (strpos($widget_type, 'embedpres') !== false || strpos($widget_type, 'Embedpress') !== false)) { // Get the embed source $settings = $element['settings'] ?? []; $source = $settings['embedpress_pro_embeded_source'] ?? ''; $url = $settings['embedpress_embeded_link'] ?? ''; if ($source) { $types[] = $source; } elseif ($url) { $types = array_merge($types, self::detect_type_from_url($url)); } // Detect PDF widget specifically (uses different setting names) if ($widget_type === 'embedpress_pdf') { $pdf_url = $settings['embedpress_pdf_Uploader']['url'] ?? ''; $pdf_link = $settings['embedpress_pdf_file_link']['url'] ?? ''; if ($pdf_url || $pdf_link) { $types[] = 'pdf'; } } } // Recursively check elements if (isset($element['elements'])) { $types = array_merge($types, self::detect_types_from_elementor_data($element['elements'])); } } return $types; } /** * Detect embed type from URL using Embera's provider detection * * @param string $url * @return array */ private static function detect_type_from_url($url) { $types = []; if (empty($url) || !is_string($url)) { return $types; } // Use Helper class which leverages Embera's built-in provider detection if (class_exists('\EmbedPress\Includes\Classes\Helper')) { $provider_name = Helper::get_provider_name($url); if (!empty($provider_name)) { // Normalize provider name to lowercase for consistency $provider_name = strtolower($provider_name); // Map provider names to asset provider keys $provider_map = [ 'youtube' => 'youtube', 'youtubechannel' => 'youtube-channel', 'vimeo' => 'vimeo', 'instagram' => 'instagram', 'instagramfeed' => 'instagram', 'opensea' => 'opensea', 'wistia' => 'wistia', 'twitch' => 'twitch', 'meetup' => 'meetup', 'googledocs' => 'google-docs', 'googlesheets' => 'google-sheets', 'googleslides' => 'google-slides', 'googlephotos' => 'google-photos', ]; // Check if provider name matches our map if (isset($provider_map[$provider_name])) { $types[] = $provider_map[$provider_name]; return $types; } // Check for document types from Helper's response if (strpos($provider_name, 'document_') === 0) { $types[] = 'document'; return $types; } } } // Fallback to manual detection for special cases not handled by Embera $url_lower = strtolower($url); // YouTube special cases (channel, live, shorts) if (strpos($url_lower, 'youtube.com') !== false || strpos($url_lower, 'youtu.be') !== false) { if (preg_match('#/(channel|c|user)/[\w-]+/live$|/@[\w-]+/live$#i', $url_lower)) { $types[] = 'youtube-live'; } elseif (strpos($url_lower, '/channel/') !== false || strpos($url_lower, '/c/') !== false || strpos($url_lower, '/@') !== false) { $types[] = 'youtube-channel'; } elseif (strpos($url_lower, '/live') !== false) { $types[] = 'youtube-live'; } elseif (strpos($url_lower, '/shorts/') !== false) { $types[] = 'youtube-shorts'; } else { $types[] = 'youtube'; } } // Google Photos (shared album links) elseif (strpos($url_lower, 'photos.app.goo.gl') !== false || strpos($url_lower, 'photos.google.com') !== false) { $types[] = 'google-photos'; } // PDF detection elseif (preg_match('/\.pdf$/i', $url)) { $types[] = 'pdf'; } // Document detection elseif (preg_match('/\.(doc|docx|ppt|pptx|xls|xlsx)$/i', $url)) { $types[] = 'document'; } // Self-hosted video elseif (preg_match('/\.(mp4|mov|avi|wmv|flv|mkv|webm|mpeg|mpg)$/i', $url)) { $types[] = 'video'; } // Self-hosted audio elseif (preg_match('/\.(mp3|wav|ogg|aac)$/i', $url)) { $types[] = 'audio'; } return $types; } }
修改文件时间
将文件时间修改为当前时间的前一年
删除文件