使用AI为博客新增网址导航功能

2025-03-03 706 0

使用的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(); ?>

相关文章

面向AI编程:使用Claude-3.7写一个文章归档页面
一键屏蔽垃圾爬虫,包括Censys、facebook、SemrushBot、GPTbot
WordPress 条件判断标签及用法大全
curl及wget命令使用教程
Linux实现免密登录以及密钥生成方法
亚洲云linux工具箱&整理一些常用的脚本(持续更新中)

发布评论