Metabox内的WP_LIST_TABLE未处理提交

时间:2014-03-19 作者:Ben

我正在尝试显示WP_List_table 在metabox中。metabox用于名为service 已注册到名为office. 表列包含操作分类法的输入字段,并允许我将其他数据链接到每个单独的分类法术语。我不认为我试图将其用于自定义帖子类型编辑屏幕上的自定义分类法这一事实是相关的。我只是为了清楚起见才提到。

现在的情况是,在我单击自定义帖子类型编辑屏幕上的发布/更新按钮之前,一切看起来都很好。如果WP_List_Table 具有批量操作,它将重定向回/wp-admin/edit.php 页面中,如果我删除了批量操作,则会显示Wordpress失败通知“您确定要执行此操作吗?-请重试”,这是一个暂时的验证错误。在这两种情况下,我为帖子更改的所有数据都不会被保存。

我在下面提供了一个链接,指向注册分类法、创建表和保存元盒数据的完整脚本。如果你愿意,可以随意摆弄它来让它工作。

http://www.writeurl.com/text/aawwgq1od5913fmyfjyu/0y84g3vcyptvrkvvfxq4/0dow449a06lj6ctkqjqo

A NOTE TO THE STACKOVERFLOW EDITORS: 我已经检查了输入我的问题时提出的问题,以及所有带有wp list table plus标记的问题,搜索了Google的深度,似乎没有一个问题与我的情况相关。

UPDATE: 如果可能的话,我希望不必使用任何bulk\\u操作。我不需要把它们放在这张桌子上。我只是出于测试目的添加了删除操作。和类方法process_bulk_action 甚至在提交时都不会被调用。

<?php
if(!class_exists(\'WP_List_Table\')) {
    require_once(ABSPATH.\'wp-admin/includes/class-wp-list-table.php\');
}

class servicesTable extends WP_List_Table {
    private $allServices;
    private $currentServices;
    private $currentServicesData;

    public function __construct(){
        parent::__construct(
            array(
                \'singular\' => \'service\',
                \'plural\' => \'services\',
                \'ajax\' => false
            )
        );
    }

    private function table_data() {
        $this->currentServices = wp_get_object_terms(get_the_ID(),array(\'service\'),array(\'fields\' => \'ids\'));
        $this->currentServicesData = (array) maybe_unserialize(get_post_meta(get_the_ID(),\'currentServices\',true));
        $this->allServices = array();
        foreach((array) get_terms(array(\'service\'),array(\'hide_empty\' => false)) as $service) {
            $this->allServices[] = array(
                \'id\' => $service->term_id,
                \'serviceTitle\' => $service->name,
                \'attachments\' => array_key_exists($service->term_id,$this->currentServicesData) ? explode(\',\',$this->currentServicesData[$service->term_id][\'attachments\']) : array(),
                \'lastServiced\' =>  (array_key_exists($service->term_id,$this->currentServicesData) && strlen($this->currentServicesData[$service->term_id][\'last_serviced\']) > 0) ? date(\'Y-m-d\',strtotime($this->currentServicesData[$service->term_id][\'last_serviced\'])) : \'\',
                \'nextService\' =>  (array_key_exists($service->term_id,$this->currentServicesData) && strlen($this->currentServicesData[$service->term_id][\'next_service\']) > 0) ? date(\'Y-m-d\',strtotime($this->currentServicesData[$service->term_id][\'next_service\'])) : \'\',
                \'invoices\' => \'\'
            );
        }
        return $this->allServices;
    }

    public function column_default($item,$columnName) {
        return array_key_exists($columnName,$item) ? $item[$columnName] : print_r($item,true);
    }

    public function get_columns(){
        return array(
            \'cb\' => \'<input type="checkbox" />\',
            \'id\' => \'ID\',
            \'serviceTitle\' => __(\'Title\',\'brokertech\'),
            \'attachments\' => __(\'Attachments\',\'brokertech\'),
            \'lastServiced\' => __(\'Last Service Date\',\'brokertech\'),
            \'nextService\' => __(\'Next Service Date\',\'brokertech\'),
            \'invoices\' => __(\'Invoices\',\'brokertech\')
        );
    }

    public function get_hidden_columns() {
        return array(\'id\');
    }

    public function get_sortable_columns() {
        return array(
            \'lastServiced\' => array(\'lastServiced\',true),
            \'nextService\' => array(\'nextService\',true)
        );
    }

    private function sort_data($a,$b) {
        $orderby = empty($_GET[\'orderby\']) ? \'nextService\' : $_GET[\'orderby\'];
        $order = empty($_GET[\'order\']) ? \'asc\' : $_GET[\'order\'];
        $result = strcmp($a[$orderby],$b[$orderby]);
        return ($order === \'asc\') ? $result : -$result;
    }

    public function prepare_items() {
        usort($this->table_data(),array(&$this,\'sort_data\'));
        $this->_column_headers = array($this->get_columns(),$this->get_hidden_columns(),$this->get_sortable_columns());
        $this->items = $this->allServices;
        wp_enqueue_script(\'services\',JS_URI.\'servicesSelector.js\',array(\'thickbox\',\'media-upload\'));
        wp_enqueue_style(\'thickbox\');
        wp_localize_script(
        \'services\',
        \'servicesData\',
            array(
                \'editAttachment\' => __(\'Edit\'),
                \'removeAttachment\' => __(\'Remove\')
            )
        );
    }

    public function column_cb($item) {
        return sprintf(\'<input type="checkbox" name="services[%s][enable]" value="%s" %s />\',$item[\'id\'],$item[\'serviceTitle\'],checked(true,in_array($item[\'id\'],$this->currentServices),false));
    }

    public function column_id($item) {
        return sprintf(\'<input type="hidden" name="services[%s][id]" value="%s" />\',$item[\'id\'],$item[\'id\']);
    }

    public function column_attachments($item) {
        $html  = sprintf(
            \'<input type="hidden" name="services[%s][attachments]" value="%s" class="listAttachments" />\',
            $item[\'id\'],
            empty($item[\'attachments\']) ? \'\' : implode(\',\',$item[\'attachments\'])
        );
        $html .= sprintf(\'<input type="button" value="%s" class="button button-secondary addServiceAttachment" data-service-id="%s" />\',__(\'Add\'),$item[\'id\']);
        $html .= "&nbsp;";
        if(empty($item[\'attachments\'])) {
            $html .= sprintf(\'<input type="button" value="%s" class="button button-secondary clearAll" data-service-id="%s" disabled="disabled" />\',__(\'Clear\'),$item[\'id\']);
        }
        else {
            $html .= sprintf(\'<input type="button" value="%s" class="button button-secondary clearAll" data-service-id="%s" />\',__(\'Clear\'),$item[\'id\']);
            $html .= "<br /><br />";
            foreach($item[\'attachments\'] as $attachment) {
                if(is_numeric($attachment)) {
                    $html .= sprintf(
                        "<div class=\'serviceAttachment\' style=\'margin-bottom: 1em;\'><span>%s</span><br /><a href=\'%s\' target=\'_blank\' class=\'button button-secondary\'>%s</a><input type=\'button\' class=\'removeServiceAttachment button button-secondary\' value=\'%s\' style=\'float:right;\' /><div style=\'clear:both;\'></div></div>",
                        get_the_title($attachment),
                        get_admin_url(get_current_blog_id(),\'post.php?post=\'.$attachment.\'&action=edit\'),
                        __(\'Edit\'),
                        __(\'Remove\')
                    );
                }
            }
        }
        return $html;
    }

    public function column_lastServiced($item) {
        return sprintf(\'<input type="date" name="services[%s][last_serviced]" value="%s" />\',$item[\'id\'],$item[\'lastServiced\']);
    }

    public function column_nextService($item) {
        return sprintf(\'<input type="date" name="services[%s][next_service]" value="%s" />\',$item[\'id\'],$item[\'nextService\']);
    }

    public function column_invoices($item) {
        $html  = sprintf(
            \'<input type="hidden" name="services[%s][invoices]" value="%s" class="listInvoices" />\',
            $item[\'id\'],
            empty($item[\'invoices\']) ? \'\' : implode(\',\',$item[\'invoices\'])
        );
        $html .= sprintf(\'<input type="button" value="%s" class="button button-secondary addInvoice" data-service-id="%s" />\',__(\'Add\'),$item[\'id\']);
        $html .= "&nbsp;";
        if(!empty($item[\'invoices\'])) {
            $html .= "<br /><br />";
            foreach($item[\'invoices\'] as $invoice) {
                if(is_numeric($invoice)) {
                    $html .= sprintf(
                        "<div class=\'serviceInvoice\' style=\'margin-bottom: 1em;\'><span>%s</span><br /><a href=\'%s\' target=\'_blank\' class=\'button button-secondary\'>%s</a><input type=\'button\' class=\'removeInvoice button button-secondary\' value=\'%s\' style=\'float:right;\' /><div style=\'clear:both;\'></div></div>",
                        get_the_title($invoice),
                        get_admin_url(get_current_blog_id(),\'post.php?post=\'.$attachment.\'&action=edit\'),
                        __(\'Edit\'),
                        __(\'Remove\')
                    );
                }
            }
        }
        return $html;
    }
}

function saveServices($postID) {
    if(empty($_POST) || (defined(\'DOING_AUTOSAVE\') && DOING_AUTOSAVE)) {
        return;
    }
    $servicesData = array();
    $services = array();
    foreach($_POST[\'services\'] as $service) {
        if(isset($service[\'enable\'])) {
            $services[] = (string) $service[\'enable\'];
                $servicesData[$service[\'id\']] = $service;
        }
    }
    empty($servicesData) ? delete_post_meta($postID,\'currentServices\') : update_post_meta($postID,\'currentServices\',$servicesData);
    wp_set_object_terms($postID,$services,\'service\');
}
add_action(\'save_post\',\'saveServices\');

function servicesMetaBox() {
    $servicesTable = new servicesTable();
    $servicesTable->prepare_items();
    $servicesTable->display();
}

$serviceTaxonomy = new brokertechPostType;
$serviceTaxonomy->createTaxonomy(
    \'service\',
    array(
        \'office\'
    ),
    __(\'Service\'),
    __(\'Services\'),
    array(
        \'public\' => true,
        \'hierarchical\' => false,
        \'query_var\' => true,
        \'update_count_callback\' => \'_update_post_term_count\',
        \'show_ui\' => true,
        \'rewrite\' => array(
            \'slug\' => __(\'services\')
        ),
        \'meta_box_cb\' => \'servicesMetaBox\'
    )
);

function addServicesTaxonomyPage() {
    add_submenu_page(
        \'edit.php?post_type=company\',
        __(\'Services\'),
        __(\'Services\'),
        \'edit_posts\',
        \'edit-tags.php?taxonomy=service&post_type=office\'
    );
}
add_action(\'admin_menu\',\'addServicesTaxonomyPage\');

function changeServicesMetaBoxPosition() {
    global $wp_meta_boxes;
    unset($wp_meta_boxes[\'office\'][\'side\'][\'core\'][\'tagsdiv-service\']);
    add_meta_box(
        \'tagsdiv-service\',
        __(\'Services\'),
        \'servicesMetaBox\',
        \'office\',
        \'normal\',
        \'low\'
    );
}
add_action(\'add_meta_boxes\',\'changeServicesMetaBoxPosition\',0);

2 个回复
最合适的回答,由SO网友:user2242022 整理而成

您只需重写该函数display_tablenav() 在父类中使用空函数。

它被解释了here.

SO网友:Michael Ecklund

我最近才遇到这个问题。

如果您在元框(位于编辑后屏幕上)中使用自定义列表表(也可以是WP列表post.phppost-new.php.)

您被重定向到帖子列表屏幕的原因(edit.php) 是因为自定义列表表生成了一个隐藏的nonce字段,该字段也是由post.phppost-new.php 第页。他们都有相同的名字,因为。。。出现意外问题。

简单的解决方案是重写在自定义列表表中创建nonce字段的函数。

自定义列表表中的问题是分页正在创建nonce。

如果你打开list-table.php 分类并搜索function display_tablenav( 您将找到创建nonce的函数。

我确信有更好的方法可以做到这一点,但我只是简单地复制了整个函数,然后将其粘贴到我的自定义列表表类中,并注释掉了创建nonce字段的部分。

Example:

/**
 * Generate the table navigation above or below the table
 *
 * @since 3.1.0
 * @access protected
 *
 * @param string $which
 */
protected function display_tablenav( $which ) {

    // REMOVED NONCE -- INTERFERING WITH SAVING POSTS ON METABOXES
    // Add better detection if this class is used on meta box or not.
    /*
    if ( \'top\' == $which ) {
        wp_nonce_field( \'bulk-\' . $this->_args[\'plural\'] );
    }
    */

    ?>
    <div class="tablenav <?php echo esc_attr( $which ); ?>">

        <div class="alignleft actions bulkactions">
            <?php $this->bulk_actions( $which ); ?>
        </div>
        <?php
        $this->extra_tablenav( $which );
        $this->pagination( $which );
        ?>

        <br class="clear"/>
    </div>
<?php
}
如果您注释掉了这段代码,您的贴子页面应该再次像正常情况一样成功提交。

结束