从博客到OA:WordPress OA 扩展全面指南

335 阅读8分钟

有个客户想要用WordPress做在线课堂,又不想用现有的解决方案,所以对WP进行了一系列开发。最后发展成了一个终极扩展教程。(当前WordPress版本或许做了一些调整,请各位只做参考,适当改良)

其中使用的插件也是可以各取所需的,有需要的同学直接定位到插件观看即可。

1. 插件加少许代码

1.1. 流程总结

  1. Role Manage Plugin 添加用户组
  2. Pinyin Permalink 优化别名(【重要】分词符号设置为:不使用分词符号)
  3. functions.php 中引入 oa-functions.php(详细在下面 ①)
  4. oa-functions.php 添加内容(详细在下面 ②)
  5. Ultimate Member 对接会员系统(详细在下面 ③)
  6. Admin Columns 实现后台列表页内容定制
  7. Better User Search 实现用户所有信息的搜索
  8. WP Admin Search Meta 搜索所有自定义字段信息
  9. Menu Editor Pro 实现不同用户看到不同后台界面
  10. 删除原有功能
    1. 删除编辑个人资料时的CSS选择器(详细在下面 ④)
    2. WP User Avatar 替换 Gravatar
  11. oa-functions.php中对版权信息进行修改(详细在下面 ⑤)
  12. functions.php中禁止自动升级(详细在下面 ⑥)
  13. wp-config.php 中禁止整个自动升级(详细在下面 ⑦)

1.2. 具体过程

1.2.1. functions.php 中引入 oa-functions.php

/**
* 引入OA系统Functions
*/
include_once('oa-functions.php');

1.2.2. oa-functions.php 添加内容

<?php
/**
* WordPress 修改用户角色名称和添加新用户角色 
* 
*/
function wpdx_change_role_name() {
    global $wp_roles;

    if ( ! isset( $wp_roles ) )
        $wp_roles = new WP_Roles();

    // 列出当前所有有效的用户角色...
    // $roles = $wp_roles->get_names();
    // print_r($roles);

    $wp_roles->role_names['zongguanliyuan'] = '总管理员';
    $wp_roles->role_names['xuesheng'] = '学生';
    $wp_roles->role_names['jiaoshi'] = '教师';
    $wp_roles->role_names['jiaoshiguanlifuzeren'] = '教师管理负责人';
    $wp_roles->role_names['chengjiguanlifuzeren'] = '成绩管理负责人';
    $wp_roles->role_names['houqinfuzeren'] = '后勤负责人';
    $wp_roles->role_names['rongyufuzeren'] = '荣誉负责人';
    $wp_roles->role_names['xiaowufuzeren'] = '校务负责人';
    $wp_roles->role_names['pingtaifuzeren'] = '平台负责人';
    $wp_roles->role_names['caiwufuzeren'] = '财务负责人';
}
add_action('init', 'wpdx_change_role_name');

?>

1.2.3. Ultimate Member 对接会员系统

  1. 创建角色匹配到系统会员上
  2. 不同会员添加不同表单
    1. 先创建表单,对应的显示部分:
      1. Title = 列表中显示的名称(可中文)
      2. Label = 前台用户看的显示的名称(可中文)
      3. Meta Key = 自定义字段索引键(英文)
      4. Help Text = 用户填写时候的帮助语句(可中文)
    2. 设置好 Privacy,可以给谁看
  3. 右侧 “Customize this form” 中 “使用全局设置” 否
    1. 设置指定角色,修改按钮描述
    2. 添加 Shortcode 到对应页面中(不重新创建页面)

1.2.4. 删除编辑个人资料时的CSS选择器

/**
* REMOVE ADMIN_PANEL CSS SELECTOR
*/
remove_action('admin_color_scheme_picker', 'admin_color_scheme_picker');

1.2.5. 5.oa-functions.php中对版权信息进行修改

/**
* ADMIN PANEL FOOTER MODIFICATION
*/
add_filter('admin_footer_text', 'left_admin_footer_text');
function left_admin_footer_text($text) {
    // 左边信息
    $text = '感谢使用智慧校园系统';
    return $text;
}

add_filter('update_footer', 'right_admin_footer_text', 11);
function right_admin_footer_text($text) {
    // 右边信息
    $text = "2.0 版本";
    return $text;
}

1.2.6. functions.php中禁止自动升级

/**
* UPDATE-RELATED
*/
add_filter('pre_site_transient_update_core',    create_function('$a', "return null;")); // 关闭核心提示
add_filter('pre_site_transient_update_plugins', create_function('$a', "return null;")); // 关闭插件提示
add_filter('pre_site_transient_update_themes',  create_function('$a', "return null;")); // 关闭主题提示
remove_action('admin_init', '_maybe_update_core');    // 禁止 WordPress 检查更新
remove_action('admin_init', '_maybe_update_plugins'); // 禁止 WordPress 更新插件
remove_action('admin_init', '_maybe_update_themes');  // 禁止 WordPress 更新主题

1.2.7. wp-config.php 中禁止整个自动升级

/** 关闭自动更新 */
define( 'AUTOMATIC_UPDATER_DISABLED', true );

2. 自定义分类和字段(纯代码)

2.1. 流程

都在 functions.php 中操作:

  1. 注册自定义文章类型
  2. 注册自定义分类
    1. 分类目录
    2. 标签
  3. 自定义字段的注册
    1. 自定义字段调用
    2. 保存自定义字段内容
  4. 自定义后台文章列表页显示字段
  5. 前台的调用
  6. 计算自定义字段值的总和
  7. 显示自定义分类法所有分类和链接

2.2. 具体代码

2.2.1. 注册自定义文章类型

注册一个自定义文章类型到WordPress。

  1. 编辑页面内包含的内容(也就是 supports ARRAY):
    • ’title’
    • ‘editor’(content)
    • ‘author’
    • ‘thumbnail’ (featured image, current theme must also support post-thumbnails)
    • ‘excerpt’
    • ‘trackbacks’
    • ‘custom-fields’
    • ‘comments’ (also will see comment count balloon on edit screen)
    • ‘revisions’ (will store revisions)
    • ‘page-attributes’ (menu order, hierarchical must be true to show Parent option)
    • ‘post-formats’ add post formats, see Post Formats
  2. 文章类型排序(自定义文章类型菜单位置,menu_position INT):
    • 5 - below Posts
    • 10 - below Media
    • 15 - below Links
    • 20 - below Pages
    • 25 - below comments
    • 60 - below first separator
    • 65 - below Plugins
    • 70 - below Users
    • 75 - below Tools
    • 80 - below Settings
    • 100 - below second separator
// Register Custom Post Type
function pt_custom_pt() {
     $labels = array(
          'name'                  => __( '名称', 'text_domain' ),
          'singular_name'         => __( '名称', 'text_domain' ),
          'menu_name'             => __( '菜单名', 'text_domain' ),
          'name_admin_bar'        => __( '管理员Bar名称', 'text_domain' ),
          'archives'              => __( '内容存档', 'text_domain' ),
          'parent_item_colon'     => __( '父级内容', 'text_domain' ),
          'all_items'             => __( '所有内容', 'text_domain' ),
          'add_new_item'          => __( '添加新的内容', 'text_domain' ),
          'add_new'               => __( '添加新的', 'text_domain' ),
          'new_item'              => __( '新的内容', 'text_domain' ),
          'edit_item'             => __( '修改内容', 'text_domain' ),
          'update_item'           => __( '更新内容', 'text_domain' ),
          'view_item'             => __( '查看内容', 'text_domain' ),
          'search_items'          => __( '搜索内容', 'text_domain' ),
          'not_found'             => __( '没有找到', 'text_domain' ),
          'not_found_in_trash'    => __( '没有找到在回收站', 'text_domain' ),
          'featured_image'        => __( '特色图片', 'text_domain' ),
          'set_featured_image'    => __( '设置特色图片', 'text_domain' ),
          'remove_featured_image' => __( '消除特色图片', 'text_domain' ),
          'use_featured_image'    => __( '用作特色图片', 'text_domain' ),
          'insert_into_item'      => __( '插入内容', 'text_domain' ),
          'uploaded_to_this_item' => __( '上传到这个内容', 'text_domain' ),
          'items_list'            => __( '内容列表', 'text_domain' ),
          'items_list_navigation' => __( '内容列表导航', 'text_domain' ),
          'filter_items_list'     => __( '内容列表过滤', 'text_domain' ),
     );
     $args = array(
          'label'                 => __( '名称', 'text_domain' ),
          'description'           => __( '简短的描述', 'text_domain' ),
          'labels'                => $labels,
          'supports'              => array( 'title','editor', 'excerpt', 'author', 'thumbnail', ),
          'taxonomies'            => array( 'category', 'post_tag' ),
          'hierarchical'          => true,
          'public'                => true,
          'show_ui'               => true,
          'show_in_menu'          => true,
          'menu_position'         => 5,
          'menu_icon'             => 'dashicons-admin-multisite',
          'show_in_admin_bar'     => true,
          'show_in_nav_menus'     => true,
          'can_export'            => true,
          'has_archive'           => true,          
          'exclude_from_search'   => false,
          'publicly_queryable'    => true,
          'capability_type'       => 'post',
     );

    register_post_type( 'pt_key_pt', $args );
}
add_action( 'init', 'pt_custom_pt', 0 );

2.2.2. 注册自定义分类

一篇文章可以属于多个分类,也可以属于多个不同种类的分类方式。分类分为 Hierarchical Taxonomy 类似于“分类目录”的样子。Non-hierarchical Taxonomy 类似于”标签“样式的。

2.2.2.1. 分类目录 Hierarchical Taxonomy

// Hierarchical Taxonomy
function my_taxonomies_custom() {
  $labels = array(
    'name'              => __( '电影分类', 'taxonomy 名称' ),
    'singular_name'     => __( '电影分类', 'taxonomy 单数名称' ),
    'search_items'      => __( '搜索电影分类' ),
    'all_items'         => __( '所有电影分类' ),
    'parent_item'       => __( '该电影分类的上级分类' ),
    'parent_item_colon' => __( '该电影分类的上级分类:' ),
    'edit_item'         => __( '编辑电影分类' ),
    'view_item'         => __( '查看电影分类' ),
    'update_item'       => __( '更新电影分类' ),
    'add_new_item'      => __( '添加新的电影分类' ),
    'new_item_name'     => __( '新电影分类' ),
    'menu_name'         => __( '电影分类' ),
  );
  $args = array(
    'labels' => $labels,
    'hierarchical' => true,
  );
  register_taxonomy( 'custom_category', 'pt_key_pt', $args );
}
add_action( 'init', 'my_taxonomies_custom', 0 );

2.2.2.2. 标签 Non-hierarchical Taxonomy

// Non-Hierarchical Taxonomy
function my_taxonomies_nonhir() {
  $labels = array(
    'name'              => __( '电影分类类似标签', 'taxonomy 名称' ),
    'singular_name'     => __( '电影分类类似标签', 'taxonomy 单数名称' ),
    'search_items'      => __( '搜索电影分类' ),
    'all_items'         => __( '所有电影分类' ),
    'edit_item'         => __( '编辑电影分类' ),
    'view_item'         => __( '查看电影分类' ),
    'update_item'       => __( '更新电影分类' ),
    'add_new_item'      => __( '添加新的电影分类' ),
    'new_item_name'     => __( '新电影分类' ),
    'menu_name'         => __( '电影分类类似标签' ),
    'popular_items'             => __( '最常用的标签' ),
    'separate_items_with_commas'  => __( '用逗号分类标签' ),
    'add_or_remove_items'         => __( '添加或删除标签' ),
    'choose_from_most_used'       => __( '从最常用的标签选取' ),
    'not_found'         => __( '没有标签,分类找到' ),
  );
  $args = array(
    'labels' => $labels,
    'hierarchical' => false,
  );
  register_taxonomy( 'nonhir_category', 'pt_key_pt', $args );
}
add_action( 'init', 'my_taxonomies_nonhir', 0 );

2.2.3. 自定义字段的注册

涉及到自定义字段的注册,实现以及保存自定义字段的内容。

// ADD META BOX
add_action( 'add_meta_boxes', 'movie_director' );
function movie_director() {
    add_meta_box(
        'movie_director',
        '电影导演',
        'movie_director_meta_box',
        'pt_key_pt',
        'side',
        'low'
    );
}

2.2.3.1. 自定义字段的回调函数

// CREATE CALLBACK FUNCTIONS FOR META BOX
function movie_director_meta_box($post) {

    // 创建临时隐藏表单,为了安全
    wp_nonce_field( 'movie_director_meta_box', 'movie_director_meta_box_nonce' );
    // 获取之前存储的值
    $value = get_post_meta( $post->ID, '_movie_director', true );

    ?>

    <label for="movie_director"></label>
    <input type="text" id="movie_director" name="movie_director" value="<?php echo esc_attr( $value ); ?>" placeholder="输入导演名称" >

    <?php
}

2.2.3.2. 保存自定义字段的内容

// SAVE DATA FOR META BOX
add_action('save_post', 'movie_director_save_meta_box');
function movie_director_save_meta_box($post_id){

    // 安全检查
    // 检查是否发送了一次性隐藏表单内容(判断是否为第三者模拟提交)
    if (!isset( $_POST['movie_director_meta_box_nonce'])) {
        return;
    }
    // 判断隐藏表单的值与之前是否相同
    if (!wp_verify_nonce( $_POST['movie_director_meta_box_nonce'], 'movie_director_meta_box')) {
        return;
    }
    // 判断该用户是否有权限
    if (!current_user_can( 'edit_post', $post_id)) {
        return;
    }

    // 判断 Meta Box 是否为空
    if (!isset( $_POST['movie_director'])) {
        return;
    }

    $movie_director = sanitize_text_field($_POST['movie_director']);
    update_post_meta($post_id, '_movie_director', $movie_director);
}

2.2.4. 自定义后台文章列表页显示的字段

实现文章列表要显示的内容,以及显示到自定义字段时显示什么,以及自定义字段的排序。

// EDITING COLUMNS FOR CUSTOM POST TYPE
add_filter( 'manage_edit-pt_key_pt_columns', 'my_edit_movie_columns' ) ;  
function my_edit_movie_columns( $columns ) {  
    $columns = array(  
        'cb' => '<input type="checkbox" />',  
        'title' => __( '名称' ),  
        'author' => __( '作者' ),  
        'categories' => __( '分类' ),  
        'tags' => __( '标签' ),
        'moviecate' => __( '电影分类' ),
        'movietags' => __( '电影标签' ),
        'director' => __( '电影导演' ),
        'comments' => __( '评论' ),
        'date' => __( '日期' ),
    );  
    return $columns;  
}

2.2.4.1. 显示自定义字段

// WHAT TO SHOW WHEN CUSTOM META BOX APPLIED
add_action( 'manage_pt_key_pt_posts_custom_column', 'my_manage_movie_columns', 10, 2 );  
function my_manage_movie_columns( $column, $post_id ) {  
    global $post;  
    /*当然你可以用if语句*/  
    switch( $column ) {  
        /* 如果栏目是'director' 的时候 */  
        case 'director' :  
            /* 得到文章的元数据. */  
            $director = get_post_meta( $post_id, '_movie_director', true );  
            /* 如果没有数据的时候给出默认显示数据为未知. */  
            if ( empty( $director ) )  
                echo __( '未知' );  
            /* 如果存在数据的话我们把描述也加上*/  
            else  
                echo __( $director );  
            break;  

        /* 如果栏目是 'movietags'的时候*/  
        case 'movietags' :  
            /* 得到文章的相应分类. */  
            $terms = get_the_terms( $post_id, 'nonhir_category' );  
            /* 如果有数据的时候,显示并加链接  */  
            if ( !empty( $terms ) ) {  
                $out = array();  
                /* 循环输出,并加链接*/  
                foreach ( $terms as $term ) {  
                    $out[] = sprintf( '<a href="%s">%s</a>',  
                                                /*这个链接地址不是自定义的,你在edit.php里面可以看到Wp_Query($arg),在这里只给arg增加即可*/  
                        esc_url( add_query_arg( array( 'post_type' => $post->post_type, 'nonhir_category' => $term->slug ), 'edit.php' ) ),  
                        esc_html( sanitize_term_field( 'name', $term->name, $term->term_id, 'nonhir_category', 'display' ) )  
                    );  
                }  
                /* join数据,并用逗号分开 */  
                echo join( ', ', $out );  
            }  
            /* 如果没有数据的时候给出默认显示数据为未知. */  
            else {  
                _e( '没有分类' );  
            }  
            break;  

        /* 如果栏目是 'moviecate'的时候*/  
        case 'moviecate' :  
            /* 得到文章的相应分类. */  
            $terms = get_the_terms( $post_id, 'custom_category' );  
            /* 如果有数据的时候,显示并加链接  */  
            if ( !empty( $terms ) ) {  
                $out = array();  
                /* 循环输出,并加链接*/  
                foreach ( $terms as $term ) {  
                    $out[] = sprintf( '<a href="%s">%s</a>',  
                                                /*这个链接地址不是自定义的,你在edit.php里面可以看到Wp_Query($arg),在这里只给arg增加即可*/  
                        esc_url( add_query_arg( array( 'post_type' => $post->post_type, 'custom_category' => $term->slug ), 'edit.php' ) ),  
                        esc_html( sanitize_term_field( 'name', $term->name, $term->term_id, 'custom_category', 'display' ) )  
                    );  
                }  
                /* join数据,并用逗号分开 */  
                echo join( ', ', $out );  
            }  
            /* 如果没有数据的时候给出默认显示数据为未知. */  
            else {  
                _e( '没有分类' );  
            }  
            break;  
        /* 跳出switch语句 */  
        default :  
            break;  
    }  
}

2.2.4.2. 自定义字段的排序

// REGISTER SORTABLE COLUMN FOR CUSTOM POST TYPE
add_filter( 'manage_edit-pt_key_pt_sortable_columns', 'my_movie_sortable_columns' );  
function my_movie_sortable_columns( $columns ) {  
    $columns['director'] = 'movie_director';  
    return $columns;  
}  
// SORTING COLUMN WHEN IN ADMIN PANEL
/* 只要当管理员在'edit.php'的时候,才处理 */  
add_action( 'load-edit.php', 'my_edit_movie_load' );  
function my_edit_movie_load() {  
    add_filter( 'request', 'my_sort_movies' );  
}  
/*对电影排序 */  
function my_sort_movies( $vars ) {  
    /* 判断是否浏览的是movie*/  
    if ( isset( $vars['post_type'] ) && 'pt_key_pt' == $vars['post_type'] ) {  
        /* 看下是否已经对duration进行排序了*/  
        if ( isset( $vars['orderby'] ) && 'director' == $vars['orderby'] ) {  
            /* 把自定义排序增加到$vars里面去 */  
            $vars = array_merge(  
                $vars,  
                array(  
                    'meta_key' => 'director',  
                    'orderby' => 'meta_value_num'
                )  
            );  
        }  
    }  
    return $vars;  
}

2.2.5. 前台调用

2.2.5.1. 调用自定义分类

简单的调用自定义分类的方法,就是在需要显示的地方加入下面的代码,可以用拆分的形式写:

<!-- 传入参数 -->
<?php
     $args = array( 
         'post_type' => 'movie', 
         'posts_per_page' => 10 ,
         'date_query' => array(
            array(
                'after'     => array(
                    'year'  => 2016,
                    'month' => 10,
                    'day'   => 1,
                ),
                'before'    => array(
                    'year'  => 2016,
                    'month' => 12,
                    'day'   => 31,
                ),
                'inclusive' => true,
            ),
        ),
     );
    $loop = new WP_Query( $args );
    while ( $loop->have_posts() ) : $loop->the_post(); ?>
<!-- 显示内容 -->
<h1><?php the_title();?></h1>
<div 
class="entry-content">
      <?php the_content(); ?>
</div>
<?php endwhile; ?>
也可以用整合的方式:

<?php

$args = array( 'post_type' => 'custom_post_type', 'posts_per_page' => 10 );
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post();
  the_title();
  echo '<div class="entry-content">';
  the_content();
  echo '</div>';
endwhile;

?>

2.2.5.2. 输出某个区间内的文章

其中可以加入日期,比如查询某个区间内的内容,就是在 $args 中加入:

'date_query' => array(
    array(
        'after'     => array(
            'year'  => 2015,
            'month' => 12,
            'day'   => 1,
        ),
        'before'    => array(
            'year'  => 2016,
            'month' => 1,
            'day'   => 1,
        ),
    'inclusive' => true,
),

2.2.5.3. 在主循环中调用自定义字段

<div class="custom-field">
    <?php
    $key_1_value = get_post_meta($post->ID, 'custom-field-name', true);
    // check if the custom field has a value
    if($key_1_value != '') {
      echo $key_1_value;
    }
    ?>
</div>

2.2.6. 计算自定义字段值的总和

昨天(《WP开发OA手记》-DAY4-)尝试了大量在后台实现计算的方法,实现的思路是正确的,先获取到当前输出的POST的某个字段的值,然后把它们加起来,显示在页面的某个地方。但真正尝试后才发现,WP后台基本都是用PHP实现的。很混乱怎么加入自己的内容。

今天,更换了思路,把计算放在前台实现。

首先,创建一个计算的页面,取名叫 test.php,再用”不同页面使用不同模板“的方法调用适当的模板。页面取名叫”计算“。

2.2.6.1. 简单计算和分开模板

  1. 【正确调用模板】在WP模板默认 page.php 文件中,加入下面代码,让模板调用正确:
<?php
$post = $wp_query->post;
if (is_page('2')){
    include(TEMPLATEPATH . '/archive.php');
} elseif (is_page('42')) {
    include(TEMPLATEPATH . '/test.php');
} else {
    include(TEMPLATEPATH . '/page-normal.php');
} ?>
  1. 【实现计算功能】然后再向 test.php 中加入以下代码实现功能:
<?php
/**
 * Displaying a form for CALCULATION
 * 试验一下功能实现的如何
 */
get_header(); ?>
<div id="primary" class="content-area">
 <main id="main" class="site-main" role="main">
<?php
/* 声明一个数组,放在这里,避免循环过程中重置,设置一个变量,保存总和 */
$queryCal = array();
$x = 0;
/**
 * 设置主循环,传入参数
 */
$args = array( 
    'post_type' => 'movie', 
    'posts_per_page' => -1,
    'date_query' => array(
        array(
            'after' => array(
                'year'  => 2014,
                'month' => 10,
                'day'   => 1,
            ),
            'before'    => array(
                'year'  => 2016,
                'month' => 12,
                'day'   => 31,
            ),
            'inclusive' => true,
        ),
    ),
);
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post(); ?>
    <!-- 显示内容 -->
    <h1><?php the_title();?></h1>
    <div class="entry-content">
          <?php the_content(); ?>
    </div>
    <div class="custom-field">
    
    <?php
    /**
     * 显示自定义字段内容
     */
    $key_1_value = get_post_meta($post->ID, 'duration', true);
    // check if the custom field has a value
    if($key_1_value != '') {
        echo $key_1_value;
    }
    ?>
    </div>
    
    <?php
    /**
     * 给数组添加值,每次循环都会添加新的值给数组
     */
    $postId = $post->ID;
    $queryCal[$postId] = $key_1_value;
    ?>
    
    <?php
    /**
     * 结束循环
     */
     endwhile; ?>
<div class="test">
    <?php    
    /**
     * 输出数组
     */
    foreach ($queryCal as $key=>$value){
        echo $key . '->' . $value . "";
        $x = $x + $value;
        echo "Current Calculation: " . $x . "";
    }
    echo "FINAL" . $x;
    ?>
</div>

 </main><!-- .site-main -->
 <?php get_sidebar( 'content-bottom' ); ?>
</div><!-- .content-area -->
<?php get_sidebar(); ?>
<?php get_footer(); ?>
  1. 【结果和过程分开】测试完成后,将计算部分放入新的模板 test-calculation.php 也就是计算结果页面,设置好这个页面和对应模板:
<?php
/**
 * Displaying a form for CALCULATION
 */
get_header(); ?>

<div id="primary" class="content-area">
    <main id="main" class="site-main" role="main">

    <?php
    /**
     * 声明一个数组,放在这里,避免循环过程中重置
     * 设置一个变量,保存总和
     */

    $queryCal = array();
    $x = 0;?>

    <?php 
    /**
     * 设置主循环,传入参数
     * 相比较上面,也就是改变了这里的内容,获取上一个页面传过来的值,并且将字符串转换为整数
     */

    $startyear = intval($_POST['startyear']);
    $startmonth = intval($_POST['startmonth']);
    $startday = intval($_POST['startday']);

    $endyear = intval($_POST['endyear']);
    $endmonth = intval($_POST['endmonth']);
    $endday = intval($_POST['endday']);

     $args = array( 
         'post_type' => 'movie', 
         'posts_per_page' => -1,
         'date_query' => array(
            array(
                'after'     => array(
                    'year'  => $startyear,
                    'month' => $startmonth,
                    'day'   => $startday,
                ),
                'before'    => array(
                    'year'  => $endyear,
                    'month' => $endmonth,
                    'day'   => $endday,
                ),
                'inclusive' => true,
            ),
        ),
     );
    $loop = new WP_Query( $args );
    while ( $loop->have_posts() ) : $loop->the_post(); ?>

    <!-- 显示内容 -->
    <h1><?php the_title();?></h1>
    <div class="entry-content">
          <?php the_content(); ?>
    </div>

    <div class="custom-field">
    
    <?php
    /**
     * 显示自定义字段内容
     */
    $key_1_value = get_post_meta($post->ID, 'duration', true);
    // check if the custom field has a value
    if($key_1_value != '') {
      echo $key_1_value;
    }
    ?>
    </div>

    <?php
    /**
     * 给数组添加值,每次循环都会添加新的值给数组
     */
    $postId = $post->ID;
    $queryCal[$postId] = $key_1_value;

    ?>

    
    <?php
    /**
     * 结束循环
     */
     endwhile; ?>

<div class="test">
    <?php
    /**
     * 输出数组
     */
    foreach ($queryCal as $key=>$value){
        echo $key . '->' . $value . "";
        $x = $x + $value;
        echo "Current Calculation: " . $x . "";
    }
    echo "FINAL" . $x;
    ?>
</div>
     </main><!-- .site-main -->
     <?php get_sidebar( 'content-bottom' ); ?>
</div><!-- .content-area -->

<?php get_sidebar(); ?>
<?php get_footer(); ?>
  1. 【提供自定义时间段的查询】将原来的 test.php 改成表格,提供开始和结束时间,以便查询:
<?php
/**
 * Displaying a form for CALCULATION
 * 注意 <form> 里面 action 的值是结果页面的 URL,不是模板文件本身
 */

get_header(); ?>

<div id="primary" class="content-area">
    <main id="main" class="site-main" role="main">

    <form method="post" action="<?php echo home_url(); ?>/index.php/result/">
        START FROM: 
        <input type="text" name="startyear" placeholder="YYYY" />
        <input type="text" name="startmonth" placeholder="MM" />
        <input type="text" name="startday" placeholder="DD" />

        END FROM: 
        <input type="text" name="endyear" placeholder="YYYY" />
        <input type="text" name="endmonth" placeholder="MM" />
        <input type="text" name="endday" placeholder="DD" />

        <input type="submit" value="查询" />
    </form>


    </main><!-- .site-main -->

    <?php get_sidebar( 'content-bottom' ); ?>

</div><!-- .content-area -->

<?php get_sidebar(); ?>
<?php get_footer(); ?>

2.2.6.2. 根据分类输出内容

上面实现了根据某个时间段输出所有内容,但设想,如果只想出现某个分类的某个时间段的内容怎么做呢?

于是,开始了漫漫征途。

  1. 通过传入参数改变显示内容

在 while loop 前面的 $args 中加入些内容,使其变成这样:

其中,$putpath 是自定义分类法,$slug 是自定义分类法下,用户自己设定的小分类

$args = array( 
     'post_type' => 'movie', 
     'tax_query' => array(
        array(
            'taxonomy' => $putpath,
            'field'    => 'slug',
            'terms'    => $slug,
        ),
    ),
        'posts_per_page' => -1 ,
        'date_query' => array(
        array(
            'after'     => array(
                'year'  => $startyear,
                'month' => $startmonth,
                'day'   => $startday,
            ),
            'before'    => array(
                'year'  => $endyear,
                'month' => $endmonth,
                'day'   => $endday,
            ),
            'inclusive' => true,
        ),
    ),
);
  1. 修改 test.php

<form> 下加入下面内容:

前两个 <option> 的值就是自定义分类法的名字了。由于小分类是用户自己加入的,所以通过让用户输入代号(也就是别名)来传入参数

支出/收入:
<select name="putpath">
  <option value="output">支出</option>
  <option value="income">收入</option>
</select>
小分类代号:<input type="text" name="slug" placeholder="此处填写小分类的代号"/>
  1. 在 test-calculation.php 中获取对应的值
$putpath = $_POST['putpath'];
$slug = $_POST['slug'];

2.2.6.3. 如果小分类为空

之前认为,这个问题很小。但解决起来,确实费了不少功夫。

解决这个问题,首先要知道WP的 tax_query 数组,这个数组包含的几个参数,如果参数不全,空或者NULL就会显示不出来。

当用户没有输入任何内容的时候,就显示不出东西来了。但现实中要让它显示全部内容。所以怎么解决?解决方法就是把当前Taxonomy下面的所有Slug全都导入成一个数组,赋值给 $args['tax_query'][0][terms],代码如下:

这一段代码放到 $args 生成之后,while loop 开始之前:

if ($slug == ""){
    $custom_terms = get_terms($putpath);    // 获取 Taxonomy 包含所有 terms 的数组含有大量内容
    $length = count($custom_terms);         // 获取数组的长度,以便轮出有用内容
    $newterms = array();                    // 创建一个准备只包含 terms 的数组
    for ($i=0; $i<$length; $i++) {
        $newterms[$i] = $custom_terms[$i]->slug;    // 给数组添加值,只添加大数组下面 Object(每个Term都是一个对象)下的 slug 属性
    };
    $args['tax_query'][0][terms] = $newterms;   // 赋值给 tax_query
};

2.2.7. 显示自定义分类法的所有分类和链接

参考:WP智库

<?php
$taxonomy = 'genre'$orderby = 'name';
$show_count = 0; // 1 为是, 0 为否
$pad_counts = 0; // 1 为是, 0 为否
$hierarchical = 1; // 1 为是, 0 为否
$title = '';

$args = array(
    'taxonomy' => $taxonomy,
    'orderby' => $orderby,
    'show_count' => $show_count,
    'pad_counts' => $pad_counts,
    'hierarchical' => $hierarchical,
    'title_li' => $title
);
?>

<ul>
<?php wp_list_categories( $args ); ?>
</ul>

2.3. 手动添加后台菜单

2.3.1. “外观”菜单中添加子菜单

2.3.1.1. add_theme_page()

<?php
add_theme_page( $page_title, $menu_title, $capability, $menu_slug, $function);   
    //page_titile - 显示在标题栏中的内容
    //menu_title - 显示在后台左边菜单的标题   
    //capability - 访问这个页面需要的权限   
    //menu_slug - 别名,需要独一无二哦   
    //function - 执行的函数 
?>

2.3.1.2. 具体操作

  1. 为了保证主题文件的干净规整,需要在 functions.php 之外再建立一个新的 php 文件。这里命名为 myfunctions.php
  2. 在 functions.php 中引用这个文件,即在页面最后添加:include_once('myfunctions.php');
  3. 在 myfunctions.php 中添加函数 add_theme_page();
function test_add_page(){
    add_theme_page('标题栏标题', '菜单标题', 'administrator', 'titlebiaoti', 'test_display');
}
  1. 创建执行的函数 test_display();
function test_display(){
    echo '<h1>THIS IS A SETTING PAGE</h1>';
}
  1. 添加动作 add_action('admin_menu', 'test_add_page');

2.3.2. 添加顶级菜单

2.3.2.1. add_menu_page()

<?php
add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $position ); 
    //page_title页面title标签信息 
    //$menu_title 菜单标题 
    //capability 权限 
    //menu_slug 别名 
    //function 执行函数 
    //icon_url 菜单图标url地址 
    //position 此菜单项在菜单中的位置,警告:如果两个菜单项的位置属性相同,其中一个可能要被覆盖
?>

其中position对应的如下:

  • 2 Dashboard
  • 4 Separator
  • 5 Posts
  • 10 Media
  • 15 Links
  • 20 Pages
  • 25 Comments
  • 59 Separator
  • 60 Appearance
  • 65 Plugins
  • 70 Users
  • 75 Tools
  • 80 Settings
  • 99 Separator

2.3.2.2. 具体操作

  1. 在 “①在‘外观’菜单中添加子页面” 中创建的 myfunctions.php 里添加下面内容
  2. 同上一个,先要为这个函数创建一个自己的函数
function test_add_top_page(){
     add_menu_page('顶级标题栏标题', '顶级菜单标题', 'edit_themes', 'dingjicaidan', 'test_display_top','','6');
}
  1. 创建可执行的函数 test_display_top
function test_display_top(){
    echo '<h1>THIS IS THE TOP PAGE</h1>';
}
  1. 添加钩子

add_action('admin_menu', 'test_add_top_page’);

往不同地方添加子菜单项

// For Dashboard
add_submenu_page( 'index.php', ... ); // Also see add_dashboard_page()
// For Posts
add_submenu_page( 'edit.php', ... ); // Also see Also see add_posts_page()
// For Media
add_submenu_page( 'upload.php', ... ); // Also see add_media_page()
// For Links
add_submenu_page( 'link-manager.php', ... ); // Also see add_links_page()
// For Pages
add_submenu_page( 'edit.php?post_type=page', ... ); // Also see add_pages_page()
// For Comments
add_submenu_page( 'edit-comments.php', ... ); // Also see add_comments_page()
// For Appearance
add_submenu_page( 'themes.php', ... ); // Also see add_theme_page()
// For Plugins
add_submenu_page( 'plugins.php', ... ); // Also see add_plugins_page()
// For Users
add_submenu_page( 'users.php', ... ); // Also see add_users_page()
// For Tools
add_submenu_page( 'tools.php', ... ); // Also see add_management_page()
// For Settings
add_submenu_page( 'options-general.php', ... ); // Also see add_options_page()
// For Custom Post Types
add_submenu_page( 'edit.php?post_type=your_post_type', ... );