Настраиваемое поле/мета, заполненное выпадающим списком существующих сообщений?


(Мой первый вопрос WP, когда-либо заданный! Будь нежен!)

Я создаю сайт, который в основном состоит из страниц (т.Е. статических), используя WP в качестве CMS. В нижней части нескольких страниц появятся 1, 2 или 3 "промо-поля" - в основном изображения кнопок, которые ссылаются на другие части сайта. Хотя на любой странице будет отображаться только до 3 промо-боксов, на выбор будет ~30 различных.

Когда мой клиент создает новую страницу, я бы хотел, чтобы он мог выберите промо-боксы из чего-то вроде выпадающего списка всех возможных промо-боксов.

Мне кажется, это должно работать так:

  • Создайте пользовательский тип публикации под названием "промо-бокс". (Хотя с таким же успехом это может быть тег для обычных сообщений.)
  • Используйте такой инструмент, как Пользовательский шаблон поля , чтобы создать раскрывающийся список в редакторе страниц, где значения параметров раскрывающегося списка динамически генерируются из списка всех существующих сообщений в промо-боксе. (Это это та часть, которую я не знаю, как сделать.)
  • Получите доступ к полученным метаданным (номер записи - это действительно все, что мне нужно, тогда я смогу получить все остальное) в шаблоне страницы.

Основываясь на ответах на другие вопросы здесь, я сначала взглянул на метабокс WPAlchemy, Сообщения-2-Сообщения и пользовательские поля SLT, но, признаюсь, документация для каждого из них немного сложнее, чем я, поэтому я не слишком углублялся.

Совет? Является ли один из вышеперечисленных инструментов правильным решение для меня, и я просто должен это выяснить? Я что-то здесь упускаю?

Author: Nic Warmenhoven, 2010-12-22

2 answers

Как автор WPAlchemy, я немного предвзят, но у вас, по сути, есть хорошая рабочая модель, которой нужно следовать в зависимости от того, какой маршрут вы выберете.

Однако, если вы используете WPAlchemy, вы бы в основном сделали что-то вроде следующего (шаг № 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 может содержать стили, с помощью которых вы можете стилизовать свою форму, и custom/meta.php по сути представляет собой HTML-файл с содержимым ФОРМЫ в мета-поле, в данном случае вашего выпадающего списка, для создания вашего выпадающего списка вы должны выполнить пользовательский запрос wp, чтобы получить все ваши пользовательские типы записей. В WPAlchemy есть некоторые специальные вспомогательные функции, помогающие создавать элементы формы.

Существует дополнительная документация , которая поможет вам при работе с шаблоном.

Основной целью WPAlchemy было сохранить контроль в руках разработчика, от стиля (внешний вид + ощущения) до определения содержимого мета-бокса.

И я, и другие всегда готовы помочь тем, кто комментирует и задает вопросы.

 7
Author: farinspace, 2010-12-22 06:07:57

Хе-хе, ты новичок! Мы разорвем тебя в клочья...!

J/k:) Мы тепло приветствуем всех новичков здесь, рады видеть вас.

Итак, я уже в 3-й раз слышу это требование, дважды от клиентов, а не снова от вас (и вашего клиента). Это говорит мне о том, что это достаточно распространенная потребность.

Мне понравился ваш анализ, поэтому я решил закодировать класс, чтобы ответить на ваш 2-й пункт. Я назвал это LittlePromoBoxes, потому что я никогда не смогу выкинь эту песню из моей головы, спасибо им. В основном я использую класс для инкапсуляции, чтобы в противном случае избежать потенциальных конфликтов имен с функциями, которые мне нужно было бы написать.

Вы можете поместить этот класс в файл вашей темы functions.php или в.PHP-файл плагина, который вы, возможно, пишете (но не волнуйтесь, он выглядит намного сложнее, чем есть на самом деле.)

Первая функция on_load() - это статическая функция, которую я вызываю в конце объявления класса, чтобы инициализируйте три (3) крючка, которые вам понадобятся (к вашему сведению, статические функции по сути являются функциями , относящимися к классу, а не к экземпляру) :

  1. Крючок init для регистрации типа записи promo-box,

  2. Крючок add_meta_boxes_post, позволяющий определить метабокс, и

  3. Крючок wp_insert_post_data, позволяющий вам захватывать выбранные рекламные коробки и сохранять их в базе данных.

Каждый из этих крючков ссылается на другой статический функция в классе (это были функции, которые я инкапсулировал, создавая класс.)

Я пропущу описание функции action_init() и моей вспомогательной функции make_labels(), предполагая, что вы знаете, как зарегистрировать тип сообщения на основе вашего вопроса.

Функция action_add_meta_boxes_post() регистрирует метабокс, используя основную функцию WordPress add_meta_box(), и я прокомментировал ее параметры, чтобы объяснить, почему я передал то, что передал для каждого. Функция обратного вызова the_little_promo_boxes_metabox(), конечно, является еще одним статическим функция класса и это то, что на самом деле отображает содержимое в метабоксе. В основном он использует основную функцию WordPress wp_dropdown_pages() для отображения списка промо-полей (обратите внимание, что он будет отображать другие типы сообщений, кроме "страницы", но только в том случае, если они помечены как 'hierarchical'=>true при регистрации типа сообщения. Почему только иерархический? Потому что так они это написали, вот почему! :)

Поскольку мы показываем три (3) выпадающих списка, нам нужно указать каждому уникальный идентификатор в HTML ("promo_box_{$i}"), но то же имя в квадратных скобках ('promo_boxes[]'), так что PHP соберет их в массив внутри переменной $_POST (к которой WordPress обращается для нас; вы увидите, как через минуту). И, конечно, нам нужно установить выбранное значение ((empty($promo_boxes[$i]) ? 0 : $promo_boxes[$i])), если действительно одно из значений было выбрано ранее.

Я также использовал основную функцию WordPress get_post_type_object(), чтобы показать, как получить метки из типа записи, а также использовал основную функцию WordPress get_post_meta() для извлечения массива идентификаторы промо-полей от использования ключа пользовательского поля "_promo_boxes", который я покажу, вам нужно сохранить следующим (обратите внимание, что я использовал предыдущее подчеркивание в имени '_promo_boxes', что заставляет WordPress скрываться от стандартного пользовательского интерфейса поля, когда пользователь редактирует сообщение.).

Последняя функция, которую нужно описать, прежде чем вы увидите код, - это filter_wp_insert_post_data(), которая получает существующие данные post в первом параметре ($data) и содержимое массива $_POST благодаря WordPress в качестве второго параметра ($postarr). Внутри этой функции мы вызываем основную функцию WordPress update_post_meta() и извлекаем массив промо-полей ($postarr['promo_boxes']), чтобы сохранить в пользовательском поле значение ключа '_promo_boxes' для сообщения, указанного массивом $_POST (т. е. $postarr['ID']).

Тем не менее, вот код для класса LittlePromoBoxes:

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

Есть еще две (2) статические функции, которые еще не упомянуты: get_promo_boxes() и get_promo_box(); это вспомогательные функции, которые помогут вам получить сообщения post_type='promo-box' по их порядковым номерам 1..3. Но для сделайте их более похожими на WordPress, вот две функции-оболочки для добавления в файл вашей темы functions.php (обратите внимание, что вы можете передать сообщение в качестве параметра, но вам не нужно этого делать, если вы не используете другой пост, который находится в Цикле):

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

Теперь вы можете вызвать одну или обе из этих функций в файле темы single.php с кодом, который может выглядеть следующим образом (этот код мог быть написан в цикле, но большинство разработчиков WordPress, похоже, любят дублировать код, поэтому они могут прочитать его вместо того, чтобы устранять избыточность. Итак, когда в Риме...):

<?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>';
?>
 14
Author: MikeSchinkel, 2017-05-23 11:33:33