一个专门为店面主题设计的功能强大的插件,可将您的网站页脚转换为引人入胜且内容丰富的部分。
###关键功能:
***类别显示** – 在页脚中显示您的博客类别,以方便导航
***页面小部件** – 在页脚中显示重要页面以快速访问
***产品标签** – 在标签云中展示您的WooCommerce产品标签
***最近的帖子** – 让访问者参与您最新的博客内容
***自定义菜单** – 将任何自定义菜单添加到您的页脚
***社交媒体链接** – 通过社交媒体图标与观众联系
***流行产品** – 突出显示您最畅销的WooCommerce产品
***自定义页脚文字** – 添加您自己的版权文本或其他信息
***移动友好** – 响应式设计在所有设备上看起来都很好
***性能优化** – 用缓存构建的快速加载时间
相关文章: WooCommerce 产品过滤器
<?php /** * Plugin Name: BDFG Footer Enhancer * Plugin URI: https://beiduofengou.net/2025/01/02/bdfg-footer-enhancer/ * Description: Enhances the Storefront theme footer with categories, pages, product tags, recent posts, custom menus, social media links, and popular products. * Version: 3.1.1 * Author: beiduofengou * Author URI: https://beiduofengou.net * Text Domain: bdfg-footer-enhancer * Domain Path: /languages * Requires at least: 5.6 * Requires PHP: 7.2 * WC requires at least: 4.0 * WC tested up to: 7.5 * * @package BDFG_Footer_Enhancer */ // Exit if accessed directly if (!defined('ABSPATH')) { exit; } /** * Main plugin class */ class BDFG_Footer_Enhancer { /** * Plugin version * * @var string */ public $version = '3.1.1'; /** * The single instance of the class * * @var BDFG_Footer_Enhancer */ protected static $_instance = null; /** * Main instance * * @return BDFG_Footer_Enhancer */ public static function instance() { if (is_null(self::$_instance)) { self::$_instance = new self(); } return self::$_instance; } /** * Constructor */ public function __construct() { $this->define_constants(); $this->includes(); $this->init_hooks(); // Load translations add_action('init', array($this, 'load_textdomain')); } /** * Define constants */ private function define_constants() { $this->define('BDFG_FOOTER_ENHANCER_VERSION', $this->version); $this->define('BDFG_FOOTER_ENHANCER_PATH', plugin_dir_path(__FILE__)); $this->define('BDFG_FOOTER_ENHANCER_URL', plugin_dir_url(__FILE__)); $this->define('BDFG_FOOTER_ENHANCER_BASENAME', plugin_basename(__FILE__)); } /** * Define constant if not already defined * * @param string $name * @param mixed $value */ private function define($name, $value) { if (!defined($name)) { define($name, $value); } } /** * Include required files */ private function includes() { // Core functions require_once BDFG_FOOTER_ENHANCER_PATH . 'includes/bdfg-core-functions.php'; // Admin if (is_admin()) { require_once BDFG_FOOTER_ENHANCER_PATH . 'includes/admin/class-bdfg-admin.php'; } // Frontend require_once BDFG_FOOTER_ENHANCER_PATH . 'includes/class-bdfg-frontend.php'; // Widgets require_once BDFG_FOOTER_ENHANCER_PATH . 'includes/widgets/class-bdfg-widgets.php'; } /** * Initialize hooks */ private function init_hooks() { register_activation_hook(__FILE__, array($this, 'activation')); register_deactivation_hook(__FILE__, array($this, 'deactivation')); add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts')); add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts')); // Add settings link to plugins page add_filter('plugin_action_links_' . BDFG_FOOTER_ENHANCER_BASENAME, array($this, 'add_plugin_action_links')); // Check if theme is Storefront add_action('after_setup_theme', array($this, 'check_theme')); } /** * Load text domain for translations */ public function load_textdomain() { load_plugin_textdomain('bdfg-footer-enhancer', false, dirname(plugin_basename(__FILE__)) . '/languages'); } /** * Plugin activation */ public function activation() { // Set default options $default_options = array( 'show_categories' => 'yes', 'show_pages' => 'yes', 'show_product_tags' => 'yes', 'show_recent_posts' => 'yes', 'recent_posts_count' => 5, 'show_custom_menu' => 'no', 'custom_menu_id' => 0, 'show_social_links' => 'yes', 'social_links' => array( 'facebook' => '', 'twitter' => '', 'instagram' => '', 'youtube' => '', 'pinterest' => '', 'linkedin' => '', ), 'show_popular_products' => 'yes', 'popular_products_count' => 4, 'custom_footer_text' => sprintf(__('© %s - BDFG Footer Enhancer by %s', 'bdfg-footer-enhancer'), date('Y'), '<a href="https://beiduofengou.net" target="_blank">beiduofengou</a>'), ); // Only set options if they don't already exist if (!get_option('bdfg_footer_enhancer_options')) { update_option('bdfg_footer_enhancer_options', $default_options); } // Add plugin version to database update_option('bdfg_footer_enhancer_version', $this->version); // Clear any existing caches bdfg_clear_all_caches(); // Clear permalinks flush_rewrite_rules(); } /** * Plugin deactivation */ public function deactivation() { // Clear any existing caches bdfg_clear_all_caches(); flush_rewrite_rules(); } /** * Enqueue frontend scripts and styles */ public function enqueue_scripts() { // Enqueue Font Awesome from CDN wp_enqueue_style('font-awesome', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css', array(), '5.15.4'); // Main CSS wp_enqueue_style('bdfg-footer-enhancer', BDFG_FOOTER_ENHANCER_URL . 'assets/css/frontend.css', array(), $this->version); // Main JS wp_enqueue_script('bdfg-footer-enhancer', BDFG_FOOTER_ENHANCER_URL . 'assets/js/frontend.js', array('jquery'), $this->version, true); wp_localize_script('bdfg-footer-enhancer', 'bdfg_footer_data', array( 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('bdfg_footer_enhancer_nonce'), 'is_mobile' => wp_is_mobile(), )); } /** * Enqueue admin scripts and styles */ public function admin_enqueue_scripts($hook) { if ('settings_page_bdfg-footer-enhancer' !== $hook) { return; } // Admin CSS wp_enqueue_style('bdfg-footer-enhancer-admin', BDFG_FOOTER_ENHANCER_URL . 'assets/css/admin.css', array(), $this->version); // Color picker wp_enqueue_style('wp-color-picker'); // Admin JS wp_enqueue_script('bdfg-footer-enhancer-admin', BDFG_FOOTER_ENHANCER_URL . 'assets/js/admin.js', array('jquery', 'wp-color-picker'), $this->version, true); } /** * Add plugin action links * * @param array $links * @return array */ public function add_plugin_action_links($links) { $plugin_links = array( '<a href="' . admin_url('options-general.php?page=bdfg-footer-enhancer') . '">' . __('Settings', 'bdfg-footer-enhancer') . '</a>', ); return array_merge($plugin_links, $links); } /** * Check if current theme is Storefront */ public function check_theme() { $current_theme = wp_get_theme(); $is_storefront = ('storefront' === $current_theme->get_template()); if (!$is_storefront) { add_action('admin_notices', array($this, 'theme_compatibility_notice')); } } /** * Display theme compatibility notice */ public function theme_compatibility_notice() { $current_screen = get_current_screen(); // Only show on plugins page and our settings page if (!in_array($current_screen->id, array('plugins', 'settings_page_bdfg-footer-enhancer'), true)) { return; } ?> <div class="notice notice-warning is-dismissible"> <p> <?php printf( __('%1$s is designed to work with the Storefront theme. Your current theme may not be fully compatible. For best results, please use Storefront or a compatible child theme.', 'bdfg-footer-enhancer'), '<strong>BDFG Footer Enhancer</strong>' ); ?> </p> </div> <?php } } /** * Returns the main instance of BDFG_Footer_Enhancer * * @return BDFG_Footer_Enhancer */ function BDFG_Footer_Enhancer() { return BDFG_Footer_Enhancer::instance(); } // Start the plugin $GLOBALS['bdfg_footer_enhancer'] = BDFG_Footer_Enhancer();
includes/bdfg-core-functions.php
<?php /** * Core Functions for BDFG Footer Enhancer * * @package BDFG_Footer_Enhancer */ // Exit if accessed directly if (!defined('ABSPATH')) { exit; } /** * Get plugin options * * @param string $key Option key * @param mixed $default Default value * @return mixed */ function bdfg_get_option($key = null, $default = null) { $options = get_option('bdfg_footer_enhancer_options', array()); if (is_null($key)) { return $options; } return isset($options[$key]) ? $options[$key] : $default; } /** * Clear all caches related to BDFG Footer Enhancer */ function bdfg_clear_all_caches() { $cache_keys = array( 'bdfg_footer_categories', 'bdfg_footer_pages', 'bdfg_footer_product_tags', 'bdfg_footer_recent_posts', 'bdfg_footer_popular_products', ); // Delete all standard caches foreach ($cache_keys as $key) { delete_transient($key); } // Clear menu cache if exists $menu_id = bdfg_get_option('custom_menu_id', 0); if ($menu_id > 0) { delete_transient('bdfg_footer_custom_menu_' . $menu_id); } // Clear object cache if using object caching if (wp_using_ext_object_cache()) { wp_cache_flush(); } } /** * Get most popular WooCommerce products * * @param int $count Number of products to fetch * @return array Array of WC_Product objects */ function bdfg_get_popular_products($count = 4) { // Bail if WooCommerce is not active if (!function_exists('wc_get_products')) { return array(); } // Try to get cached products $cached_products = get_transient('bdfg_popular_products_' . $count); if (false !== $cached_products) { return $cached_products; } // Get popular products $args = array( 'status' => 'publish', 'limit' => $count, 'orderby' => 'popularity', 'order' => 'DESC', 'return' => 'objects', ); $products = wc_get_products($args); // Cache products for 6 hours set_transient('bdfg_popular_products_' . $count, $products, 6 * HOUR_IN_SECONDS); return $products; } /** * Format widget title with BDFG branding * * @param string $title Widget title * @return string Formatted title */ function bdfg_format_widget_title($title) { return '<span class="bdfg-title-icon"><i class="fas fa-angle-right"></i></span> ' . $title; } /** * Get social network icon class * * @param string $network Social network name * @return string Icon class */ function bdfg_get_social_icon_class($network) { $icons = array( 'facebook' => 'fab fa-facebook-f', 'twitter' => 'fab fa-twitter', 'instagram' => 'fab fa-instagram', 'youtube' => 'fab fa-youtube', 'pinterest' => 'fab fa-pinterest-p', 'linkedin' => 'fab fa-linkedin-in', 'tiktok' => 'fab fa-tiktok', ); return isset($icons[$network]) ? $icons[$network] : 'fab fa-' . $network; } /** * Get the appropriate image size for footer widgets * * @return string Image size name */ function bdfg_get_footer_thumbnail_size() { return apply_filters('bdfg_footer_thumbnail_size', 'thumbnail'); } /** * Format price with BDFG styling * * @param string $price_html Price HTML from WooCommerce * @return string Formatted price HTML */ function bdfg_format_price($price_html) { return '<span class="bdfg-price">' . $price_html . '</span>'; } /** * Get formatted post date * * @param int $post_id Post ID * @return string Formatted date */ function bdfg_get_post_date($post_id) { $time_string = '<time class="entry-date published updated" datetime="%1$s">%2$s</time>'; $time_string = sprintf( $time_string, esc_attr(get_the_date('c', $post_id)), esc_html(get_the_date('', $post_id)) ); return sprintf( '<span class="bdfg-post-date">%s</span>', $time_string ); }
includes/admin/class-bdfg-admin.php
相关文章: WooCommerce 预定功能插件
<?php /** * Admin functionality for BDFG Footer Enhancer * * @package BDFG_Footer_Enhancer * @author beiduofengou */ if (!defined('ABSPATH')) { exit; } /** * Admin class */ class BDFG_Admin { /** * Constructor */ public function __construct() { add_action('admin_menu', array($this, 'add_admin_menu')); add_action('admin_init', array($this, 'register_settings')); // Add link to settings in plugins list add_filter('plugin_row_meta', array($this, 'plugin_row_meta'), 10, 2); // Add custom meta box to help promote other BDFG plugins add_action('add_meta_boxes', array($this, 'add_promo_meta_box')); } /** * Add admin menu */ public function add_admin_menu() { add_options_page( __('BDFG Footer Enhancer', 'bdfg-footer-enhancer'), __('BDFG Footer', 'bdfg-footer-enhancer'), 'manage_options', 'bdfg-footer-enhancer', array($this, 'admin_page') ); } /** * Register settings */ public function register_settings() { register_setting('bdfg_footer_enhancer_settings', 'bdfg_footer_enhancer_options', array($this, 'sanitize_settings')); // General settings section add_settings_section( 'bdfg_footer_general', __('General Settings', 'bdfg-footer-enhancer'), array($this, 'general_settings_callback'), 'bdfg-footer-enhancer' ); // Content settings section add_settings_section( 'bdfg_footer_content', __('Content Settings', 'bdfg-footer-enhancer'), array($this, 'content_settings_callback'), 'bdfg-footer-enhancer' ); // Social settings section add_settings_section( 'bdfg_footer_social', __('Social Media Settings', 'bdfg-footer-enhancer'), array($this, 'social_settings_callback'), 'bdfg-footer-enhancer' ); // Advanced settings section add_settings_section( 'bdfg_footer_advanced', __('Advanced Settings', 'bdfg-footer-enhancer'), array($this, 'advanced_settings_callback'), 'bdfg-footer-enhancer' ); } /** * General settings callback */ public function general_settings_callback() { echo '<p>' . __('Configure general settings for your enhanced footer.', 'bdfg-footer-enhancer') . '</p>'; } /** * Content settings callback */ public function content_settings_callback() { echo '<p>' . __('Configure which content elements to display in your footer.', 'bdfg-footer-enhancer') . '</p>'; } /** * Social settings callback */ public function social_settings_callback() { echo '<p>' . __('Configure social media links for your footer.', 'bdfg-footer-enhancer') . '</p>'; } /** * Advanced settings callback */ public function advanced_settings_callback() { echo '<p>' . __('Advanced settings for more control over your footer.', 'bdfg-footer-enhancer') . '</p>'; } /** * Sanitize settings * * @param array $input * @return array */ public function sanitize_settings($input) { $sanitized_input = array(); // Checkboxes $checkboxes = array( 'show_categories', 'show_pages', 'show_product_tags', 'show_recent_posts', 'show_custom_menu', 'show_social_links', 'show_popular_products', 'enable_cache', ); foreach ($checkboxes as $checkbox) { $sanitized_input[$checkbox] = isset($input[$checkbox]) ? 'yes' : 'no'; } // Numbers $sanitized_input['recent_posts_count'] = isset($input['recent_posts_count']) ? absint($input['recent_posts_count']) : 5; $sanitized_input['popular_products_count'] = isset($input['popular_products_count']) ? absint($input['popular_products_count']) : 4; $sanitized_input['custom_menu_id'] = isset($input['custom_menu_id']) ? absint($input['custom_menu_id']) : 0; $sanitized_input['cache_time'] = isset($input['cache_time']) ? absint($input['cache_time']) : 12; // Social links $social_networks = array('facebook', 'twitter', 'instagram', 'youtube', 'pinterest', 'linkedin', 'tiktok'); foreach ($social_networks as $network) { $sanitized_input['social_links'][$network] = isset($input['social_links'][$network]) ? esc_url_raw($input['social_links'][$network]) : ''; } // Custom footer text $sanitized_input['custom_footer_text'] = isset($input['custom_footer_text']) ? wp_kses_post($input['custom_footer_text']) : ''; // Clear cache when settings are saved bdfg_clear_all_caches(); return $sanitized_input; } /** * Admin page */ public function admin_page() { $options = bdfg_get_option(); ?> <div class="wrap bdfg-admin-wrap"> <h1 class="bdfg-admin-header"> <img src="<?php echo BDFG_FOOTER_ENHANCER_URL . 'assets/images/bdfg-logo.png'; ?>" alt="BDFG" class="bdfg-logo" /> <?php _e('Footer Enhancer Settings', 'bdfg-footer-enhancer'); ?> </h1> <div class="bdfg-admin-notices"> <?php settings_errors(); ?> </div> <div class="bdfg-admin-content"> <div class="bdfg-admin-main"> <form method="post" action="options.php"> <?php settings_fields('bdfg_footer_enhancer_settings'); ?> <div class="bdfg-settings-tabs"> <ul class="bdfg-tabs-nav"> <li class="active"><a href="#general-settings"><?php _e('General', 'bdfg-footer-enhancer'); ?></a></li> <li><a href="#content-settings"><?php _e('Content', 'bdfg-footer-enhancer'); ?></a></li> <li><a href="#social-settings"><?php _e('Social Media', 'bdfg-footer-enhancer'); ?></a></li> <li><a href="#advanced-settings"><?php _e('Advanced', 'bdfg-footer-enhancer'); ?></a></li> </ul> <div class="bdfg-tabs-content"> <div id="general-settings" class="bdfg-tab-content active"> <table class="form-table"> <tr> <th scope="row"><?php _e('Categories', 'bdfg-footer-enhancer'); ?></th> <td> <label> <input type="checkbox" name="bdfg_footer_enhancer_options[show_categories]" value="yes" <?php checked('yes', isset($options['show_categories']) ? $options['show_categories'] : 'yes'); ?> /> <?php _e('Show categories in footer', 'bdfg-footer-enhancer'); ?> </label> </td> </tr> <tr> <th scope="row"><?php _e('Pages', 'bdfg-footer-enhancer'); ?></th> <td> <label> <input type="checkbox" name="bdfg_footer_enhancer_options[show_pages]" value="yes" <?php checked('yes', isset($options['show_pages']) ? $options['show_pages'] : 'yes'); ?> /> <?php _e('Show pages in footer', 'bdfg-footer-enhancer'); ?> </label> </td> </tr> <tr> <th scope="row"><?php _e('Product Tags', 'bdfg-footer-enhancer'); ?></th> <td> <label> <input type="checkbox" name="bdfg_footer_enhancer_options[show_product_tags]" value="yes" <?php checked('yes', isset($options['show_product_tags']) ? $options['show_product_tags'] : 'yes'); ?> /> <?php _e('Show product tags in footer', 'bdfg-footer-enhancer'); ?> </label> <p class="description"><?php _e('Requires WooCommerce to be active.', 'bdfg-footer-enhancer'); ?></p> </td> </tr> </table> </div> <div id="content-settings" class="bdfg-tab-content"> <table class="form-table"> <tr> <th scope="row"><?php _e('Recent Posts', 'bdfg-footer-enhancer'); ?></th> <td> <label> <input type="checkbox" name="bdfg_footer_enhancer_options[show_recent_posts]" value="yes" <?php checked('yes', isset($options['show_recent_posts']) ? $options['show_recent_posts'] : 'yes'); ?> /> <?php _e('Show recent posts in footer', 'bdfg-footer-enhancer'); ?> </label> <p> <label> <?php _e('Number of posts to show:', 'bdfg-footer-enhancer'); ?> <input type="number" name="bdfg_footer_enhancer_options[recent_posts_count]" value="<?php echo isset($options['recent_posts_count']) ? esc_attr($options['recent_posts_count']) : 5; ?>" min="1" max="10" /> </label> </p> </td> </tr> <tr> <th scope="row"><?php _e('Custom Menu', 'bdfg-footer-enhancer'); ?></th> <td> <label> <input type="checkbox" name="bdfg_footer_enhancer_options[show_custom_menu]" value="yes" <?php checked('yes', isset($options['show_custom_menu']) ? $options['show_custom_menu'] : 'no'); ?> /> <?php _e('Show custom menu in footer', 'bdfg-footer-enhancer'); ?> </label> <p> <label> <?php _e('Select menu:', 'bdfg-footer-enhancer'); ?> <select name="bdfg_footer_enhancer_options[custom_menu_id]"> <option value="0"><?php _e('-- Select a menu --', 'bdfg-footer-enhancer'); ?></option> <?php $menus = wp_get_nav_menus(); foreach ($menus as $menu) { printf( '<option value="%d" %s>%s</option>', $menu->term_id, selected(isset($options['custom_menu_id']) ? $options['custom_menu_id'] : 0, $menu->term_id, false), esc_html($menu->name) ); } ?> </select> </label> </p> </td> </tr> <tr> <th scope="row"><?php _e('Popular Products', 'bdfg-footer-enhancer'); ?></th> <td> <label> <input type="checkbox" name="bdfg_footer_enhancer_options[show_popular_products]" value="yes" <?php checked('yes', isset($options['show_popular_products']) ? $options['show_popular_products'] : 'yes'); ?> /> <?php _e('Show popular products in footer', 'bdfg-footer-enhancer'); ?> </label> <p> <label> <?php _e('Number of products to show:', 'bdfg-footer-enhancer'); ?> <input type="number" name="bdfg_footer_enhancer_options[popular_products_count]" value="<?php echo isset($options['popular_products_count']) ? esc_attr($options['popular_products_count']) : 4; ?>" min="1" max="8" /> </label> </p> <p class="description"><?php _e('Requires WooCommerce to be active.', 'bdfg-footer-enhancer'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('Custom Footer Text', 'bdfg-footer-enhancer'); ?></th> <td> <textarea name="bdfg_footer_enhancer_options[custom_footer_text]" rows="3" class="large-text"><?php echo isset($options['custom_footer_text']) ? esc_textarea($options['custom_footer_text']) : ''; ?></textarea> <p class="description"> <?php _e('Enter custom text to appear at the bottom of the footer. HTML is allowed. Use %year% to insert the current year.', 'bdfg-footer-enhancer'); ?> </p> </td> </tr> </table> </div> <div id="social-settings" class="bdfg-tab-content"> <table class="form-table"> <tr> <th scope="row"><?php _e('Social Links', 'bdfg-footer-enhancer'); ?></th> <td> <label> <input type="checkbox" name="bdfg_footer_enhancer_options[show_social_links]" value="yes" <?php checked('yes', isset($options['show_social_links']) ? $options['show_social_links'] : 'yes'); ?> /> <?php _e('Show social links in footer', 'bdfg-footer-enhancer'); ?> </label> </td> </tr> </table> <div class="bdfg-social-links-container" <?php echo (isset($options['show_social_links']) && $options['show_social_links'] === 'no') ? 'style="display:none;"' : ''; ?>> <table class="form-table"> <?php $social_networks = array( 'facebook' => __('Facebook', 'bdfg-footer-enhancer'), 'twitter' => __('Twitter', 'bdfg-footer-enhancer'), 'instagram' => __('Instagram', 'bdfg-footer-enhancer'), 'youtube' => __('YouTube', 'bdfg-footer-enhancer'), 'pinterest' => __('Pinterest', 'bdfg-footer-enhancer'), 'linkedin' => __('LinkedIn', 'bdfg-footer-enhancer'), 'tiktok' => __('TikTok', 'bdfg-footer-enhancer'), ); foreach ($social_networks as $key => $name) { $value = isset($options['social_links'][$key]) ? $options['social_links'][$key] : ''; ?> <tr> <th scope="row"><?php echo esc_html($name); ?></th> <td> <input type="url" name="bdfg_footer_enhancer_options[social_links][<?php echo esc_attr($key); ?>]" value="<?php echo esc_url($value); ?>" class="regular-text" placeholder="https://" /> <?php if ($key === 'facebook') : ?> <p class="description"><?php _e('Enter your full profile URL.', 'bdfg-footer-enhancer'); ?></p> <?php endif; ?> </td> </tr> <?php } ?> </table> </div> </div> <div id="advanced-settings" class="bdfg-tab-content"> <table class="form-table"> <tr> <th scope="row"><?php _e('Caching', 'bdfg-footer-enhancer'); ?></th> <td> <label> <input type="checkbox" name="bdfg_footer_enhancer_options[enable_cache]" value="yes" <?php checked('yes', isset($options['enable_cache']) ? $options['enable_cache'] : 'yes'); ?> /> <?php _e('Enable caching for footer elements', 'bdfg-footer-enhancer'); ?> </label> <p class="description"><?php _e('Caching improves performance by storing footer elements temporarily.', 'bdfg-footer-enhancer'); ?></p> <p> <label> <?php _e('Cache duration (hours):', 'bdfg-footer-enhancer'); ?> <input type="number" name="bdfg_footer_enhancer_options[cache_time]" value="<?php echo isset($options['cache_time']) ? esc_attr($options['cache_time']) : 12; ?>" min="1" max="72" /> </label> </p> <p> <a href="#" class="button" id="bdfg-clear-cache"><?php _e('Clear Cache Now', 'bdfg-footer-enhancer'); ?></a> <span class="bdfg-cache-notice"></span> </p> </td> </tr> </table> </div> </div> </div> <?php submit_button(__('Save Settings', 'bdfg-footer-enhancer'), 'primary', 'submit', true, array('id' => 'bdfg-save-settings')); ?> </form> </div> <div class="bdfg-admin-sidebar"> <div class="bdfg-admin-box"> <h3><?php _e('About BDFG Footer Enhancer', 'bdfg-footer-enhancer'); ?></h3> <p><?php _e('Enhance your Storefront theme\'s footer with categories, pages, product tags, recent posts, custom menus, social media links, and popular products.', 'bdfg-footer-enhancer'); ?></p> <p><strong><?php _e('Version', 'bdfg-footer-enhancer'); ?>:</strong> <?php echo BDFG_FOOTER_ENHANCER_VERSION; ?></p> <p><a href="https://beiduofengou.net/plugins/bdfg-footer-enhancer" target="_blank"><?php _e('Plugin Homepage', 'bdfg-footer-enhancer'); ?></a></p> </div> <div class="bdfg-admin-box bdfg-rate-box"> <h3><span class="dashicons dashicons-star-filled"></span> <?php _e('Rate This Plugin', 'bdfg-footer-enhancer'); ?></h3> <p><?php _e('If you find this plugin useful, please leave a 5-star rating. It helps a lot!', 'bdfg-footer-enhancer'); ?></p> <a href="https://wordpress.org/support/plugin/bdfg-footer-enhancer/reviews/#new-post" class="button button-primary" target="_blank"><?php _e('Rate on WordPress.org', 'bdfg-footer-enhancer'); ?></a> </div> <div class="bdfg-admin-box bdfg-support-box"> <h3><span class="dashicons dashicons-sos"></span> <?php _e('Need Help?', 'bdfg-footer-enhancer'); ?></h3> <p><?php _e('Having issues with the plugin? Our support team is here to help.', 'bdfg-footer-enhancer'); ?></p> <a href="https://beiduofengou.net/support" class="button" target="_blank"><?php _e('Get Support', 'bdfg-footer-enhancer'); ?></a> </div> </div> </div> </div> <?php } /** * Add plugin row meta * * @param array $links * @param string $file * @return array */ public function plugin_row_meta($links, $file) { if (BDFG_FOOTER_ENHANCER_BASENAME === $file) { $row_meta = array( 'docs' => '<a href="' . esc_url('https://beiduofengou.net/docs/bdfg-footer-enhancer/') . '" target="_blank" aria-label="' . esc_attr__('View BDFG Footer Enhancer documentation', 'bdfg-footer-enhancer') . '">' . esc_html__('Docs', 'bdfg-footer-enhancer') . '</a>', 'support' => '<a href="' . esc_url('https://beiduofengou.net/support') . '" target="_blank" aria-label="' . esc_attr__('Get support for BDFG Footer Enhancer', 'bdfg-footer-enhancer') . '">' . esc_html__('Support', 'bdfg-footer-enhancer') . '</a>', ); return array_merge($links, $row_meta); } return $links; } /** * Add promo meta box */ public function add_promo_meta_box() { add_meta_box( 'bdfg_promo_meta_box', __('BDFG Plugins', 'bdfg-footer-enhancer'), array($this, 'render_promo_meta_box'), 'settings_page_bdfg-footer-enhancer', 'side', 'high' ); } /** * Render promo meta box */ public function render_promo_meta_box() { ?> <div class="bdfg-promo-box"> <p><?php _e('Check out our other plugins to enhance your WordPress site:', 'bdfg-footer-enhancer'); ?></p> <ul class="bdfg-promo-list"> <li><a href="https://beiduofengou.net/plugins/bdfg-product-enhancer" target="_blank"><?php _e('BDFG Product Enhancer', 'bdfg-footer-enhancer'); ?></a></li> <li><a href="https://beiduofengou.net/plugins/bdfg-checkout-plus" target="_blank"><?php _e('BDFG Checkout Plus', 'bdfg-footer-enhancer'); ?></a></li> <li><a href="https://beiduofengou.net/plugins/bdfg-seo-tools" target="_blank"><?php _e('BDFG SEO Tools', 'bdfg-footer-enhancer'); ?></a></li> </ul> <p><a href="https://beiduofengou.net/plugins" class="button" target="_blank"><?php _e('View All Plugins', 'bdfg-footer-enhancer'); ?></a></p> </div> <?php } } // Initialize admin class new BDFG_Admin();
includes/class-bdfg-frontend.php
<?php /** * Frontend functionality for BDFG Footer Enhancer * * @package BDFG_Footer_Enhancer * @author beiduofengou */ if (!defined('ABSPATH')) { exit; } /** * Frontend class */ class BDFG_Frontend { /** * Options * * @var array */ private $options; /** * Cache enabled flag * * @var bool */ private $cache_enabled; /** * Cache duration * * @var int */ private $cache_duration; /** * Constructor */ public function __construct() { $this->options = bdfg_get_option(); $this->cache_enabled = isset($this->options['enable_cache']) ? ($this->options['enable_cache'] === 'yes') : true; $this->cache_duration = isset($this->options['cache_time']) ? absint($this->options['cache_time']) * HOUR_IN_SECONDS : 12 * HOUR_IN_SECONDS; // Add footer widgets add_action('storefront_footer', array($this, 'add_footer_widgets'), 15); // Replace footer credit text add_filter('storefront_credit_link', array($this, 'custom_footer_credit'), 10, 1); // Add footer content container add_action('wp_footer', array($this, 'add_footer_content_container')); // AJAX handlers add_action('wp_ajax_bdfg_get_popular_products', array($this, 'ajax_get_popular_products')); add_action('wp_ajax_nopriv_bdfg_get_popular_products', array($this, 'ajax_get_popular_products')); add_action('wp_ajax_bdfg_clear_cache', array($this, 'ajax_clear_cache')); // Cache handling add_action('save_post', array($this, 'clear_footer_cache')); add_action('deleted_post', array($this, 'clear_footer_cache')); add_action('created_term', array($this, 'clear_footer_cache')); add_action('edited_term', array($this, 'clear_footer_cache')); add_action('delete_term', array($this, 'clear_footer_cache')); add_action('woocommerce_product_set_stock', array($this, 'clear_footer_cache')); add_action('woocommerce_variation_set_stock', array($this, 'clear_footer_cache')); add_action('woocommerce_product_set_visibility', array($this, 'clear_footer_cache')); } /** * Add footer widgets */ public function add_footer_widgets() { // Create footer container echo '<div class="bdfg-footer-widgets-container">'; // Show categories if (isset($this->options['show_categories']) && 'yes' === $this->options['show_categories']) { $this->render_categories_widget(); } // Show pages if (isset($this->options['show_pages']) && 'yes' === $this->options['show_pages']) { $this->render_pages_widget(); } // Show product tags if (isset($this->options['show_product_tags']) && 'yes' === $this->options['show_product_tags']) { $this->render_product_tags_widget(); } // Show recent posts if (isset($this->options['show_recent_posts']) && 'yes' === $this->options['show_recent_posts']) { $this->render_recent_posts_widget(); } // Show custom menu if (isset($this->options['show_custom_menu']) && 'yes' === $this->options['show_custom_menu']) { $this->render_custom_menu_widget(); } // Show social links if (isset($this->options['show_social_links']) && 'yes' === $this->options['show_social_links']) { $this->render_social_links_widget(); } // Show popular products if (isset($this->options['show_popular_products']) && 'yes' === $this->options['show_popular_products']) { $this->render_popular_products_widget(); } echo '</div>'; } /** * Render categories widget */ private function render_categories_widget() { $cache_key = 'bdfg_footer_categories'; if ($this->cache_enabled && false !== ($cached_html = get_transient($cache_key))) { echo $cached_html; return; } $categories = get_categories(array( 'orderby' => 'name', 'order' => 'ASC', 'hide_empty' => true, 'number' => 10, )); if (empty($categories)) { return; } ob_start(); ?> <div class="bdfg-footer-widget bdfg-footer-categories"> <div class="bdfg-widget-title"> <h4><?php echo bdfg_format_widget_title(__('Categories', 'bdfg-footer-enhancer')); ?></h4> </div> <div class="bdfg-widget-content"> <ul class="bdfg-list"> <?php foreach ($categories as $category) { printf( '<li><a href="%s" class="bdfg-link bdfg-category-link"><i class="fas fa-angle-right"></i> %s</a></li>', esc_url(get_category_link($category->term_id)), esc_html($category->name) ); } ?> </ul> </div> </div> <?php $html = ob_get_clean(); if ($this->cache_enabled) { set_transient($cache_key, $html, $this->cache_duration); } echo $html; } /** * Render pages widget */ private function render_pages_widget() { $cache_key = 'bdfg_footer_pages'; if ($this->cache_enabled && false !== ($cached_html = get_transient($cache_key))) { echo $cached_html; return; } $excluded_pages = array('cart', 'checkout', 'my-account'); $excluded_page_ids = array(); // Get IDs of pages to exclude foreach ($excluded_pages as $page_slug) { $page = get_page_by_path($page_slug); if ($page) { $excluded_page_ids[] = $page->ID; } } $pages = get_pages(array( 'sort_column' => 'menu_order,post_title', 'post_status' => 'publish', 'exclude' => implode(',', $excluded_page_ids), 'number' => 10, )); if (empty($pages)) { return; } ob_start(); ?> <div class="bdfg-footer-widget bdfg-footer-pages"> <div class="bdfg-widget-title"> <h4><?php echo bdfg_format_widget_title(__('Pages', 'bdfg-footer-enhancer')); ?></h4> </div> <div class="bdfg-widget-content"> <ul class="bdfg-list"> <?php foreach ($pages as $page) { printf( '<li><a href="%s" class="bdfg-link bdfg-page-link"><i class="fas fa-angle-right"></i> %s</a></li>', esc_url(get_permalink($page->ID)), esc_html($page->post_title) ); } ?> </ul> </div> </div> <?php $html = ob_get_clean(); if ($this->cache_enabled) { set_transient($cache_key, $html, $this->cache_duration); } echo $html; } /** * Render product tags widget */ private function render_product_tags_widget() { // Check if WooCommerce is active if (!function_exists('WC')) { return; } $cache_key = 'bdfg_footer_product_tags'; if ($this->cache_enabled && false !== ($cached_html = get_transient($cache_key))) { echo $cached_html; return; } $product_tags = get_terms(array( 'taxonomy' => 'product_tag', 'hide_empty' => true, 'orderby' => 'count', 'order' => 'DESC', 'number' => 15, )); if (empty($product_tags) || is_wp_error($product_tags)) { return; } ob_start(); ?> <div class="bdfg-footer-widget bdfg-footer-product-tags"> <div class="bdfg-widget-title"> <h4><?php echo bdfg_format_widget_title(__('Product Tags', 'bdfg-footer-enhancer')); ?></h4> </div> <div class="bdfg-widget-content"> <div class="bdfg-tag-cloud"> <?php foreach ($product_tags as $tag) { printf( '<a href="%s" class="bdfg-tag-link">%s</a>', esc_url(get_term_link($tag)), esc_html($tag->name) ); } ?> </div> </div> </div> <?php $html = ob_get_clean(); if ($this->cache_enabled) { set_transient($cache_key, $html, $this->cache_duration); } echo $html; } /** * Render recent posts widget */ private function render_recent_posts_widget() { $cache_key = 'bdfg_footer_recent_posts'; if ($this->cache_enabled && false !== ($cached_html = get_transient($cache_key))) { echo $cached_html; return; } $recent_posts_count = isset($this->options['recent_posts_count']) ? absint($this->options['recent_posts_count']) : 5; $recent_posts = get_posts(array( 'numberposts' => $recent_posts_count, 'post_status' => 'publish', )); if (empty($recent_posts)) { return; } ob_start(); ?> <div class="bdfg-footer-widget bdfg-footer-recent-posts"> <div class="bdfg-widget-title"> <h4><?php echo bdfg_format_widget_title(__('Recent Blog Posts', 'bdfg-footer-enhancer')); ?></h4> </div> <div class="bdfg-widget-content"> <ul class="bdfg-post-list"> <?php foreach ($recent_posts as $post) { setup_postdata($post); ?> <li class="bdfg-post-item"> <a href="<?php echo esc_url(get_permalink($post->ID)); ?>" class="bdfg-link bdfg-post-link"> <span class="bdfg-post-title"><?php echo esc_html(get_the_title($post->ID)); ?></span> <?php echo bdfg_get_post_date($post->ID); ?> </a> </li> <?php } wp_reset_postdata(); ?> </ul> </div> </div> <?php $html = ob_get_clean(); if ($this->cache_enabled) { set_transient($cache_key, $html, $this->cache_duration); } echo $html; } /** * Render custom menu widget */ private function render_custom_menu_widget() { $menu_id = isset($this->options['custom_menu_id']) ? absint($this->options['custom_menu_id']) : 0; if (0 === $menu_id) { return; } $cache_key = 'bdfg_footer_custom_menu_' . $menu_id; if ($this->cache_enabled && false !== ($cached_html = get_transient($cache_key))) { echo $cached_html; return; } $menu = wp_get_nav_menu_object($menu_id); if (!$menu) { return; } ob_start(); ?> <div class="bdfg-footer-widget bdfg-footer-custom-menu"> <div class="bdfg-widget-title"> <h4><?php echo bdfg_format_widget_title(esc_html($menu->name)); ?></h4> </div> <div class="bdfg-widget-content"> <?php wp_nav_menu(array( 'menu' => $menu_id, 'container' => false, 'menu_class' => 'bdfg-menu', 'depth' => 1, 'before' => '<i class="fas fa-angle-right"></i> ', )); ?> </div> </div> <?php $html = ob_get_clean(); if ($this->cache_enabled) { set_transient($cache_key, $html, $this->cache_duration); } echo $html; } /** * Render social links widget */ private function render_social_links_widget() { $social_links = isset($this->options['social_links']) ? $this->options['social_links'] : array(); if (empty($social_links) || !is_array($social_links)) { return; } // Check if any social link is set $has_links = false; foreach ($social_links as $link) { if (!empty($link)) { $has_links = true; break; } } if (!$has_links) { return; } ob_start(); ?> <div class="bdfg-footer-widget bdfg-footer-social-links"> <div class="bdfg-widget-title"> <h4><?php echo bdfg_format_widget_title(__('Connect With Us', 'bdfg-footer-enhancer')); ?></h4> </div> <div class="bdfg-widget-content"> <div class="bdfg-social-icons"> <?php foreach ($social_links as $network => $url) { if (!empty($url)) { $icon_class = bdfg_get_social_icon_class($network); printf( '<a href="%s" target="_blank" rel="noopener noreferrer" class="bdfg-social-icon bdfg-social-%s" title="%s"><span class="screen-reader-text">%s</span><i class="%s"></i></a>', esc_url($url), esc_attr($network), esc_attr(ucfirst($network)), esc_html(ucfirst($network)), esc_attr($icon_class) ); } } ?> </div> </div> </div> <?php echo ob_get_clean(); } /** * Render popular products widget */ private function render_popular_products_widget() { // Check if WooCommerce is active if (!function_exists('WC')) { return; } $cache_key = 'bdfg_footer_popular_products'; if ($this->cache_enabled && false !== ($cached_html = get_transient($cache_key))) { echo $cached_html; return; } $count = isset($this->options['popular_products_count']) ? absint($this->options['popular_products_count']) : 4; $products = bdfg_get_popular_products($count); if (empty($products)) { return; } ob_start(); ?> <div class="bdfg-footer-widget bdfg-footer-popular-products"> <div class="bdfg-widget-title"> <h4><?php echo bdfg_format_widget_title(__('Popular Products', 'bdfg-footer-enhancer')); ?></h4> </div> <div class="bdfg-widget-content"> <ul class="bdfg-product-list"> <?php foreach ($products as $product) { ?> <li class="bdfg-product-item"> <a href="<?php echo esc_url(get_permalink($product->get_id())); ?>" class="bdfg-product-link"> <?php if ($product->get_image_id()) : ?> <span class="bdfg-product-thumb"> <?php echo $product->get_image(bdfg_get_footer_thumbnail_size()); ?> </span> <?php endif; ?> <span class="bdfg-product-info"> <span class="bdfg-product-title"><?php echo esc_html($product->get_name()); ?></span> <span class="bdfg-product-price"><?php echo bdfg_format_price($product->get_price_html()); ?></span> </span> </a> </li> <?php } ?> </ul> </div> </div> <?php $html = ob_get_clean(); if ($this->cache_enabled) { set_transient($cache_key, $html, $this->cache_duration); } echo $html; } /** * Add footer content container */ public function add_footer_content_container() { // Add a container for potential AJAX-loaded content echo '<div id="bdfg-footer-dynamic-content" style="display:none;"></div>'; } /** * AJAX handler for getting popular products */ public function ajax_get_popular_products() { check_ajax_referer('bdfg_footer_enhancer_nonce', 'nonce'); $count = isset($_POST['count']) ? absint($_POST['count']) : 4; // Check if WooCommerce is active if (!function_exists('WC')) { wp_send_json_error('WooCommerce is not active'); wp_die(); } $products = bdfg_get_popular_products($count); $product_data = array(); foreach ($products as $product) { $product_data[] = array( 'id' => $product->get_id(), 'name' => $product->get_name(), 'url' => get_permalink($product->get_id()), 'price' => $product->get_price_html(), 'image' => $product->get_image(bdfg_get_footer_thumbnail_size()), ); } wp_send_json_success($product_data); wp_die(); } /** * AJAX handler for clearing cache */ public function ajax_clear_cache() { check_ajax_referer('bdfg_footer_enhancer_nonce', 'nonce'); // Check user capabilities if (!current_user_can('manage_options')) { wp_send_json_error(__('You do not have permission to perform this action', 'bdfg-footer-enhancer')); wp_die(); } bdfg_clear_all_caches(); wp_send_json_success(__('Cache cleared successfully', 'bdfg-footer-enhancer')); wp_die(); } /** * Clear footer cache * * @param int $post_id The ID of the post being saved */ public function clear_footer_cache($post_id = 0) { // Only clear cache if caching is enabled if ($this->cache_enabled) { bdfg_clear_all_caches(); } } /** * Custom footer credit text * * @param string $text Default footer text * @return string Modified footer text */ public function custom_footer_credit($text) { $custom_text = bdfg_get_option('custom_footer_text', ''); if (!empty($custom_text)) { // Replace %year% with current year $custom_text = str_replace('%year%', date('Y'), $custom_text); return $custom_text; } return $text; } } // Initialize frontend class new BDFG_Frontend();
includes/widgets/class-bdfg-widgets.php
相关文章: WordPress 智能缓存管理
<?php /** * Custom widgets for BDFG Footer Enhancer * * @package BDFG_Footer_Enhancer * @author beiduofengou */ if (!defined('ABSPATH')) { exit; } /** * Register widgets */ function bdfg_register_widgets() { register_widget('BDFG_Categories_Widget'); register_widget('BDFG_Recent_Posts_Widget'); if (class_exists('WooCommerce')) { register_widget('BDFG_Popular_Products_Widget'); } } add_action('widgets_init', 'bdfg_register_widgets'); /** * Categories Widget Class */ class BDFG_Categories_Widget extends WP_Widget { /** * Register widget with WordPress. */ public function __construct() { parent::__construct( 'bdfg_categories_widget', // Base ID __('BDFG Categories', 'bdfg-footer-enhancer'), // Name array('description' => __('Display a styled list of categories', 'bdfg-footer-enhancer')) // Args ); } /** * Front-end display of widget. * * @param array $args Widget arguments. * @param array $instance Saved values from database. */ public function widget($args, $instance) { $title = !empty($instance['title']) ? $instance['title'] : __('Categories', 'bdfg-footer-enhancer'); $title = apply_filters('widget_title', $title, $instance, $this->id_base); $max_items = !empty($instance['max_items']) ? absint($instance['max_items']) : 10; $categories = get_categories(array( 'orderby' => 'name', 'order' => 'ASC', 'hide_empty' => true, 'number' => $max_items, )); if (empty($categories)) { return; } echo $args['before_widget']; if ($title) { echo $args['before_title'] . bdfg_format_widget_title($title) . $args['after_title']; } ?> <ul class="bdfg-list bdfg-categories-list"> <?php foreach ($categories as $category) { printf( '<li><a href="%s" class="bdfg-link bdfg-category-link"><i class="fas fa-angle-right"></i> %s</a></li>', esc_url(get_category_link($category->term_id)), esc_html($category->name) ); } ?> </ul> <?php echo $args['after_widget']; } /** * Back-end widget form. * * @param array $instance Previously saved values from database. */ public function form($instance) { $title = !empty($instance['title']) ? $instance['title'] : __('Categories', 'bdfg-footer-enhancer'); $max_items = !empty($instance['max_items']) ? absint($instance['max_items']) : 10; ?> <p> <label for="<?php echo esc_attr($this->get_field_id('title')); ?>"><?php _e('Title:', 'bdfg-footer-enhancer'); ?></label> <input class="widefat" id="<?php echo esc_attr($this->get_field_id('title')); ?>" name="<?php echo esc_attr($this->get_field_name('title')); ?>" type="text" value="<?php echo esc_attr($title); ?>"> </p> <p> <label for="<?php echo esc_attr($this->get_field_id('max_items')); ?>"><?php _e('Maximum items to show:', 'bdfg-footer-enhancer'); ?></label> <input class="tiny-text" id="<?php echo esc_attr($this->get_field_id('max_items')); ?>" name="<?php echo esc_attr($this->get_field_name('max_items')); ?>" type="number" min="1" max="20" value="<?php echo esc_attr($max_items); ?>"> </p> <?php } /** * Sanitize widget form values as they are saved. * * @param array $new_instance Values just sent to be saved. * @param array $old_instance Previously saved values from database. * * @return array Updated safe values to be saved. */ public function update($new_instance, $old_instance) { $instance = array(); $instance['title'] = (!empty($new_instance['title'])) ? sanitize_text_field($new_instance['title']) : ''; $instance['max_items'] = (!empty($new_instance['max_items'])) ? absint($new_instance['max_items']) : 10; return $instance; } } /** * Recent Posts Widget Class */ class BDFG_Recent_Posts_Widget extends WP_Widget { /** * Register widget with WordPress. */ public function __construct() { parent::__construct( 'bdfg_recent_posts_widget', // Base ID __('BDFG Recent Posts', 'bdfg-footer-enhancer'), // Name array('description' => __('Display stylish recent blog posts with dates', 'bdfg-footer-enhancer')) // Args ); } /** * Front-end display of widget. * * @param array $args Widget arguments. * @param array $instance Saved values from database. */ public function widget($args, $instance) { $title = !empty($instance['title']) ? $instance['title'] : __('Recent Blog Posts', 'bdfg-footer-enhancer'); $title = apply_filters('widget_title', $title, $instance, $this->id_base); $number = !empty($instance['number']) ? absint($instance['number']) : 5; $show_date = !empty($instance['show_date']) ? '1' : '0'; $show_thumbnail = !empty($instance['show_thumbnail']) ? '1' : '0'; $recent_posts = get_posts(array( 'numberposts' => $number, 'post_status' => 'publish', )); if (empty($recent_posts)) { return; } echo $args['before_widget']; if ($title) { echo $args['before_title'] . bdfg_format_widget_title($title) . $args['after_title']; } ?> <ul class="bdfg-post-list"> <?php foreach ($recent_posts as $post) { ?> <li class="bdfg-post-item"> <?php if ($show_thumbnail && has_post_thumbnail($post->ID)) : ?> <div class="bdfg-post-thumb"> <a href="<?php echo esc_url(get_permalink($post->ID)); ?>"> <?php echo get_the_post_thumbnail($post->ID, 'thumbnail'); ?> </a> </div> <?php endif; ?> <div class="bdfg-post-content"> <a href="<?php echo esc_url(get_permalink($post->ID)); ?>" class="bdfg-post-link"> <span class="bdfg-post-title"><?php echo esc_html(get_the_title($post->ID)); ?></span> </a> <?php if ($show_date) : echo bdfg_get_post_date($post->ID); endif; ?> </div> </li> <?php } wp_reset_postdata(); ?> </ul> <?php echo $args['after_widget']; } /** * Back-end widget form. * * @param array $instance Previously saved values from database. */ public function form($instance) { $title = !empty($instance['title']) ? $instance['title'] : __('Recent Blog Posts', 'bdfg-footer-enhancer'); $number = !empty($instance['number']) ? absint($instance['number']) : 5; $show_date = !empty($instance['show_date']) ? (bool) $instance['show_date'] : true; $show_thumbnail = !empty($instance['show_thumbnail']) ? (bool) $instance['show_thumbnail'] : false; ?> <p> <label for="<?php echo esc_attr($this->get_field_id('title')); ?>"><?php _e('Title:', 'bdfg-footer-enhancer'); ?></label> <input class="widefat" id="<?php echo esc_attr($this->get_field_id('title')); ?>" name="<?php echo esc_attr($this->get_field_name('title')); ?>" type="text" value="<?php echo esc_attr($title); ?>"> </p> <p> <label for="<?php echo esc_attr($this->get_field_id('number')); ?>"><?php _e('Number of posts to show:', 'bdfg-footer-enhancer'); ?></label> <input class="tiny-text" id="<?php echo esc_attr($this->get_field_id('number')); ?>" name="<?php echo esc_attr($this->get_field_name('number')); ?>" type="number" min="1" max="10" value="<?php echo esc_attr($number); ?>"> </p> <p> <input class="checkbox" type="checkbox" <?php checked($show_date); ?> id="<?php echo esc_attr($this->get_field_id('show_date')); ?>" name="<?php echo esc_attr($this->get_field_name('show_date')); ?>" /> <label for="<?php echo esc_attr($this->get_field_id('show_date')); ?>"><?php _e('Display post date?', 'bdfg-footer-enhancer'); ?></label> </p> <p> <input class="checkbox" type="checkbox" <?php checked($show_thumbnail); ?> id="<?php echo esc_attr($this->get_field_id('show_thumbnail')); ?>" name="<?php echo esc_attr($this->get_field_name('show_thumbnail')); ?>" /> <label for="<?php echo esc_attr($this->get_field_id('show_thumbnail')); ?>"><?php _e('Display post thumbnail?', 'bdfg-footer-enhancer'); ?></label> </p> <?php } /** * Sanitize widget form values as they are saved. * * @param array $new_instance Values just sent to be saved. * @param array $old_instance Previously saved values from database. * * @return array Updated safe values to be saved. */ public function update($new_instance, $old_instance) { $instance = array(); $instance['title'] = (!empty($new_instance['title'])) ? sanitize_text_field($new_instance['title']) : ''; $instance['number'] = (!empty($new_instance['number'])) ? absint($new_instance['number']) : 5; $instance['show_date'] = !empty($new_instance['show_date']) ? 1 : 0; $instance['show_thumbnail'] = !empty($new_instance['show_thumbnail']) ? 1 : 0; return $instance; } } /** * Popular Products Widget Class */ class BDFG_Popular_Products_Widget extends WP_Widget { /** * Register widget with WordPress. */ public function __construct() { parent::__construct( 'bdfg_popular_products_widget', // Base ID __('BDFG Popular Products', 'bdfg-footer-enhancer'), // Name array('description' => __('Display popular WooCommerce products', 'bdfg-footer-enhancer')) // Args ); } /** * Front-end display of widget. * * @param array $args Widget arguments. * @param array $instance Saved values from database. */ public function widget($args, $instance) { if (!class_exists('WooCommerce')) { return; } $title = !empty($instance['title']) ? $instance['title'] : __('Popular Products', 'bdfg-footer-enhancer'); $title = apply_filters('widget_title', $title, $instance, $this->id_base); $number = !empty($instance['number']) ? absint($instance['number']) : 4; $show_thumbnail = !empty($instance['show_thumbnail']) ? (bool) $instance['show_thumbnail'] : true; $show_price = !empty($instance['show_price']) ? (bool) $instance['show_price'] : true; $products = bdfg_get_popular_products($number); if (empty($products)) { return; } echo $args['before_widget']; if ($title) { echo $args['before_title'] . bdfg_format_widget_title($title) . $args['after_title']; } ?> <ul class="bdfg-product-list"> <?php foreach ($products as $product) { ?> <li class="bdfg-product-item"> <a href="<?php echo esc_url(get_permalink($product->get_id())); ?>" class="bdfg-product-link"> <?php if ($show_thumbnail && $product->get_image_id()) : ?> <span class="bdfg-product-thumb"> <?php echo $product->get_image(bdfg_get_footer_thumbnail_size()); ?> </span> <?php endif; ?> <span class="bdfg-product-info"> <span class="bdfg-product-title"><?php echo esc_html($product->get_name()); ?></span> <?php if ($show_price) : ?> <span class="bdfg-product-price"><?php echo bdfg_format_price($product->get_price_html()); ?></span> <?php endif; ?> </span> </a> </li> <?php } ?> </ul> <?php echo $args['after_widget']; } /** * Back-end widget form. * * @param array $instance Previously saved values from database. */ public function form($instance) { $title = !empty($instance['title']) ? $instance['title'] : __('Popular Products', 'bdfg-footer-enhancer'); $number = !empty($instance['number']) ? absint($instance['number']) : 4; $show_thumbnail = !empty($instance['show_thumbnail']) ? (bool) $instance['show_thumbnail'] : true; $show_price = !empty($instance['show_price']) ? (bool) $instance['show_price'] : true; ?> <p> <label for="<?php echo esc_attr($this->get_field_id('title')); ?>"><?php _e('Title:', 'bdfg-footer-enhancer'); ?></label> <input class="widefat" id="<?php echo esc_attr($this->get_field_id('title')); ?>" name="<?php echo esc_attr($this->get_field_name('title')); ?>" type="text" value="<?php echo esc_attr($title); ?>"> </p> <p> <label for="<?php echo esc_attr($this->get_field_id('number')); ?>"><?php _e('Number of products to show:', 'bdfg-footer-enhancer'); ?></label> <input class="tiny-text" id="<?php echo esc_attr($this->get_field_id('number')); ?>" name="<?php echo esc_attr($this->get_field_name('number')); ?>" type="number" min="1" max="8" value="<?php echo esc_attr($number); ?>"> </p> <p> <input class="checkbox" type="checkbox" <?php checked($show_thumbnail); ?> id="<?php echo esc_attr($this->get_field_id('show_thumbnail')); ?>" name="<?php echo esc_attr($this->get_field_name('show_thumbnail')); ?>" /> <label for="<?php echo esc_attr($this->get_field_id('show_thumbnail')); ?>"><?php _e('Display product image?', 'bdfg-footer-enhancer'); ?></label> </p> <p> <input class="checkbox" type="checkbox" <?php checked($show_price); ?> id="<?php echo esc_attr($this->get_field_id('show_price')); ?>" name="<?php echo esc_attr($this->get_field_name('show_price')); ?>" /> <label for="<?php echo esc_attr($this->get_field_id('show_price')); ?>"><?php _e('Display product price?', 'bdfg-footer-enhancer'); ?></label> </p> <?php } /** * Sanitize widget form values as they are saved. * * @param array $new_instance Values just sent to be saved. * @param array $old_instance Previously saved values from database. * * @return array Updated safe values to be saved. */ public function update($new_instance, $old_instance) { $instance = array(); $instance['title'] = (!empty($new_instance['title'])) ? sanitize_text_field($new_instance['title']) : ''; $instance['number'] = (!empty($new_instance['number'])) ? absint($new_instance['number']) : 4; $instance['show_thumbnail'] = !empty($new_instance['show_thumbnail']) ? 1 : 0; $instance['show_price'] = !empty($new_instance['show_price']) ? 1 : 0; return $instance; } }
assets/css/frontend.css
/** * BDFG Footer Enhancer - Frontend Styles * * @package BDFG_Footer_Enhancer * @author beiduofengou * @version 3.1.1 */ /* Footer Widgets Container */ .bdfg-footer-widgets-container { display: flex; flex-wrap: wrap; margin: 0 -15px; padding: 20px 0; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } /* Footer Widget */ .bdfg-footer-widget { flex: 1 1 300px; margin: 0 15px 30px; min-width: 200px; } /* Widget Title */ .bdfg-widget-title { margin-bottom: 20px; } .bdfg-widget-title h4 { font-size: 16px; font-weight: 600; margin: 0 0 10px; text-transform: uppercase; letter-spacing: 0.5px; color: #fff; padding-bottom: 10px; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .bdfg-title-icon { margin-right: 5px; color: #7f54b3; } /* Lists */ .bdfg-list { list-style: none; margin: 0; padding: 0; } .bdfg-list li { margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px dotted rgba(255, 255, 255, 0.1); } .bdfg-list li:last-child { border-bottom: none; } .bdfg-list .fas { margin-right: 5px; color: #7f54b3; font-size: 12px; transition: margin-right 0.2s ease; } .bdfg-list a:hover .fas { margin-right: 8px; } /* Links */ .bdfg-link { text-decoration: none; color: #f8f8f8; display: inline-block; transition: color 0.2s ease; } .bdfg-link:hover { color: #7f54b3; text-decoration: none; } /* Post List */ .bdfg-post-list { list-style: none; margin: 0; padding: 0; } .bdfg-post-item { margin-bottom: 12px; padding-bottom: 12px; border-bottom: 1px dotted rgba(255, 255, 255, 0.1); display: flex; align-items: center; } .bdfg-post-item:last-child { border-bottom: none; } .bdfg-post-thumb { flex: 0 0 50px; margin-right: 10px; } .bdfg-post-thumb img { border-radius: 3px; width: 100%; height: auto; display: block; } .bdfg-post-content { flex: 1; } .bdfg-post-title { display: block; font-weight: 500; margin-bottom: 4px; } .bdfg-post-date { display: block; font-size: 12px; color: #bbb; } /* Tag Cloud */ .bdfg-tag-cloud { display: flex; flex-wrap: wrap; gap: 8px; } .bdfg-tag-link { display: inline-block; background: rgba(255, 255, 255, 0.1); color: #f8f8f8; padding: 4px 10px; border-radius: 3px; font-size: 12px; line-height: 1.4; text-decoration: none; transition: all 0.2s ease; } .bdfg-tag-link:hover { background: #7f54b3; color: #fff; text-decoration: none; } /* Social Icons */ .bdfg-social-icons { display: flex; flex-wrap: wrap; gap: 10px; } .bdfg-social-icon { display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; background: rgba(255, 255, 255, 0.1); color: #f8f8f8; border-radius: 50%; text-decoration: none; transition: all 0.2s ease; } .bdfg-social-icon:hover { background: #7f54b3; color: #fff; transform: translateY(-3px); text-decoration: none; } .bdfg-social-facebook:hover { background: #3b5998; } .bdfg-social-twitter:hover { background: #1da1f2; } .bdfg-social-instagram:hover { background: #e1306c; } .bdfg-social-youtube:hover { background: #ff0000; } .bdfg-social-pinterest:hover { background: #bd081c; } .bdfg-social-linkedin:hover { background: #0077b5; } .bdfg-social-tiktok:hover { background: #000000; } /* Product List */ .bdfg-product-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); grid-gap: 15px; } .bdfg-product-item { margin-bottom: 0; } .bdfg-product-link { text-decoration: none; color: #f8f8f8; display: flex; flex-direction: column; height: 100%; transition: transform 0.2s ease; } .bdfg-product-link:hover { transform: translateY(-3px); color: #f8f8f8; text-decoration: none; } .bdfg-product-thumb { margin-bottom: 8px; display: block; } .bdfg-product-thumb img { border-radius: 3px; width: 100%; height: auto; display: block; } .bdfg-product-info { display: flex; flex-direction: column; flex: 1; } .bdfg-product-title { font-size: 14px; font-weight: 500; margin-bottom: 5px; line-height: 1.3; } .bdfg-product-price { font-size: 13px; color: #7f54b3; } /* Menu */ .bdfg-menu { list-style: none; margin: 0; padding: 0; } .bdfg-menu li { margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px dotted rgba(255, 255, 255, 0.1); } .bdfg-menu li:last-child { border-bottom: none; } .bdfg-menu a { text-decoration: none; color: #f8f8f8; transition: color 0.2s ease; } .bdfg-menu a:hover { color: #7f54b3; text-decoration: none; } /* Responsive */ @media screen and (max-width: 767px) { .bdfg-footer-widget { flex: 0 0 100%; margin-bottom: 20px; } .bdfg-product-list { grid-template-columns: repeat(2, 1fr); } }
assets/css/admin.css
相关文章: WooCommerce 尺寸图表插件
/** * BDFG Footer Enhancer - Admin Styles * * @package BDFG_Footer_Enhancer * @author beiduofengou * @version 3.1.1 */ /* Admin Wrap */ .bdfg-admin-wrap { max-width: 1200px; margin: 20px 0; } /* Admin Header */ .bdfg-admin-header { display: flex; align-items: center; margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #ddd; } .bdfg-logo { width: 40px; height: 40px; margin-right: 15px; } /* Admin Content */ .bdfg-admin-content { display: flex; flex-wrap: wrap; margin: 0 -15px; } .bdfg-admin-main { flex: 1 1 800px; padding: 0 15px; margin-bottom: 20px; } .bdfg-admin-sidebar { flex: 0 0 300px; padding: 0 15px; } /* Settings Tabs */ .bdfg-settings-tabs { margin-top: 20px; background: #fff; border: 1px solid #ccd0d4; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); } .bdfg-tabs-nav { display: flex; flex-wrap: wrap; margin: 0; padding: 0; list-style: none; background: #f9f9f9; border-bottom: 1px solid #ccd0d4; } .bdfg-tabs-nav li { margin: 0; } .bdfg-tabs-nav a { display: block; padding: 12px 15px; text-decoration: none; color: #555; font-weight: 500; border-right: 1px solid #ccd0d4; border-bottom: 1px solid transparent; margin-bottom: -1px; transition: all 0.2s ease; white-space: nowrap; } .bdfg-tabs-nav li.active a { background: #fff; border-bottom-color: #fff; color: #23282d; } .bdfg-tabs-nav a:hover { color: #7f54b3; } .bdfg-tab-content { display: none; padding: 20px; } .bdfg-tab-content.active { display: block; } /* Admin Boxes */ .bdfg-admin-box { background: #fff; border: 1px solid #ccd0d4; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); margin-bottom: 20px; padding: 15px; } .bdfg-admin-box h3 { margin-top: 0; padding-bottom: 10px; border-bottom: 1px solid #eee; font-size: 14px; } .bdfg-admin-box .dashicons { color: #7f54b3; margin-right: 5px; } /* Rate box */ .bdfg-rate-box { background: #f8f5ff; border-color: #d5c8ea; } /* Support box */ .bdfg-support-box { background: #f8fcff; border-color: #c8e1ea; } /* Social links container */ .bdfg-social-links-container { background: #f9f9f9; padding: 15px; border: 1px solid #e5e5e5; border-radius: 3px; margin-top: 10px; } /* Cache notice */ .bdfg-cache-notice { display: inline-block; margin-left: 10px; padding: 5px 0; font-style: italic; } /* Footer */ .bdfg-admin-footer { margin-top: 30px; text-align: center; color: #666; font-size: 12px; } /* Responsive */ @media screen and (max-width: 782px) { .bdfg-admin-content { flex-direction: column; } .bdfg-tabs-nav { flex-wrap: nowrap; overflow-x: auto; } .bdfg-tabs-nav a { padding: 10px 12px; font-size: 13px; } }
assets/js/admin.js
/** * BDFG Footer Enhancer - Admin Scripts * * @package BDFG_Footer_Enhancer * @author beiduofengou * @version 3.1.1 * @last_updated 2025-03-05 by beiduofengou */ (function($) { 'use strict'; // Document ready $(document).ready(function() { // Initialize tabs initTabs(); // Initialize color picker initColorPicker(); // Social links toggle initSocialLinksToggle(); // Cache clearing initCacheClear(); }); /** * Initialize tabs functionality */ function initTabs() { $('.bdfg-tabs-nav a').on('click', function(e) { e.preventDefault(); // Get target tab var target = $(this).attr('href'); // Remove active class from all tabs and content $('.bdfg-tabs-nav li').removeClass('active'); $('.bdfg-tab-content').removeClass('active'); // Add active class to current tab and content $(this).parent('li').addClass('active'); $(target).addClass('active'); // Save active tab to sessionStorage sessionStorage.setItem('bdfg_active_tab', target); }); // Check for saved tab var activeTab = sessionStorage.getItem('bdfg_active_tab'); if (activeTab && $(activeTab).length) { $('.bdfg-tabs-nav li').removeClass('active'); $('.bdfg-tab-content').removeClass('active'); $('a[href="' + activeTab + '"]').parent('li').addClass('active'); $(activeTab).addClass('active'); } } /** * Initialize color picker */ function initColorPicker() { if ($.fn.wpColorPicker) { $('.bdfg-color-picker').wpColorPicker(); } } /** * Initialize social links toggle */ function initSocialLinksToggle() { var $checkbox = $('input[name="bdfg_footer_enhancer_options[show_social_links]"]'); var $container = $('.bdfg-social-links-container'); $checkbox.on('change', function() { if ($(this).is(':checked')) { $container.slideDown(); } else { $container.slideUp(); } }); } /** * Initialize cache clearing functionality */ function initCacheClear() { $('#bdfg-clear-cache').on('click', function(e) { e.preventDefault(); var $button = $(this); var $notice = $('.bdfg-cache-notice'); $button.prop('disabled', true).text('Clearing...'); $.ajax({ url: ajaxurl, type: 'POST', data: { action: 'bdfg_clear_cache', nonce: bdfg_footer_data.nonce }, success: function(response) { if (response.success) { $notice.text(response.data).css('color', 'green'); } else { $notice.text(response.data).css('color', 'red'); } setTimeout(function() { $button.prop('disabled', false).text('Clear Cache Now'); }, 1000); }, error: function() { $notice.text('Error clearing cache').css('color', 'red'); $button.prop('disabled', false).text('Clear Cache Now'); } }); }); } })(jQuery);
assets/js/frontend.js
/** * BDFG Footer Enhancer - Frontend Scripts * * @package BDFG_Footer_Enhancer * @author beiduofengou * @version 3.1.1 * @last_updated 2025-03-05 by beiduofengou */ (function($) { 'use strict'; // Document ready $(document).ready(function() { // Initialize lazy load for product images initLazyLoad(); // Initialize mobile footer toggles if (bdfg_footer_data.is_mobile) { initMobileToggles(); } }); /** * Initialize lazy loading for product images */ function initLazyLoad() { // Only run if IntersectionObserver is supported if ('IntersectionObserver' in window) { var lazyImages = [].slice.call(document.querySelectorAll('.bdfg-product-thumb img')); var imageObserver = new IntersectionObserver(function(entries, observer) { entries.forEach(function(entry) { if (entry.isIntersecting) { var lazyImage = entry.target; // Replace src with data-src if (lazyImage.dataset.src) { lazyImage.src = lazyImage.dataset.src; } // Replace srcset with data-srcset if (lazyImage.dataset.srcset) { lazyImage.srcset = lazyImage.dataset.srcset; } lazyImage.classList.add('loaded'); imageObserver.unobserve(lazyImage); } }); }); lazyImages.forEach(function(lazyImage) { imageObserver.observe(lazyImage); }); } } /** * Initialize mobile footer toggles */ function initMobileToggles() { $('.bdfg-widget-title').on('click', function() { var $content = $(this).next('.bdfg-widget-content'); if ($content.is(':visible')) { $content.slideUp(); $(this).removeClass('active'); } else { $content.slideDown(); $(this).addClass('active'); } }); } /** * AJAX load popular products * * @param {number} count Number of products to load * @param {string} containerId ID of container element */ function loadPopularProducts(count, containerId) { var $container = $('#' + containerId); if ($container.length === 0) { return; } $container.html('<p>Loading products...</p>'); $.ajax({ url: bdfg_footer_data.ajax_url, type: 'POST', data: { action: 'bdfg_get_popular_products', nonce: bdfg_footer_data.nonce, count: count }, success: function(response) { if (response.success && response.data) { var products = response.data; var html = '<ul class="bdfg-product-list">'; for (var i = 0; i < products.length; i++) { html += '<li class="bdfg-product-item">'; html += '<a href="' + products[i].url + '" class="bdfg-product-link">'; if (products[i].image) { html += '<span class="bdfg-product-thumb">' + products[i].image + '</span>'; } html += '<span class="bdfg-product-info">'; html += '<span class="bdfg-product-title">' + products[i].name + '</span>'; html += '<span class="bdfg-product-price">' + products[i].price + '</span>'; html += '</span>'; html += '</a>'; html += '</li>'; } html += '</ul>'; $container.html(html); } else { $container.html('<p>No products found</p>'); } }, error: function() { $container.html('<p>Error loading products</p>'); } }); } // Expose functions to global scope window.bdfgFooter = { loadPopularProducts: loadPopularProducts }; })(jQuery);