WooCommerce 页脚增强器

一个专门为店面主题设计的功能强大的插件,可将您的网站页脚转换为引人入胜且内容丰富的部分。

###关键功能:
***类别显示** – 在页脚中显示您的博客类别,以方便导航
***页面小部件** – 在页脚中显示重要页面以快速访问
***产品标签** – 在标签云中展示您的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);

 

Leave a Comment