WordPress 后台文章和评论快捷按钮编辑

一、评论列表的操作

先记录一下在后台评论列表项目里面添加快捷按钮的办法:

1.1. 添加按钮的 Markup

/**
 * 插入【置顶】的评论操作标签
 */
function comment_row_action( $actions, $comment ) {
    // 置顶/取消置顶
    if(get_comment_meta($comment->comment_ID, 'is_sticky', true) === '1') {
        $new_actions['stick'] = '<a class="comment-action-custom"
            href="javascript:;" data-action="unstick" data-post-id="'.$comment->comment_post_ID.'"
            data-comment-id="'.$comment->comment_ID.'">取消置顶</a>';
    } else {
        $new_actions['unstick'] = '<a class="comment-action-custom"
            href="javascript:;" data-action="stick" data-post-id="'.$comment->comment_post_ID.'"
            data-comment-id="'.$comment->comment_ID.'">置顶</a>';
    }

    // 在前边插入新增的两个动作链接并返回
    return array_merge($new_actions, $actions);
}
add_filter('comment_row_actions', 'comment_row_action', 10, 2);

加入上面的代码到 functions.php 之后,我们在后台的评论列表里面就可以看到多了一个快捷按钮“置顶”或者“取消置顶”出来,视乎状态。

注意上述的 <a> 标签里面有几个重要的属性:

  1. class="comment-action-custom"
  2. data-action="..."
  3. data-post-id="..."
  4. data-comment-id="..."

当且仅当存在这几个属性,点击这个按钮的时候,才会触发自动的 ajax 异步提交去后台修改状态。至于如何发送 ajax,下一节说明:

1.2. 添加评论按钮的动作响应

当点击了这个我们自定义的按钮之后,相应就会向后台的 /wp-admin/admin-ajax.php 发送一个 POST 请求。

然后我们可以稍为看一下 admin-ajax.php 的源码,不长,很好理解。

可以发现 php 里面的异步 ajax 动作都是通过这个脚本来处理的,同时在底部,根据用户是否已经登录,分为两路交由了两个 do_action 钩子来处理这个请求:

  1. 对于登录的情况:do_action( 'wp_ajax_' . $_REQUEST['action'] );
  2. 对于未登录的情况:do_action( ‘wp_ajax_nopriv_’ . $_REQUEST[‘action’] );

可见,我们只要定义 wp_ajax_<action_name> 的钩子处理函数,就可以捕获到向 admin-ajax.php 发送的,通过 ?action=<action_name> 指明了动作名称的请求,并对其进行针对性的处理。

那么我们刚才定义的两个按钮,他们的 action 为 comment_action_custom,然后通过 $_REQUEST['action_comment'] 可以获取到 stick 和 unstick 这两个动作,我们添加这个钩子处理函数,就可以处理这个响应的后台事件:

/**
 * ajax 处理新增的评论操作动作【置顶】
 */
function add_comment_action_custom() {
    if(!empty($_REQUEST['action_comment']) && !empty($_REQUEST['comment_id'])) {
        // 执行修改的动作
        $action_comment = $_REQUEST['action_comment'];
        $comment_id = intval($_REQUEST['comment_id']);
        $comment = get_comment($comment_id);
        switch($action_comment) {
            case 'stick':
                update_comment_meta($comment_id, 'is_sticky', 1);
                break;
            case 'unstick':
                update_comment_meta($comment_id, 'is_sticky', 0);
                break;
        }
        // 获取修改后的 markup
        ob_start();
        $wp_list_table = _get_list_table(
            strpos($_SERVER['HTTP_REFERER'], 'wp-admin/post.php') === false ?
                'WP_Comments_List_Table' : 'WP_Post_Comments_List_Table',
            array( 'screen' => 'edit-comments' )
        );
        $wp_list_table->single_row( $comment );
        $comment_list_item = ob_get_clean();
        // 打包输出
        $x = new WP_Ajax_Response();
        $x->add( array(
            'what' => 'edit_comment',
            'id' => $comment->comment_ID,
            'data' => $comment_list_item,
            'position' => -1
        ));
        $x->send();
        exit(0);
    }
}
add_action('wp_ajax_comment_action_custom', 'add_comment_action_custom');

注意,除了接收这个 ajax 请求并处理,我们还需要返回一个标准化的 WP_Ajax_Response 来适配内核对的这种异步提交的处理。

为了写这个,我对源码研究了很久,简而言之,WP_Ajax_Response返回的响应是一个 xml 格式的内容,而里面就包含有整个评论的行的 Markup。

我们如果从页面上面操作一下这些按钮,会发现整个行会闪一下,然后状态会发生变化,实际上,这个 ajax 返回的是整个新的行的 markup,wordpress 会在接收到这个响应的时候会整个行进行刷新,用新的 Markup 替换掉旧的。

注意上面的代码有一段 _get_list_table(strpos($_SERVER['HTTP_REFERER'], 'wp-admin/post.php') === false 的判定,这个是由于出现评论列表的地方有两个,一个是在文章页的底部,一个是所有评论的列表页。这两个列表页接受的钩子都一样,但是展示的 markup 是不一样的,我们需要根据不同的情况进行处理。

这一段是呕心沥血查源码才找出来的梗,当时是参照已有的按钮处理方法才找出来的,不能理解的话还是再仔细翻一下源码相关的段落。

1.3. 点击之后的前端响应

注意上面这段替换的流程,由于这一部分接口本身 WordPress 没有打算开放吧,所以我只好查看内核的 js 源码是怎么处理的。

于是我们在后台页面的底部加入这部分的脚本,来处理 class="comment-action-custom" 的按钮。


/** * 客户端点击评论操作时的动作 */ function add_comment_action_script() { ?> <script> jQuery(function($) { $('body').on('click', '.comment-action-custom', function() { var comment_id = parseInt($(this).data('comment-id')); var comment_post_id = parseInt($(this).data('comment-post-id')); $.post(ajaxurl, { action: 'comment_action_custom', action_comment: $(this).data('action'), comment_id: comment_id, comment_post_id: comment_post_id }, function(xml) { var $old = $('#comment-' + comment_id); var $new = $.trim(wpAjax.parseAjaxResponse(xml).responses[0].data); $old.after($new).remove(); }); }); }); </script> <?php } add_action('admin_footer', 'add_comment_action_script');

1.4. 优化显示,展示 [顶] 的标记

现在为了能够在后台展示评论属于置顶的状态,我们要找一个地方写上这个标识。

找来找去,就在作者前面加吧,方式如下,不加赘述,而且这个也不一定需要,请看:

/**
 * 修改后台显示的评论作者状态,加上 [顶] 的标识
 */
function add_admin_comment_author_state($author, $comment_ID, $comment) {
    if(is_admin()) {
        if(get_comment_meta($comment->comment_ID, 'is_sticky', true) === '1') {
            $author = '[顶]'.$author;
        }
    }
    return $author;
}
add_filter('get_comment_author', 'add_admin_comment_author_state', 10, 3);

二、文章列表的操作

其实原理是相当接近的,但是在实际操作的时候,对于状态的更新这里就直接刷新页面简单处理了:

/**
 * 添加所有 post 类型的置顶功能
 */
add_filter('post_row_actions', function($actions, $post) {

    $new_actions = array();

    // 置顶/取消置顶
    if(get_post_meta($post->ID, 'is_sticky', true) === '1') {
        $new_actions['stick'] = '<a class="post-action-custom"
            href="javascript:;" data-action="unstick"
            data-post-type="'.$post->post_type.'"
            data-post-id="'.$post->ID.'">取消置顶</a>';
    } else {
        $new_actions['unstick'] = '<a class="post-action-custom"
            href="javascript:;" data-action="stick"
            data-post-id="'.$post->ID.'">置顶</a>';
    }

    // 在前边插入新增的两个动作链接并返回
    return array_merge($new_actions, $actions);

}, 10, 2);


/**
 * 客户端点击文章操作时的动作
 */
add_action('admin_footer', function () { ?>
    <script>
        jQuery(function($) {
            $('body').on('click', '.post-action-custom', function() {
                var post_id = parseInt($(this).data('post-id'));
                $.post(ajaxurl, {
                    action: 'post_action_custom',
                    action_post: $(this).data('action'),
                    post_type: $(this).data('post-type'),
                    post_ID: $(this).data('post-id')
                }, function() {
                    location.reload();
                });
            });
        });
    </script>
<?php });


/**
 * ajax 处理新增的文章操作动作【置顶】
 */
add_action('wp_ajax_post_action_custom', function () {
    if(!empty($_REQUEST['action_post']) && !empty($_REQUEST['post_ID'])) {
        // 执行修改的动作
        $action_post = $_REQUEST['action_post'];
        $post_id = intval($_REQUEST['post_ID']);
        $post = get_post($post_id);
        $sticky_posts = get_option('sticky_posts');
        switch($action_post) {
            case 'stick':
                update_post_meta($post_id, 'is_sticky', 1);
                $sticky_posts []= $post_id;
                break;
            case 'unstick':
                update_post_meta($post_id, 'is_sticky', 0);
                $key = array_search($post_id, $sticky_posts);
                array_splice($sticky_posts, $key,1);
                break;
        }
        update_option('sticky_posts', $sticky_posts);
        exit(0);
    }
});


/**
 * @param $id
 * 更新文章的时候根据置顶设置设定 is_sticky 值
 */
function set_stick_after_post_update($id) {
    update_post_meta($id, 'is_sticky', in_array($id, get_option( 'sticky_posts' )) ? 1 : 0);
}
add_action('post_updated', 'set_stick_after_post_update');


/**
 * @param $option
 * 更新置顶状态的时候刷新所有的 is_sticky 属性
 */
function update_sticky_posts($option) {
    if($option == 'sticky_posts') {
        $posts = get_posts(array('posts_per_page' => -1, 'post_status' => 'any'));
        foreach($posts as $post) {
            update_post_meta($post->ID, 'is_sticky', is_sticky($post->ID) ? 1 : 0);
        }
    }
}
add_action('updated_option', 'update_sticky_posts');

【转载请附】愿以此功德,回向 >>

原文链接:https://www.huangwenchao.com.cn/2015/06/wordpress-admin-link.html【WordPress 后台文章和评论快捷按钮编辑】

《WordPress 后台文章和评论快捷按钮编辑》有1个想法

  1. 猪八戒网上看到你之前的信息,不知道现在还有空帮忙做个pdf分享的web app吗?blankspot@163.com

发表评论

电子邮件地址不会被公开。 必填项已用*标注