初版提交

This commit is contained in:
feng 2025-01-22 23:58:39 +08:00
parent d6c5a3de10
commit d2b6b76399
8 changed files with 1310 additions and 0 deletions

0
assets/css/lunar-calendar.css Executable file
View file

115
assets/css/style.css Executable file
View file

@ -0,0 +1,115 @@
.wrap.wplc-settings-wrap {
max-width: 800px;
margin: 3% auto;
}
.wrap.wplc-settings-wrap h1 {
text-align: center;
margin: 0 0 1rem;
}
form {
padding: 6%;
background-color: #ffffff;
border-radius: 1px;
box-shadow: 0 0 0 1px #ccd0d4, 0 1px 1px 1px rgba(0, 0, 0, .04);
}
@media screen and (max-width: 782px) {
.form-table input.regular-text {
width: auto !important;
}
.form-table {
width: 100% !important;
}
.auto-fold #wpcontent {
padding-left: 10px;
padding-right: 10px;
}
}
.form-table td p {
margin-top: 15px;
margin-bottom: 0;
}
.description code {
line-height: 2;
}
.preview-title {
margin: 20px 0 10px;
font-size: 14px;
}
.preview-content {
padding: 15px;
background: #eff2ff;
border: 1px solid #e6ebfe;
border-radius: 0px;
text-align: center;
font-size: 14px;
}
.lunar-preview {
margin: 15px 0;
padding: 15px;
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 4px;
}
div#lunar_date_preview {
padding: 6%;
background-color: #ffffff;
margin: 5% 0;
border-radius: 1px;
box-shadow: 0 0 0 1px #ccd0d4, 0 1px 1px 1px rgba(0, 0, 0, .04);
}
/* 标签页导航样式 */
.nav-tab-wrapper {
margin-bottom: 20px;
}
.nav-tab {
padding: 10px 15px;
font-weight: 400;
border: 1px solid #c3c4c7;
border-bottom: 1px solid #c3c4c7;
text-decoration: none;
background-color: #f1f1f1;
margin-right: 5px;
}
.nav-tab-active {
background-color: #fff;
border-bottom: 1px solid #fff!important;
}
/* 关于插件标签页样式 */
.about-plugin-tab {
margin-top: 20px;
}
.about-plugin-tab h2 {
margin-bottom: 15px;
}
.about-plugin-tab p {
margin: 10px 0;
}
.plugin-copyright {
color: #777777;
}
.nav-tab-wrapper, .wrap h2.nav-tab-wrapper, h1.nav-tab-wrapper {
border-bottom: 0px solid #c3c4c7;
}
#wpfooter {
display: none;
}

BIN
assets/images/wpdate-banner.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

42
assets/js/script.js Executable file
View file

@ -0,0 +1,42 @@
jQuery(document).ready(function($) {
function updatePreview() {
var format = $('input[name="wplc_display_format"]').val();
var displayItems = {
year: $('input[name="wplc_display_items[year]"]').is(':checked') ? 1 : 0,
month: $('input[name="wplc_display_items[month]"]').is(':checked') ? 1 : 0,
day: $('input[name="wplc_display_items[day]"]').is(':checked') ? 1 : 0,
zodiac: $('input[name="wplc_display_items[zodiac]"]').is(':checked') ? 1 : 0,
festival: $('input[name="wplc_display_items[festival]"]').is(':checked') ? 1 : 0,
solar_term: $('input[name="wplc_display_items[solar_term]"]').is(':checked') ? 1 : 0
};
$.ajax({
url: wplcAdmin.ajaxurl,
type: 'POST',
data: {
action: 'lunar_date_preview',
nonce: wplcAdmin.nonce,
format: format,
display_items: displayItems
},
success: function(response) {
if (response.success) {
$('#lunar_date_preview').html(response.data.preview);
} else {
$('#lunar_date_preview').html('<div class="error">预览失败,请重试。</div>');
}
},
error: function() {
$('#lunar_date_preview').html('<div class="error">请求失败,请检查网络连接。</div>');
}
});
}
// 绑定事件
$('input[name="wplc_display_format"], input[name^="wplc_display_items"]').on('input change', function() {
updatePreview();
});
// 初始化预览
updatePreview();
});

View file

@ -0,0 +1,331 @@
<?php
class WPLC_Admin {
public function __construct() {
add_action('admin_menu', array($this, 'add_admin_menu'));
add_action('admin_init', array($this, 'register_settings'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
}
/**
* 加载管理页面的脚本和样式
*/
public function enqueue_admin_scripts($hook) {
// 只在插件设置页面加载脚本和样式
if ('settings_page_wpdate-calendar' !== $hook) {
return;
}
// 加载样式文件
wp_enqueue_style(
'wpdate-calendar-admin',
WPLC_PLUGIN_URL . 'assets/css/style.css',
array(),
'1.0.0'
);
// 加载脚本
wp_enqueue_script(
'wpdate-calendar-admin',
WPLC_PLUGIN_URL . 'assets/js/script.js',
array('jquery'),
WPLC_VERSION, // 使用插件版本常量
true
);
// 传递数据到前端
wp_localize_script(
'wpdate-calendar-admin', // 脚本句柄,必须与 wp_enqueue_script 中的句柄一致
'wplcAdmin', // 前端 JavaScript 对象的名称
array(
'nonce' => wp_create_nonce('lunar_date_preview'), // 添加 nonce
'ajaxurl' => admin_url('admin-ajax.php') // 添加 ajaxurl
)
);
}
/**
* 添加管理菜单
*/
public function add_admin_menu() {
add_options_page(
'文派日历设置', // 页面标题
'农历日期', // 菜单标题
'manage_options', // 权限
'wpdate-calendar', // 菜单 slug
array($this, 'display_admin_page') // 回调函数
);
}
/**
* 注册设置
*/
public function register_settings() {
// 注册设置项
register_setting('wplc_options', 'wplc_enable_lunar');
register_setting('wplc_options', 'wplc_display_items');
register_setting('wplc_options', 'wplc_display_format');
register_setting('wplc_options', 'wplc_enable_solar_festival'); // 新增阳历节日设置
register_setting('wplc_options', 'wplc_show_lunar_in_admin');
// 添加设置区块
add_settings_section(
'wplc_display_section', // 区块 ID
__('显示设置', 'wpdate-calendar'), // 区块标题
array($this, 'display_section_info'), // 回调函数
'wpdate-calendar' // 页面 slug
);
// 添加启用农历显示字段
add_settings_field(
'wplc_enable_lunar', // 字段 ID
__('启用农历显示', 'wpdate-calendar'), // 字段标题
array($this, 'enable_lunar_field'), // 回调函数
'wpdate-calendar', // 页面 slug
'wplc_display_section' // 区块 ID
);
// 添加在后台右上角显示农历字段
add_settings_field(
'wplc_show_lunar_in_admin', // 字段 ID
__('启用问候显示', 'wpdate-calendar'), // 字段标题
array($this, 'show_lunar_in_admin_field'), // 回调函数
'wpdate-calendar', // 页面 slug
'wplc_display_section' // 区块 ID
);
// 添加显示格式字段
add_settings_field(
'wplc_display_format', // 字段 ID
__('显示格式', 'wpdate-calendar'), // 字段标题
array($this, 'display_format_field'), // 回调函数
'wpdate-calendar', // 页面 slug
'wplc_display_section' // 区块 ID
);
// 添加显示项目字段
add_settings_field(
'wplc_display_items', // 字段 ID
__('显示项目', 'wpdate-calendar'), // 字段标题
array($this, 'display_items_field'), // 回调函数
'wpdate-calendar', // 页面 slug
'wplc_display_section' // 区块 ID
);
}
/**
* 启用农历显示字段的回调函数
*/
public function enable_lunar_field() {
?>
<label>
<input type="checkbox" name="wplc_enable_lunar" value="1" <?php checked(get_option('wplc_enable_lunar', true)); ?>>
<?php _e('自动在文章日期旁显示农历', 'wpdate-calendar'); ?>
</label>
<?php
}
/**
* 在后台右上角显示农历字段的回调函数
*/
public function show_lunar_in_admin_field() {
?>
<label>
<input type="checkbox" name="wplc_show_lunar_in_admin" value="1" <?php checked(get_option('wplc_show_lunar_in_admin', true)); ?>>
<?php _e('在网站后台右上角显示农历', 'wpdate-calendar'); ?>
</label>
<?php
}
/**
* 显示设置区块的描述信息
*/
public function display_section_info() {
echo '配置农历日期的显示方式';
}
/**
* 显示格式字段的回调函数
*/
public function display_format_field() {
$format = get_option('wplc_display_format', '%date% (%lunar%)');
?>
<input type="text" name="wplc_display_format" value="<?php echo esc_attr($format); ?>" class="regular-text">
<p class="description" style="text-align: justify;">
<?php _e('自定义您需要显示的信息,可用日期格式参数:', 'wpdate-calendar'); ?>
<br><?php _e('原始日期', 'wpdate-calendar'); ?> - <code>%date%</code>
<br><?php _e('农历年份', 'wpdate-calendar'); ?> - <code>%lunar_year%</code>
<br><?php _e('农历月份', 'wpdate-calendar'); ?> - <code>%lunar_month%</code>
<br><?php _e('农历日期', 'wpdate-calendar'); ?> - <code>%lunar_day%</code>
<br><?php _e('生肖属相', 'wpdate-calendar'); ?> - <code>%zodiac%</code>
<br><?php _e('农历节日', 'wpdate-calendar'); ?> - <code>%lunar_festival%</code>
<br><?php _e('阳历节日', 'wpdate-calendar'); ?> - <code>%solar_festival%</code>
<br><?php _e('完整农历', 'wpdate-calendar'); ?> - <code>%lunar%</code>
</p>
<?php
}
/**
* 显示项目字段
*/
public function display_items_field() {
$items = get_option('wplc_display_items', array(
'year' => true,
'month' => true,
'day' => true,
'zodiac' => false,
'lunar_festival' => true,
'solar_festival' => true,
'solar_term' => true
));
// 如果 $items 是字符串,则将其转换为数组
if (is_string($items)) {
$items = maybe_unserialize($items);
if (!is_array($items)) {
$items = array();
}
}
?>
<fieldset>
<legend class="screen-reader-text">显示项目设置</legend>
<h4>基本信息</h4>
<label>
<input type="checkbox" name="wplc_display_items[year]" value="1" <?php checked(isset($items['year']) ? $items['year'] : false); ?>>
农历年份
</label><br>
<label>
<input type="checkbox" name="wplc_display_items[month]" value="1" <?php checked(isset($items['month']) ? $items['month'] : false); ?>>
农历月份
</label><br>
<label>
<input type="checkbox" name="wplc_display_items[day]" value="1" <?php checked(isset($items['day']) ? $items['day'] : false); ?>>
农历日期
</label><br>
<label>
<input type="checkbox" name="wplc_display_items[zodiac]" value="1" <?php checked(isset($items['zodiac']) ? $items['zodiac'] : false); ?>>
生肖属相
</label><br>
<h4>节日与节气</h4>
<label>
<input type="checkbox" name="wplc_display_items[lunar_festival]" value="1" <?php checked(isset($items['lunar_festival']) ? $items['lunar_festival'] : false); ?>>
农历节日
</label><br>
<label>
<input type="checkbox" name="wplc_display_items[solar_festival]" value="1" <?php checked(isset($items['solar_festival']) ? $items['solar_festival'] : false); ?>>
阳历节日
</label><br>
<label>
<input type="checkbox" name="wplc_display_items[solar_term]" value="1" <?php checked(isset($items['solar_term']) ? $items['solar_term'] : false); ?>>
二十四节气
</label>
</fieldset>
<?php
}
/**
* 显示管理页面
*/
public function display_admin_page() {
if (!current_user_can('manage_options')) {
return;
}
// 获取当前活动的标签页
$active_tab = isset($_GET['tab']) ? $_GET['tab'] : 'display_settings';
?>
<div class="wrap wplc-settings-wrap">
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
<!-- 标签页导航 -->
<h2 class="nav-tab-wrapper">
<a href="?page=wpdate-calendar&tab=display_settings" class="nav-tab <?php echo $active_tab == 'display_settings' ? 'nav-tab-active' : ''; ?>">设置选项</a>
<a href="?page=wpdate-calendar&tab=about" class="nav-tab <?php echo $active_tab == 'about' ? 'nav-tab-active' : ''; ?>">关于插件</a>
</h2>
<form action="options.php" method="post">
<?php
if ($active_tab == 'display_settings') {
settings_fields('wplc_options');
do_settings_sections('wpdate-calendar');
submit_button();
} elseif ($active_tab == 'about') {
$this->display_about_tab();
}
?>
</form>
<!-- 农历日期预览 -->
<?php if ($active_tab == 'display_settings') : ?>
<div id="lunar_date_preview">
<h3><?php _e('预览效果', 'wpdate-calendar'); ?></h3>
<p><?php _e('当前设置下的农历日期显示效果:', 'wpdate-calendar'); ?></p>
<div id="lunar_preview_content">
<?php
$example_date = date_i18n(get_option('date_format'));
$example_lunar = '辛丑年正月初一';
$example_format = get_option('wplc_display_format', '%date% %lunar%');
$preview_data = array(
'%date%' => $example_date,
'%lunar%' => $example_lunar,
'%lunar_year%' => '辛丑年',
'%lunar_month%' => '正月',
'%lunar_day%' => '初一',
'%zodiac%' => '牛',
'%lunar_festival%' => '春节',
'%solar_festival%' => '元旦',
'%solar_term%' => '立春'
);
$preview_text = str_replace(
array_keys($preview_data),
array_values($preview_data),
$example_format
);
echo esc_html($preview_text);
?>
</div>
</div>
<?php endif; ?>
</div>
<?php
}
/**
* 显示“关于插件”标签页的内容
*/
public function display_about_tab() {
$image_url = plugins_url('assets/images/wpdate-banner.jpg', dirname(__FILE__));
?>
<div class="about-plugin-tab">
<h2><?php _e('关于插件', 'wpdate-calendar'); ?></h2>
<p><?php _e('文派日历WPDate是一款独特且实用的免费插件可以让 WordPress 显示中国农历日期,精准展示万年历、节气及传统节日,支持高度自定义,为您的网站增添东方文化韵味。
', 'wpdate-calendar'); ?></p></br>
<img src="<?php echo esc_url($image_url); ?>" alt="WPDate Banner" style="max-width: 100%; height: auto;">
<p><?php _e('创业数十载,不知今夕是何年。
', 'wpdate-calendar'); ?></p></br>
<p><?php _e('由于工作太忙很多时候会忘记时间和日期即便假期和节日也会遗漏未来希望可以多一些时间给到生活。WPDate 插件首发于 2025 1 月正值小年寒冬腊月。
', 'wpdate-calendar'); ?></p></br>
<p><?php _e('春节临近祝全球华人及中国用户新春快乐阖家幸福并且以此推进了文派开源WenPai.org项目一小步。
', 'wpdate-calendar'); ?></p></br>
<h2><?php _e('帮助支持', 'wpdate-calendar'); ?></h2>
<p><?php _e('关于更多此插件信息,您可以在下面地址找到,这将作为文派·寻鹿建站套件的一部分,我们将会在继续完善。
', 'wpdate-calendar'); ?></p></br>
<p><?php _e('插件作者:', 'wpdate-calendar'); ?> <a href="https://wenpai.org" target="_blank">文派开源WenPai.org↗</a></p>
<p><?php _e('官方网站:', 'wpdate-calendar'); ?> <a href="https://wpdate.com" target="_blank">WPDate.com ↗</a></p>
<p><?php _e('插件主页:', 'wpdate-calendar'); ?> <a href="https://wenpai.org/plugins/wpdate-calendar" target="_blank">WenPai.org/plugins/wpdate-calendar</a></p>
<p><?php _e('代码仓库:', 'wpdate-calendar'); ?> <a href="https://github.com/WenPai-org/wpdate-calendar" target="_blank">/WenPai-org/wpdate-calendar</a></p></br>
<div class="plugin-copyright">
<p><?php _e('Copyright © 2025 · WPDate.com , All Rights Reserved. 文派 (广州) 科技有限公司;
', 'wpdate-calendar'); ?></p>
</div>
</div>
</div>
<?php
}
}

493
includes/class-lunar-calendar.php Executable file
View file

@ -0,0 +1,493 @@
<?php
class WPDate_Lunar_Calendar {
private static $instance = null;
private $admin;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$this->load_dependencies();
$this->init_hooks();
$this->admin = new WPLC_Admin(); // 初始化管理类
}
private function load_dependencies() {
require_once WPLC_PLUGIN_DIR . 'includes/class-lunar-converter.php';
require_once WPLC_PLUGIN_DIR . 'includes/class-lunar-calendar-admin.php';
}
private function init_hooks() {
// 日期显示钩子
add_filter('get_the_date', array($this, 'append_lunar_date'), 10, 2);
add_filter('the_date', array($this, 'append_lunar_date'), 10, 2);
add_filter('get_the_time', array($this, 'append_lunar_date'), 10, 2);
add_filter('the_time', array($this, 'append_lunar_date'), 10, 2);
add_filter('get_the_modified_date', array($this, 'append_lunar_date'), 10, 2);
add_filter('the_modified_date', array($this, 'append_lunar_date'), 10, 2);
// 添加样式和脚本
add_action('wp_enqueue_scripts', array($this, 'enqueue_styles'));
add_action('wp_loaded', array($this, 'register_ajax_handlers'));
add_action('init', array($this, 'register_shortcode'));
// 在后台右上角显示农历
add_action('admin_notices', array($this, 'display_lunar_in_admin'));
}
public function enqueue_styles() {
wp_enqueue_style(
'wpdate-calendar',
WPLC_PLUGIN_URL . 'assets/css/lunar-calendar.css',
array(),
WPLC_VERSION
);
}
public function get_lunar_date($solar_date) {
$cache_key = 'wplc_' . md5($solar_date);
$lunar_date = get_transient($cache_key);
if (false !== $lunar_date) {
return $lunar_date;
}
$date = date_parse($solar_date);
if (!$date || !isset($date['year'], $date['month'], $date['day'])) {
return '';
}
$lunar = WPLC_Lunar_Converter::solar_to_lunar(
$date['year'],
$date['month'],
$date['day']
);
if (!$lunar) {
return '';
}
$festival = '';
if (get_option('wplc_show_festivals', true)) {
$festival = WPLC_Lunar_Converter::get_festival($lunar['month'], $lunar['day']);
}
$solar_term = '';
if (get_option('wplc_show_solar_terms', true)) {
$solar_term = WPLC_Lunar_Converter::get_solar_term($date['month'], $date['day']);
}
$lunar_text = sprintf(
'%s年%s月%s%s',
WPLC_Lunar_Converter::get_chinese_year($lunar['year']),
WPLC_Lunar_Converter::get_chinese_month($lunar['month'], $lunar['leap']),
WPLC_Lunar_Converter::get_chinese_day($lunar['day']),
($festival ? " {$festival}" : '') . ($solar_term ? " {$solar_term}" : '')
);
set_transient($cache_key, $lunar_text, DAY_IN_SECONDS);
return $lunar_text;
}
public function append_lunar_date($the_date, $format = '') {
// 排除RSS订阅和后台请求
if (is_feed() || is_admin()) {
return $the_date;
}
// 检查是否启用农历显示
if (!get_option('wplc_enable_lunar', true)) {
return $the_date;
}
$post_id = get_the_ID();
if (!$post_id) {
return $the_date;
}
$post_date = get_post_time('Y-m-d', false, $post_id);
if (!$post_date) {
return $the_date;
}
$lunar_info = $this->get_lunar_date_info($post_date);
if (!$lunar_info) {
return $the_date;
}
$replacements = array(
'%date%' => $the_date,
'%lunar_year%' => $lunar_info['year']. '年',
'%lunar_month%' => $lunar_info['month']. '月',
'%lunar_day%' => $lunar_info['day'],
'%zodiac%' => $lunar_info['zodiac'],
'%lunar_festival%' => $lunar_info['lunar_festival'],
'%solar_festival%' => $lunar_info['solar_festival'],
'%festival%' => $lunar_info['festival'],
'%solar_term%' => $lunar_info['solar_term'],
'%lunar%' => sprintf('%s%s%s',
$lunar_info['year'],
$lunar_info['month'],
$lunar_info['day']
)
);
$display_format = get_option('wplc_display_format', '%date% (%lunar%)');
$display_items = get_option('wplc_display_items', array(
'year' => true,
'month' => true,
'day' => true,
'zodiac' => false,
'festival' => true,
'solar_term' => true
));
if (!$display_items['year']) {
$replacements['%lunar_year%'] = '';
}
if (!$display_items['month']) {
$replacements['%lunar_month%'] = '';
}
if (!$display_items['day']) {
$replacements['%lunar_day%'] = '';
}
if (!$display_items['zodiac']) {
$replacements['%zodiac%'] = '';
}
if (!$display_items['festival']) {
$replacements['%festival%'] = '';
}
if (!$display_items['solar_term']) {
$replacements['%solar_term%'] = '';
}
$final_text = str_replace(
array_keys($replacements),
array_values($replacements),
$display_format
);
$final_text = preg_replace('/\s+/', ' ', $final_text);
$final_text = preg_replace('/\(\s*\)/', '', $final_text);
$final_text = trim($final_text);
return sprintf('<span class="lunar-date">%s</span>', $final_text);
}
private function get_lunar_date_info($date) {
$timestamp = strtotime($date);
if (!$timestamp) {
return false;
}
list($year, $month, $day) = explode('-', date('Y-m-d', $timestamp));
$lunar = WPLC_Lunar_Converter::solar_to_lunar($year, $month, $day);
if (!$lunar) {
return false;
}
$festivals = $this->get_festivals($lunar['month'], $lunar['day']);
$solar_term = $this->get_solar_term($year, $month, $day);
return array(
'year' => $this->get_lunar_year($lunar['year']),
'month' => $this->get_lunar_month($lunar['month']),
'day' => $this->get_lunar_day($lunar['day']),
'zodiac' => $this->get_zodiac($lunar['year']),
'lunar_festival' => $festivals['lunar'],
'solar_festival' => $festivals['solar'],
'festival' => $festivals['combined'],
'solar_term' => $solar_term
);
}
private function get_lunar_year($year) {
$heavenly_stems = array('甲','乙','丙','丁','戊','己','庚','辛','壬','癸');
$earthly_branches = array('子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥');
$zodiac = array('鼠','牛','虎','兔','龙','蛇','马','羊','猴','鸡','狗','猪');
$year = $year - 4;
$heavenly_stem = $heavenly_stems[$year % 10];
$earthly_branch = $earthly_branches[$year % 12];
$zodiac_name = $zodiac[$year % 12];
return $heavenly_stem . $earthly_branch . $zodiac_name;
}
private function get_lunar_month($month) {
$months = array('正','二','三','四','五','六','七','八','九','十','冬','腊');
return $months[$month - 1];
}
private function get_lunar_day($day) {
$days = array('初一','初二','初三','初四','初五','初六','初七','初八','初九','初十',
'十一','十二','十三','十四','十五','十六','十七','十八','十九','二十',
'廿一','廿二','廿三','廿四','廿五','廿六','廿七','廿八','廿九','三十');
return $days[$day - 1];
}
private function get_zodiac($year) {
$zodiac = array('鼠','牛','虎','兔','龙','蛇','马','羊','猴','鸡','狗','猪');
return $zodiac[($year - 4) % 12];
}
private function get_festivals($lunar_month, $lunar_day) {
$lunar_festivals = array(
'1-1' => '春节',
'1-15' => '元宵节',
'2-2' => '龙抬头',
'5-5' => '端午节',
'7-7' => '七夕节',
'7-15' => '中元节',
'8-15' => '中秋节',
'9-9' => '重阳节',
'10-1' => '寒衣节',
'10-15' => '下元节',
'12-8' => '腊八节',
'12-23' => '小年',
'12-30' => '除夕'
);
$solar_festivals = array(
'1-1' => '元旦',
'2-14' => '情人节',
'3-8' => '妇女节',
'3-12' => '植树节',
'4-1' => '愚人节',
'5-1' => '劳动节',
'5-4' => '青年节',
'6-1' => '儿童节',
'9-10' => '教师节',
'10-1' => '国庆节',
'12-24' => '平安夜',
'12-25' => '圣诞节'
);
$lunar_key = $lunar_month . '-' . $lunar_day;
$solar_key = date('n-j');
$lunar_festival = isset($lunar_festivals[$lunar_key]) ? $lunar_festivals[$lunar_key] : '';
$solar_festival = isset($solar_festivals[$solar_key]) ? $solar_festivals[$solar_key] : '';
$combined = array_filter(array($lunar_festival, $solar_festival));
return array(
'lunar' => $lunar_festival,
'solar' => $solar_festival,
'combined' => implode('/', $combined)
);
}
private function get_solar_term($year, $month, $day) {
$terms = array(
array(6.11,20.84,4.6295, '小寒','立春','惊蛰'),
array(20.84,35.6,19.4599, '大寒','雨水','春分'),
array(35.6,50.36,34.2904, '立春','惊蛰','清明'),
array(50.36,65.12,49.1208, '雨水','春分','谷雨'),
array(65.12,79.88,63.9513, '惊蛰','清明','立夏'),
array(79.88,94.64,78.7817, '春分','谷雨','小满'),
array(94.64,109.4,93.6122, '清明','立夏','芒种'),
array(109.4,124.16,108.4426,'谷雨','小满','夏至'),
array(124.16,138.92,123.2731,'立夏','芒种','小暑'),
array(138.92,153.68,138.1035,'小满','夏至','大暑'),
array(153.68,168.44,152.934,'芒种','小暑','立秋'),
array(168.44,183.2,167.7644,'夏至','大暑','处暑'),
array(183.2,197.96,182.5949,'小暑','立秋','白露'),
array(197.96,212.72,197.4253,'大暑','处暑','秋分'),
array(212.72,227.48,212.2558,'立秋','白露','寒露'),
array(227.48,242.24,227.0862,'处暑','秋分','霜降'),
array(242.24,257,241.9167, '白露','寒露','立冬'),
array(257,271.76,256.7471, '秋分','霜降','小雪'),
array(271.76,286.52,271.5776,'寒露','立冬','大雪'),
array(286.52,301.28,286.408,'霜降','小雪','冬至'),
array(301.28,316.04,301.2385,'立冬','大雪','小寒'),
array(316.04,330.8,316.0689,'小雪','冬至','大寒'),
array(330.8,345.56,330.8994,'大雪','小寒','立春'),
array(345.56,360.32,345.7298,'冬至','大寒','雨水')
);
// 计算节气
$term_name = '';
$solar_longitude = $this->get_solar_longitude($year, $month, $day);
foreach ($terms as $term) {
if ($solar_longitude >= $term[0] && $solar_longitude < $term[1]) {
if (abs($solar_longitude - $term[2]) < 0.5) {
$term_name = $term[3];
}
break;
}
}
return $term_name;
}
private function get_solar_longitude($year, $month, $day) {
$days = floor(365.242 * ($year - 2000) + 30.42 * $month + $day - 21);
return ($days * 0.985647 + 15) % 360;
}
public function register_shortcode() {
add_shortcode('lunar_date', array($this, 'lunar_date_shortcode'));
}
public function lunar_date_shortcode($atts) {
$atts = shortcode_atts(array(
'post_id' => get_the_ID(),
'format' => get_option('wplc_display_format', '%date% (%lunar%)'),
'date' => ''
), $atts, 'lunar_date');
if (!empty($atts['date'])) {
$post_date = $atts['date'];
} else {
$post = get_post($atts['post_id']);
if (!$post) {
return '';
}
$post_date = $post->post_date;
}
$lunar_info = $this->get_lunar_date_info($post_date);
if (!$lunar_info) {
return '';
}
$replacements = array(
'%date%' => date_i18n(get_option('date_format'), strtotime($post_date)),
'%lunar_year%' => $lunar_info['year'] . '年',
'%lunar_month%' => $lunar_info['month'] . '月',
'%lunar_day%' => $lunar_info['day'],
'%zodiac%' => $lunar_info['zodiac'],
'%lunar_festival%' => $lunar_info['lunar_festival'],
'%solar_festival%' => $lunar_info['solar_festival'],
'%festival%' => $lunar_info['festival'],
'%solar_term%' => $lunar_info['solar_term'],
'%lunar%' => sprintf('%s年%s月%s',
$lunar_info['year'],
$lunar_info['month'],
$lunar_info['day']
)
);
$final_text = str_replace(
array_keys($replacements),
array_values($replacements),
$atts['format']
);
return sprintf('<span class="lunar-date">%s</span>', $final_text);
}
public function register_ajax_handlers() {
add_action('wp_ajax_lunar_date_preview', array($this, 'handle_preview_ajax'));
}
public function handle_preview_ajax() {
check_ajax_referer('lunar_date_preview', 'nonce');
$format = sanitize_text_field($_POST['format']);
$display_items = isset($_POST['display_items']) ? array_map('sanitize_text_field', $_POST['display_items']) : array();
$sample_date = current_time('mysql');
$lunar_info = $this->get_lunar_date_info($sample_date);
if (!$lunar_info) {
wp_send_json_error(array('message' => '无法获取农历信息'));
}
$replacements = array(
'%date%' => date_i18n(get_option('date_format'), strtotime($sample_date)),
'%lunar_year%' => $lunar_info['year'] . '年',
'%lunar_month%' => $lunar_info['month'] . '月',
'%lunar_day%' => $lunar_info['day'],
'%zodiac%' => $lunar_info['zodiac'],
'%lunar_festival%' => $lunar_info['lunar_festival'],
'%solar_festival%' => $lunar_info['solar_festival'],
'%festival%' => $lunar_info['festival'],
'%solar_term%' => $lunar_info['solar_term'],
'%lunar%' => sprintf('%s年%s月%s',
$lunar_info['year'],
$lunar_info['month'],
$lunar_info['day']
)
);
if (!$display_items['year']) {
$replacements['%lunar_year%'] = '';
}
if (!$display_items['month']) {
$replacements['%lunar_month%'] = '';
}
if (!$display_items['day']) {
$replacements['%lunar_day%'] = '';
}
if (!$display_items['zodiac']) {
$replacements['%zodiac%'] = '';
}
if (!$display_items['festival']) {
$replacements['%festival%'] = '';
}
if (!$display_items['solar_term']) {
$replacements['%solar_term%'] = '';
}
$final_text = str_replace(
array_keys($replacements),
array_values($replacements),
$format
);
$final_text = preg_replace('/\s+/', ' ', $final_text);
$final_text = preg_replace('/\(\s*\)/', '', $final_text);
$final_text = trim($final_text);
wp_send_json_success(array(
'preview' => sprintf(
'<div class="preview-title">%s</div><div class="preview-content">%s</div>',
__('预览效果:', 'wpdate-calendar'),
$final_text
)
));
}
/**
* 在后台右上角显示农历日期
*/
public function display_lunar_in_admin() {
if (!get_option('wplc_show_lunar_in_admin', true)) {
return;
}
$screen = get_current_screen();
if ($screen->id !== 'dashboard') {
return;
}
$current_date = current_time('Y-m-d');
$lunar_info = $this->get_lunar_date_info($current_date);
if (!$lunar_info) {
return;
}
$lunar_text = sprintf(
'%s年%s月%s',
$lunar_info['year'],
$lunar_info['month'],
$lunar_info['day']
);
echo '
<div id="lunar-date-admin" style="float: right; padding: 5px 10px; margin: 0; font-size: 12px; line-height: 1.6666;">
' . esc_html($lunar_text) . '
</div>
';
}
}

View file

@ -0,0 +1,261 @@
<?php
class WPLC_Lunar_Converter {
// 农历数据表 1900-2100 年
private static $lunar_info = array(
0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2,//1900-1909
0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977,//1910-1919
0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970,//1920-1929
0x06566,0x0d4a0,0x0ea50,0x06e95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950,//1930-1939
0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557,//1940-1949
0x06ca0,0x0b550,0x15355,0x04da0,0x0a5b0,0x14573,0x052b0,0x0a9a8,0x0e950,0x06aa0,//1950-1959
0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0,//1960-1969
0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b6a0,0x195a6,//1970-1979
0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570,//1980-1989
0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x055c0,0x0ab60,0x096d5,0x092e0,//1990-1999
0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5,//2000-2009
0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930,//2010-2019
0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530,//2020-2029
0x05aa0,0x076a3,0x096d0,0x04afb,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45,//2030-2039
0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0,//2040-2049
);
// 天干
private static $gan = array('甲','乙','丙','丁','戊','己','庚','辛','壬','癸');
// 地支
private static $zhi = array('子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥');
// 生肖
private static $animals = array('鼠','牛','虎','兔','龙','蛇','马','羊','猴','鸡','狗','猪');
// 节气
private static $solar_terms = array(
'小寒','大寒','立春','雨水','惊蛰','春分',
'清明','谷雨','立夏','小满','芒种','夏至',
'小暑','大暑','立秋','处暑','白露','秋分',
'寒露','霜降','立冬','小雪','大雪','冬至'
);
// 节气数据表
private static $solar_terms_offset = array(
'0123', '2112', '4101', '6090',
'8079', '9068', '1157', '3146',
'5135', '7124', '9113', '1102',
'3091', '5080', '7069', '9058',
'1047', '3036', '5025', '7014',
'9003', '0992', '2981', '4970'
);
// 农历节日
private static $lunar_festivals = array(
'0101' => '春节',
'0115' => '元宵节',
'0505' => '端午节',
'0707' => '七夕节',
'0815' => '中秋节',
'0909' => '重阳节',
'1208' => '腊八节',
'1230' => '除夕'
);
// 阳历节日
private static $solar_festivals = array(
'0101' => '元旦',
'0214' => '情人节',
'0308' => '妇女节',
'0312' => '植树节',
'0401' => '愚人节',
'0501' => '劳动节',
'0504' => '青年节',
'0601' => '儿童节',
'0701' => '建党节',
'0801' => '建军节',
'0910' => '教师节',
'1001' => '国庆节',
'1225' => '圣诞节'
);
public static function solar_to_lunar($year, $month, $day) {
// 计算与1900年1月31日相差的天数
$offset = self::get_offset_days($year, $month, $day);
// 计算农历年份
$i = 1900;
for($i = 1900; $i < 2101 && $offset > 0; $i++) {
$year_days = self::get_year_days($i);
$offset -= $year_days;
}
if($offset < 0) {
$offset += $year_days;
$i--;
}
$lunar_year = $i;
// 计算农历月份
$leap = self::get_leap_month($lunar_year);
$is_leap = false;
for($i = 1; $i < 13 && $offset > 0; $i++) {
if($leap > 0 && $i == ($leap + 1) && !$is_leap) {
--$i;
$is_leap = true;
$days = self::get_leap_days($lunar_year);
} else {
$days = self::get_month_days($lunar_year, $i);
}
if($is_leap && $i == ($leap + 1)) {
$is_leap = false;
}
$offset -= $days;
}
if($offset == 0 && $leap > 0 && $i == $leap + 1) {
if($is_leap) {
$is_leap = false;
} else {
$is_leap = true;
--$i;
}
}
if($offset < 0) {
$offset += $days;
--$i;
}
$lunar_month = $i;
$lunar_day = $offset + 1;
// 计算天干地支年
$gan_year = ($lunar_year - 4) % 10;
$zhi_year = ($lunar_year - 4) % 12;
// 构建结果数组
$result = array(
'year' => $lunar_year,
'month' => $lunar_month,
'day' => $lunar_day,
'leap' => $is_leap,
'gan_year' => self::$gan[$gan_year],
'zhi_year' => self::$zhi[$zhi_year],
'animal' => self::$animals[$zhi_year]
);
// 添加节气信息
$result['solar_term'] = self::get_solar_term($year, $month, $day);
// 添加阳历节日
$solar_festival_key = sprintf('%02d%02d', $month, $day);
$result['solar_festival'] = isset(self::$solar_festivals[$solar_festival_key])
? self::$solar_festivals[$solar_festival_key]
: '';
// 添加农历节日
$lunar_festival_key = sprintf('%02d%02d', $lunar_month, $lunar_day);
$result['lunar_festival'] = isset(self::$lunar_festivals[$lunar_festival_key])
? self::$lunar_festivals[$lunar_festival_key]
: '';
// 特殊处理除夕
if ($lunar_month == 12 &&
$lunar_day == self::get_month_days($lunar_year, 12)) {
$result['lunar_festival'] = '除夕';
}
return $result;
}
private static function get_offset_days($year, $month, $day) {
$offset = 0;
for($i = 1900; $i < $year; $i++) {
if(self::is_leap_year($i)) {
$offset += 366;
} else {
$offset += 365;
}
}
for($i = 1; $i < $month; $i++) {
$offset += self::get_solar_month_days($year, $i);
}
$offset += $day - 1;
return $offset - 30;
}
private static function is_leap_year($year) {
return ($year % 4 == 0 && $year % 100 != 0) || ($year % 400 == 0);
}
private static function get_solar_month_days($year, $month) {
$days = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
if ($month == 2 && self::is_leap_year($year)) {
return 29;
}
return $days[$month - 1];
}
private static function get_year_days($year) {
$sum = 348;
for ($i = 0x8000; $i > 0x8; $i >>= 1) {
$sum += (self::$lunar_info[$year - 1900] & $i) ? 1 : 0;
}
return $sum + self::get_leap_days($year);
}
private static function get_leap_days($year) {
if (self::get_leap_month($year)) {
return (self::$lunar_info[$year - 1900] & 0x10000) ? 30 : 29;
}
return 0;
}
private static function get_leap_month($year) {
return self::$lunar_info[$year - 1900] & 0xf;
}
private static function get_month_days($year, $month) {
return (self::$lunar_info[$year - 1900] & (0x10000 >> $month)) ? 30 : 29;
}
private static function get_solar_term($year, $month, $day) {
$index = ($month - 1) * 2;
$term1_day = floor(self::get_term_day($year, $index));
$term2_day = floor(self::get_term_day($year, $index + 1));
if ($day == $term1_day) {
return self::$solar_terms[$index];
}
if ($day == $term2_day) {
return self::$solar_terms[$index + 1];
}
return '';
}
private static function get_term_day($year, $n) {
$offset = self::$solar_terms_offset[$n];
// 确保 offset 是一个有效的字符串
if (!is_string($offset) || strlen($offset) < 4) {
return 0; // 返回一个默认值以避免错误
}
$diff = $year - 1900;
$century = floor($diff / 100);
$year_offset = $diff % 100;
// 修正计算公式
$day = (int)substr($offset, 0, 2) +
$century * (int)substr($offset, 2, 1) +
floor($year_offset * (int)substr($offset, 3, 1) / 100);
return $day;
}
}

68
wpdate.php Executable file
View file

@ -0,0 +1,68 @@
<?php
/**
* Plugin Name: WPDate
* Plugin URI: https://wpdate.com/lunar-calendar
* Description: WordPress 显示中国农历日期,精准展示万年历、节气及传统节日,支持高度自定义,为您的网站增添东方文化韵味。
* Version: 1.0.0
* Author: WPDate.com
* Author URI: https://wpdate.com
* License: GPL v2 or later
* Text Domain: wpdate-calendar
* Domain Path: /languages
*/
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('WPLC_VERSION', '1.0.0');
define('WPLC_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('WPLC_PLUGIN_URL', plugin_dir_url(__FILE__));
// 加载主类
require_once WPLC_PLUGIN_DIR . 'includes/class-lunar-calendar.php';
// 初始化插件
function wpdate_lunar_calendar_init() {
return WPDate_Lunar_Calendar::get_instance();
}
// 激活插件时的处理
function wpdate_lunar_calendar_activate() {
// 添加默认选项
add_option('wplc_enable_lunar', true);
add_option('wplc_display_format', '【%lunar%】');
add_option('wplc_show_festivals', true);
add_option('wplc_show_solar_terms', true);
// 刷新重写规则
flush_rewrite_rules();
}
// 停用插件时的处理
function wpdate_lunar_calendar_deactivate() {
// 清理缓存
global $wpdb;
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_wplc_%'");
// 刷新重写规则
flush_rewrite_rules();
}
// 注册激活和停用钩子
register_activation_hook(__FILE__, 'wpdate_lunar_calendar_activate');
register_deactivation_hook(__FILE__, 'wpdate_lunar_calendar_deactivate');
// 加载语言文件
add_action('plugins_loaded', function() {
load_plugin_textdomain(
'wpdate-calendar',
false,
dirname(plugin_basename(__FILE__)) . '/languages/'
);
});
// 启动插件
add_action('plugins_loaded', 'wpdate_lunar_calendar_init');