Como tornar os status de metabólitos aberto / fechado e oculto / mostrado salvos por postagem?

8

Meu problema real é um pouco complexo, então vou tentar resumi-lo e mantê-lo simples.

Estou trabalhando em um aplicativo personalizado com base no WordPress. Eu registrei um tipo de post personalizado, vamos chamá-lo de "pessoas", onde eu armazeno informações sobre ... pessoas.

O CPT suporta apenas o título do post e os campos padrão de conteúdo, mas existem alguns metaboxes para armazenar informações de pessoas (pense em meu aplicativo como um catálogo de endereços).

Portanto, há um metabox para armazenar informações pessoais, uma para armazenar informações de redes sociais, outra para armazenar informações relacionadas ao trabalho, ou seja, se essa pessoa for para mim um cliente, um fornecedor, se tivermos créditos ou débitos ...

Eu simplifiquei aqui, mas há uma quantidade consistente de metaboxes, digamos 12.

Meu problema é que algumas pessoas para as quais quero armazenar informações são apenas contatos aleatórios, e quero armazenar apenas informações pessoais, outras são amigos e quero armazenar informações pessoais e de redes sociais, outras são clientes ou fornecedores e eu quero armazenar informações relacionadas ao trabalho.

Se, ao editar um post, eu ocultar (através do menu de opções de tela ) ou fechar qualquer metabox que eu don ' Eu preciso, quando eu abrir outro post onde eu preciso deles, eu tenho que mostrar ou abri-los novamente. Isso porque a posição / status / ordem dos metabóxes são salvos por usuário como metadados do usuário .

Se você imaginar em alguns posts eu preciso de 2 metaboxes, em 10 e em 5, você entende que é irritante porque manter todos eles exibidos / abertos torna a tela de edição acessível (barra de rolagem parece infinita), e às vezes a informação eu olhar para é no final da página depois de um monte de metaboxes sem informação ...

Pergunta:

É possível salvar a posição / status / ordem dos metabóxos em uma base por post para um tipo de postagem específico?

PS: Eu sei que alguns js / jQuery podem resolver o problema, mas se possível eu evitaria soluções de javascript.

    
por gmazzap 13.09.2014 / 17:41

2 respostas

6

Como apontado por birgire em sua resposta , o WordPress usa o AJAX para atualizar O status e os dados de metaboxes transmitidos na solicitação do AJAX não incluem ID de postagem e dificultam a atualização do status das caixas por postagem.

Quando descobri que a ação AJAX usada pelo WordPress é 'closed-postboxes' , procurei por esta string na pasta admin js para descobrir como o WordPress faz a solicitação AJAX.

Descobri que acontece em postbox.js na linha # 118 .

Parece assim:

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
  });
}

Essencialmente, o WordPress analisa itens do DOM com classe 'caixa postal' e classe 'fechado' e cria uma lista separada por vírgulas de seus IDs. O mesmo é feito para itens DOM ocultos com classe 'caixa postal'.

Então, meu pensamento foi: Eu posso criar um metabox fake que tenha as classes certas e que esteja oculto, definindo seu ID para conter o ID do post, e assim eu posso recuperá-lo em um Pedido AJAX.

Isso é o que eu fiz:

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 );
    }
});

Desta forma eu criei um metabox que está sempre fechado e sempre oculto, então o WordPress enviará seu ID como $_POST var na requisição AJAX, e uma vez que o id da caixa falsa contenha um post de forma previsível, eu sou capaz de reconhecer o post.

Depois disso, observei como o WordPress executa a tarefa AJAX.

Em admin-ajax.php na linha 72 , WordPress engancha 'wp_ajax_closed-postboxes' com prioridade 1.

Então, para agir antes do WordPress, eu poderia enganchar a mesma ação com a prioridade 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 );

Ter dados salvos em um post meta tornou possível filtrar get_user_option_closedpostboxes_mycpt e get_user_option_metaboxhidden_mycpt (ambas as variações do get_user_option_{$option} filter) para forçar as opções de carregamento do WordPress de post meta:

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 );

e

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 );
    
por gmazzap 26.10.2014 / 10:54
7

O problema principal:

O principal problema aqui é que nas chamadas fechamento - , ocultação - e ordenação - ajax, não há nenhum ID de postagem enviado com o carga útil. Aqui estão dois exemplos de dados de formulário:

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]:

Poderíamos resolver isso usando outra chamada personalizada do ajax.

Poderíamos, é claro, apenas conectar-se ao gancho save_post e modificar os dados toda vez que a postagem fosse salva. Mas essa não é a experiência normal da interface do usuário, então isso não é considerado aqui

Existe outra solução não elegante disponível com PHP, descrita abaixo:

Uma solução não JavaScript:

A questão é onde armazenar os dados? Como metadados do usuário , pós metadados ou talvez em uma tabela personalizada?

Aqui, armazenamos como meta-dados do usuário e pegamos o fechamento das caixas-meta post como exemplo.

Quando o valor meta closedpostboxes_post é atualizado, também o salvamos no valor meta closedpostboxes_post_{post_id} .

Em seguida, nós seqüestramos a busca de closedpostboxes_post para substituí-la com o meta valor correspondente com base no ID do usuário e na ID do post.

a) Atualização durante a ação closed-postboxes ajax:

Podemos buscar o ID do post, por meio do wp_get_referer() e, em seguida, usar o função url_to_postid() acessível. Eu primeiro soube sobre essa função "engraçada" depois de ler a resposta de @s_ha_dum , alguns meses atrás ;-) Infelizmente a função não reconhece ?post=123 GET variáveis, mas podemos fazer um pequeno truque apenas alterando-o para p=123 para contornar isso.

Podemos ligar a updated_user_meta , que é acionado logo após a atualização dos metadados do usuário para 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) Buscando dados:

Podemos nos conectar ao gancho get_user_option_closedpostboxes_post para modificar os dados buscados da meta de usuário 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 );

Também podemos pensar no caso em que não há closedpostboxes_post_{post_id} disponível para postagens. Por isso, usará as últimas configurações salvas de closedpostboxes_post . Talvez você queira ter tudo aberto ou fechado, nesse caso padrão. Seria fácil modificar esse comportamento.

Para outros tipos de postagens personalizadas, podemos usar o gancho closedpostboxes_{post_type} correspondente.

O mesmo deve ser possível para ordenação e ocultação de metaboxes com a meta de usuário metaboxhidden_{post_type} e meta-box-order_{post_data} .

ps: desculpe por essa resposta muito longa no fim de semana, já que eles devem sempre ser curtos & jolly; -)

    
por birgire 13.09.2014 / 22:39

Tags