如何在每个帖子的基础上保存打开/关闭和隐藏/显示元对象状态?

时间:2014-09-13 作者:gmazzap

我真正的问题有点复杂,所以我将尝试在这里抽象它并保持简单。

我正在开发基于WordPress的自定义应用程序。我注册了一个自定义的帖子类型,让我们称之为“人”,在这里我存储有关。。。人

CPT只支持post title和post content默认字段,但有一些元数据库可以存储个人信息(将我的应用程序视为通讯簿)。

所以有一个元数据库来存储个人信息,一个用来存储社交网络信息,另一个用来存储与工作相关的信息,也就是说,如果这个人对我来说是客户、供应商,如果我们有信用或借记。。。

我在这里进行了简化,但有一致数量的代谢组,比如说12个。

我的问题是,我想存储信息的一些人只是随机联系人,我只想存储个人信息,其他人是朋友,我想存储个人信息和社交网络信息,其他人是客户或供应商,我想存储与工作相关的信息。

如果在编辑帖子时隐藏(通过screen option menu) 或者关闭任何我不需要的metabox,当我打开另一篇需要它们的帖子时,我必须再次显示或打开它们。那个because metaboxes position/status/order are saved on per-user basis as user metadata.

如果你想象在一些帖子中,我需要2个元框,10个或5个元框,你就会明白这很烦人,因为保持所有元框的显示/打开会使编辑屏幕变得不易访问(滚动条似乎无穷无尽),有时我查找的信息是在一堆没有信息的元框之后的页面末尾。。。

Question:

是否可以为特定职位类型保存每个职位的元数据库位置/状态/订单?

PS:我知道一些js/jQuery可以解决这个问题,但如果可能的话,我会避免使用javascript解决方案

2 个回复
最合适的回答,由SO网友:gmazzap 整理而成

正如所指出的birgire 在里面his answer, WordPress使用AJAX更新元框状态,AJAX请求中传递的数据不包括帖子id,这使得很难根据帖子更新框状态。

一旦我发现WordPress使用的AJAX操作是\'closed-postboxes\', 我在admin js文件夹中搜索了这个字符串,以找到WordPress是如何发出AJAX请求的。

我发现它发生在postbox.js at line #118.

看起来是这样的:

save_state : function(page) {
  var closed = $(\'.postbox\').filter(\'.closed\').map(function() {
      return this.id;
    }).get().join(\',\');
  var hidden = $(\'.postbox\').filter(\':hidden\').map(function() {
      return this.id;
    }).get().join(\',\');
  $.post(ajaxurl, {
    action: \'closed-postboxes\',
    closed: closed,
    hidden: hidden,
    closedpostboxesnonce: jQuery(\'#closedpostboxesnonce\').val(),
    page: page
  });
}
本质上,WordPress查看类为“postbox”和类为“closed”的DOM项,并创建以逗号分隔的ID列表。对于类为“postbox”的隐藏DOM项,也会执行相同的操作。

因此,我的想法是:我可以创建一个具有正确类且隐藏的伪元盒,将其id设置为包含post id,这样我就可以在AJAX请求中检索它。

这就是我所做的:

add_action( \'dbx_post_sidebar\', function() {
    global $post;
    if ( $post->post_type === \'mycpt\' ) {
        $id = $post->ID;
        $f = \'<span id="fakebox_pid_%d" class="postbox closed" style="display:none;"></span>\';
        printf( $f, $id );
    }
});
通过这种方式,我创建了一个始终处于关闭和隐藏状态的元盒,因此WordPress将以$_POST AJAX请求中的var,并且一旦假框id以可预测的方式包含帖子id,我就能够识别帖子。

之后,我研究了WordPress如何执行AJAX任务。

在里面admin-ajax.php at line 72, WordPress挂钩\'wp_ajax_closed-postboxes\' 优先级为1。

所以,要在WordPress之前执行操作,我可以挂接优先级为0的相同操作。

add_action( \'wp_ajax_closed-postboxes\', function() {

    // check if we are in right post type: WordPress passes it in \'page\' post var
    $page = filter_input( INPUT_POST, \'page\', FILTER_SANITIZE_STRING );
    if ( $page !== \'mycpt\' ) return;

    // get post data
    $data = filter_input_array( INPUT_POST, array(
        \'closed\' => array( \'filter\' => FILTER_SANITIZE_STRING ),
        \'hidden\' => array( \'filter\' => FILTER_SANITIZE_STRING )
    ) );

    // search among closed boxes for the "fake" one, and return if not found
    $look_for_fake = array_filter( explode( \',\', $data[ \'closed\' ] ), function( $id ) {
         return strpos( $id, \'fakebox_pid_\' ) === 0;
    } );
    if ( empty( $look_for_fake ) ) return;

    $post_id = str_replace( \'fakebox_pid_\', \'\', $look_for_fake[0] );
    $user_id = get_current_user_id();

    // remove fake id from values
    $closed = implode(\',\', array_diff( explode(\',\', $data[\'closed\'] ), $look_for_fake ) );
    $hidden = implode(\',\', array_diff( explode(\',\', $data[\'hidden\'] ), $look_for_fake ) );

    // save metabox status on a per-post and per-user basis in a post meta
    update_post_meta( $post_id, "_mycpt_closed_boxes_{user_id}", $closed );
    update_post_meta( $post_id, "_mycpt_hidden_boxes_{user_id}", $hidden );

}, 0 );
将数据保存在post meta中可以进行筛选get_user_option_closedpostboxes_mycptget_user_option_metaboxhidden_mycpt (两种不同的get_user_option_{$option} 过滤器)强制从post meta加载WordPress选项:

add_filter( \'get_user_option_closedpostboxes_mycpt\', function ( $result, $key, $user ) {
    global $post;
    $meta = get_post_meta( $post->ID, "_mycpt_closed_boxes_{$user->ID}", TRUE );
    if ( ! empty( $meta ) ) {
        $result = $meta;
    }
    return $result;
}, 10, 3 );
以及

add_filter( \'get_user_option_metaboxhidden_mycpt\', function ( $result, $key, $user ) {
    global $post;
    $meta = get_post_meta( $post->ID, "_mycpt_hidden_boxes_{$user->ID}", TRUE );
    if ( ! empty( $meta ) ) {
        $result = $meta;
    }
    return $result;
}, 10, 3 );

SO网友:birgire

主要问题:

这里的主要问题是,在关闭、隐藏和排序ajax调用中,没有随负载一起发送post ID。以下是两个表单数据示例:

1) action:closed-postboxes
closed:formatdiv,tagsdiv-post_tag,trackbacksdiv,authordiv
hidden:slugdiv
closedpostboxesnonce:8723ee108f
page:post

2) action:meta-box-order
_ajax_nonce:b6b48d2d16
page_columns:2
page:post
order[side]:submitdiv,formatdiv,categorydiv,tagsdiv-post_tag,postimagediv
order[normal]:postexcerpt,postcustom,trackbacksdiv,commentsdiv,authordiv
order[advanced]:
我们可以通过使用另一个自定义ajax调用来解决这个问题。

我们当然可以save_post 每次保存帖子时,钩住并修改数据。但这不是正常的UI体验,所以这里不考虑这一点

PHP提供了另一种非优雅的解决方案,如下所述:

非Javascript解决方案:

问题是在哪里存储数据?作为元数据用户,发布元数据,或者在自定义表中发布元数据?

这里,我们将其存储为用户元数据,并以post元数据框的关闭为例。

closedpostboxes_post 元值已更新,我们将其保存到closedpostboxes_post_{post_id} 还有元价值。

然后我们劫持了closedpostboxes_post 根据用户id和帖子id,使用相应的元值覆盖它。

a) Updating during the closed-postboxes ajax action:

我们可以通过wp_get_referer() 然后使用handyurl_to_postid() 作用我是在阅读了answer from @s_ha_dum, 几个月前;-)不幸的是,函数无法识别?post=123 获取变量,但我们可以通过将其更改为p=123 绕过它。

我们可以加入updated_user_meta, 这是在closedpostboxes_post 已更新:

add_action( \'updated_user_meta\',                           
    function ( $meta_id, $object_id, $meta_key, $_meta_value )
    {
        $post_id = url_to_postid( str_replace( \'post=\', \'p=\', wp_get_referer() ) );
        if( \'closedpostboxes_post\' === $meta_key && $post_id > 0 )
            update_user_meta( 
                $object_id, 
                \'closedpostboxes_post_\' . $post_id, 
                $_meta_value 
            );
    }
, 10, 4 );

b) Fetching data:

我们可以在get_user_option_closedpostboxes_post 钩子来修改从closedpostboxes_post 用户元:

add_filter( \'get_user_option_closedpostboxes_post\',
    function ( $result, $option, $user )
    {
        $post_id = filter_input( INPUT_GET, \'post\', FILTER_SANITIZE_NUMBER_INT );
        $newresult = get_user_option( \'closedpostboxes_post_\'. $post_id , $user->ID );
        return ( $newresult ) ? $newresult : $result;
    }
, 10, 3 );
我们可能还想考虑一下没有基于post的情况closedpostboxes_post_{post_id} 可获得的因此,它将使用closedpostboxes_post. 在默认情况下,您可能希望全部打开或全部关闭。很容易改变这种行为。

对于其他自定义帖子类型,我们可以使用相应的closedpostboxes_{post_type}

对于具有metaboxhidden_{post_type}meta-box-order_{post_data} 用户元。

ps:很抱歉这个周末的答案太长,因为它们应该总是简短的&;jolly;-)

结束

相关推荐

将字符计数添加到自定义Metabox

我知道有一种方法可以将字符计数器添加到WP中的摘录元盒,但我想将字符计数器添加到自定义元盒。下面的脚本将获取元数据库中的计数器,元数据库中有选项卡,但不计数。任何帮助都会很好。谢谢,这是我在StackExchange中的第一个问题。jQuery(document).ready(function(){ jQuery(\"#bgnp-metabox-tabs\").after(\"<p style=\\\"text-align:left;\\\"><small>Exce