问题描述

(我的第一个 WP 问题曾经问过!温柔!)

我正在构建一个主要是页面 (即静态) 的网站,使用 WP 作为 CMS 。在几页的底部,将出现 1,2 或 3 个”promo boxes” – 基本上 button-images 链接到站点的其他部分。虽然在任何给定的页面上只能出现 3 个促销框,但可以选择 30 个不同的促销框。

当我的客户创建一个新页面时,我希望他能够从所有可能的促销框的下拉列表中选择促销框。

看来我应该这样工作:

  • 创建名为”promo-box” 的自定义帖子类型。 (尽管它可以很容易地成为常规帖子的标签。)

  • 使用类似 Custom Field Template 的工具在页面编辑器上创建一个下拉列表,其中从所有现有的 promo-box 帖子的列表中动态生成下拉选项的值。 (这是我不知道该怎么做的部分)

  • 访问生成的元数据 (发布号真的是我需要的,然后我可以得到所有其他) 在页面模板上。

根据对其他问题的回应,我已经初步看过 WPAlchemy MetaBox,Post-2-Posts 和 SLT Custom Fields,但是我承认每个文档的文档比我都微乎其微,所以我还没有被挖掘出来太深了

建议吗?上面的工具之一是我正确的解决方案,我只需要弄清楚?我在这里遗漏了什么吗?

最佳解决方案

作为 WPAlchemyauthor,我有点偏见,但您基本上有一个很好的工作模式概述遵循,根据你选择的路线。

但是,如果使用 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 样式,custom/meta.php 本质上是一个具有元数据框的 FORM 内容的 HTML 文件,在这种情况下,您的下拉菜单将生成您的下拉菜单,您将执行一个自定义 wp 查询来获取所有的自定义帖子类型。 WPAlchemy 有一些特殊的帮助函数来帮助创建表单元素。

另外还有一个 documentation 来帮助你在模板中工作。

WPAlchemy 的主要目标是将开发者掌握控制权,从造型 (外观+感觉) 到元框内容定义。

我和他人总是乐意帮助那些发表评论和提问的人。

次佳解决方案

呵呵,你是个新手!我们要撕裂你的碎片…!

j /k 🙂 我们热烈欢迎这里的所有新手,很高兴有你。

所以这是我第三次听到这个要求,两次来自客户,不再来自你 (和你的客户) 。这告诉我这是一个很常见的需要。

我喜欢你的分析,所以我决定编写一个类来解决你的第二点。我调用 LittlePromoBoxes,因为我不能让 this song 出来,感谢 them 。基本上我使用类来封装,以避免与我需要编写的函数发生潜在的命名冲突。

您可以将此类放在主题的 functions.php 文件中,或者在您可能正在编写的插件的.PHP 文件中 (但不要担心,它看起来比它复杂得多) 。

第一个函数 on_load()是一个静态函数,我在类声明的末尾调用初始化你需要的三 (3) 个钩子 (fyi 静态函数本质上是 functions related to the class,而不是实例):

  1. init 挂钩注册 promo-box 帖子类型,

  2. add_meta_boxes_post 钩子允许您定义 metabox,和

  3. wp_insert_post_data 钩子允许您捕获所选的促销框并保存到数据库。

这些钩子中的每一个引用了类中的另一个静态函数 (这些是我通过创建类封装的函数) 。

我将跳过描述 action_init()函数和 make_labels()帮助函数,假设您知道如何根据您的问题注册一个帖子类型。

action_add_meta_boxes_post()功能使用 WordPress 核心函数 add_meta_box()注册 metabox,我已经评论过它的参数,以解释为什么我通过了我为每个通过了。回调函数 the_little_promo_boxes_metabox()当然是该类的另一个静态函数,它实际上是在 metabox 中显示的内容。它主要使用 WordPress 核心函数 wp_dropdown_pages()来显示一个促销框列表 (注意它将显示除了’page’ 之外的其他帖子类型,但只有在他们的帖子类型注册中被标记为'hierarchical'=>true,为什么只有层次结构?因为这样写了,这就是为什么!:)

由于我们显示了三 (3) 个下拉列表,所以我们需要在 HTML("promo_box_{$i}") 中给出每个唯一的 ID,但是使用方括号 ('promo_boxes[]') 赋予相同的名称,以便 PHP 将它们收集到 $_POST 变量中的数组 (WordPress 访问对我们来说,你会看到如何在一分钟内) 。当然,我们需要设置选择的值 ((empty($promo_boxes[$i]) ? 0 : $promo_boxes[$i])),如果其中一个值以前被选中。

我还使用 WordPress 核心函数 get_post_type_object()来显示如何从帖子类型获取标签,并且还使用 WordPress 核心函数 get_post_meta()从使用自定义字段键’_promo_boxes’ 来检索一个促销框 ID 数组,我会显示你有保存下一个 (注意我使用名称'_promo_boxes'中的一个前面的下划线,导致 WordPress 在用户编辑帖子时从标准自定义字段 UI 隐藏) 。

在您看到代码之前,描述的最后一个功能是 filter_wp_insert_post_data(),它接收第一个参数 ($data) 中的现有帖子数据以及 $_POST 数组的内容,这得益于 WordPress 作为第二个参数 ($postarr) 。在这个功能里面,我们称之为 WordPress 核心函数 update_post_meta(),并提取促销框数组 ($postarr['promo_boxes']),以保存 $_POST 数组 (即 $postarr['ID']) 指定的帖子'_promo_boxes'的自定义字段值。

也就是说,这是 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'的帖子。但是要让他们更多的 WordPress 像这里是两个包装函数添加到您的主题的 functions.php 文件 (注意,你可以传递一个参数,但你不必,除非你使用不同的帖子,一个在 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);
}

现在您可以在 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>';
?>

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。