保存自定义字段时添加验证和错误处理?


27

我有一个在帖子类型上定义自定义字段的函数。假设该字段为“副标题”。

保存帖子后,我想对输入内容进行一些验证,并在必要时在帖子编辑屏幕上显示错误消息。就像是:

// Handle post updating
function wpse_update_post_custom_values($post_id, $post) {

    // Do some checking...
    if($_POST['subhead'] != 'value i expect') {

        // Add an error here
        $errors->add('oops', 'There was an error.');

    }

    return $errors;

} 
add_action('save_post','wpse_update_post_custom_values',1,2);

我试图将其挂钩到save_post动作,但是我不知道如何处理错误。似乎没有错误对象传递到函数中,并且如果我创建自己的WP_Error obj并将其返回,则无论哪种机制都不会在后期编辑页面上吐出错误,因此不会尊重它。

我目前在我的自定义meta框内有一个页面错误消息,但这并不理想-我宁愿有一个大的,红色的,最顶部的错误,如WP通常显示。

有任何想法吗?

更新:

根据@Denis的回答,我尝试了一些不同的方法。将错误存储为全局变量是行不通的,因为Wordpress在save_post过程中进行了重定向,这会在显示全局变量之前将其杀死。

我最终将它们存储在meta字段中。问题是您需要清除它们,否则当您导航到另一个页面时它们不会消失,因此我不得不在admin_footer上附加另一个函数,以清除错误。

我不会期望这么常见的错误处理(更新帖子)会很笨拙。我是否缺少明显的东西,或者这是最好的方法?

// Handle post updating
function wpse_5102_update_post_custom_values($post_id, $post) {

    // To keep the errors in
    $errors = false;

    // Do some validation...
    if($_POST['subhead'] != 'value i expect') {

        // Add an error here
        $errors .= 'whoops...there was an error.';

    }

    update_option('my_admin_errors', $errors);

    return;

} 
add_action('save_post','wpse_5102_update_post_custom_values',1,2);


// Display any errors
function wpse_5102_admin_notice_handler() {

    $errors = get_option('my_admin_errors');

    if($errors) {

        echo '<div class="error"><p>' . $errors . '</p></div>';

    }   

}
add_action( 'admin_notices', 'wpse_5102_admin_notice_handler' );


// Clear any errors
function wpse_5102__clear_errors() {

    update_option('my_admin_errors', false);

}
add_action( 'admin_footer', 'wpse_5102_clear_errors' );

好问题。我认为,admin_footer如果在通知处理程序函数末尾清除错误,就可以摆脱困境。简化了一点。
Geert)

您如何处理重新填充表单字段(包含可能的无效数据)?
Geert)

我有一个基本问题。这是什么Wordpress php文件?

@Karen这将在自定义插件文件或您的functions.php中。
MathSmath 2011年

我可能会遗漏一些明显的东西,但是update_option('my_admin_errors', false);在if末尾的if语句之后立即运行会更有效wpse_5102_admin_notice_handler()吗?
安德鲁·奥德里

Answers:


6

将错误存储在您的类中或全局变量中,可能在瞬态或元数据中存储,并在POST请求的管理员通知中显示它们。WP没有任何Flash消息处理程序。


感谢您指出我的方向!我最终使用meta来存储错误,因为尝试将其作为全局属性或属性时遇到了问题。我现在正在更新我的答案,以解释我的操作方式...请让我知道这是否是您建议的那种方式,或者是否有更好的方法让我无法理解。
MathSmath 2010年

是的,是的。也许,再三考虑,就将其存储在会话变量中。这是为了使多个作者可以同时编辑帖子。:-)另外,我相信不可能在一个选项中存储false。而是存储一个空字符串。
Denis de Bernardy 2010年

6

我建议使用会话,因为当两个用户同时进行编辑时,这不会产生奇怪的效果。所以这就是我要做的:

会话不是由wordpress启动的。因此,您需要在插件,functions.php甚至wp-config.php中启动会话

if (!session_id())
  session_start();

保存帖子时,将错误和通知附加到会话中:

function my_save_post($post_id, $post) {
   if($something_went_wrong) {
     //Append error notice if something went wrong
     $_SESSION['my_admin_notices'] .= '<div class="error"><p>This or that went wrong</p></div>';
     return false; //might stop processing here
   }
   if($somthing_to_notice) {  //i.e. successful saving
     //Append notice if something went wrong
     $_SESSION['my_admin_notices'] .= '<div class="updated"><p>Post updated</p></div>';
   }

   return true;
} 
add_action('save_post','my_save_post');

打印通知和错误,然后清除会话中的消息:

function my_admin_notices(){
  if(!empty($_SESSION['my_admin_notices'])) print  $_SESSION['my_admin_notices'];
  unset ($_SESSION['my_admin_notices']);
}
add_action( 'admin_notices', 'my_admin_notices' );

修复会话版本:第一次使用会话变量时不要使用。= only =如果打开调试,则可以检查原因...

3
我也一直在这样做,但是如果您向如此广泛的受众发布插件,人们最终会讨厌您。Wordpress不会实例化会话,因为它被设计为无状态的并且不需要它们,并且一些奇怪的服务器设置会破坏它。使用过渡API-codex.wordpress.org/Transients_API代替会话,您将保持兼容性。只是认为值得在这里标出不这样做的原因。
pospi 2012年

@pospi似乎与get_option和update_option函数的原始用法存在类似的问题。因此,我猜解决方案将是将当前用户的ID附加到密钥上?
Gazillion

是的,完全可以!只要您添加一些东西来唯一标识用户,您就可以避免登录用户之间的消息混淆(:
pospi 2013年

5

基于pospi的使用瞬态建议,我提出了以下建议。唯一的问题是没有钩子可以将消息放置在其他消息所在的位置之下,因此我不得不做一个jQuery hack才能将其放置到那里。h2

首先,在您save_post(或类似的)处理程序期间保存错误消息。我为它提供了60秒的短生命周期,因此它足够长,可以进行重定向。

if($has_error)
{
  set_transient( "acme_plugin_error_msg_$post_id", $error_msg, 60 );
}

然后,只需在下一页加载时检索该错误消息并显示它即可。我也将其删除,因此不会显示两次。

add_action('admin_notices', 'acme_plugin_show_messages');

function acme_plugin_show_messages()
{
  global $post;
  if ( false !== ( $msg = get_transient( "acme_plugin_error_msg_{$post->ID}" ) ) && $msg) {
    delete_transient( "acme_plugin_error_msg_{$post->ID}" );
    echo "<div id=\"acme-plugin-message\" class=\"error below-h2\"><p>$msg</p></div>";
  }
}

由于admin_notices在生成主要页面内容之前触发,因此通知不是其他后期编辑消息的去向,因此我不得不使用此jQuery将其移动到那里:

jQuery('h2').after(jQuery('#acme-plugin-message'));

由于帖子ID是临时名称的一部分,因此它应在大多数多用户环境中都有效,除非有多个用户同时编辑同一帖子。


您能否详细说明“由于帖子ID是临时名称的一部分”?我使用这种技术创建了一个处理错误消息的类,但是我需要我的构造函数传递一个user_ID。散列密钥时,瞬态API是否使用user_id?(我问,因为法典似乎没提到这一点)
Gazillion

否,但是您可以手动添加。在我上面发布的代码中,瞬变的名称为acme_plugin_error_msg_POSTID。您可以像这样添加用户ID acme_plugin_error_msg_POSTID_USERID
2015年

2

save_post运行时,它已经保存了数据库的讯息。

研究WordPress核心代码(更具体地讲,是wp-includes/post.phpupdate_post()功能),没有内置的方法可以在将请求保存到数据库之前对其进行拦截。

但是,我们可以挂钩pre_post_update并使用,header()get_post_edit_link()防止帖子被保存。

<?php

/**
*   Performs validation before saving/inserting custom post type
*/
function custom_post_site_save($post_id, $post_data) {
    // If this is just a revision, don't do anything.
    if (wp_is_post_revision($post_id))
        return;

    if ($post_data['post_type'] == 'my_custom_post_type') {
        // Deny post titles with less than 5 characters
        if (strlen($post_data['post_title'] < 5)) {
            header('Location: '.get_edit_post_link($post_id, 'redirect'));
            exit;
        }
    }
}
add_action( 'pre_post_update', 'custom_post_site_save', 10, 2);

如果您要通知用户出了什么问题,请检查以下要点:https : //gist.github.com/Luc45/09f2f9d0c0e574c0285051b288a0f935


谢谢您,无论是初次发布还是更新帖子,都可以完美地处理验证。您节省了我很多时间和精力。
扎德

1

您为什么不借助某些Javascript来验证您的字段?我认为这将是最好的方法。


谢谢你的建议!为了简单起见,我没有考虑这个问题,因为我正在尝试处理文件上传错误,因此它需要在服务器端进行。还是)感谢你的建议!
MathSmath 2010年

javascript验证并不能阻止某些攻击,服务器端验证是唯一安全的方法。此外,wordpress提供了一些不错的工具来验证用户数据。但是,如果它只是在将数据发送到服务器之前检查一些值,那么您是对的,您可以在低服务器中节省一些时间^^
nderambure 2011年

1

尝试使用上面的脚本时,我遇到了一个奇怪的问题。帖子更新后,编辑屏幕上会显示两条消息。一种显示来自先前保存的内容状态,另一种显示当前内容的状态。例如,如果我正确保存帖子,然后出错,则第一个是“ error”,第二个是“ ok”-尽管它们是同时生成的。如果我更改脚本并仅添加一条消息(例如“错误”),则以“错误”启动一个更新,然后再以“确定”进行另一次更新,“错误”消息仍然存在(第二次显示)。我必须再次保存“确定”才能摆脱它。我真的不知道出什么问题了,我已经在三台不同的本地服务器上对其进行了测试,并且每台本地服务器上都存在相同的问题。


我对上面提到的脚本的第二个版本进行了更多测试,似乎如果“错误”消息确实附加在会话数组上,则会显示在编辑屏幕上。如果没有任何消息(一切正常),并且上一条消息是错误的,它将显示在屏幕上。奇怪的是,它是在保存时生成的(未缓存)-我已经在错误消息正文中使用date()对其进行了检查。我现在很困惑。
jlub 2011年

好的,以防万一其他人从他的头上拔头发-事实证明,WordPress修订系统是问题所在(可能是某种错误?)。我已禁用它,现在一切都很好。

0

我编写了一个插件,该插件添加了用于帖子编辑屏幕的Flash错误处理功能,并防止在需要填写的字段之前发布帖子:

https://github.com/interconnectit/required-fields

它允许您将任何发布字段都强制设置为必填项,但是您可以使用它提供的API来通过自定义错误消息和验证功能将所有自定义字段设置为必需。默认情况下,检查该字段是否为空。


如果遇到它们,请不要在github上添加任何问题。我还需要更好地记录API,因为您可以使用一些辅助过滤器。
sanchothefat 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.