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:
Your Name
2026-08-18 16:05:14 +08:00
commit 6d4368fbd1
17 changed files with 4103 additions and 0 deletions
Executable
+83
View File
@@ -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(); ?>
Executable
+191
View File
@@ -0,0 +1,191 @@
# TechBlog Pro - WordPress Theme
一个专为IT技术分享设计的现代化WordPress主题,具有清爽的界面、强大的代码高亮支持和优秀的阅读体验。
![TechBlog Pro](screenshot.png)
## ✨ 特性
### 🎨 设计特色
- **现代化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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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>&copy; <?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
View File
@@ -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
View File
@@ -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">
+424
View File
@@ -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');
Executable
+99
View File
@@ -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
View File
@@ -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');
}
});
});
})();
Executable
+25
View File
@@ -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(); ?>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Executable
+68
View File
@@ -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
View File
@@ -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
View File
@@ -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(); ?>
Executable
+1475
View File
File diff suppressed because it is too large Load Diff