Pole niestandardowe / meta wypełnione przez rozwijane istniejące posty?

11

(Moje pierwsze pytanie dotyczące WP kiedykolwiek zadane! Bądź łagodny!)

Buduję witrynę składającą się głównie ze stron (tj. Statycznych), używając WP jako CMS. Na dole kilku stron pojawią się 1, 2 lub 3 „pola promocyjne” - w zasadzie obrazy przycisków, które prowadzą do innych części witryny. Chociaż na danej stronie pojawią się tylko 3 pola promocyjne, będzie około 30 różnych do wyboru.

Gdy mój klient tworzy nową stronę, chciałbym, aby mógł wybrać pudełka promocyjne z czegoś w rodzaju listy rozwijanej wszystkich możliwych pudeł promocyjnych.

Wydaje mi się, że powinno to działać tak:

  • Utwórz niestandardowy typ postu o nazwie „pole promocyjne”. (Choć równie łatwo może to być tag zwykłych postów).
  • Użyj narzędzia takiego jak Niestandardowy szablon pola, aby utworzyć menu rozwijane w edytorze stron, w którym wartości opcji menu rozwijanych są dynamicznie generowane z listy wszystkich istniejących postów w polu promocyjnym. ( To jest część, której nie umiem zrobić. )
  • Uzyskaj dostęp do wynikowych metadanych (numer wpisu jest naprawdę wszystkim, czego potrzebuję, a następnie mogę uzyskać wszystko inne) w szablonie strony.

Opierając się na odpowiedziach na inne pytania tutaj, przyjrzałem się najpierw WPAlchemy MetaBox, Posts-2-Posts i SLT Custom Fields, ale przyznaję, że dokumentacja dla każdego z nich jest nieco bardziej maniakalna niż ja, więc nie zagłębiłem się zbyt głęboko.

Rada? Czy jedno z powyższych narzędzi jest dla mnie właściwym rozwiązaniem i muszę to rozgryźć? Czy coś mi umyka?

Nic Warmenhoven
źródło
Wow, dziękuję za całe wsparcie! Mam nadzieję, że i tak nie dewaluuję czasu i hojności MikeSchinkela, ale wybrałem odpowiedź WPAlchemy jako „oficjalną” odpowiedź. Nadal jestem na tyle nowy w PHP / Wordpress, że nie jestem jeszcze zbyt wygodny w korzystaniu z klas, haków i funkcji statycznych. Mam nadzieję, że kiedyś będę tak biegły jak wszyscy!
Nic Warmenhoven,

Odpowiedzi:

7

Jako autor WPAlchemy jestem nieco stronniczy, ale zasadniczo masz dobry model roboczy nakreślony do naśladowania w zależności od wybranej trasy.

Jeśli jednak używasz WPAlchemy, w zasadzie zrobiłbyś coś takiego: (krok # 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.cssmoże zawierać style, w których można stylizować formularz, i custom/meta.phpzasadniczo jest plikiem HTML z zawartością FORMULARZA w polu meta, w tym przypadku listą rozwijaną, aby wygenerować listę rozwijaną, należy wykonać niestandardowe zapytanie wp, aby uzyskać wszystkie niestandardowe posty typy. WPAlchemy ma specjalne funkcje pomocnicze pomagające w tworzeniu elementów formularza.

Istnieje dodatkowa dokumentacja pomocna podczas pracy w szablonie.

Głównym celem WPAlchemy było utrzymanie kontroli w rękach dewelopera, od stylizacji (look + feel) do definicji zawartości meta-box.

A ja i inni zawsze jesteśmy gotowi pomóc tym, którzy komentują i zadają pytania.

farinspace
źródło
1
Dobra odpowiedź, ale czy mogę zasugerować dołączenie tego dodatkowego żądania arkusza stylów specjalnie do ekranu edytora postów. To samo można powiedzieć o tworzeniu metaboksu, że najlepiej byłoby uzależnić się do_meta_boxesod jakiejś logiki warunkowej lub alternatywnie na add_meta_boxes_{%TYPE%}..
t31os
14

Hehe, jesteś nowicjuszem! Rozerwamy cię na strzępy ...!

j / k :) Serdecznie witamy wszystkich początkujących tutaj, cieszę się, że cię mamy.

Po raz trzeci usłyszałem ten wymóg, dwa razy od klientów, a nie od ciebie (i twojego klienta). To mówi mi, że jest to dość powszechna potrzeba.

WordPress Custom Metabox pokazuje trzy (3) listy rozwijane

Podobała mi się twoja analiza, więc postanowiłem zakodować klasę, aby zająć się twoim drugim punktem. Nazwałem go LittlePromoBoxes, ponieważ nigdy nie mogę dostać tej piosenki z mojej głowy, dzięki nimi . Zasadniczo używam tej klasy do enkapsulacji, aby w przeciwnym razie uniknąć potencjalnych konfliktów nazw z funkcjami, które musiałbym napisać.

Możesz umieścić tę klasę w functions.phppliku motywu lub w pliku .PHP wtyczki, którą możesz pisać (ale nie martw się, wygląda na dużo bardziej złożoną niż jest.)

Pierwsza funkcja on_load()jest funkcją statyczną, którą wywołuję na końcu deklaracji klasy, aby zainicjować trzy (3) zaczepy, których potrzebujesz (funkcje statyczne fyi są zasadniczo funkcjami związanymi z klasą , a nie instancją) :

  1. initHak zarejestrować promo-boxrodzaj postu,

  2. add_meta_boxes_postHak, co pozwala na określenie METABOX i

  3. wp_insert_post_dataHak, co pozwala na przechwytywanie wybranych pól promocyjnych i zapisać do bazy danych.

Każdy z tych haków odwołuje się do innej funkcji statycznej w klasie (były to funkcje, które hermetyzowałem, tworząc klasę).

Pominę opisywanie action_init()funkcji i mojej make_labels()funkcji pomocnika, zakładając, że wiesz, jak zarejestrować typ postu na podstawie twojego pytania.

action_add_meta_boxes_post()Funkcja rejestruje METABOX przy użyciu funkcji rdzenia WordPress add_meta_box()i mam skomentował To parametry, które wyjaśniają, dlaczego mijałem co minąłem dla każdego. Funkcja wywołania zwrotnego the_little_promo_boxes_metabox()jest oczywiście kolejną funkcją statyczną klasy i właśnie to wyświetla zawartość w metaboksie. Używa przede wszystkim podstawowej funkcji WordPress wp_dropdown_pages()do wyświetlania listy pól promocyjnych (pamiętaj, że wyświetla inne typy postów oprócz „strony”, ale tylko wtedy, gdy są oznaczone jako będące 'hierarchical'=>truew rejestracji typu postów. Dlaczego tylko hierarchiczne? Bo właśnie w ten sposób napisałem to, dlatego! :)

Ponieważ pokazujemy trzy (3) menu rozwijane, musimy nadać każdemu unikalny identyfikator w kodzie HTML ( "promo_box_{$i}"), ale o tej samej nazwie w nawiasach kwadratowych ( 'promo_boxes[]'), aby PHP zgromadził je w tablicy wewnątrz $_POSTzmiennej (do której WordPress ma dla nas dostęp; zobaczysz jak za chwilę) . I oczywiście musimy ustawić wybraną wartość ( (empty($promo_boxes[$i]) ? 0 : $promo_boxes[$i])), jeśli rzeczywiście jedna z wartości została wcześniej wybrana.

Użyłem również funkcji rdzenia WordPress, get_post_type_object()aby pokazać, jak uzyskać etykiety z typu postu, a także funkcji rdzenia WordPress, get_post_meta()aby pobrać tablicę identyfikatorów pól promocyjnych z niestandardowego klucza pola „_promo_boxes”, który pokażę, że masz aby zapisać następny (uwaga: użyłem poprzedzającego podkreślenia w nazwie, '_promo_boxes'który powoduje, że WordPress ukrywa się przed standardowym interfejsem użytkownika niestandardowego pola, gdy użytkownik edytuje post.) .

Ostatnią funkcją, którą należy opisać, zanim zobaczysz kod, jest to, że filter_wp_insert_post_data()odbiera istniejące dane postu w pierwszym parametrze ( $data) i zawartość $_POSTtablicy dzięki WordPressowi jako drugiemu parametrowi ( $postarr). Wewnątrz tej funkcji wywołujemy funkcję podstawową WordPress update_post_meta()i wyodrębniamy tablicę pól promocyjnych ( $postarr['promo_boxes']), aby zapisać niestandardową wartość pola dla klucza '_promo_boxes'dla wpisu określonego przez $_POSTtablicę (tj $postarr['ID'].).

To powiedziawszy, oto kod dla LittlePromoBoxesklasy:

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

Są jeszcze dwie (2) funkcje statyczne, o których jeszcze nie wspomniano: get_promo_boxes()oraz get_promo_box(); są to funkcje pomocnicze, które pomogą ci odzyskać posty post_type='promo-box'według ich numerów porządkowych 1..3. Ale aby uczynić je bardziej WordPress, tak jak tutaj, są dwie funkcje otoki do dodania do functions.phppliku motywu (pamiętaj, że możesz przekazać post jako parametr, ale nie musisz tego robić, chyba że używasz innego posta niż ten w 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);
}

Teraz możesz wywołać jedną lub obie te funkcje w single.phppliku motywu za pomocą kodu, który może wyglądać następująco (ten kod mógł zostać napisany w pętli, ale większość funkcji WordPress lubi powielać kod, aby mogli go odczytać zamiast eliminować nadmiarowość Tak więc, kiedy jesteś w Rzymie ...):

<?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>';
?>
MikeSchinkel
źródło
1
Nigdy nie przestajesz mnie zadziwiać swoimi odpowiedziami, wysiłkiem, który musisz wykonać, aby stworzyć kod i wyjaśnić każdy krok .. niesamowite! .. (Twoja wzmianka o małych pudełkach każe mi myśleć o jednym z moich ulubionych seriali telewizyjnych) ..
t31os
1
@ t31os - Dzięki! Kiedy zaczynam odpowiadać, nie mogę się powstrzymać. Chyba obsesyjne / kompulsywne. Ale przynajmniej dobrze wykorzystuję!
MikeSchinkel,
@toscho - Dzięki. Tak, tak rzadko dodam humoru, że jeśli chodzi o mnie, nie mogę się oprzeć. :-)
MikeSchinkel,