GET_POST()与全局$POST或$GLOBAL[‘POST’]

时间:2016-02-16 作者:Mat

我正在编写一个小部件插件,需要访问帖子信息。

我见过人们使用3种不同的方法:

global $post;
if ( isset( $GLOBALS[\'post\'] ) ) $post = $GLOBALS[\'post\'];
$post = get_post();
This post 解释前两种解决方案之间的差异。请您确认get_post() 如果没有args,则执行相同的操作(对于read only 目的)?

此外,关于if ( isset( $GLOBALS[\'post\'] ) ): 我想这意味着post 可以是未定义的。有人能在哪种情况下解释一下吗?

在我的例子中,这是页面中的一个小部件(不是post)。因此,可以安全地假设小部件代码在循环之后执行,post 在这种情况下,是否始终定义为页面内容?

1 个回复
最合适的回答,由SO网友:Pieter Goosen 整理而成

本质上,就所有技术目的而言,

get_post() == $post == $GLOBALS[\'post\']
正如@tosho在linked post, $post === $GLOBALS[\'post\'], 所以我不想谈这个。

我们感兴趣的是get_post() 同样的。为此,我们需要查看source code. 如您所见,我们在函数的前两行中得到了答案,但我们没有将任何内容传递给get_post()

if ( empty( $post ) && isset( $GLOBALS[\'post\'] ) )
    $post = $GLOBALS[\'post\'];
关于if ( isset( $GLOBALS[\'post\'] ) ): 我想这意味着post可以是未定义的。

是的,它可以,这取决于上下文。此外,就像任何全球性事件一样,它也可能是不确定的,无论是无意中还是无意中,都可能产生灾难性的影响。这就是为什么globals是一个令人讨厌的邪恶的东西。在不知情的情况下使用全局变量作为局部变量是导致意外、不可调试代码失败的首要原因。

这个$post 全局由设置WP_Query::the_post(), 但是它可以被任何自定义代码更改,所以永远不要依赖它,特别是在循环之外。

假设小部件代码在循环之后执行是否安全

NEVER EVER 假设任何事情。这是编码时最危险的事情。简单地假设某些东西会导致可怕的bug、安全漏洞,可能会泄露非常个人的信息,从而导致你入狱等等。以这样的方式对待你编写的所有代码,以便在某些东西失败时安全地处理特定的事件或行为,并且总是抱着这样的心态编写代码:你的代码会失败,它会被黑客攻击。

同样,小部件可以在循环之前或之后运行,甚至可以在循环内部运行,因此不要假设它会以某种方式运行。

如果这是一个真实的页面(在后端页面部分创建),那么您可以使用get_queried_object() 获取当前页面对象。它比$post 全球的你应该慢慢读一遍this answer by @gmazzapmy question here

编辑-更好的替代方案get_queried_object()

从你的评论到我的回答

我明白了$post 可以在我访问它之前进行修改。但这不是也适用于$wp_query (通过“自定义”或“辅助”查询进行修改)?如果是,我不应该测试吗is_main_query() 依赖之前get_queried_object()? 我假设主查询是基于请求的url的,对吗?如果is_main_query() 是假的,那么我能用什么呢?

非常正确,主查询对象存储在$wp_query 全局变量。使用$wp_query 作为局部变量,它会打断主查询对象,并将其设置为使用全局对象的任何对象。而且query_posts 将主查询对象设置为当前自定义查询,这也会打断它。

确实,查询对象依赖于主查询对象的完整性,这确实会get_queried_object() 脆弱的一般来说get_queried_object() 仍然比$post 因为任何自定义查询都使用the_post()setup_postdata( $post ) 设置$post 全局到当前循环中的当前帖子。忘记用重置自定义查询wp_reset_postdata() 会给你留下错误的贴子对象$post.

至于get_queried_object(), 如果有人仍在使用query_posts, 如果他们想承担后果,这取决于他们。

我喜欢这样的想法,即你真的想要并且正在寻找更可靠的替代方案$post AND get_queried_object(), 从你的评论中可以很明显地看出这一点。你的评论实际上引发了我不久前正在做的事情,我完全忘记了,我想最重要的是,包括我在内,都忘记了一个非常重要的全局变量,除了内部的过滤器和操作之外,它永远不会被修改WP_Query 它本身就是$GLOBALS[\'wp_the_query\']. $GLOBALS[\'wp_the_query\'] 保存实际的主查询对象。$GLOBALS[\'wp_query\']AKA)$wp_query)只是$GLOBALS[\'wp_the_query\'].

让我们快速查看设置位置。在当前版本(Wordpress 4.4.2)中,您可以在lines 291 - 304 in `wp-settings.php

/**
 * WordPress Query object
 * @global WP_Query $wp_the_query
 * @since 2.0.0
 */
$GLOBALS[\'wp_the_query\'] = new WP_Query();
/**
 * Holds the reference to @see $wp_the_query
 * Use this global for WordPress queries
 * @global WP_Query $wp_query
 * @since 1.5.0
 */
$GLOBALS[\'wp_query\'] = $GLOBALS[\'wp_the_query\'];
我不知道WordPress早在什么时候,但这很可能是为了适应query_posts, 因为如果你看wp_reset_query() 之后应该使用query_posts, 它会重置$wp_query 返回到$GLOBALS[\'wp_the_query\'].

这意味着,即使我们破坏了主查询对象($wp_query),我们还有一份完全可用的副本$GLOBALS[\'wp_the_query\'].

考虑到所有这些,如果您真的需要一种99.99%可靠的方法来获取当前查询的对象,那么$GLOBALS[\'wp_the_query\']->get_queried_object(). 这将是最终可靠的方法,无需自己重新运行主查询。

在我结束发言之前,你还谈到了is_main_query() 检查(,本质上检查当前WP_Query 实例等于$GLOBALS[\'wp_the_query\'])。在这种情况下,它不会真正工作,因为它只返回一个布尔值。

结论-要可靠地在单个贴子页面上获取当前查询的对象,或者在任何单一页面和归档页面上获取当前查询的对象,请使用$GLOBALS[\'wp_the_query\'] 全球的

$GLOBALS[\'wp_the_query\']->get_queried_object()