Initial commit: TechBlog Pro WordPress theme
Features: - Modern UI with dark mode support - Code highlighting with copy button - Auto table of contents - Reading time & views counter - Responsive design - Admin settings page - AJAX search
This commit is contained in:
@@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* 404 Template
|
||||||
|
*
|
||||||
|
* @package TechBlog Pro
|
||||||
|
*/
|
||||||
|
|
||||||
|
get_header();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<article class="post-card" style="text-align: center; padding: 80px 20px;">
|
||||||
|
<div style="font-size: 6rem; margin-bottom: 24px;">🚀</div>
|
||||||
|
<h1 class="post-title" style="font-size: 2rem; margin-bottom: 16px;">404</h1>
|
||||||
|
<h2 style="font-size: 1.5rem; font-weight: 600; margin-bottom: 16px;">页面未找到</h2>
|
||||||
|
<div class="post-excerpt" style="max-width: 480px; margin: 0 auto;">
|
||||||
|
<p>抱歉,您访问的页面不存在。可能已被移动或删除。</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top: 32px; display: flex; justify-content: center; gap: 16px;">
|
||||||
|
<a href="<?php echo esc_url(home_url('/')); ?>"
|
||||||
|
style="display: inline-flex; align-items: center; gap: 8px; padding: 12px 24px; background: var(--primary-color); color: white; border-radius: 8px; font-weight: 600;">
|
||||||
|
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/>
|
||||||
|
<polyline points="9 22 9 12 15 12 15 22"/>
|
||||||
|
</svg>
|
||||||
|
返回首页
|
||||||
|
</a>
|
||||||
|
<button onclick="history.back()"
|
||||||
|
style="display: inline-flex; align-items: center; gap: 8px; padding: 12px 24px; background: var(--bg-secondary); color: var(--text-primary); border: 1px solid var(--border-color); border-radius: 8px; font-weight: 600; cursor: pointer;">
|
||||||
|
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<line x1="19" y1="12" x2="5" y2="12"/>
|
||||||
|
<polyline points="12 19 5 12 12 5"/>
|
||||||
|
</svg>
|
||||||
|
返回上页
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Search Box -->
|
||||||
|
<div style="margin-top: 48px; max-width: 400px; margin-left: auto; margin-right: auto;">
|
||||||
|
<p style="margin-bottom: 16px; color: var(--text-muted);">或者搜索您想要的内容:</p>
|
||||||
|
<form role="search" method="get" action="<?php echo esc_url(home_url('/')); ?>">
|
||||||
|
<div style="display: flex; gap: 8px;">
|
||||||
|
<input type="search" name="s" placeholder="搜索文章..."
|
||||||
|
style="flex: 1; padding: 12px 16px; border: 1px solid var(--border-color); border-radius: 8px; font-size: 1rem; background: var(--bg-primary); color: var(--text-primary);">
|
||||||
|
<button type="submit"
|
||||||
|
style="padding: 12px 20px; background: var(--primary-color); color: white; border: none; border-radius: 8px; font-weight: 600; cursor: pointer;">
|
||||||
|
搜索
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Recent Posts -->
|
||||||
|
<div style="margin-top: 48px; padding-top: 32px; border-top: 1px solid var(--border-color);">
|
||||||
|
<h3 style="font-size: 1rem; font-weight: 600; margin-bottom: 20px; color: var(--text-muted);">📖 最近发布的文章</h3>
|
||||||
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; max-width: 640px; margin: 0 auto;">
|
||||||
|
<?php
|
||||||
|
$recent = new WP_Query(array(
|
||||||
|
'posts_per_page' => 3,
|
||||||
|
'post_status' => 'publish',
|
||||||
|
));
|
||||||
|
if ($recent->have_posts()) :
|
||||||
|
while ($recent->have_posts()) : $recent->the_post();
|
||||||
|
?>
|
||||||
|
<a href="<?php the_permalink(); ?>"
|
||||||
|
style="padding: 16px; background: var(--bg-secondary); border-radius: 8px; text-align: left; border: 1px solid var(--border-color);">
|
||||||
|
<div style="font-size: 0.8125rem; color: var(--text-muted); margin-bottom: 8px;">
|
||||||
|
<?php echo get_the_date('Y-m-d'); ?>
|
||||||
|
</div>
|
||||||
|
<div style="font-weight: 500; color: var(--text-primary); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;">
|
||||||
|
<?php the_title(); ?>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<?php
|
||||||
|
endwhile;
|
||||||
|
wp_reset_postdata();
|
||||||
|
endif;
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<?php get_footer(); ?>
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
# TechBlog Pro - WordPress Theme
|
||||||
|
|
||||||
|
一个专为IT技术分享设计的现代化WordPress主题,具有清爽的界面、强大的代码高亮支持和优秀的阅读体验。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## ✨ 特性
|
||||||
|
|
||||||
|
### 🎨 设计特色
|
||||||
|
- **现代化UI** - 清爽简洁的设计风格
|
||||||
|
- **暗色模式** - 一键切换深色/浅色主题
|
||||||
|
- **响应式布局** - 完美适配各种设备
|
||||||
|
- **流畅动画** - 细腻的过渡效果
|
||||||
|
|
||||||
|
### 📝 博客功能
|
||||||
|
- **代码高亮** - 专门优化的代码块样式
|
||||||
|
- **一键复制** - 代码块支持快速复制
|
||||||
|
- **阅读时间** - 自动计算文章阅读时间
|
||||||
|
- **阅读进度** - 顶部进度条显示
|
||||||
|
- **文章目录** - 自动生成TOC目录导航
|
||||||
|
- **阅读统计** - 记录文章浏览次数
|
||||||
|
|
||||||
|
### 🔧 技术特性
|
||||||
|
- **SEO友好** - 语义化HTML结构
|
||||||
|
- **性能优化** - 图片懒加载、平滑滚动
|
||||||
|
- **键盘快捷键** - Ctrl+K 搜索、ESC 关闭
|
||||||
|
- **AJAX搜索** - 实时搜索建议
|
||||||
|
- **自定义小工具** - 分类、标签、最新文章
|
||||||
|
|
||||||
|
## 📦 安装
|
||||||
|
|
||||||
|
### 方法一:后台上传
|
||||||
|
1. 下载主题zip文件
|
||||||
|
2. 进入 WordPress 后台 → 外观 → 主题
|
||||||
|
3. 点击「添加」→「上传主题」
|
||||||
|
4. 选择下载的zip文件并安装
|
||||||
|
5. 激活主题
|
||||||
|
|
||||||
|
### 方法二:FTP上传
|
||||||
|
1. 解压主题文件
|
||||||
|
2. 通过FTP上传到 `/wp-content/themes/techblog-wp-theme/`
|
||||||
|
3. 进入 WordPress 后台 → 外观 → 主题
|
||||||
|
4. 激活 TechBlog Pro 主题
|
||||||
|
|
||||||
|
## ⚙️ 配置
|
||||||
|
|
||||||
|
### 菜单设置
|
||||||
|
进入 **外观 → 菜单**:
|
||||||
|
- 创建一个新菜单
|
||||||
|
- 选择「主导航菜单」位置
|
||||||
|
- 添加分类/页面/自定义链接
|
||||||
|
|
||||||
|
### 小工具设置
|
||||||
|
进入 **外观 → 小工具**:
|
||||||
|
- **主侧边栏** - 文章页面右侧显示
|
||||||
|
- **页脚栏 1/2/3** - 页脚三列布局
|
||||||
|
|
||||||
|
### 自定义设置
|
||||||
|
进入 **外观 → 自定义**:
|
||||||
|
- **首页横幅** - 设置首页标题和描述
|
||||||
|
- **社交媒体** - 添加社交链接(GitHub、Twitter等)
|
||||||
|
|
||||||
|
### 代码块语言
|
||||||
|
在编辑器中使用代码块时,设置语言可以显示对应的标签:
|
||||||
|
```
|
||||||
|
// 语言会自动显示在代码块左上角
|
||||||
|
console.log('Hello World');
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 推荐分类结构
|
||||||
|
|
||||||
|
适合IT技术博客的分类建议:
|
||||||
|
|
||||||
|
```
|
||||||
|
├── Linux
|
||||||
|
│ ├── 系统管理
|
||||||
|
│ ├── Shell脚本
|
||||||
|
│ └── 性能优化
|
||||||
|
├── DevOps
|
||||||
|
│ ├── Docker
|
||||||
|
│ ├── Kubernetes
|
||||||
|
│ ├── CI/CD
|
||||||
|
│ └── 监控运维
|
||||||
|
├── 编程开发
|
||||||
|
│ ├── Python
|
||||||
|
│ ├── Go
|
||||||
|
│ ├── JavaScript
|
||||||
|
│ └── 数据库
|
||||||
|
├── 云计算
|
||||||
|
│ ├── AWS
|
||||||
|
│ ├── Azure
|
||||||
|
│ └── 阿里云
|
||||||
|
└── 网络安全
|
||||||
|
├── 防火墙
|
||||||
|
└── 渗透测试
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📁 文件结构
|
||||||
|
|
||||||
|
```
|
||||||
|
techblog-wp-theme/
|
||||||
|
├── style.css # 主样式表
|
||||||
|
├── functions.php # 主题函数
|
||||||
|
├── header.php # 页头模板
|
||||||
|
├── footer.php # 页脚模板
|
||||||
|
├── index.php # 首页模板
|
||||||
|
├── single.php # 文章详情模板
|
||||||
|
├── page.php # 页面模板
|
||||||
|
├── archive.php # 归档模板
|
||||||
|
├── search.php # 搜索结果模板
|
||||||
|
├── 404.php # 404页面模板
|
||||||
|
├── comments.php # 评论模板
|
||||||
|
├── js/
|
||||||
|
│ └── main.js # 主脚本文件
|
||||||
|
└── README.md # 主题说明文档
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🛠️ 开发指南
|
||||||
|
|
||||||
|
### 添加自定义样式
|
||||||
|
在子主题或自定义CSS中添加:
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* 自定义主色调 */
|
||||||
|
:root {
|
||||||
|
--primary-color: #your-color;
|
||||||
|
--secondary-color: #your-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 自定义代码块背景 */
|
||||||
|
.post-content pre {
|
||||||
|
background: #your-code-bg;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 添加自定义功能
|
||||||
|
在子主题的 `functions.php` 中添加:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// 添加自定义功能
|
||||||
|
function my_custom_features() {
|
||||||
|
// 你的代码
|
||||||
|
}
|
||||||
|
add_action('after_setup_theme', 'my_custom_features');
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🌐 浏览器支持
|
||||||
|
|
||||||
|
- Chrome (最新)
|
||||||
|
- Firefox (最新)
|
||||||
|
- Safari (最新)
|
||||||
|
- Edge (最新)
|
||||||
|
|
||||||
|
## 📝 更新日志
|
||||||
|
|
||||||
|
### v1.0.0 (2024)
|
||||||
|
- 初始版本发布
|
||||||
|
- 暗色模式支持
|
||||||
|
- 代码高亮和复制功能
|
||||||
|
- 目录自动生成
|
||||||
|
- 响应式设计
|
||||||
|
|
||||||
|
## 💡 使用技巧
|
||||||
|
|
||||||
|
### 快捷键
|
||||||
|
- `Ctrl + K` / `Cmd + K` - 打开搜索
|
||||||
|
- `ESC` - 关闭搜索/弹窗
|
||||||
|
|
||||||
|
### Markdown 支持
|
||||||
|
主题完美支持 Gutenberg 编辑器中的代码块,建议使用 WordPress 内置的代码块功能。
|
||||||
|
|
||||||
|
### 图片优化
|
||||||
|
- 建议文章图片宽度 780px
|
||||||
|
- 使用 WebP 格式可提升加载速度
|
||||||
|
- 主题自动支持图片懒加载
|
||||||
|
|
||||||
|
## 🤝 贡献
|
||||||
|
|
||||||
|
欢迎提交 Issue 和 Pull Request!
|
||||||
|
|
||||||
|
## 📄 许可证
|
||||||
|
|
||||||
|
GPL v2 or later
|
||||||
|
|
||||||
|
## 👨💻 作者
|
||||||
|
|
||||||
|
TechBlog Team
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**享受你的技术写作之旅!** 🚀
|
||||||
Executable
+143
@@ -0,0 +1,143 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Archive Template
|
||||||
|
*
|
||||||
|
* @package TechBlog Pro
|
||||||
|
*/
|
||||||
|
|
||||||
|
get_header();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!-- Archive Header -->
|
||||||
|
<div class="archive-header" style="margin-bottom: 32px;">
|
||||||
|
<?php if (is_category()) : ?>
|
||||||
|
<h1 style="font-size: 1.75rem; font-weight: 700; margin-bottom: 8px;">
|
||||||
|
📂 <?php single_cat_title(); ?>
|
||||||
|
</h1>
|
||||||
|
<?php if (category_description()) : ?>
|
||||||
|
<p style="color: var(--text-secondary);"><?php echo category_description(); ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
<p style="color: var(--text-muted); font-size: 0.9375rem;">
|
||||||
|
共 <?php echo $wp_query->found_posts; ?> 篇文章
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<?php elseif (is_tag()) : ?>
|
||||||
|
<h1 style="font-size: 1.75rem; font-weight: 700; margin-bottom: 8px;">
|
||||||
|
🏷️ 标签:<?php single_tag_title(); ?>
|
||||||
|
</h1>
|
||||||
|
<p style="color: var(--text-muted); font-size: 0.9375rem;">
|
||||||
|
共 <?php echo $wp_query->found_posts; ?> 篇文章
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<?php elseif (is_author()) : ?>
|
||||||
|
<h1 style="font-size: 1.75rem; font-weight: 700; margin-bottom: 8px;">
|
||||||
|
👤 作者:<?php the_author(); ?>
|
||||||
|
</h1>
|
||||||
|
<?php if (get_the_author_meta('description')) : ?>
|
||||||
|
<p style="color: var(--text-secondary);"><?php echo get_the_author_meta('description'); ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php elseif (is_year()) : ?>
|
||||||
|
<h1 style="font-size: 1.75rem; font-weight: 700; margin-bottom: 8px;">
|
||||||
|
📅 <?php echo get_the_date('Y'); ?> 年
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<?php elseif (is_month()) : ?>
|
||||||
|
<h1 style="font-size: 1.75rem; font-weight: 700; margin-bottom: 8px;">
|
||||||
|
📅 <?php echo get_the_date('Y年m月'); ?>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<?php elseif (is_day()) : ?>
|
||||||
|
<h1 style="font-size: 1.75rem; font-weight: 700; margin-bottom: 8px;">
|
||||||
|
📅 <?php echo get_the_date('Y年m月d日'); ?>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<?php elseif (is_search()) : ?>
|
||||||
|
<h1 style="font-size: 1.75rem; font-weight: 700; margin-bottom: 8px;">
|
||||||
|
🔍 搜索:<?php echo get_search_query(); ?>
|
||||||
|
</h1>
|
||||||
|
<p style="color: var(--text-muted); font-size: 0.9375rem;">
|
||||||
|
找到 <?php echo $wp_query->found_posts; ?> 个结果
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<?php else : ?>
|
||||||
|
<h1 style="font-size: 1.75rem; font-weight: 700; margin-bottom: 8px;">
|
||||||
|
📄 归档
|
||||||
|
</h1>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Posts Grid -->
|
||||||
|
<div class="posts-grid">
|
||||||
|
<?php if (have_posts()) : ?>
|
||||||
|
<?php while (have_posts()) : the_post(); ?>
|
||||||
|
<article class="post-card" <?php post_class(); ?>>
|
||||||
|
<div class="post-card-header">
|
||||||
|
<?php
|
||||||
|
$categories = get_the_category();
|
||||||
|
if (!empty($categories)) :
|
||||||
|
?>
|
||||||
|
<a href="<?php echo esc_url(get_category_link($categories[0]->term_id)); ?>" class="post-category">
|
||||||
|
<?php echo esc_html($categories[0]->name); ?>
|
||||||
|
</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<span class="post-date">
|
||||||
|
<time datetime="<?php echo get_the_date('c'); ?>">
|
||||||
|
<?php echo get_the_date('Y年m月d日'); ?>
|
||||||
|
</time>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 class="post-card-title">
|
||||||
|
<a href="<?php the_permalink(); ?>">
|
||||||
|
<?php the_title(); ?>
|
||||||
|
</a>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="post-excerpt">
|
||||||
|
<?php the_excerpt(); ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="post-card-footer">
|
||||||
|
<div class="post-meta">
|
||||||
|
<span class="post-meta-item">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<circle cx="12" cy="12" r="10"/>
|
||||||
|
<polyline points="12,6 12,12 16,14"/>
|
||||||
|
</svg>
|
||||||
|
<?php echo techblog_reading_time(); ?> 分钟阅读
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a href="<?php the_permalink(); ?>" class="read-more">
|
||||||
|
阅读全文
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<line x1="5" y1="12" x2="19" y2="12"/>
|
||||||
|
<polyline points="12,5 19,12 12,19"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<?php endwhile; ?>
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
<?php
|
||||||
|
the_posts_pagination(array(
|
||||||
|
'mid_size' => 2,
|
||||||
|
'prev_text' => '← 上一页',
|
||||||
|
'next_text' => '下一页 →',
|
||||||
|
));
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php else : ?>
|
||||||
|
<article class="post-card">
|
||||||
|
<h2 class="post-card-title">暂无文章</h2>
|
||||||
|
<div class="post-excerpt">
|
||||||
|
<p>该分类下暂无文章。</p>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php get_footer(); ?>
|
||||||
Executable
+118
@@ -0,0 +1,118 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Comments Template
|
||||||
|
*
|
||||||
|
* @package TechBlog Pro
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (post_password_required()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div id="comments" class="comments-area">
|
||||||
|
|
||||||
|
<?php if (have_comments()) : ?>
|
||||||
|
<h3 class="comments-title">
|
||||||
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/>
|
||||||
|
</svg>
|
||||||
|
<?php
|
||||||
|
$comments_number = get_comments_number();
|
||||||
|
printf(
|
||||||
|
esc_html(_n('%d 条评论', '%d 条评论', $comments_number, 'techblog')),
|
||||||
|
$comments_number
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<ol class="comment-list">
|
||||||
|
<?php
|
||||||
|
wp_list_comments(array(
|
||||||
|
'style' => 'ol',
|
||||||
|
'short_ping' => true,
|
||||||
|
'avatar_size' => 48,
|
||||||
|
'callback' => 'techblog_comment_template',
|
||||||
|
));
|
||||||
|
?>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
the_comments_navigation(array(
|
||||||
|
'prev_text' => '← 较旧的评论',
|
||||||
|
'next_text' => '较新的评论 →',
|
||||||
|
));
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (!comments_open() && get_comments_number() && post_type_supports(get_post_type(), 'comments')) : ?>
|
||||||
|
<p class="no-comments">评论已关闭</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
comment_form(array(
|
||||||
|
'class_form' => 'comment-form',
|
||||||
|
'title_reply' => '',
|
||||||
|
'comment_notes_before' => '',
|
||||||
|
'comment_field' => '
|
||||||
|
<div class="comment-form-group">
|
||||||
|
<label for="comment">
|
||||||
|
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/>
|
||||||
|
</svg>
|
||||||
|
发表评论
|
||||||
|
</label>
|
||||||
|
<textarea id="comment" name="comment" rows="4" required placeholder="说点什么..."></textarea>
|
||||||
|
</div>',
|
||||||
|
'submit_button' => '<button type="submit" class="submit-btn">
|
||||||
|
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<line x1="22" y1="2" x2="11" y2="13"/>
|
||||||
|
<polygon points="22 2 15 22 11 13 2 9 22 2"/>
|
||||||
|
</svg>
|
||||||
|
提交评论
|
||||||
|
</button>',
|
||||||
|
));
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Custom Comment Template
|
||||||
|
*/
|
||||||
|
function techblog_comment_template($comment, $args, $depth) {
|
||||||
|
$tag = ('div' === $args['style']) ? 'div' : 'li';
|
||||||
|
?>
|
||||||
|
<<?php echo $tag; ?> id="comment-<?php comment_ID(); ?>" <?php comment_class('comment-item'); ?>>
|
||||||
|
<div class="comment-body">
|
||||||
|
<div class="comment-avatar">
|
||||||
|
<?php echo get_avatar($comment, 48); ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="comment-content">
|
||||||
|
<div class="comment-header">
|
||||||
|
<span class="comment-author">
|
||||||
|
<?php echo get_comment_author_link(); ?>
|
||||||
|
</span>
|
||||||
|
<time datetime="<?php echo get_comment_date('c'); ?>">
|
||||||
|
<?php echo get_comment_date('Y年m月d日'); ?>
|
||||||
|
</time>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="comment-text">
|
||||||
|
<?php comment_text(); ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="comment-actions">
|
||||||
|
<?php
|
||||||
|
comment_reply_link(array_merge($args, array(
|
||||||
|
'depth' => $depth,
|
||||||
|
'max_depth' => $args['max_depth'],
|
||||||
|
)));
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
+194
@@ -0,0 +1,194 @@
|
|||||||
|
/* TechBlog Pro Admin Styles */
|
||||||
|
|
||||||
|
.techblog-admin-wrapper {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 200px 1fr;
|
||||||
|
gap: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #ccd0d4;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
height: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab-wrapper .nav-tab {
|
||||||
|
display: block;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid #ccd0d4;
|
||||||
|
border-radius: 0;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
text-decoration: none;
|
||||||
|
color: #2271b1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab-wrapper .nav-tab:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab-wrapper .nav-tab:hover {
|
||||||
|
background: #f0f0f1;
|
||||||
|
color: #135e96;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab-wrapper .nav-tab.nav-tab-active {
|
||||||
|
background: #2563eb;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #2563eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content {
|
||||||
|
display: none;
|
||||||
|
background: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #ccd0d4;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content .form-table th {
|
||||||
|
width: 150px;
|
||||||
|
padding: 15px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content .form-table td {
|
||||||
|
padding: 15px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content .form-table input[type="text"],
|
||||||
|
.tab-content .form-table input[type="url"],
|
||||||
|
.tab-content .form-table input[type="email"],
|
||||||
|
.tab-content .form-table textarea,
|
||||||
|
.tab-content .form-table select {
|
||||||
|
min-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content .form-table input[type="color"] {
|
||||||
|
width: 60px;
|
||||||
|
height: 36px;
|
||||||
|
padding: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content .form-table fieldset label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content .form-table fieldset input[type="checkbox"] {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* About Card */
|
||||||
|
.techblog-about-card {
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techblog-about-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techblog-about-header h2 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techblog-about-header .version {
|
||||||
|
background: #2563eb;
|
||||||
|
color: #fff;
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 100px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techblog-about-card h3 {
|
||||||
|
margin-top: 24px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techblog-about-card ul {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techblog-about-card li {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techblog-about-card a {
|
||||||
|
color: #2563eb;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techblog-about-card a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Submit Button */
|
||||||
|
.submit {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit .button-primary {
|
||||||
|
background: #2563eb;
|
||||||
|
border-color: #2563eb;
|
||||||
|
padding: 0 20px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 14px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit .button-primary:hover {
|
||||||
|
background: #1d4ed8;
|
||||||
|
border-color: #1d4ed8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 782px) {
|
||||||
|
.techblog-admin-wrapper {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab-wrapper {
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab-wrapper .nav-tab {
|
||||||
|
border-bottom: none;
|
||||||
|
border-right: 1px solid #ccd0d4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab-wrapper .nav-tab:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content .form-table input[type="text"],
|
||||||
|
.tab-content .form-table input[type="url"],
|
||||||
|
.tab-content .form-table input[type="email"],
|
||||||
|
.tab-content .form-table textarea,
|
||||||
|
.tab-content .form-table select {
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+130
@@ -0,0 +1,130 @@
|
|||||||
|
</div><!-- /.content-area -->
|
||||||
|
|
||||||
|
<!-- Sidebar -->
|
||||||
|
<aside class="sidebar">
|
||||||
|
<?php if (is_active_sidebar('sidebar-main')) : ?>
|
||||||
|
<?php dynamic_sidebar('sidebar-main'); ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<!-- Default Sidebar Content -->
|
||||||
|
|
||||||
|
<!-- Categories Widget -->
|
||||||
|
<div class="sidebar-widget">
|
||||||
|
<h3 class="widget-title">📂 文章分类</h3>
|
||||||
|
<ul class="category-list">
|
||||||
|
<?php
|
||||||
|
$categories = get_categories(array(
|
||||||
|
'orderby' => 'count',
|
||||||
|
'order' => 'DESC',
|
||||||
|
'number' => 10,
|
||||||
|
));
|
||||||
|
foreach ($categories as $cat) :
|
||||||
|
?>
|
||||||
|
<li>
|
||||||
|
<a href="<?php echo esc_url(get_category_link($cat->term_id)); ?>">
|
||||||
|
<?php echo esc_html($cat->name); ?>
|
||||||
|
<span class="category-count"><?php echo $cat->count; ?></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Recent Posts Widget -->
|
||||||
|
<div class="sidebar-widget">
|
||||||
|
<h3 class="widget-title">📝 最新文章</h3>
|
||||||
|
<ul class="recent-posts-list">
|
||||||
|
<?php
|
||||||
|
$recent_posts = new WP_Query(array(
|
||||||
|
'posts_per_page' => 5,
|
||||||
|
'post_status' => 'publish',
|
||||||
|
));
|
||||||
|
if ($recent_posts->have_posts()) :
|
||||||
|
while ($recent_posts->have_posts()) : $recent_posts->the_post();
|
||||||
|
?>
|
||||||
|
<li>
|
||||||
|
<a href="<?php the_permalink(); ?>" class="recent-post-title">
|
||||||
|
<?php the_title(); ?>
|
||||||
|
</a>
|
||||||
|
<span class="recent-post-date">
|
||||||
|
<?php echo get_the_date('Y-m-d'); ?>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<?php
|
||||||
|
endwhile;
|
||||||
|
wp_reset_postdata();
|
||||||
|
endif;
|
||||||
|
?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tags Widget -->
|
||||||
|
<div class="sidebar-widget">
|
||||||
|
<h3 class="widget-title">🏷️ 热门标签</h3>
|
||||||
|
<div class="tag-cloud">
|
||||||
|
<?php
|
||||||
|
$tags = get_tags(array(
|
||||||
|
'orderby' => 'count',
|
||||||
|
'order' => 'DESC',
|
||||||
|
'number' => 20,
|
||||||
|
));
|
||||||
|
foreach ($tags as $tag) :
|
||||||
|
?>
|
||||||
|
<a href="<?php echo esc_url(get_tag_link($tag->term_id)); ?>">
|
||||||
|
<?php echo esc_html($tag->name); ?>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</aside>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="site-footer">
|
||||||
|
<div class="footer-inner">
|
||||||
|
<?php if (is_active_sidebar('footer-1')) : ?>
|
||||||
|
<?php dynamic_sidebar('footer-1'); ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<div class="footer-section">
|
||||||
|
<h3>关于我们</h3>
|
||||||
|
<p>一个专注于IT技术分享的博客,涵盖Linux运维、编程开发、云计算、容器技术等领域。</p>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (is_active_sidebar('footer-2')) : ?>
|
||||||
|
<?php dynamic_sidebar('footer-2'); ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<div class="footer-section">
|
||||||
|
<h3>快速链接</h3>
|
||||||
|
<ul class="footer-links">
|
||||||
|
<li><a href="<?php echo esc_url(home_url('/')); ?>">首页</a></li>
|
||||||
|
<li><a href="<?php echo esc_url(get_permalink(get_option('page_for_posts'))); ?>">博客</a></li>
|
||||||
|
<li><a href="<?php echo esc_url(home_url('/category/linux')); ?>">Linux</a></li>
|
||||||
|
<li><a href="<?php echo esc_url(home_url('/category/docker')); ?>">Docker</a></li>
|
||||||
|
<li><a href="<?php echo esc_url(home_url('/category/kubernetes')); ?>">Kubernetes</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (is_active_sidebar('footer-3')) : ?>
|
||||||
|
<?php dynamic_sidebar('footer-3'); ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<div class="footer-section">
|
||||||
|
<h3>联系方式</h3>
|
||||||
|
<ul class="footer-links">
|
||||||
|
<li><a href="https://github.com" target="_blank">GitHub</a></li>
|
||||||
|
<li><a href="mailto:contact@example.com">Email</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer-bottom">
|
||||||
|
<span>© <?php echo date('Y'); ?> <?php bloginfo('name'); ?>. All rights reserved.</span>
|
||||||
|
<span>Powered by WordPress | Theme: TechBlog Pro</span>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<?php wp_footer(); ?>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Executable
+459
@@ -0,0 +1,459 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* TechBlog Pro Theme Functions
|
||||||
|
*
|
||||||
|
* @package TechBlog Pro
|
||||||
|
* @version 1.0.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
defined('ABSPATH') || exit;
|
||||||
|
|
||||||
|
// Theme Constants
|
||||||
|
define('TECHBLOG_VERSION', '1.0.0');
|
||||||
|
define('TECHBLOG_DIR', get_template_directory());
|
||||||
|
define('TECHBLOG_URI', get_template_directory_uri());
|
||||||
|
|
||||||
|
// Include admin options
|
||||||
|
require_once TECHBLOG_DIR . '/inc/admin-options.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Theme Setup
|
||||||
|
*/
|
||||||
|
function techblog_setup() {
|
||||||
|
// Add theme support
|
||||||
|
add_theme_support('title-tag');
|
||||||
|
add_theme_support('post-thumbnails');
|
||||||
|
add_theme_support('custom-logo', array(
|
||||||
|
'height' => 40,
|
||||||
|
'width' => 200,
|
||||||
|
'flex-height' => true,
|
||||||
|
'flex-width' => true,
|
||||||
|
));
|
||||||
|
add_theme_support('html5', array(
|
||||||
|
'search-form',
|
||||||
|
'comment-form',
|
||||||
|
'comment-list',
|
||||||
|
'gallery',
|
||||||
|
'caption',
|
||||||
|
'style',
|
||||||
|
'script',
|
||||||
|
));
|
||||||
|
add_theme_support('editor-styles');
|
||||||
|
add_theme_support('responsive-embeds');
|
||||||
|
add_theme_support('wp-block-styles');
|
||||||
|
|
||||||
|
// Register Navigation Menus
|
||||||
|
register_nav_menus(array(
|
||||||
|
'primary' => esc_html__('主导航菜单', 'techblog'),
|
||||||
|
'footer' => esc_html__('页脚菜单', 'techblog'),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Set content width
|
||||||
|
if (!isset($content_width)) {
|
||||||
|
$content_width = 780;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action('after_setup_theme', 'techblog_setup');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue Styles and Scripts
|
||||||
|
*/
|
||||||
|
function techblog_scripts() {
|
||||||
|
// Google Fonts
|
||||||
|
wp_enqueue_style('techblog-fonts',
|
||||||
|
'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap',
|
||||||
|
array(),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
// Main Stylesheet
|
||||||
|
wp_enqueue_style('techblog-style',
|
||||||
|
get_stylesheet_uri(),
|
||||||
|
array(),
|
||||||
|
TECHBLOG_VERSION
|
||||||
|
);
|
||||||
|
|
||||||
|
// Main JavaScript
|
||||||
|
wp_enqueue_script('techblog-main',
|
||||||
|
TECHBLOG_URI . '/js/main.js',
|
||||||
|
array(),
|
||||||
|
TECHBLOG_VERSION,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Localize script
|
||||||
|
wp_localize_script('techblog-main', 'techblog', array(
|
||||||
|
'ajaxurl' => admin_url('admin-ajax.php'),
|
||||||
|
'nonce' => wp_create_nonce('techblog-nonce'),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
add_action('wp_enqueue_scripts', 'techblog_scripts');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register Sidebars
|
||||||
|
*/
|
||||||
|
function techblog_widgets_init() {
|
||||||
|
register_sidebar(array(
|
||||||
|
'name' => esc_html__('主侧边栏', 'techblog'),
|
||||||
|
'id' => 'sidebar-main',
|
||||||
|
'description' => esc_html__('文章页面右侧的侧边栏', 'techblog'),
|
||||||
|
'before_widget' => '<div id="%1$s" class="sidebar-widget %2$s">',
|
||||||
|
'after_widget' => '</div>',
|
||||||
|
'before_title' => '<h3 class="widget-title">',
|
||||||
|
'after_title' => '</h3>',
|
||||||
|
));
|
||||||
|
|
||||||
|
register_sidebar(array(
|
||||||
|
'name' => esc_html__('页脚栏 1', 'techblog'),
|
||||||
|
'id' => 'footer-1',
|
||||||
|
'description' => esc_html__('页脚第一列', 'techblog'),
|
||||||
|
'before_widget' => '<div id="%1$s" class="footer-section %2$s">',
|
||||||
|
'after_widget' => '</div>',
|
||||||
|
'before_title' => '<h3>',
|
||||||
|
'after_title' => '</h3>',
|
||||||
|
));
|
||||||
|
|
||||||
|
register_sidebar(array(
|
||||||
|
'name' => esc_html__('页脚栏 2', 'techblog'),
|
||||||
|
'id' => 'footer-2',
|
||||||
|
'description' => esc_html__('页脚第二列', 'techblog'),
|
||||||
|
'before_widget' => '<div id="%1$s" class="footer-section %2$s">',
|
||||||
|
'after_widget' => '</div>',
|
||||||
|
'before_title' => '<h3>',
|
||||||
|
'after_title' => '</h3>',
|
||||||
|
));
|
||||||
|
|
||||||
|
register_sidebar(array(
|
||||||
|
'name' => esc_html__('页脚栏 3', 'techblog'),
|
||||||
|
'id' => 'footer-3',
|
||||||
|
'description' => esc_html__('页脚第三列', 'techblog'),
|
||||||
|
'before_widget' => '<div id="%1$s" class="footer-section %2$s">',
|
||||||
|
'after_widget' => '</div>',
|
||||||
|
'before_title' => '<h3>',
|
||||||
|
'after_title' => '</h3>',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
add_action('widgets_init', 'techblog_widgets_init');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom Excerpt Length
|
||||||
|
*/
|
||||||
|
function techblog_excerpt_length($length) {
|
||||||
|
return 25;
|
||||||
|
}
|
||||||
|
add_filter('excerpt_length', 'techblog_excerpt_length');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom Excerpt More
|
||||||
|
*/
|
||||||
|
function techblog_excerpt_more($more) {
|
||||||
|
return '...';
|
||||||
|
}
|
||||||
|
add_filter('excerpt_more', 'techblog_excerpt_more');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add Code Language Class to Pre Tags
|
||||||
|
*/
|
||||||
|
function techblog_code_block_attributes($block_content, $block) {
|
||||||
|
if ($block['blockName'] === 'core/code') {
|
||||||
|
if (!empty($block['attrs']['language'])) {
|
||||||
|
$lang = esc_attr($block['attrs']['language']);
|
||||||
|
$block_content = str_replace(
|
||||||
|
'<pre class="wp-block-code',
|
||||||
|
'<pre class="wp-block-code lang-' . $lang,
|
||||||
|
$block_content
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $block_content;
|
||||||
|
}
|
||||||
|
add_filter('render_block', 'techblog_code_block_attributes', 10, 2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate Table of Contents
|
||||||
|
*/
|
||||||
|
function techblog_generate_toc($content) {
|
||||||
|
if (!is_single()) {
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
preg_match_all('/<h([2-3])[^>]*>(.*?)<\/h[2-3]>/is', $content, $matches, PREG_SET_ORDER);
|
||||||
|
|
||||||
|
if (count($matches) < 3) {
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
$toc = '<div class="toc-container"><nav class="toc">';
|
||||||
|
$toc .= '<div class="toc-title"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 6h16M4 12h16M4 18h16"/></svg> 目录</div>';
|
||||||
|
$toc .= '<ul class="toc-list">';
|
||||||
|
|
||||||
|
$headings = array();
|
||||||
|
|
||||||
|
foreach ($matches as $match) {
|
||||||
|
$level = $match[1];
|
||||||
|
$text = strip_tags($match[2]);
|
||||||
|
$id = sanitize_title($text);
|
||||||
|
$id = preg_replace('/[^a-z0-9\-]/', '', $id);
|
||||||
|
|
||||||
|
// Ensure unique IDs
|
||||||
|
if (in_array($id, $headings)) {
|
||||||
|
$id .= '-' . count($headings);
|
||||||
|
}
|
||||||
|
$headings[] = $id;
|
||||||
|
|
||||||
|
$class = $level == 3 ? ' class="toc-h3"' : '';
|
||||||
|
$toc .= '<li><a href="#' . esc_attr($id) . '"' . $class . '>' . esc_html($text) . '</a></li>';
|
||||||
|
|
||||||
|
// Add ID to heading in content
|
||||||
|
$content = str_replace(
|
||||||
|
$match[0],
|
||||||
|
'<h' . $level . ' id="' . esc_attr($id) . '">' . $match[2] . '</h' . $level . '>',
|
||||||
|
$content
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$toc .= '</ul></nav></div>';
|
||||||
|
|
||||||
|
// Insert TOC after first paragraph or before first heading
|
||||||
|
$first_p = strpos($content, '</p>');
|
||||||
|
if ($first_p !== false) {
|
||||||
|
$content = substr($content, 0, $first_p + 4) . $toc . substr($content, $first_p + 4);
|
||||||
|
} else {
|
||||||
|
$content = $toc . $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
add_filter('the_content', 'techblog_generate_toc', 20);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add Copy Button to Code Blocks
|
||||||
|
*/
|
||||||
|
function techblog_add_code_copy_button($content) {
|
||||||
|
if (!is_single() && !is_page()) {
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = preg_replace_callback(
|
||||||
|
'/<pre([^>]*)>(.*?)<\/pre>/is',
|
||||||
|
function($matches) {
|
||||||
|
$attrs = $matches[1];
|
||||||
|
$code = $matches[2];
|
||||||
|
|
||||||
|
// Extract language if present
|
||||||
|
$lang = '';
|
||||||
|
if (preg_match('/lang-([a-z0-9]+)/', $attrs, $lang_match)) {
|
||||||
|
$lang = strtoupper($lang_match[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$header = '<div class="code-header">';
|
||||||
|
$header .= '<span class="code-lang">' . ($lang ?: 'CODE') . '</span>';
|
||||||
|
$header .= '<button class="copy-btn" onclick="copyCode(this)">';
|
||||||
|
$header .= '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>';
|
||||||
|
$header .= '复制</button></div>';
|
||||||
|
|
||||||
|
return '<pre' . $attrs . '>' . $header . $code . '</pre>';
|
||||||
|
},
|
||||||
|
$content
|
||||||
|
);
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
add_filter('the_content', 'techblog_add_code_copy_button', 25);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom Walker for Navigation Menu
|
||||||
|
*/
|
||||||
|
class TechBlog_Nav_Walker extends Walker_Nav_Menu {
|
||||||
|
function start_el(&$output, $item, $depth = 0, $args = null, $id = 0) {
|
||||||
|
$classes = empty($item->classes) ? array() : (array) $item->classes;
|
||||||
|
$class = join(' ', array_filter($classes));
|
||||||
|
|
||||||
|
if (in_array('current-menu-item', $classes) || in_array('current_page_item', $classes)) {
|
||||||
|
$class .= ' current';
|
||||||
|
}
|
||||||
|
|
||||||
|
$output .= '<a href="' . esc_url($item->url) . '" class="' . esc_attr($class) . '">';
|
||||||
|
$output .= esc_html($item->title);
|
||||||
|
$output .= '</a>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reading Time
|
||||||
|
*/
|
||||||
|
function techblog_reading_time() {
|
||||||
|
$content = get_the_content();
|
||||||
|
$word_count = str_word_count(strip_tags($content));
|
||||||
|
$reading_time = ceil($word_count / 200); // Average reading speed
|
||||||
|
return $reading_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Post Views (Simple implementation)
|
||||||
|
*/
|
||||||
|
function techblog_get_post_views() {
|
||||||
|
$count = get_post_meta(get_the_ID(), 'post_views', true);
|
||||||
|
return $count ? intval($count) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function techblog_set_post_views() {
|
||||||
|
if (!is_single()) return;
|
||||||
|
|
||||||
|
$post_id = get_the_ID();
|
||||||
|
$count = get_post_meta($post_id, 'post_views', true);
|
||||||
|
|
||||||
|
if ($count == '') {
|
||||||
|
$count = 0;
|
||||||
|
delete_post_meta($post_id, 'post_views');
|
||||||
|
add_post_meta($post_id, 'post_views', '0');
|
||||||
|
} else {
|
||||||
|
$count++;
|
||||||
|
update_post_meta($post_id, 'post_views', $count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action('wp_head', 'techblog_set_post_views');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format View Count
|
||||||
|
*/
|
||||||
|
function techblog_format_views($count) {
|
||||||
|
if ($count >= 10000) {
|
||||||
|
return round($count / 10000, 1) . 'w';
|
||||||
|
} elseif ($count >= 1000) {
|
||||||
|
return round($count / 1000, 1) . 'k';
|
||||||
|
}
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom Comment Form
|
||||||
|
*/
|
||||||
|
function techblog_comment_form_defaults($defaults) {
|
||||||
|
$defaults['comment_notes_before'] = '';
|
||||||
|
$defaults['comment_field'] = '<div class="comment-form-field">
|
||||||
|
<textarea id="comment" name="comment" rows="5" required></textarea>
|
||||||
|
</div>';
|
||||||
|
return $defaults;
|
||||||
|
}
|
||||||
|
add_filter('comment_form_defaults', 'techblog_comment_form_defaults');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Theme Customizer
|
||||||
|
*/
|
||||||
|
function techblog_customize_register($wp_customize) {
|
||||||
|
// Hero Section
|
||||||
|
$wp_customize->add_section('techblog_hero', array(
|
||||||
|
'title' => esc_html__('首页横幅', 'techblog'),
|
||||||
|
'priority' => 30,
|
||||||
|
));
|
||||||
|
|
||||||
|
$wp_customize->add_setting('hero_title', array(
|
||||||
|
'default' => '探索技术世界',
|
||||||
|
'sanitize_callback' => 'sanitize_text_field',
|
||||||
|
));
|
||||||
|
$wp_customize->add_control('hero_title', array(
|
||||||
|
'label' => esc_html__('横幅标题', 'techblog'),
|
||||||
|
'section' => 'techblog_hero',
|
||||||
|
'type' => 'text',
|
||||||
|
));
|
||||||
|
|
||||||
|
$wp_customize->add_setting('hero_description', array(
|
||||||
|
'default' => '分享最新的IT技术、编程教程、系统运维经验',
|
||||||
|
'sanitize_callback' => 'sanitize_textarea_field',
|
||||||
|
));
|
||||||
|
$wp_customize->add_control('hero_description', array(
|
||||||
|
'label' => esc_html__('横幅描述', 'techblog'),
|
||||||
|
'section' => 'techblog_hero',
|
||||||
|
'type' => 'textarea',
|
||||||
|
));
|
||||||
|
|
||||||
|
// Social Links
|
||||||
|
$wp_customize->add_section('techblog_social', array(
|
||||||
|
'title' => esc_html__('社交媒体', 'techblog'),
|
||||||
|
'priority' => 35,
|
||||||
|
));
|
||||||
|
|
||||||
|
$social_platforms = array(
|
||||||
|
'github' => 'GitHub',
|
||||||
|
'twitter' => 'Twitter / X',
|
||||||
|
'gitee' => 'Gitee',
|
||||||
|
'email' => '邮箱',
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($social_platforms as $key => $label) {
|
||||||
|
$wp_customize->add_setting('social_' . $key, array(
|
||||||
|
'default' => '',
|
||||||
|
'sanitize_callback' => 'esc_url_raw',
|
||||||
|
));
|
||||||
|
$wp_customize->add_control('social_' . $key, array(
|
||||||
|
'label' => $label,
|
||||||
|
'section' => 'techblog_social',
|
||||||
|
'type' => 'url',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action('customize_register', 'techblog_customize_register');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom Post Type for Projects (optional)
|
||||||
|
*/
|
||||||
|
function techblog_register_post_types() {
|
||||||
|
register_post_type('project', array(
|
||||||
|
'labels' => array(
|
||||||
|
'name' => esc_html__('项目', 'techblog'),
|
||||||
|
'singular_name' => esc_html__('项目', 'techblog'),
|
||||||
|
'add_new' => esc_html__('添加项目', 'techblog'),
|
||||||
|
'add_new_item' => esc_html__('添加新项目', 'techblog'),
|
||||||
|
'edit_item' => esc_html__('编辑项目', 'techblog'),
|
||||||
|
'all_items' => esc_html__('所有项目', 'techblog'),
|
||||||
|
'view_item' => esc_html__('查看项目', 'techblog'),
|
||||||
|
'search_items' => esc_html__('搜索项目', 'techblog'),
|
||||||
|
),
|
||||||
|
'public' => true,
|
||||||
|
'has_archive' => true,
|
||||||
|
'menu_icon' => 'dashicons-portfolio',
|
||||||
|
'supports' => array('title', 'editor', 'thumbnail', 'excerpt'),
|
||||||
|
'rewrite' => array('slug' => 'project'),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
add_action('init', 'techblog_register_post_types');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AJAX Search
|
||||||
|
*/
|
||||||
|
function techblog_ajax_search() {
|
||||||
|
check_ajax_referer('techblog-nonce', 'nonce');
|
||||||
|
|
||||||
|
$search_term = sanitize_text_field($_POST['search']);
|
||||||
|
|
||||||
|
if (empty($search_term)) {
|
||||||
|
wp_send_json_error('请输入搜索关键词');
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = new WP_Query(array(
|
||||||
|
's' => $search_term,
|
||||||
|
'posts_per_page' => 5,
|
||||||
|
'post_status' => 'publish',
|
||||||
|
));
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
|
||||||
|
if ($query->have_posts()) {
|
||||||
|
while ($query->have_posts()) {
|
||||||
|
$query->the_post();
|
||||||
|
$results[] = array(
|
||||||
|
'title' => get_the_title(),
|
||||||
|
'url' => get_the_permalink(),
|
||||||
|
'excerpt' => wp_trim_words(get_the_excerpt(), 20),
|
||||||
|
'date' => get_the_date('Y-m-d'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_reset_postdata();
|
||||||
|
|
||||||
|
wp_send_json_success($results);
|
||||||
|
}
|
||||||
|
add_action('wp_ajax_techblog_search', 'techblog_ajax_search');
|
||||||
|
add_action('wp_ajax_nopriv_techblog_search', 'techblog_ajax_search');
|
||||||
Executable
+104
@@ -0,0 +1,104 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html <?php language_attributes(); ?> data-theme="light">
|
||||||
|
<head>
|
||||||
|
<meta charset="<?php bloginfo('charset'); ?>">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="description" content="<?php bloginfo('description'); ?>">
|
||||||
|
<?php wp_head(); ?>
|
||||||
|
</head>
|
||||||
|
<body <?php body_class(); ?>>
|
||||||
|
<?php wp_body_open(); ?>
|
||||||
|
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="header-inner">
|
||||||
|
<!-- Logo -->
|
||||||
|
<a href="<?php echo esc_url(home_url('/')); ?>" class="site-logo">
|
||||||
|
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M16 2L2 9l14 7 14-7L16 2zM2 23l14 7 14-7M2 16l14 7 14-7"/>
|
||||||
|
</svg>
|
||||||
|
<?php bloginfo('name'); ?>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Navigation -->
|
||||||
|
<nav class="main-nav" id="main-nav">
|
||||||
|
<?php
|
||||||
|
if (has_nav_menu('primary')) {
|
||||||
|
wp_nav_menu(array(
|
||||||
|
'theme_location' => 'primary',
|
||||||
|
'container' => false,
|
||||||
|
'items_wrap' => '%3$s',
|
||||||
|
'walker' => new TechBlog_Nav_Walker(),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
// Default menu
|
||||||
|
?>
|
||||||
|
<a href="<?php echo esc_url(home_url('/')); ?>" class="current">首页</a>
|
||||||
|
<a href="<?php echo esc_url(get_permalink(get_option('page_for_posts'))); ?>">博客</a>
|
||||||
|
<?php
|
||||||
|
// Get categories
|
||||||
|
$categories = get_categories(array('number' => 4, 'orderby' => 'count', 'order' => 'DESC'));
|
||||||
|
foreach ($categories as $cat) {
|
||||||
|
echo '<a href="' . esc_url(get_category_link($cat->term_id)) . '">' . esc_html($cat->name) . '</a>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Header Actions -->
|
||||||
|
<div class="header-actions">
|
||||||
|
<button class="search-toggle" id="search-toggle" aria-label="搜索">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<circle cx="11" cy="11" r="8"/>
|
||||||
|
<path d="m21 21-4.3-4.3"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="theme-toggle" id="theme-toggle" aria-label="切换主题">
|
||||||
|
<svg class="sun-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<circle cx="12" cy="12" r="5"/>
|
||||||
|
<line x1="12" y1="1" x2="12" y2="3"/>
|
||||||
|
<line x1="12" y1="21" x2="12" y2="23"/>
|
||||||
|
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
|
||||||
|
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
|
||||||
|
<line x1="1" y1="12" x2="3" y2="12"/>
|
||||||
|
<line x1="21" y1="12" x2="23" y2="12"/>
|
||||||
|
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>
|
||||||
|
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
|
||||||
|
</svg>
|
||||||
|
<svg class="moon-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display:none">
|
||||||
|
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="mobile-menu-toggle" id="mobile-menu-toggle" aria-label="菜单">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<line x1="3" y1="6" x2="21" y2="6"/>
|
||||||
|
<line x1="3" y1="12" x2="21" y2="12"/>
|
||||||
|
<line x1="3" y1="18" x2="21" y2="18"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Search Overlay -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-container">
|
||||||
|
<form role="search" method="get" action="<?php echo esc_url(home_url('/')); ?>">
|
||||||
|
<div class="search-input-wrapper">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<circle cx="11" cy="11" r="8"/>
|
||||||
|
<path d="m21 21-4.3-4.3"/>
|
||||||
|
</svg>
|
||||||
|
<input type="search" class="search-input" name="s" placeholder="搜索文章..." autocomplete="off" autofocus>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="search-hint">
|
||||||
|
<span>输入关键词搜索</span>
|
||||||
|
<kbd>ESC</kbd> 关闭
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<main class="site-container">
|
||||||
|
<div class="content-area">
|
||||||
@@ -0,0 +1,424 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Theme Options Page
|
||||||
|
*
|
||||||
|
* @package TechBlog Pro
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Add theme options page
|
||||||
|
function techblog_add_admin_menu() {
|
||||||
|
add_theme_page(
|
||||||
|
'TechBlog Pro 设置',
|
||||||
|
'主题设置',
|
||||||
|
'manage_options',
|
||||||
|
'techblog-settings',
|
||||||
|
'techblog_options_page_html'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
add_action('admin_menu', 'techblog_add_admin_menu');
|
||||||
|
|
||||||
|
// Register settings
|
||||||
|
function techblog_register_settings() {
|
||||||
|
// General Settings
|
||||||
|
register_setting('techblog_options', 'techblog_hero_title');
|
||||||
|
register_setting('techblog_options', 'techblog_hero_desc');
|
||||||
|
register_setting('techblog_options', 'techblog_footer_text');
|
||||||
|
|
||||||
|
// Social Links
|
||||||
|
register_setting('techblog_options', 'techblog_social_github');
|
||||||
|
register_setting('techblog_options', 'techblog_social_twitter');
|
||||||
|
register_setting('techblog_options', 'techblog_social_gitee');
|
||||||
|
register_setting('techblog_options', 'techblog_social_email');
|
||||||
|
register_setting('techblog_options', 'techblog_social_wechat');
|
||||||
|
|
||||||
|
// Appearance
|
||||||
|
register_setting('techblog_options', 'techblog_primary_color', array(
|
||||||
|
'default' => '#2563eb'
|
||||||
|
));
|
||||||
|
register_setting('techblog_options', 'techblog_code_theme', array(
|
||||||
|
'default' => 'dark'
|
||||||
|
));
|
||||||
|
register_setting('techblog_options', 'techblog_show_toc', array(
|
||||||
|
'default' => '1'
|
||||||
|
));
|
||||||
|
register_setting('techblog_options', 'techblog_show_reading_time', array(
|
||||||
|
'default' => '1'
|
||||||
|
));
|
||||||
|
register_setting('techblog_options', 'techblog_show_views', array(
|
||||||
|
'default' => '1'
|
||||||
|
));
|
||||||
|
register_setting('techblog_options', 'techblog_enable_dark_mode', array(
|
||||||
|
'default' => '1'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
add_action('admin_init', 'techblog_register_settings');
|
||||||
|
|
||||||
|
// Admin page HTML
|
||||||
|
function techblog_options_page_html() {
|
||||||
|
if (!current_user_can('manage_options')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['settings-updated'])) {
|
||||||
|
add_settings_error('techblog_messages', 'techblog_message', '设置已保存', 'updated');
|
||||||
|
}
|
||||||
|
|
||||||
|
settings_errors('techblog_messages');
|
||||||
|
?>
|
||||||
|
<div class="wrap">
|
||||||
|
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
|
||||||
|
|
||||||
|
<div class="techblog-admin-wrapper">
|
||||||
|
<!-- Tabs -->
|
||||||
|
<nav class="nav-tab-wrapper">
|
||||||
|
<a href="#general" class="nav-tab nav-tab-active" data-tab="general">常规设置</a>
|
||||||
|
<a href="#social" class="nav-tab" data-tab="social">社交媒体</a>
|
||||||
|
<a href="#appearance" class="nav-tab" data-tab="appearance">外观设置</a>
|
||||||
|
<a href="#about" class="nav-tab" data-tab="about">关于主题</a>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<form method="post" action="options.php" class="techblog-settings-form">
|
||||||
|
<?php settings_fields('techblog_options'); ?>
|
||||||
|
|
||||||
|
<!-- General Settings Tab -->
|
||||||
|
<div id="tab-general" class="tab-content active">
|
||||||
|
<table class="form-table">
|
||||||
|
<tr>
|
||||||
|
<th scope="row">首页横幅标题</th>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="techblog_hero_title"
|
||||||
|
value="<?php echo esc_attr(get_option('techblog_hero_title', '探索技术世界')); ?>"
|
||||||
|
class="regular-text" />
|
||||||
|
<p class="description">首页顶部横幅的标题文字</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">首页横幅描述</th>
|
||||||
|
<td>
|
||||||
|
<textarea name="techblog_hero_desc" rows="3" class="large-text"><?php echo esc_textarea(get_option('techblog_hero_desc', '分享最新的IT技术、编程教程、系统运维经验')); ?></textarea>
|
||||||
|
<p class="description">首页顶部横幅的描述文字</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">页脚文字</th>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="techblog_footer_text"
|
||||||
|
value="<?php echo esc_attr(get_option('techblog_footer_text', '专注于IT技术分享')); ?>"
|
||||||
|
class="regular-text" />
|
||||||
|
<p class="description">页脚显示的描述文字</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Social Links Tab -->
|
||||||
|
<div id="tab-social" class="tab-content">
|
||||||
|
<table class="form-table">
|
||||||
|
<tr>
|
||||||
|
<th scope="row">
|
||||||
|
<label>
|
||||||
|
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor" style="vertical-align: middle; margin-right: 8px;">
|
||||||
|
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
||||||
|
</svg>
|
||||||
|
GitHub
|
||||||
|
</label>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<input type="url" name="techblog_social_github"
|
||||||
|
value="<?php echo esc_attr(get_option('techblog_social_github')); ?>"
|
||||||
|
class="regular-text" placeholder="https://github.com/yourusername" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">
|
||||||
|
<label>
|
||||||
|
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor" style="vertical-align: middle; margin-right: 8px;">
|
||||||
|
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
|
||||||
|
</svg>
|
||||||
|
Twitter / X
|
||||||
|
</label>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<input type="url" name="techblog_social_twitter"
|
||||||
|
value="<?php echo esc_attr(get_option('techblog_social_twitter')); ?>"
|
||||||
|
class="regular-text" placeholder="https://twitter.com/yourusername" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">
|
||||||
|
<label>
|
||||||
|
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor" style="vertical-align: middle; margin-right: 8px;">
|
||||||
|
<path d="M11.984 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.016 0zm6.09 5.333c.328 0 .593.266.593.593v1.633h1.633a.593.593 0 0 1 0 1.186h-1.633v1.633a.593.593 0 0 1-1.186 0V10.35h-1.633a.593.593 0 0 1 0-1.186h1.633V7.533c0-.327.266-.593.593-.593zM12 3.6a8.4 8.4 0 1 0 0 16.8 8.4 8.4 0 0 0 0-16.8z"/>
|
||||||
|
</svg>
|
||||||
|
Gitee
|
||||||
|
</label>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<input type="url" name="techblog_social_gitee"
|
||||||
|
value="<?php echo esc_attr(get_option('techblog_social_gitee')); ?>"
|
||||||
|
class="regular-text" placeholder="https://gitee.com/yourusername" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">
|
||||||
|
<label>
|
||||||
|
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" style="vertical-align: middle; margin-right: 8px;">
|
||||||
|
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>
|
||||||
|
<polyline points="22,6 12,13 2,6"/>
|
||||||
|
</svg>
|
||||||
|
邮箱
|
||||||
|
</label>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<input type="email" name="techblog_social_email"
|
||||||
|
value="<?php echo esc_attr(get_option('techblog_social_email')); ?>"
|
||||||
|
class="regular-text" placeholder="your@email.com" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">
|
||||||
|
<label>
|
||||||
|
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor" style="vertical-align: middle; margin-right: 8px;">
|
||||||
|
<path d="M8.691 2.188C3.891 2.188 0 5.476 0 9.53c0 2.212 1.17 4.203 3.002 5.55a.59.59 0 0 1 .213.665l-.39 1.48c-.019.07-.048.141-.048.213 0 .163.13.295.29.295a.326.326 0 0 0 .167-.054l1.903-1.114a.864.864 0 0 1 .717-.098 10.16 10.16 0 0 0 2.837.403c.276 0 .543-.027.811-.05-.857-2.578.157-4.972 1.932-6.446 1.703-1.415 3.882-1.98 5.853-1.838-.576-3.583-4.196-6.348-8.596-6.348zM5.785 5.991c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 0 1-1.162 1.178A1.17 1.17 0 0 1 4.623 7.17c0-.651.52-1.18 1.162-1.18zm5.813 0c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 0 1-1.162 1.178 1.17 1.17 0 0 1-1.162-1.178c0-.651.52-1.18 1.162-1.18zm5.34 2.867c-1.797-.052-3.746.512-5.28 1.786-1.72 1.428-2.687 3.72-1.78 6.22.942 2.453 3.666 4.229 6.884 4.229.826 0 1.622-.12 2.361-.336a.722.722 0 0 1 .598.082l1.584.926a.272.272 0 0 0 .14.047c.134 0 .24-.111.24-.247 0-.06-.023-.12-.038-.177l-.327-1.233a.582.582 0 0 1-.023-.156.49.49 0 0 1 .201-.398C23.024 18.48 24 16.82 24 14.98c0-3.21-2.931-5.837-6.656-6.088V8.89c-.135-.01-.27-.027-.407-.032zm-2.53 3.274c.535 0 .969.44.969.982a.976.976 0 0 1-.969.983.976.976 0 0 1-.969-.983c0-.542.434-.982.97-.982zm4.844 0c.535 0 .969.44.969.982a.976.976 0 0 1-.969.983.976.976 0 0 1-.969-.983c0-.542.434-.982.97-.982z"/>
|
||||||
|
</svg>
|
||||||
|
微信号
|
||||||
|
</label>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="techblog_social_wechat"
|
||||||
|
value="<?php echo esc_attr(get_option('techblog_social_wechat')); ?>"
|
||||||
|
class="regular-text" placeholder="your-wechat-id" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Appearance Tab -->
|
||||||
|
<div id="tab-appearance" class="tab-content">
|
||||||
|
<table class="form-table">
|
||||||
|
<tr>
|
||||||
|
<th scope="row">主题色</th>
|
||||||
|
<td>
|
||||||
|
<input type="color" name="techblog_primary_color"
|
||||||
|
value="<?php echo esc_attr(get_option('techblog_primary_color', '#2563eb')); ?>" />
|
||||||
|
<p class="description">选择主题的主色调</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">代码块主题</th>
|
||||||
|
<td>
|
||||||
|
<select name="techblog_code_theme">
|
||||||
|
<option value="dark" <?php selected(get_option('techblog_code_theme', 'dark'), 'dark'); ?>>深色</option>
|
||||||
|
<option value="light" <?php selected(get_option('techblog_code_theme', 'dark'), 'light'); ?>>浅色</option>
|
||||||
|
</select>
|
||||||
|
<p class="description">代码块的配色方案</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">功能开关</th>
|
||||||
|
<td>
|
||||||
|
<fieldset>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="techblog_show_toc" value="1"
|
||||||
|
<?php checked(get_option('techblog_show_toc', '1'), '1'); ?> />
|
||||||
|
显示文章目录
|
||||||
|
</label><br>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="techblog_show_reading_time" value="1"
|
||||||
|
<?php checked(get_option('techblog_show_reading_time', '1'), '1'); ?> />
|
||||||
|
显示阅读时间
|
||||||
|
</label><br>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="techblog_show_views" value="1"
|
||||||
|
<?php checked(get_option('techblog_show_views', '1'), '1'); ?> />
|
||||||
|
显示阅读次数
|
||||||
|
</label><br>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="techblog_enable_dark_mode" value="1"
|
||||||
|
<?php checked(get_option('techblog_enable_dark_mode', '1'), '1'); ?> />
|
||||||
|
启用暗色模式切换
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- About Tab -->
|
||||||
|
<div id="tab-about" class="tab-content">
|
||||||
|
<div class="techblog-about-card">
|
||||||
|
<div class="techblog-about-header">
|
||||||
|
<h2>TechBlog Pro</h2>
|
||||||
|
<span class="version">v1.0.0</span>
|
||||||
|
</div>
|
||||||
|
<p>一个专为IT技术分享设计的现代化WordPress主题。</p>
|
||||||
|
|
||||||
|
<h3>✨ 主题特性</h3>
|
||||||
|
<ul>
|
||||||
|
<li>🎨 现代化UI设计,支持暗色模式</li>
|
||||||
|
<li>📝 代码高亮 + 一键复制</li>
|
||||||
|
<li>📑 自动生成文章目录</li>
|
||||||
|
<li>⏱️ 阅读时间估算</li>
|
||||||
|
<li>📊 阅读次数统计</li>
|
||||||
|
<li>🔍 AJAX实时搜索</li>
|
||||||
|
<li>📱 完美响应式布局</li>
|
||||||
|
<li>⚡ 性能优化(懒加载、平滑滚动)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>🔗 相关链接</h3>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://github.com/techblog-pro" target="_blank">GitHub 仓库</a></li>
|
||||||
|
<li><a href="https://github.com/techblog-pro/issues" target="_blank">问题反馈</a></li>
|
||||||
|
<li><a href="https://github.com/techblog-pro/wiki" target="_blank">使用文档</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php submit_button('保存设置'); ?>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.techblog-admin-wrapper {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 200px 1fr;
|
||||||
|
gap: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #ccd0d4;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab-wrapper .nav-tab {
|
||||||
|
display: block;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid #ccd0d4;
|
||||||
|
border-radius: 0;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab-wrapper .nav-tab:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab-wrapper .nav-tab:hover {
|
||||||
|
background: #f0f0f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab-wrapper .nav-tab.nav-tab-active {
|
||||||
|
background: #2563eb;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #2563eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content {
|
||||||
|
display: none;
|
||||||
|
background: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #ccd0d4;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techblog-about-card {
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techblog-about-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techblog-about-header h2 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techblog-about-header .version {
|
||||||
|
background: #2563eb;
|
||||||
|
color: #fff;
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 100px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techblog-about-card h3 {
|
||||||
|
margin-top: 24px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techblog-about-card ul {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techblog-about-card li {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techblog-about-card a {
|
||||||
|
color: #2563eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 782px) {
|
||||||
|
.techblog-admin-wrapper {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab-wrapper {
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab-wrapper .nav-tab {
|
||||||
|
border-bottom: none;
|
||||||
|
border-right: 1px solid #ccd0d4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
jQuery(document).ready(function($) {
|
||||||
|
// Tab switching
|
||||||
|
$('.nav-tab-wrapper .nav-tab').on('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var tab = $(this).data('tab');
|
||||||
|
|
||||||
|
// Update active tab
|
||||||
|
$('.nav-tab-wrapper .nav-tab').removeClass('nav-tab-active');
|
||||||
|
$(this).addClass('nav-tab-active');
|
||||||
|
|
||||||
|
// Show tab content
|
||||||
|
$('.tab-content').removeClass('active');
|
||||||
|
$('#tab-' + tab).addClass('active');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add admin styles
|
||||||
|
function techblog_admin_styles($hook) {
|
||||||
|
if ('appearance_page_techblog-settings' !== $hook) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wp_enqueue_style('techblog-admin', TECHBLOG_URI . '/css/admin.css', array(), TECHBLOG_VERSION);
|
||||||
|
}
|
||||||
|
add_action('admin_enqueue_scripts', 'techblog_admin_styles');
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Main Template File
|
||||||
|
*
|
||||||
|
* @package TechBlog Pro
|
||||||
|
*/
|
||||||
|
|
||||||
|
get_header();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!-- Hero Section -->
|
||||||
|
<?php if (is_front_page()) : ?>
|
||||||
|
<section class="hero-section">
|
||||||
|
<h1 class="hero-title"><?php echo esc_html(get_theme_mod('hero_title', '探索技术世界')); ?></h1>
|
||||||
|
<p class="hero-description"><?php echo esc_html(get_theme_mod('hero_description', '分享最新的IT技术、编程教程、系统运维经验')); ?></p>
|
||||||
|
</section>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<!-- Posts Grid -->
|
||||||
|
<div class="posts-grid">
|
||||||
|
<?php if (have_posts()) : ?>
|
||||||
|
<?php while (have_posts()) : the_post(); ?>
|
||||||
|
<article class="post-card" <?php post_class(); ?>>
|
||||||
|
<div class="post-card-header">
|
||||||
|
<?php
|
||||||
|
$categories = get_the_category();
|
||||||
|
if (!empty($categories)) :
|
||||||
|
?>
|
||||||
|
<a href="<?php echo esc_url(get_category_link($categories[0]->term_id)); ?>" class="post-category">
|
||||||
|
<?php echo esc_html($categories[0]->name); ?>
|
||||||
|
</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<span class="post-date">
|
||||||
|
<time datetime="<?php echo get_the_date('c'); ?>">
|
||||||
|
<?php echo get_the_date('Y年m月d日'); ?>
|
||||||
|
</time>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 class="post-card-title">
|
||||||
|
<a href="<?php the_permalink(); ?>">
|
||||||
|
<?php the_title(); ?>
|
||||||
|
</a>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="post-excerpt">
|
||||||
|
<?php the_excerpt(); ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="post-card-footer">
|
||||||
|
<div class="post-meta">
|
||||||
|
<span class="post-meta-item">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<circle cx="12" cy="12" r="10"/>
|
||||||
|
<polyline points="12,6 12,12 16,14"/>
|
||||||
|
</svg>
|
||||||
|
<?php echo techblog_reading_time(); ?> 分钟阅读
|
||||||
|
</span>
|
||||||
|
<span class="post-meta-item">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
|
||||||
|
<circle cx="12" cy="12" r="3"/>
|
||||||
|
</svg>
|
||||||
|
<?php echo techblog_format_views(techblog_get_post_views()); ?> 阅读
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a href="<?php the_permalink(); ?>" class="read-more">
|
||||||
|
阅读全文
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<line x1="5" y1="12" x2="19" y2="12"/>
|
||||||
|
<polyline points="12,5 19,12 12,19"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<?php endwhile; ?>
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
<?php
|
||||||
|
the_posts_pagination(array(
|
||||||
|
'mid_size' => 2,
|
||||||
|
'prev_text' => '← 上一页',
|
||||||
|
'next_text' => '下一页 →',
|
||||||
|
));
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php else : ?>
|
||||||
|
<article class="post-card">
|
||||||
|
<h2 class="post-card-title">暂无文章</h2>
|
||||||
|
<div class="post-excerpt">
|
||||||
|
<p>还没有发布任何文章,请稍后再来。</p>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php get_footer(); ?>
|
||||||
Executable
+334
@@ -0,0 +1,334 @@
|
|||||||
|
/**
|
||||||
|
* TechBlog Pro - Main JavaScript
|
||||||
|
*
|
||||||
|
* @package TechBlog Pro
|
||||||
|
* @version 1.0.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// ==================== Theme Toggle ====================
|
||||||
|
const ThemeManager = {
|
||||||
|
init() {
|
||||||
|
this.toggle = document.getElementById('theme-toggle');
|
||||||
|
this.sunIcon = this.toggle?.querySelector('.sun-icon');
|
||||||
|
this.moonIcon = this.toggle?.querySelector('.moon-icon');
|
||||||
|
|
||||||
|
if (!this.toggle) return;
|
||||||
|
|
||||||
|
// Load saved theme
|
||||||
|
const savedTheme = localStorage.getItem('theme') || 'light';
|
||||||
|
this.setTheme(savedTheme);
|
||||||
|
|
||||||
|
// Toggle event
|
||||||
|
this.toggle.addEventListener('click', () => {
|
||||||
|
const current = document.documentElement.getAttribute('data-theme');
|
||||||
|
this.setTheme(current === 'dark' ? 'light' : 'dark');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setTheme(theme) {
|
||||||
|
document.documentElement.setAttribute('data-theme', theme);
|
||||||
|
localStorage.setItem('theme', theme);
|
||||||
|
|
||||||
|
if (this.sunIcon && this.moonIcon) {
|
||||||
|
this.sunIcon.style.display = theme === 'dark' ? 'none' : 'block';
|
||||||
|
this.moonIcon.style.display = theme === 'dark' ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== Search Overlay ====================
|
||||||
|
const SearchManager = {
|
||||||
|
init() {
|
||||||
|
this.overlay = document.getElementById('search-overlay');
|
||||||
|
this.toggle = document.getElementById('search-toggle');
|
||||||
|
this.input = this.overlay?.querySelector('.search-input');
|
||||||
|
|
||||||
|
if (!this.overlay || !this.toggle) return;
|
||||||
|
|
||||||
|
// Open search
|
||||||
|
this.toggle.addEventListener('click', () => this.open());
|
||||||
|
|
||||||
|
// Close on overlay click
|
||||||
|
this.overlay.addEventListener('click', (e) => {
|
||||||
|
if (e.target === this.overlay) this.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Keyboard shortcuts
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
// CMD/CTRL + K to open
|
||||||
|
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
|
||||||
|
e.preventDefault();
|
||||||
|
this.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ESC to close
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
open() {
|
||||||
|
this.overlay.classList.add('active');
|
||||||
|
setTimeout(() => this.input?.focus(), 100);
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
},
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.overlay.classList.remove('active');
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== Mobile Menu ====================
|
||||||
|
const MobileMenu = {
|
||||||
|
init() {
|
||||||
|
this.toggle = document.getElementById('mobile-menu-toggle');
|
||||||
|
this.nav = document.getElementById('main-nav');
|
||||||
|
|
||||||
|
if (!this.toggle || !this.nav) return;
|
||||||
|
|
||||||
|
this.toggle.addEventListener('click', () => {
|
||||||
|
this.nav.classList.toggle('active');
|
||||||
|
this.toggle.classList.toggle('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close on outside click
|
||||||
|
document.addEventListener('click', (e) => {
|
||||||
|
if (!this.nav.contains(e.target) && !this.toggle.contains(e.target)) {
|
||||||
|
this.nav.classList.remove('active');
|
||||||
|
this.toggle.classList.remove('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== Table of Contents ====================
|
||||||
|
const TOCManager = {
|
||||||
|
init() {
|
||||||
|
this.tocLinks = document.querySelectorAll('.toc-list a');
|
||||||
|
this.headings = [];
|
||||||
|
|
||||||
|
if (this.tocLinks.length === 0) return;
|
||||||
|
|
||||||
|
// Collect headings
|
||||||
|
this.tocLinks.forEach(link => {
|
||||||
|
const id = link.getAttribute('href')?.slice(1);
|
||||||
|
const heading = document.getElementById(id);
|
||||||
|
if (heading) {
|
||||||
|
this.headings.push({ id, element: heading, link });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Scroll spy
|
||||||
|
this.observer = new IntersectionObserver(
|
||||||
|
(entries) => this.handleIntersection(entries),
|
||||||
|
{ rootMargin: '-80px 0px -80% 0px' }
|
||||||
|
);
|
||||||
|
|
||||||
|
this.headings.forEach(({ element }) => {
|
||||||
|
this.observer.observe(element);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Smooth scroll
|
||||||
|
this.tocLinks.forEach(link => {
|
||||||
|
link.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const id = link.getAttribute('href')?.slice(1);
|
||||||
|
const target = document.getElementById(id);
|
||||||
|
if (target) {
|
||||||
|
target.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
handleIntersection(entries) {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
// Remove all active states
|
||||||
|
this.tocLinks.forEach(link => link.classList.remove('active'));
|
||||||
|
|
||||||
|
// Add active to current
|
||||||
|
const activeLink = this.headings.find(h => h.id === entry.target.id)?.link;
|
||||||
|
activeLink?.classList.add('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== Code Copy ====================
|
||||||
|
window.copyCode = function(button) {
|
||||||
|
const pre = button.closest('pre');
|
||||||
|
const code = pre?.querySelector('code');
|
||||||
|
|
||||||
|
if (!code) return;
|
||||||
|
|
||||||
|
const text = code.textContent;
|
||||||
|
|
||||||
|
navigator.clipboard.writeText(text).then(() => {
|
||||||
|
const originalText = button.innerHTML;
|
||||||
|
button.innerHTML = `
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<polyline points="20 6 9 17 4 12"/>
|
||||||
|
</svg>
|
||||||
|
已复制
|
||||||
|
`;
|
||||||
|
button.style.color = '#22c55e';
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
button.innerHTML = originalText;
|
||||||
|
button.style.color = '';
|
||||||
|
}, 2000);
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Failed to copy:', err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== Reading Progress ====================
|
||||||
|
const ReadingProgress = {
|
||||||
|
init() {
|
||||||
|
this.progressBar = document.createElement('div');
|
||||||
|
this.progressBar.style.cssText = `
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 0%;
|
||||||
|
height: 3px;
|
||||||
|
background: linear-gradient(90deg, var(--primary-color), var(--accent-color));
|
||||||
|
z-index: 9999;
|
||||||
|
transition: width 0.1s ease;
|
||||||
|
`;
|
||||||
|
document.body.appendChild(this.progressBar);
|
||||||
|
|
||||||
|
window.addEventListener('scroll', () => this.update());
|
||||||
|
},
|
||||||
|
|
||||||
|
update() {
|
||||||
|
const scrollTop = window.scrollY;
|
||||||
|
const docHeight = document.documentElement.scrollHeight - window.innerHeight;
|
||||||
|
const progress = (scrollTop / docHeight) * 100;
|
||||||
|
|
||||||
|
this.progressBar.style.width = `${Math.min(progress, 100)}%`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== Lazy Load Images ====================
|
||||||
|
const LazyLoad = {
|
||||||
|
init() {
|
||||||
|
if ('loading' in HTMLImageElement.prototype) {
|
||||||
|
// Native lazy loading supported
|
||||||
|
document.querySelectorAll('img[loading="lazy"]').forEach(img => {
|
||||||
|
img.src = img.dataset.src;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Fallback with IntersectionObserver
|
||||||
|
this.observer = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
const img = entry.target;
|
||||||
|
img.src = img.dataset.src;
|
||||||
|
this.observer.unobserve(img);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ rootMargin: '50px' }
|
||||||
|
);
|
||||||
|
|
||||||
|
document.querySelectorAll('img[data-src]').forEach(img => {
|
||||||
|
this.observer.observe(img);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== Copy Link ====================
|
||||||
|
window.copyLink = function() {
|
||||||
|
const url = window.location.href;
|
||||||
|
navigator.clipboard.writeText(url).then(() => {
|
||||||
|
const btn = document.querySelector('.share-copy');
|
||||||
|
btn.classList.add('copied');
|
||||||
|
btn.title = '已复制';
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
btn.classList.remove('copied');
|
||||||
|
btn.title = '复制链接';
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== Back to Top ====================
|
||||||
|
const BackToTop = {
|
||||||
|
init() {
|
||||||
|
this.button = document.createElement('button');
|
||||||
|
this.button.innerHTML = `
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="20" height="20">
|
||||||
|
<line x1="12" y1="19" x2="12" y2="5"/>
|
||||||
|
<polyline points="5 12 12 5 19 12"/>
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
|
this.button.style.cssText = `
|
||||||
|
position: fixed;
|
||||||
|
bottom: 24px;
|
||||||
|
right: 24px;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
z-index: 100;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
box-shadow: var(--shadow-md);
|
||||||
|
`;
|
||||||
|
|
||||||
|
this.button.addEventListener('click', () => {
|
||||||
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
|
});
|
||||||
|
|
||||||
|
document.body.appendChild(this.button);
|
||||||
|
|
||||||
|
window.addEventListener('scroll', () => this.toggle());
|
||||||
|
},
|
||||||
|
|
||||||
|
toggle() {
|
||||||
|
if (window.scrollY > 300) {
|
||||||
|
this.button.style.opacity = '1';
|
||||||
|
this.button.style.visibility = 'visible';
|
||||||
|
} else {
|
||||||
|
this.button.style.opacity = '0';
|
||||||
|
this.button.style.visibility = 'hidden';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== Initialize ====================
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
ThemeManager.init();
|
||||||
|
SearchManager.init();
|
||||||
|
MobileMenu.init();
|
||||||
|
TOCManager.init();
|
||||||
|
ReadingProgress.init();
|
||||||
|
LazyLoad.init();
|
||||||
|
BackToTop.init();
|
||||||
|
|
||||||
|
// Add current page class to nav
|
||||||
|
const currentPath = window.location.pathname;
|
||||||
|
document.querySelectorAll('.main-nav a').forEach(link => {
|
||||||
|
if (link.pathname === currentPath) {
|
||||||
|
link.classList.add('current');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Page Template
|
||||||
|
*
|
||||||
|
* @package TechBlog Pro
|
||||||
|
*/
|
||||||
|
|
||||||
|
get_header();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<article class="single-post" <?php post_class(); ?>>
|
||||||
|
<?php while (have_posts()) : the_post(); ?>
|
||||||
|
|
||||||
|
<header class="post-header">
|
||||||
|
<h1 class="post-title"><?php the_title(); ?></h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="post-content">
|
||||||
|
<?php the_content(); ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php endwhile; ?>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<?php get_footer(); ?>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
Executable
+68
@@ -0,0 +1,68 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 900">
|
||||||
|
<!-- Background -->
|
||||||
|
<rect width="1200" height="900" fill="#f8fafc"/>
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<rect x="0" y="0" width="1200" height="64" fill="#ffffff" stroke="#e2e8f0"/>
|
||||||
|
<text x="40" y="40" font-family="Arial, sans-serif" font-size="20" font-weight="bold" fill="#1e293b">TechBlog Pro</text>
|
||||||
|
|
||||||
|
<!-- Navigation -->
|
||||||
|
<text x="900" y="40" font-family="Arial, sans-serif" font-size="14" fill="#475569">首页 博客 Linux Docker K8s</text>
|
||||||
|
|
||||||
|
<!-- Hero Section -->
|
||||||
|
<rect x="40" y="100" width="1120" height="180" rx="16" fill="url(#gradient1)"/>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="gradient1" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||||
|
<stop offset="0%" style="stop-color:#2563eb"/>
|
||||||
|
<stop offset="100%" style="stop-color:#7c3aed"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<text x="80" y="170" font-family="Arial, sans-serif" font-size="36" font-weight="bold" fill="#ffffff">探索技术世界</text>
|
||||||
|
<text x="80" y="220" font-family="Arial, sans-serif" font-size="18" fill="rgba(255,255,255,0.9)">分享最新的IT技术、编程教程、系统运维经验</text>
|
||||||
|
|
||||||
|
<!-- Post Card 1 -->
|
||||||
|
<rect x="40" y="320" width="780" height="200" rx="12" fill="#ffffff" stroke="#e2e8f0"/>
|
||||||
|
<rect x="60" y="340" width="80" height="24" rx="12" fill="#2563eb"/>
|
||||||
|
<text x="80" y="357" font-family="Arial, sans-serif" font-size="10" fill="#ffffff">LINUX</text>
|
||||||
|
<text x="60" y="400" font-family="Arial, sans-serif" font-size="20" font-weight="bold" fill="#1e293b">Ubuntu 24.04 LTS 安装配置指南</text>
|
||||||
|
<text x="60" y="440" font-family="Arial, sans-serif" font-size="14" fill="#475569">详细介绍如何在服务器上安装和配置 Ubuntu 24.04 LTS...</text>
|
||||||
|
<text x="60" y="490" font-family="Arial, sans-serif" font-size="12" fill="#94a3b8">⏱ 8 分钟阅读 👁 1.2k 阅读</text>
|
||||||
|
|
||||||
|
<!-- Post Card 2 -->
|
||||||
|
<rect x="40" y="540" width="780" height="160" rx="12" fill="#ffffff" stroke="#e2e8f0"/>
|
||||||
|
<rect x="60" y="560" width="90" height="24" rx="12" fill="#7c3aed"/>
|
||||||
|
<text x="82" y="577" font-family="Arial, sans-serif" font-size="10" fill="#ffffff">DOCKER</text>
|
||||||
|
<text x="60" y="620" font-family="Arial, sans-serif" font-size="20" font-weight="bold" fill="#1e293b">Docker Compose 实战教程</text>
|
||||||
|
<text x="60" y="650" font-family="Arial, sans-serif" font-size="14" fill="#475569">使用 Docker Compose 编排多容器应用...</text>
|
||||||
|
|
||||||
|
<!-- Sidebar -->
|
||||||
|
<rect x="860" y="320" width="300" height="200" rx="12" fill="#ffffff" stroke="#e2e8f0"/>
|
||||||
|
<text x="880" y="360" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#1e293b">📂 文章分类</text>
|
||||||
|
<text x="880" y="395" font-family="Arial, sans-serif" font-size="13" fill="#475569">Linux (24)</text>
|
||||||
|
<text x="880" y="425" font-family="Arial, sans-serif" font-size="13" fill="#475569">Docker (18)</text>
|
||||||
|
<text x="880" y="455" font-family="Arial, sans-serif" font-size="13" fill="#475569">Kubernetes (15)</text>
|
||||||
|
<text x="880" y="485" font-family="Arial, sans-serif" font-size="13" fill="#475569">Python (12)</text>
|
||||||
|
|
||||||
|
<rect x="860" y="540" width="300" height="160" rx="12" fill="#ffffff" stroke="#e2e8f0"/>
|
||||||
|
<text x="880" y="580" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#1e293b">🏷️ 热门标签</text>
|
||||||
|
<rect x="880" y="600" width="60" height="28" rx="14" fill="#f1f5f9"/>
|
||||||
|
<text x="895" y="619" font-family="Arial, sans-serif" font-size="11" fill="#475569">Docker</text>
|
||||||
|
<rect x="950" y="600" width="80" height="28" rx="14" fill="#f1f5f9"/>
|
||||||
|
<text x="965" y="619" font-family="Arial, sans-serif" font-size="11" fill="#475569">Kubernetes</text>
|
||||||
|
<rect x="1040" y="600" width="50" height="28" rx="14" fill="#f1f5f9"/>
|
||||||
|
<text x="1050" y="619" font-family="Arial, sans-serif" font-size="11" fill="#475569">Linux</text>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<rect x="0" y="780" width="1200" height="120" fill="#f8fafc" stroke="#e2e8f0"/>
|
||||||
|
<text x="40" y="830" font-family="Arial, sans-serif" font-size="14" fill="#475569">一个专注于IT技术分享的博客</text>
|
||||||
|
<text x="40" y="870" font-family="Arial, sans-serif" font-size="12" fill="#94a3b8">© 2024 TechBlog Pro. All rights reserved.</text>
|
||||||
|
|
||||||
|
<!-- Dark mode toggle -->
|
||||||
|
<circle cx="1140" cy="32" r="16" fill="none" stroke="#475569" stroke-width="2"/>
|
||||||
|
<path d="M1132 32a8 8 0 0116 0" fill="#475569"/>
|
||||||
|
|
||||||
|
<!-- Search icon -->
|
||||||
|
<circle cx="1100" cy="32" r="8" fill="none" stroke="#475569" stroke-width="2"/>
|
||||||
|
<line x1="1106" y1="38" x2="1112" y2="44" stroke="#475569" stroke-width="2"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.5 KiB |
Executable
+102
@@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Search Results Template
|
||||||
|
*
|
||||||
|
* @package TechBlog Pro
|
||||||
|
*/
|
||||||
|
|
||||||
|
get_header();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="archive-header" style="margin-bottom: 32px;">
|
||||||
|
<h1 style="font-size: 1.75rem; font-weight: 700; margin-bottom: 8px;">
|
||||||
|
🔍 搜索结果:<?php echo get_search_query(); ?>
|
||||||
|
</h1>
|
||||||
|
<p style="color: var(--text-muted); font-size: 0.9375rem;">
|
||||||
|
<?php if ($wp_query->found_posts > 0) : ?>
|
||||||
|
找到 <?php echo $wp_query->found_posts; ?> 个相关结果
|
||||||
|
<?php else : ?>
|
||||||
|
未找到相关结果
|
||||||
|
<?php endif; ?>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="posts-grid">
|
||||||
|
<?php if (have_posts()) : ?>
|
||||||
|
<?php while (have_posts()) : the_post(); ?>
|
||||||
|
<article class="post-card" <?php post_class(); ?>>
|
||||||
|
<div class="post-card-header">
|
||||||
|
<?php
|
||||||
|
$categories = get_the_category();
|
||||||
|
if (!empty($categories)) :
|
||||||
|
?>
|
||||||
|
<a href="<?php echo esc_url(get_category_link($categories[0]->term_id)); ?>" class="post-category">
|
||||||
|
<?php echo esc_html($categories[0]->name); ?>
|
||||||
|
</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<span class="post-date">
|
||||||
|
<time datetime="<?php echo get_the_date('c'); ?>">
|
||||||
|
<?php echo get_the_date('Y年m月d日'); ?>
|
||||||
|
</time>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 class="post-card-title">
|
||||||
|
<a href="<?php the_permalink(); ?>">
|
||||||
|
<?php the_title(); ?>
|
||||||
|
</a>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="post-excerpt">
|
||||||
|
<?php the_excerpt(); ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="post-card-footer">
|
||||||
|
<div class="post-meta">
|
||||||
|
<span class="post-meta-item">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<circle cx="12" cy="12" r="10"/>
|
||||||
|
<polyline points="12,6 12,12 16,14"/>
|
||||||
|
</svg>
|
||||||
|
<?php echo techblog_reading_time(); ?> 分钟阅读
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a href="<?php the_permalink(); ?>" class="read-more">
|
||||||
|
阅读全文
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<line x1="5" y1="12" x2="19" y2="12"/>
|
||||||
|
<polyline points="12,5 19,12 12,19"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<?php endwhile; ?>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
the_posts_pagination(array(
|
||||||
|
'mid_size' => 2,
|
||||||
|
'prev_text' => '← 上一页',
|
||||||
|
'next_text' => '下一页 →',
|
||||||
|
));
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php else : ?>
|
||||||
|
<article class="post-card" style="text-align: center; padding: 60px 20px;">
|
||||||
|
<div style="font-size: 3rem; margin-bottom: 16px;">🔍</div>
|
||||||
|
<h2 class="post-card-title" style="font-size: 1.5rem;">未找到相关内容</h2>
|
||||||
|
<div class="post-excerpt">
|
||||||
|
<p>抱歉,没有找到与 "<?php echo get_search_query(); ?>" 相关的文章。</p>
|
||||||
|
<p style="margin-top: 16px;">您可以尝试:</p>
|
||||||
|
<ul style="text-align: left; max-width: 300px; margin: 16px auto 0;">
|
||||||
|
<li>检查关键词是否正确</li>
|
||||||
|
<li>尝试其他关键词</li>
|
||||||
|
<li>浏览我们的文章分类</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php get_footer(); ?>
|
||||||
Executable
+154
@@ -0,0 +1,154 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Single Post Template
|
||||||
|
*
|
||||||
|
* @package TechBlog Pro
|
||||||
|
*/
|
||||||
|
|
||||||
|
get_header();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<article class="single-post" <?php post_class(); ?>>
|
||||||
|
<?php while (have_posts()) : the_post(); ?>
|
||||||
|
|
||||||
|
<header class="post-header">
|
||||||
|
<?php
|
||||||
|
$categories = get_the_category();
|
||||||
|
if (!empty($categories)) :
|
||||||
|
?>
|
||||||
|
<a href="<?php echo esc_url(get_category_link($categories[0]->term_id)); ?>" class="post-category">
|
||||||
|
<?php echo esc_html($categories[0]->name); ?>
|
||||||
|
</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<h1 class="post-title"><?php the_title(); ?></h1>
|
||||||
|
|
||||||
|
<div class="post-meta-full">
|
||||||
|
<div class="author-avatar">
|
||||||
|
<?php echo get_avatar(get_the_author_meta('ID'), 40); ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<a href="<?php echo esc_url(get_author_posts_url(get_the_author_meta('ID'))); ?>">
|
||||||
|
<?php the_author(); ?>
|
||||||
|
</a>
|
||||||
|
<span style="margin: 0 8px;">·</span>
|
||||||
|
<time datetime="<?php echo get_the_date('c'); ?>">
|
||||||
|
<?php echo get_the_date('Y年m月d日'); ?>
|
||||||
|
</time>
|
||||||
|
<span style="margin: 0 8px;">·</span>
|
||||||
|
<span><?php echo techblog_reading_time(); ?> 分钟阅读</span>
|
||||||
|
<span style="margin: 0 8px;">·</span>
|
||||||
|
<span><?php echo techblog_format_views(techblog_get_post_views()); ?> 次阅读</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="post-content">
|
||||||
|
<?php
|
||||||
|
the_content();
|
||||||
|
|
||||||
|
// Link Pages (for multi-page posts)
|
||||||
|
wp_link_pages(array(
|
||||||
|
'before' => '<div class="page-links">分页:',
|
||||||
|
'after' => '</div>',
|
||||||
|
));
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Share & Tags -->
|
||||||
|
<footer class="post-footer">
|
||||||
|
<?php
|
||||||
|
$tags = get_the_tags();
|
||||||
|
if (!empty($tags)) :
|
||||||
|
?>
|
||||||
|
<div class="post-tags">
|
||||||
|
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M20.59 13.41l-7.17 7.17a2 2 0 01-2.83 0L2 12V2h10l8.59 8.59a2 2 0 010 2.82z"/>
|
||||||
|
<line x1="7" y1="7" x2="7.01" y2="7"/>
|
||||||
|
</svg>
|
||||||
|
<?php foreach ($tags as $tag) : ?>
|
||||||
|
<a href="<?php echo esc_url(get_tag_link($tag->term_id)); ?>">
|
||||||
|
<?php echo esc_html($tag->name); ?>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="share-section">
|
||||||
|
<span class="share-label">
|
||||||
|
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<circle cx="18" cy="5" r="3"/>
|
||||||
|
<circle cx="6" cy="12" r="3"/>
|
||||||
|
<circle cx="18" cy="19" r="3"/>
|
||||||
|
<line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/>
|
||||||
|
<line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/>
|
||||||
|
</svg>
|
||||||
|
分享文章
|
||||||
|
</span>
|
||||||
|
<div class="share-buttons">
|
||||||
|
<a href="https://twitter.com/intent/tweet?url=<?php echo urlencode(get_the_permalink()); ?>&text=<?php echo urlencode(get_the_title()); ?>"
|
||||||
|
target="_blank" class="share-btn share-twitter" title="分享到 Twitter">
|
||||||
|
<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor">
|
||||||
|
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.linkedin.com/shareArticle?mini=true&url=<?php echo urlencode(get_the_permalink()); ?>&title=<?php echo urlencode(get_the_title()); ?>"
|
||||||
|
target="_blank" class="share-btn share-linkedin" title="分享到 LinkedIn">
|
||||||
|
<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor">
|
||||||
|
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<button class="share-btn share-copy" onclick="copyLink()" title="复制链接">
|
||||||
|
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71"/>
|
||||||
|
<path d="M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<!-- Post Navigation -->
|
||||||
|
<nav class="post-navigation" style="display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin-bottom: 48px;">
|
||||||
|
<?php
|
||||||
|
$prev_post = get_previous_post();
|
||||||
|
$next_post = get_next_post();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php if ($prev_post) : ?>
|
||||||
|
<a href="<?php echo esc_url(get_permalink($prev_post)); ?>"
|
||||||
|
style="padding: 20px; background: var(--bg-secondary); border-radius: 12px; border: 1px solid var(--border-color);">
|
||||||
|
<span style="font-size: 0.8125rem; color: var(--text-muted);">← 上一篇</span>
|
||||||
|
<div style="font-weight: 600; margin-top: 8px; color: var(--text-primary);">
|
||||||
|
<?php echo esc_html($prev_post->post_title); ?>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<?php else : ?>
|
||||||
|
<div></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($next_post) : ?>
|
||||||
|
<a href="<?php echo esc_url(get_permalink($next_post)); ?>"
|
||||||
|
style="padding: 20px; background: var(--bg-secondary); border-radius: 12px; border: 1px solid var(--border-color); text-align: right;">
|
||||||
|
<span style="font-size: 0.8125rem; color: var(--text-muted);">下一篇 →</span>
|
||||||
|
<div style="font-weight: 600; margin-top: 8px; color: var(--text-primary);">
|
||||||
|
<?php echo esc_html($next_post->post_title); ?>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<?php else : ?>
|
||||||
|
<div></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Comments -->
|
||||||
|
<?php
|
||||||
|
if (comments_open() || get_comments_number()) {
|
||||||
|
comments_template();
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php endwhile; ?>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<?php get_footer(); ?>
|
||||||
Reference in New Issue
Block a user