从ADD_SUBMENU_PAGE()回调重定向时出现‘Headers Always Sent’错误

时间:2016-08-01 作者:Lee

这是一个非常常见的问题,但我读到的所有答案都与我的情况无关。

我正在编写一个自定义插件,它可以读取和写入/更新自定义数据库表中的数据(非常简单)。

但是,当进行更新时,我希望重定向到主页,然后在页面上显示成功管理通知。但是,在提交表单时wp_safe_redirect 我得到以下信息:

警告:无法修改标题信息-标题已由C:\\wamp64\\www\\bellavou\\wp includes\\formatting.php:4593)中的C:\\wamp64\\www\\bellavou\\wp includes\\pluggable发送。php在线1167

我的插件文件和对重定向的调用中没有任何空格wpdb->update 通话内容如下:

if($wpdb->update( 
    \'wp_before_after\', 
    $bv_before_after_data, 
    array( \'id\' => $bv_id ), 
    array( 
        \'%s\',   // value1
        \'%s\',   // value2
        \'%s\',   // value3
        \'%d\',   // value4
        \'%d\',   // value5
        \'%d\',   // value6
        \'%d\',   // value7
        \'%d\',   // value8
        \'%s\',   // value9
        \'%s\',   // value10
        \'%s\',   // value11
        \'%s\',   // value12
    ), 
    array( \'%d\' ) 
    )) {
        // Success
        wp_safe_redirect(\'/wp-admin/admin.php?page=bv_before_afters_main&updated=1\');
    } else {
        // Error
        echo \'<div class="notice notice-error is-dismissible"><p>Could not be updated! (Maybe there was nothing to update?)</p></div>\';
    }
我如何才能正确订购,使重定向和管理通知正常工作?

更新时间:

我的主插件文件如下所示(包括其他页面):

// Create page in WP Admin
function my_admin_menu() {
    add_menu_page( \'Before & After Photos\', \'Before & Afters\', \'edit_posts\', \'bv_before_afters_main\', \'bv_before_afters_main\', \'dashicons-format-gallery\', 58  );
    add_submenu_page( \'bv_before_afters_main\', \'Add set\', \'Add set\', \'edit_posts\', \'bv_before_afters_add\', \'bv_before_afters_add\' );
    add_submenu_page( \'bv_before_afters_main\', \'Edit set\', \'Edit set\', \'edit_posts\', \'bv_before_afters_edit\', \'bv_before_afters_edit\' );    
}
add_action( \'admin_menu\', \'my_admin_menu\' );

// Apply stylesheets
function bv_before_afters_styles(){
    wp_enqueue_style( \'bv_before_after_styles\', plugins_url( \'/bv_before_afters.css\', __FILE__ ) );
}
add_action(\'admin_print_styles\', \'bv_before_afters_styles\');

// Display the main page
function bv_before_afters_main(){
    include_once plugin_dir_path( __FILE__ ).\'/views/view_all.php\';
}

// Display the edit page
function bv_before_afters_edit(){
    include_once plugin_dir_path( __FILE__ ).\'/views/edit.php\';
}

// Display the add page
function bv_before_afters_add(){
    include_once plugin_dir_path( __FILE__ ).\'/views/add.php\';
}
(重定向代码在edit.php)

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

背景

臭名昭著的;Headers already sent"E;如果在服务器响应的HTTP头已经发送到浏览器之后,有人试图修改服务器响应的HTTP头,那么这个错误就很可怕了,也就是说,服务器应该只生成响应的主体。

这通常以以下两种方式之一发生:

在WordPress完成头文件的编写之前,代码过早地打印内容-这会将HTTP响应推送到浏览器,并强制在过程中调度HTTP头文件。WordPress或第三方代码通常会正确修改标题的任何尝试都会随后产生错误wp_safe_redirect() 函数通过设置300-范围HTTP状态标头。由于的回调函数参数add_menu_page()add_submenu_page() 用于在已生成仪表板侧栏和浮动工具栏后打印自定义标记,但在WordPress执行回调时太晚,无法使用wp_safe_redirect() 作用如评论中所述,解决方案是移动$wpdb->update()wp_safe_redirect() 在您的views/edit.php 查看模板和;挂钩“;将它们转换为在发送HTTP标头之前(在将任何HTML发送到浏览器之前)发生的操作。

解决问题the action reference for the typical admin-page request, 有理由假设\'send_headers\' action是可以可靠修改HTTP头的最新版本。因此,可以通过将一个函数附加到该操作或之前包含重定向逻辑的函数来实现所需的结果,但您需要手动检查显示的管理页面,以确保只处理$wpdb->update() 以及随后的重定向views/edit.php 样板

WordPress为这种上下文功能提供了一个快捷方式the \'load-{page hook}\' action, 对于加载的每个管理页面,它都会动态触发。当您呼叫add_submenu_page() 将返回{page hook} 值,该值用于钩住要执行的操作当您的自定义模板加载时,可以按照以下格式推断页面钩子{parent page slug}_page_{child page slug}. 从代码中获取值,然后,我们最终得到\'load-bv_before_afters_main_page_bv_before_afters_edit\' 操作,仅在加载views/edit.php 样板

最后一个问题是是否$wpdb->update() 给您的views/edit.php 用于确定是否显示错误消息的模板。这可以使用全局变量或自定义操作来完成,但是更好的解决方案是附加一个函数,将错误打印到\'admin_notices\' 正是由于这个原因而存在的操作。\'admin_notices\' 将在WordPress呈现自定义视图模板之前触发,确保错误消息最终出现在页面顶部。

Note

这个$wpdb->update() 方法返回更新的行数或false 如果遇到错误-这意味着成功的更新查询不能更改任何行并返回0, 你的if() 条件将惰性地计算为false 并显示错误消息。因此,如果您希望仅在调用实际失败时显示错误,则应比较$wpdb->update()\'s返回值false 使用标识比较运算符!==.

实施结合以上所有内容,一个解决方案可能如下所示。在这里,为了便于参考,我使用了一个额外的数组来保存管理页面的页面段塞,以确保没有与打字错误相关的问题,并在必要时使段塞更容易更改。

的整个部分views/edit.php 您最初发布的文件现在将驻留在操作挂钩中,以及用于处理编辑表单的任何其他业务逻辑中。

Plugin File:

$bv_admin_page_slugs = [
  \'main\' => \'bv_before_afters_main\',
  \'edit\' => \'bv_before_afters_edit\',
  \'add\'  => \'bv_before_afters_add\'
];

add_action( \'admin_menu\', \'bv_register_admin_pages\' );

// Create page in WP Admin
function bv_register_admin_pages() {
    add_menu_page(
      \'Before & After Photos\',
      \'Before & Afters\',
      \'edit_posts\',
      $bv_admin_page_slugs[\'main\'],
      \'bv_before_afters_main\',
      \'dashicons-format-gallery\',
      58
    );

    add_submenu_page(
      $bv_admin_page_slugs[\'main\'],
      \'Add set\',
      \'Add set\',
      \'edit_posts\',
      $bv_admin_page_slugs[\'add\'],
      \'bv_before_afters_add\'
    );

    add_submenu_page(
      $bv_admin_page_slugs[\'main\'],
      \'Edit set\',
      \'Edit set\',
      \'edit_posts\',
      $bv_admin_page_slugs[\'edit\'],
      \'bv_before_afters_edit\'
    );    
}

// Process the update/redirect logic whenever the the custom edit page is visited
add_action(
  \'load-\' . $bv_admin_page_slugs[\'main\'] . \'_page_\' . $bv_admin_page_slugs[\'edit\'],
  \'bv_update_before_after\'
);

// Performs a redirect on a successful update, adds an error message otherwise
function bv_update_before_after() {
  // Don\'t process an edit if one was not submitted
  if( /* (An edit was NOT submitted) */ )
    return;

  $result = $wpdb->update( /* (Your Arguments) */ );

  if( $result !== false ) {
    wp_safe_redirect(\'/wp-admin/admin.php?page=\' . $bv_admin_page_slugs[\'main\'] . \'&updated=1\');
    exit;
  }
  else {
    // Tell WordPress to print the error when it usually prints errors
    add_action(
      \'admin_notices\',
      function() {
        echo \'<div class="notice notice-error is-dismissible"><p>Could not be updated!</p></div>\';
      }
    );
  } 
}

// Apply stylesheets
function bv_before_afters_styles(){
    wp_enqueue_style( \'bv_before_after_styles\', plugins_url( \'/bv_before_afters.css\', __FILE__ ) );
}
add_action(\'admin_print_styles\', \'bv_before_afters_styles\');

// Display the main page
function bv_before_afters_main(){
    include_once plugin_dir_path( __FILE__ ).\'/views/view_all.php\';
}

// Display the edit page
function bv_before_afters_edit(){
    include_once plugin_dir_path( __FILE__ ).\'/views/edit.php\';
}

// Display the add page
function bv_before_afters_add(){
    include_once plugin_dir_path( __FILE__ ).\'/views/add.php\';
}

SO网友:Anders Lund

我没有发送任何新的标题,所以很难找到它。

尝试检查DOM。在DOM的顶部,出于某种原因,我在顶部有一个狂野的评论部分,这破坏了标题的其余部分。

我删除了注释部分,由于某种原因,它呈现在DOM的顶部。

希望这对其他人有帮助

相关推荐

在何处定义了Java脚本属性窗口._wpCustomHeaderSetting?

我试图修改wp-includes/js/wp-custom头中定义的Javascript函数的行为。js,更改最小窗口高度以显示视频标题。为此,我需要修改属性window._wpCustomHeaderSettings.minHeight在我的脚本运行时,window._wpCustomHeaderSettings 尚未定义,因此我使用window._wpCustomHeaderSettings = window._wpCustomHeaderSettings || {}, 然后设置属性minHeight