Campo personalizado / meta preenchido por dropdown de posts existentes?

11

(Minha primeira pergunta sobre o WP já foi feita! Seja gentil!)

Estou criando um site que é principalmente páginas (ou seja, estáticas), usando o WP como CMS. Na parte inferior de várias páginas, aparecerão 1, 2 ou 3 "promo boxes" - basicamente, imagens de botão com links para outras partes do site. Embora apenas 3 caixas promocionais apareçam em qualquer página, haverá ~ 30 diferentes para escolher.

Quando meu cliente cria uma nova página, eu gostaria que ele escolhesse caixas promocionais de algo como uma lista suspensa de todas as possíveis caixas promocionais.

Parece que isso deve funcionar assim:

  • Crie um tipo de postagem personalizado chamado "promo-box". (Embora possa ser facilmente uma tag para posts comuns.)
  • Use uma ferramenta como Modelo de campo personalizado para criar um menu suspenso no editor de páginas, no qual o Os valores das opções suspensas são gerados dinamicamente a partir da lista de todas as postagens de caixa promocional existentes. ( Esta é a parte que não sei como fazer. )
  • Acesse os metadados resultantes (o número de postagem é realmente tudo o que preciso, então posso obter todo o resto) no modelo de página.

Com base nas respostas a outras perguntas aqui, analisei inicialmente o WPAlchemy MetaBox, Posts-2-Posts e SLT Custom Fields, mas confesso que a documentação de cada um deles é um pouco mais nerd do que eu, então não se aprofundou muito.

Conselhos? Uma das ferramentas acima é a solução certa para mim e eu só tenho que descobrir isso? Estou faltando alguma coisa aqui?

    
por Nic Warmenhoven 22.12.2010 / 01:00

2 respostas

7

Como o autor do WPAlchemy , eu sou um pouco preconceituoso, mas você essencialmente tem um bom modelo de trabalho delineado para seguir dependendo de qual rota você escolher.

No entanto, se estiver usando o WPAlchemy, você basicamente faria algo como o seguinte (etapa 2):

//  functions.php

include_once 'WPAlchemy/MetaBox.php';

if (is_admin()) 
{
    // a custom style sheet if you want to do some fancy styling for your form
    wp_enqueue_style('custom_meta_css', TEMPLATEPATH . '/custom/meta.css');
}

// define the meta box
$custom_metabox = new WPAlchemy_MetaBox(array
(
    'id' => '_custom_meta',
    'title' => 'My Custom Meta',
    'template' => TEMPLATEPATH . '/custom/meta.php'
));

custom/meta.css pode conter estilos com os quais você pode estilizar seu formulário e custom/meta.php é essencialmente um arquivo HTML com o conteúdo FORM da caixa meta, nesse caso, seu menu suspenso, para gerar sua lista suspensa você faria um consulta wp personalizada para obter todos os seus tipos de postagem personalizados. O WPAlchemy tem algumas funções auxiliares especiais para ajudar na criação de seus elementos de formulário.

Existe documentação adicional para ajudá-lo a trabalhar no modelo.

O principal objetivo do WPAlchemy era manter o controle nas mãos do desenvolvedor, desde o estilo (look + feel) até a definição de conteúdo da caixa meta.

Eu e os outros estamos sempre dispostos a ajudar aqueles que comentam e fazem perguntas.

    
por farinspace 22.12.2010 / 07:07
14

Hehe, você é um novato! Nós vamos rasgar você em pedaços ...!

j / k:) Oferecemos calorosas boas-vindas a todos os novatos aqui, felizes em ter você.

Então esta é a terceira vez que eu ouço essa exigência, duas vezes de clientes e não de você (e do seu cliente). Isso me diz que é uma necessidade razoavelmente comum.

Gosteidasuaanálise,entãodecidiprogramarumaturmaparaabordarseusegundoponto.EuchameideLittlePromoBoxesporqueeununcaconsigotiraressa desta música , graças a eles . Basicamente eu uso a classe para encapsular para evitar conflitos de nomenclatura em potencial com as funções que precisaria escrever.

Você pode colocar essa classe no arquivo functions.php do seu tema ou em um arquivo .PHP de um plugin que você possa estar escrevendo (mas não se preocupe, ela parece muito mais complexa do que é.)

A primeira função on_load() é uma função estática que eu chamo no final da declaração de classe para inicializar os três (3) ganchos que você precisará (fyi funções estáticas são essencialmente funções relacionadas à classe , não à instância) :

  1. O gancho init para registrar o tipo de postagem promo-box ,

  2. O gancho add_meta_boxes_post para permitir que você defina o metabox e

  3. O gancho wp_insert_post_data para permitir que você capture as caixas promocionais selecionadas e salve no banco de dados.

Cada um desses ganchos faz referência a outra função estática na classe (essas eram as funções que eu estava encapsulando criando a classe.)

Ignorarei a descrição da função action_init() e da minha função make_labels() , desde que você saiba como registrar um tipo de postagem com base na sua pergunta.

A função action_add_meta_boxes_post() registra o metabox usando a função principal do WordPress add_meta_box() e eu comentei seus parâmetros para explicar por que passei o que passei para cada um. A função de retorno de chamada the_little_promo_boxes_metabox() é, obviamente, outra função estática da classe e é o que realmente exibe o conteúdo no metabox. Ele usa principalmente a função principal wp_dropdown_pages() do WordPress para exibir uma lista de caixas promocionais (observe que ele exibirá outros tipos de postagem além de 'página', mas somente se eles estiverem marcados como 'hierarchical'=>true no registro de tipo de postagem. Por que apenas hierárquico? Porque é assim que eles escreveram, é por isso!:)

Como estamos exibindo três (3) menus suspensos, precisamos fornecer a cada um um ID exclusivo no HTML ( "promo_box_{$i}" ), mas o mesmo nome entre colchetes ( 'promo_boxes[]' ) para que o PHP os colete em um array dentro de $_POST variable (que o WordPress acessa para nós; você verá como em um minuto) . E é claro que precisamos definir o valor selecionado ( (empty($promo_boxes[$i]) ? 0 : $promo_boxes[$i]) ) se, de fato, um dos valores tiver sido selecionado anteriormente.

Também usei a função principal get_post_type_object() do WordPress para mostrar como obter os rótulos de um tipo de postagem e também usar a função principal get_post_meta() do WordPress para recuperar uma matriz de IDs de caixa promocional usando a chave do campo personalizado ' _promo_boxes 'que mostrarei para salvar próximo (observe que usei um sublinhado anterior no nome '_promo_boxes' , o que faz com que o WordPress se esconda da interface do usuário do campo personalizado padrão quando o usuário está editando a postagem.) .

A última função para descrever antes de ver o código é filter_wp_insert_post_data() , que recebe os dados de postagem existentes no primeiro parâmetro ( $data ) e o conteúdo da matriz $_POST graças ao WordPress como o segundo parâmetro (% código%). Dentro dessa função chamamos a função principal $postarr do WordPress e extraímos a matriz de caixas promocionais ( update_post_meta() ) para salvar no valor do campo personalizado para a chave $postarr['promo_boxes'] da postagem especificada pela matriz '_promo_boxes' (ou seja, $_POST ).

Dito isso, aqui está o código para a classe $postarr['ID'] :

class LittlePromoBoxes {
  static function on_load() {
    add_action('init',array(__CLASS__,'action_init'));
    add_action('add_meta_boxes_post',array(__CLASS__,'action_add_meta_boxes_post'));
    add_filter('wp_insert_post_data',array(__CLASS__,'filter_wp_insert_post_data'),10,2);
  }
  static function action_init() {
    register_post_type('promo-box',array(
      'labels'          => self::make_labels('Promo Box','Promo Boxes'),
      'public_queryable'=> false,
      'hierarchical'    => true,  // IMPORTANT!!! wp_dropdown_pages() requires 'hierarchical'=>true
      'show_ui'         => true,
      'query_var'       => false,
      'supports'        => array('title','editor','thumbnail','custom-fields'),
      'show_in_nav_menus'=>true,
      'exclude_from_search'=>true,
    ));
  }
  static function make_labels($singular,$plural=false,$args=array()) {
    if ($plural===false)
      $plural = $singular . 's';
    elseif ($plural===true)
      $plural = $singular;
    $defaults = array(
      'name'              =>_x($plural,'post type general name'),
      'singular_name'      =>_x($singular,'post type singular name'),
      'add_new'            =>_x('Add New',$singular),
      'add_new_item'      =>__("Add New $singular"),
      'edit_item'          =>__("Edit $singular"),
      'new_item'          =>__("New $singular"),
      'view_item'          =>__("View $singular"),
      'search_items'      =>__("Search $plural"),
      'not_found'          =>__("No $plural Found"),
      'not_found_in_trash'=>__("No $plural Found in Trash"),
      'parent_item_colon' =>'',
    );
    return wp_parse_args($args,$defaults);
  }
  static function action_add_meta_boxes_post($post) {
    add_meta_box(
      'little-promo-boxes',   // Metabox Name, used as the "id" for a wrapping div
      'Little Promo Boxes',   // Metabox Title, visible to the user
      array(__CLASS__,'the_little_promo_boxes_metabox'), // Callback function
      'post',                 // Add to the Edit screen for Post Types of 'post'  
      'side',                 // Show it in the sidebar (if center then it would be 'normal'
      'low'                   // Show it below metaboxes that specify 'high'
    );
  }
  static function the_little_promo_boxes_metabox($post) {
    $pto = get_post_type_object('promo-box');
    $default_options = array(
      'post_type' => 'promo-box',
      'show_option_none' => "Select a {$pto->labels->singular_name}",
    );
    $promo_boxes = get_post_meta($post->ID,'_promo_boxes',true);
    for($i=0; $i<=2; $i++) {
      wp_dropdown_pages(array_merge($default_options,array(
        'id'       => "promo_box_{$i}",
        'name'     => 'promo_boxes[]',
        'selected' => (empty($promo_boxes[$i]) ? 0 : $promo_boxes[$i]),
      )));
    }
  }
  static function filter_wp_insert_post_data($data, $postarr) {
    update_post_meta($postarr['ID'],'_promo_boxes',$postarr['promo_boxes']);
    return $data;
  }
  static function get_promo_boxes($post=false) {
    static $promo_boxes=array();
    if (!$post)
      $post = $GLOBALS['post'];
    if (!isset($promo_boxes[$post->ID])) {
      $promo_boxes[$post->ID] = get_post_meta($post->ID,'_promo_boxes',true);
      $index = 0;
      foreach($promo_boxes[$post->ID] as $promo_box_id) {
        $promo_boxes[$post->ID][$index++] = (is_numeric($promo_box_id) ? get_post($promo_box_id) : false);
      }
    }
    return $promo_boxes[$post->ID];
  }
  static function get_promo_box($number,$post=false) {
    $promo_boxes = self::get_promo_boxes($post);
    return $promo_boxes[$number-1];
  }
}
LittlePromoBoxes::on_load();

Ainda há duas (2) funções estáticas ainda não mencionadas: LittlePromoBoxes e get_promo_boxes() ; estas são funções auxiliares para ajudá-lo a recuperar as mensagens de get_promo_box() por seus números ordinais 1..3. Mas para torná-los mais WordPress como aqui são duas funções de wrapper para adicionar ao arquivo post_type='promo-box' do seu tema (note que você pode passar uma postagem como um parâmetro, mas você não precisa a menos que você esteja usando uma postagem diferente aquele em The Loop ):

function get_little_promo_boxes($post=false) {
  return LittlePromoBoxes::get_promo_boxes($post);
}
function get_little_promo_box($number,$post=false) {
  return LittlePromoBoxes::get_promo_box($number,$post);
}

Agora você pode chamar uma ou ambas as funções no seu arquivo de tema functions.php com código que pode ser parecido com este (esse código poderia ter sido escrito em um loop, mas a maioria dos temas do WordPress parece duplicar o código para que eles possam ler em vez de eliminar a redundância. Então, quando em Roma ...):

<?php
  $promo_boxes = get_little_promo_boxes();
  if (isset($promo_boxes[1]))
    echo '<div id="promo-box1" class="promo-box">' . get_the_title($promo_boxes[1]->ID) . '</div>';
  if (isset($promo_boxes[2]))
    echo '<div id="promo-box2" class="promo-box">' . get_the_title($promo_boxes[2]->ID) . '</div>';
  if (isset($promo_boxes[3]))
    echo '<div id="promo-box3" class="promo-box">' . get_the_title($promo_boxes[3]->ID) . '</div>';
?>
    
por MikeSchinkel 22.12.2010 / 11:54