使用的AI
腾讯元宝、问小白、deepseek官方、Grok3
实现的功能
- 后台新增或更新网址导航
- 后台设置网址导航一级分类&二级分类
- 支持使用排序值为网址导航卡片和分类排序
- 网址导航卡片支持显示图标
- 暗夜模式支持(不一定适用所有主题)
- 手机屏幕适配
演示



样式目前比较简陋,后面我会继续把她开发成自己的模样(车轱辘咕噜)~
使用教程
主题functions.php文件新增
// 注册网址导航文章类型
function register_webnav_post_type() {
register_post_type('webnav', array(
'labels' => array(
'name' => __('网址导航'),
'singular_name' => __('导航项目'),
),
'public' => true,
'has_archive' => true,
'supports' => array('title'),
'menu_icon' => 'dashicons-admin-links',
'map_meta_cap' => true,
'rewrite' => array('slug' => 'webnav'),
'show_in_rest' => false // 确保不触发文章类型变更
));
}
add_action('init', 'register_webnav_post_type');
// 注册导航分类
function register_nav_category() {
register_taxonomy('nav_category', 'webnav', array(
'label' => __('导航分类'),
'hierarchical' => true,
'show_admin_column' => true,
'rewrite' => array('slug' => 'nav-category'),
'show_in_rest' => false
));
}
add_action('init', 'register_nav_category');
// 添加导航信息元字段
function add_nav_meta_boxes() {
add_meta_box(
'nav_info',
'导航信息',
'nav_meta_box_callback',
'webnav',
'normal',
'high'
);
}
add_action('add_meta_boxes', 'add_nav_meta_boxes');
function nav_meta_box_callback($post) {
wp_nonce_field('nav_meta_save', 'nav_meta_nonce');
// 获取现有数据
$meta_data = [
'_nav_url' => get_post_meta($post->ID, '_nav_url', true),
'_nav_desc' => get_post_meta($post->ID, '_nav_desc', true),
'_nav_order' => get_post_meta($post->ID, '_nav_order', true) ?: 10,
'_nav_image_url' => get_post_meta($post->ID, '_nav_image_url', true)
];
// 输入字段结构
echo '<div style="display:grid;gap:15px;padding:10px 0;">';
echo '<div>
<label style="display:block;margin-bottom:5px;font-weight:500;">网站URL</label>
<input type="url" name="_nav_url" value="'.esc_url($meta_data['_nav_url']).'"
placeholder="https://example.com/" style="width:100%" required>
</div>';
echo '<div>
<label style="display:block;margin-bottom:5px;font-weight:500;">描述说明</label>
<textarea name="_nav_desc" style="width:100%;height:80px"
placeholder="网站简要描述">'.esc_textarea($meta_data['_nav_desc']).'</textarea>
</div>';
echo '<div>
<label style="display:block;margin-bottom:5px;font-weight:500;">图片地址</label>
<input type="url" name="_nav_image_url" value="'.esc_url($meta_data['_nav_image_url']).'"
placeholder="https://example.com/logo.png" style="width:100%">
<p style="color:#666;font-size:0.9em;margin:5px 0 0;">直接输入图片完整URL地址</p>
</div>';
echo '<div>
<label style="display:block;margin-bottom:5px;font-weight:500;">排序数字</label>
<input type="number" name="_nav_order" value="'.esc_attr($meta_data['_nav_order']).'"
min="1" max="999" style="width:120px">
<p style="color:#666;font-size:0.9em;margin:5px 0 0;">数字越小排序越靠前</p>
</div>';
echo '</div>';
}
// 保存元数据
function save_nav_meta_data($post_id) {
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (!isset($_POST['nav_meta_nonce']) || !wp_verify_nonce($_POST['nav_meta_nonce'], 'nav_meta_save')) return;
if (!current_user_can('edit_post', $post_id)) return;
$fields = [
'_nav_url' => 'esc_url_raw',
'_nav_desc' => 'sanitize_textarea_field',
'_nav_order' => 'intval',
'_nav_image_url' => 'esc_url_raw'
];
foreach ($fields as $key => $sanitize) {
if (isset($_POST[$key])) {
$value = call_user_func($sanitize, $_POST[$key]);
update_post_meta($post_id, $key, $value);
} else {
if ($key === '_nav_order') {
update_post_meta($post_id, $key, 10);
} else {
delete_post_meta($post_id, $key);
}
}
}
}
add_action('save_post_webnav', 'save_nav_meta_data');
// 分类排序功能(保持不变)
function add_category_order_field($term) {
$order = get_term_meta($term->term_id, 'category_order', true) ?: 10;
echo '<div class="form-field">
<label>分类排序</label>
<input type="number" name="category_order" value="'.esc_attr($order).'">
<p>数字越小排序越靠前</p>
</div>';
}
add_action('nav_category_add_form_fields', 'add_category_order_field');
function edit_category_order_field($term) {
$order = get_term_meta($term->term_id, 'category_order', true) ?: 10;
echo '<tr class="form-field">
<th><label>分类排序</label></th>
<td>
<input type="number" name="category_order" value="'.esc_attr($order).'">
<p class="description">数字越小排序越靠前</p>
</td>
</tr>';
}
add_action('nav_category_edit_form_fields', 'edit_category_order_field');
function save_category_order_data($term_id) {
if (isset($_POST['category_order'])) {
update_term_meta($term_id, 'category_order', absint($_POST['category_order']));
}
}
add_action('created_nav_category', 'save_category_order_data');
add_action('edited_nav_category', 'save_category_order_data');
主题目录下网址导航页面代码:page-custom-nav.php
<?php
/**
* Template Name: 网站导航模板
*/
get_header(); ?>
<style>
/* 保持原有所有CSS完全不变 */
.webnav-container {
max-width: 1400px;
margin: 0 auto;
display: grid;
grid-template-columns: 240px 1fr;
gap: 30px;
padding: 20px;
min-height: calc(100vh - 400px);
}
.nav-sidebar {
position: sticky;
top: 100px;
background: #f8f9fa;
padding: 20px;
border-radius: 8px;
height: fit-content;
}
.parent-cat {
position: relative;
}
.parent-cat > a {
display: block;
padding: 10px;
color: #333;
text-decoration: none;
}
.toggle {
position: absolute;
right: 10px;
top: 12px;
cursor: pointer;
}
.child-cats {
display: none;
margin-left: 15px;
border-left: 2px solid #ddd;
padding-left: 10px;
}
.nav-items {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 15px;
}
.nav-item {
background: #fff;
border: 1px solid #eee;
border-radius: 8px;
padding: 15px;
min-height: 100px;
transition: transform 0.2s;
}
.nav-item-content {
display: flex;
align-items: flex-start;
gap: 12px;
height: 100%;
}
.nav-icon {
width: 32px;
height: 32px;
border-radius: 6px;
flex-shrink: 0;
object-fit: cover;
background: #f5f5f5;
}
.nav-info {
flex: 1;
}
.nav-info h4 {
margin: 0 0 8px;
font-size: 16px;
}
.nav-info p {
color: #666;
margin: 0;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* 暗夜模式 */
.dark .nav-sidebar {
background: #2c2e3c;
}
.dark .parent-cat > a {
color: #e0e0e0;
}
.dark .nav-item {
background: #373a47;
border-color: #464959;
}
.dark .nav-info p {
color: #a0a0a0;
}
.dark .child-cats {
border-color: #464959;
}
.dark .nav-icon {
background: #444;
}
@media (max-width: 768px) {
.webnav-container {
grid-template-columns: 1fr;
padding: 10px;
min-height: calc(100vh - 300px);
}
.nav-sidebar {
display: none;
}
.mobile-menu-btn {
position: fixed;
bottom: 240px;
right: 20px;
z-index: 1001;
width: 36px;
height: 36px;
border-radius: 50%;
background: rgba(255,255,255,0.95);
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
border: none;
font-size: 22px;
backdrop-filter: blur(10px);
}
.dark .mobile-menu-btn {
background: rgba(44,46,60,0.95);
box-shadow: 0 4px 12px rgba(255,255,255,0.15);
color: #FFF;
}
.mobile-sidebar {
position: fixed;
bottom: 280px;
right: 20px;
width: 260px;
max-height: 60vh;
background: rgba(255,255,255,0.98);
border-radius: 12px;
transform: scale(0);
transform-origin: bottom right;
transition: 0.2s;
z-index: 999;
padding: 16px;
overflow-y: auto;
}
.mobile-sidebar.active {
transform: scale(1);
}
.nav-items {
grid-template-columns: repeat(2, 1fr);
gap: 10px;
}
.nav-item {
min-height: 90px;
padding: 12px;
}
.nav-info p {
-webkit-line-clamp: 1;
}
.nav-icon {
width: 28px;
height: 28px;
}
}
@media (min-width: 1200px) {
.h3, h3 {
font-size: 1.2rem;
}}
</style>
<script>
document.addEventListener('DOMContentLoaded', function(){
// 平滑滚动函数
function smoothScroll(targetId) {
const target = document.querySelector(targetId);
if(target) {
const offset = 100; // 留出顶部空间
window.scrollTo({
top: target.offsetTop - offset,
behavior: 'smooth'
});
}
}
// 桌面端分类切换
document.querySelectorAll('.parent-cat').forEach(item => {
const toggle = item.querySelector('.toggle');
const childList = item.querySelector('.child-cats');
if(childList) {
toggle.textContent = '+';
item.querySelector('a').addEventListener('click', e => {
e.preventDefault();
const targetId = e.currentTarget.getAttribute('href');
smoothScroll(targetId);
childList.style.display = childList.style.display === 'block' ? 'none' : 'block';
toggle.textContent = childList.style.display === 'block' ? '-' : '+';
});
} else {
item.querySelector('a').addEventListener('click', e => {
e.preventDefault();
smoothScroll(e.currentTarget.getAttribute('href'));
});
}
});
// 移动端菜单处理
if(window.innerWidth <= 768) {
const mobileBtn = document.createElement('button');
mobileBtn.className = 'mobile-menu-btn';
mobileBtn.innerHTML = '☰';
document.body.prepend(mobileBtn);
const mobileMenu = document.createElement('div');
mobileMenu.className = 'mobile-sidebar';
mobileMenu.innerHTML = document.querySelector('.nav-sidebar').innerHTML;
document.body.appendChild(mobileMenu);
mobileBtn.addEventListener('click', (e) => {
e.stopPropagation();
mobileMenu.classList.toggle('active');
});
document.addEventListener('click', (e) => {
if(!mobileMenu.contains(e.target) && !mobileBtn.contains(e.target)) {
mobileMenu.classList.remove('active');
}
});
mobileMenu.querySelectorAll('.parent-cat').forEach(item => {
const childList = item.querySelector('.child-cats');
if(childList) {
const toggle = document.createElement('span');
toggle.className = 'toggle';
toggle.textContent = '+';
item.prepend(toggle);
item.querySelector('a').addEventListener('click', e => {
e.preventDefault();
const targetId = e.currentTarget.getAttribute('href');
smoothScroll(targetId);
childList.style.display = childList.style.display === 'block' ? 'none' : 'block';
toggle.textContent = childList.style.display === 'block' ? '-' : '+';
});
} else {
item.querySelector('a').addEventListener('click', e => {
e.preventDefault();
smoothScroll(e.currentTarget.getAttribute('href'));
mobileMenu.classList.remove('active');
});
}
});
}
});
</script>
<div class="webnav-container">
<aside class="nav-sidebar">
<h3>导航分类</h3>
<ul>
<?php
$main_cats = get_terms(array(
'taxonomy' => 'nav_category',
'parent' => 0,
'meta_key' => 'category_order',
'orderby' => 'meta_value_num',
'order' => 'ASC',
'hide_empty' => false
));
foreach($main_cats as $cat) :
$children = get_terms(array(
'taxonomy' => 'nav_category',
'parent' => $cat->term_id,
'meta_key' => 'category_order',
'orderby' => 'meta_value_num',
'order' => 'ASC',
'hide_empty' => false
));
?>
<li class="parent-cat">
<a href="#cat-<?php echo $cat->term_id; ?>">
<?php echo $cat->name; ?>
<?php if($children) echo '<span class="toggle"></span>'; ?>
</a>
<?php if($children) : ?>
<ul class="child-cats">
<?php foreach($children as $child) : ?>
<li><a href="#cat-<?php echo $child->term_id; ?>"><?php echo $child->name; ?></a></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
</aside>
<main>
<?php foreach($main_cats as $main_cat) : ?>
<section id="cat-<?php echo $main_cat->term_id; ?>">
<h2><?php echo $main_cat->name; ?></h2>
<?php
$sub_cats = get_terms(array(
'taxonomy' => 'nav_category',
'parent' => $main_cat->term_id,
'meta_key' => 'category_order',
'orderby' => 'meta_value_num',
'order' => 'ASC',
'hide_empty' => false
));
if($sub_cats) :
foreach($sub_cats as $sub_cat) :
?>
<div class="sub-category">
<h3 id="cat-<?php echo $sub_cat->term_id; ?>"><?php echo $sub_cat->name; ?></h3>
<div class="nav-items">
<?php
$posts = get_posts(array(
'post_type' => 'webnav',
'tax_query' => array(array(
'taxonomy' => 'nav_category',
'field' => 'term_id',
'terms' => $sub_cat->term_id
)),
'meta_key' => '_nav_order',
'orderby' => 'meta_value_num',
'order' => 'ASC',
'posts_per_page' => -1
));
foreach($posts as $post) :
$image_url = get_post_meta($post->ID, '_nav_image_url', true);
?>
<a href="<?php echo esc_url(get_post_meta($post->ID, '_nav_url', true)); ?>" class="nav-item-link" target="_blank">
<div class="nav-item">
<div class="nav-item-content">
<?php if(!empty($image_url)) : ?>
<img src="<?php echo esc_url($image_url); ?>"
class="nav-icon"
alt="<?php echo esc_attr(get_the_title($post)); ?> logo">
<?php endif; ?>
<div class="nav-info">
<h4><?php echo get_the_title($post); ?></h4>
<p><?php echo esc_html(get_post_meta($post->ID, '_nav_desc', true)); ?></p>
</div>
</div>
</div>
</a>
<?php endforeach; ?>
</div>
</div>
<?php endforeach; ?>
<?php else : ?>
<div class="nav-items">
<?php
$posts = get_posts(array(
'post_type' => 'webnav',
'tax_query' => array(array(
'taxonomy' => 'nav_category',
'field' => 'term_id',
'terms' => $main_cat->term_id
)),
'meta_key' => '_nav_order',
'orderby' => 'meta_value_num',
'order' => 'ASC',
'posts_per_page' => -1
));
foreach($posts as $post) :
$image_url = get_post_meta($post->ID, '_nav_image_url', true);
?>
<a href="<?php echo esc_url(get_post_meta($post->ID, '_nav_url', true)); ?>" class="nav-item-link" target="_blank">
<div class="nav-item">
<div class="nav-item-content">
<?php if(!empty($image_url)) : ?>
<img src="<?php echo esc_url($image_url); ?>"
class="nav-icon"
alt="<?php echo esc_attr(get_the_title($post)); ?> logo">
<?php endif; ?>
<div class="nav-info">
<h4><?php echo get_the_title($post); ?></h4>
<p><?php echo esc_html(get_post_meta($post->ID, '_nav_desc', true)); ?></p>
</div>
</div>
</div>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
</section>
<?php endforeach; ?>
</main>
</div>
<?php get_footer(); ?>