呵呵,你是新手!我们要撕成碎片...! 
j / k :)   我们热烈欢迎所有新手在这里感到高兴。
因此,这是我第三次听到此要求,这是两次来自客户,而不是您(以及您的客户)。这告诉我这是相当普遍的需求。  

我喜欢您的分析,所以我决定编写一个类来解决您的第二点。我把它叫做LittlePromoBoxes是因为我永远无法得到这首歌了我的头,感谢他们。基本上,我使用该类进行封装,以免与我需要编写的功能发生潜在的命名冲突。
您可以将此类放在您主题的functions.php文件中,或者放在您可能正在编写的插件的.PHP文件中(但请放心,它看上去比实际要复杂得多。)  
第一个函数on_load()是一个静态函数,我在类声明的末尾调用该函数来初始化您需要的三(3)个钩子(fyi静态函数本质上是与类相关的函数,而不是与实例相关的函数):
- init用于注册- promo-box帖子类型的钩子,
 
- 该- add_meta_boxes_post挂钩允许您定义metabox,和
 
- wp_insert_post_data允许您捕获所选促销框并将其保存到数据库的挂钩。
 
这些钩子中的每一个都引用类中的另一个静态函数(这些是我通过创建类封装的函数)。 
假设您知道如何根据您的问题注册帖子类型,我将跳过对action_init()函数和make_labels()辅助函数的描述。
该action_add_meta_boxes_post()函数使用WordPress核心函数注册metabox,add_meta_box()并且我已注释了它的参数以解释为什么我传递了每个传递的内容。回调函数the_little_promo_boxes_metabox()当然是该类的另一个静态函数,它实际上是在metabox中显示内容的函数。它主要使用WordPress核心功能wp_dropdown_pages()显示促销框列表(请注意,它将显示除“页面”之外的其他帖子类型,但前提是它们被标记为'hierarchical'=>true处于其帖子类型注册中。写了,这就是为什么!!  
由于我们显示了三(3)个下拉列表,因此我们需要在HTML("promo_box_{$i}")中为每个ID赋予唯一的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)中接收现有的帖子数据,并通过$_POSTWordPress作为第二个参数($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文件中(请注意,您可以将帖子作为参数传递,但是除非您使用与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 themers似乎都希望复制代码,以便他们可以读取它而不是消除冗余)因此,在罗马时...):
<?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>';
?>