【问题标题】:Wordpress post object is modified after get_header() is called in the theme在主题中调用 get_header() 后修改 Wordpress 帖子对象
【发布时间】:2018-04-03 14:07:34
【问题描述】:

我的主题中有一个自定义页面,我在其中从不同的数据库表创建帖子,然后我想在 wordpress 中进行显示,就好像它是普通帖子一样。它似乎大部分时间都有效,但随机似乎在我调用 get_header() 后修改了帖子,我不明白为什么。

我已经在 apache 中设置了一个 mod 重写规则来命中一个 php 文件,在这里我得到了我需要的数据并构建了 php 对象。我使用此函数填充 wordpress 帖子对象。

function BuildSimplePost($title, $body)
{
    require_once( SITEROOT . '/wp-load.php' );
    @$post = new WP_Post();
    @$post->ID = -1; 
    $post->post_parent  = 0;
    $post->post_title = $title;
    $post->post_name = "simple-response";
    $post->post_excerpt = substr($body, 0, 100);
    $post->comment_status = "closed";
    $post->ping_status = "closed";
    $post->post_type = "page";
    $post->post_content = $body;
    return $post;
}

文章排序后,我会将这篇文章推送到 wordpress 查询对象中,让主题完成剩下的工作。

$posts = array($post);
$wp_query->posts = $posts;
$wp_query->post_count = count($posts);
$wp_query->found_posts = count($posts);
$wp_query->max_num_pages = 1;
$wp_query->post = $post;
$wp_query->is_404 = 0;
$wp_query->is_singular = 1;
$wp_query->is_single = 1;
$wp_query->page_id = $post->ID;

include get_template_directory()."/external-page.php";

external-page.php 内部没有什么奇怪的。它实际上是删除了一些 html 的 single.php 的副本。我遇到的问题是,当在此文件中调用 get_header(); 时,帖子会更改为其他内容。然后这会触发重定向,将用户带到网站上属于 wordpress 的不同页面。

有人知道为什么 get_header 方法会导致这样的重定向吗?

【问题讨论】:

  • 你看过wordpress生成的实际源代码吗?
  • @ArtisticPhoenix wordpress 有很多源代码。你能指定我需要看什么代码吗?
  • 不是真的,但你可能会看到 2 个<head> 标签或一些非常混乱的标签,或者像meta refresh,除非你看,否则谁知道。也许你在那里看到复活节兔子?在你真正知道之前,你不会知道你认为你知道什么。
  • 所以你绕过了 WP 用于处理自定义帖子类型的所有机制,转而使用你自己奇怪的法兰安装后门方法......为什么?
  • 您也可以尝试ob_start(); get_header(); $content = ob_get_clean();,它会执行该函数但在缓冲区中捕获输出,然后您将知道标头中是否有一些内容正在执行此操作或某些功能。这是一个你必须消除事物的过程。

标签: php wordpress


【解决方案1】:

很难确切地说出您的帖子发生了什么变化。在我看来,你有两个选择:

  1. 继续将您的内容放回帖子中。这不是 WordPress 解决此问题的方法,但它可能是更简单的方法。 @ArtisticPhoenix 上面的回答是正确的概念,但错误的具体代码。
  2. 创建自定义帖子类型,这是 WordPress 的方式。 @CBroe 提供了这一点,并且对您对他的问题的回答(恕我直言)应该是:“无论您的帖子类型有多复杂,您应该将其封装在 CPT 中,如果您使用 WordPress。”

放回您的内容

在某处保留您的帖子对象的副本,并在发生任何更改后立即将其放回。您可以创建一个新的全局:

global $mypost;
$mypost = BuildSimplePost(...);

如果您知道$title$body 参数,您可以在每次需要时再次调用您的函数。您还可以使用瞬态、update_option/get_option 调用或其他几种方式。

有几个过滤器可能是cuplrit:

  • the_post 操作应该更改 $post。这是它真正做的一件事。您可能希望像这样坐在钩子堆栈的顶部:add_filter('the_post', function() { global $post, $mypost; $post = $mypost; }, 10000);
  • 在设置wp 对象之前,有几个动作,你很可能会改变$post,因为在此之前它是免费游戏。您可能有插件或主题挂钩:parse_requestparse_querypre_get_postsposts_selection。您可以为每个过滤器尝试add_filter('parse_request', function() { global $post; $post = $mypost; }, 10000); 之类的东西。
  • 我看到一些插件开发人员在调用template_redirectget_headerloop_start 和@987654340 操作期间添加了更改$post 全局的内容(以及他们可能不应该更改的其他内容) @。哎呀,我自己做过几次。尽管我认为它们不太可疑,但您可以尝试使用这些过滤器进行相同的操作。

如果这不能恢复您的内容,您可以尝试一些非常肮脏的东西,例如在调用 the_post 之前强制它。这没有什么钩子,但如果你控制主题很容易。

WP 方式

我知道您认为您的帖子非常复杂,但我会根据多年来深入 WP 代码的经验为您提供这一点:打破 WP 帖子模型会让人心痛。如果您没有使用帖子并且没有按照预期的方式使用它们,那么您可能不应该使用 WP。还有其他框架可以提供用户身份验证、主题、数据库持久性、事件、REST 等功能,而无需 WP 的开销。

另一种方式

话虽如此,我过去使用过 WP,因为它是我无法控制的需求的一部分。当我的帖子变得太复杂时,我会像这样创建一个包装器对象:

class MyPostWrapper {
  private $_Post;
  private $_Meta = array();

  public function __construct($post) {
    $this->_Post = get_post($post);
    $this->_Meta = $this->_LoadMeta();
  }

  private function _LoadMeta() {
    // Load everything into $_Meta: other tables, options, post meta, etc.
  }

  public function __get($name) {
    if (array_key_exists($name, $this->_Meta))
      return $this->_Meta[$name];
  }

  // Use a similar implementation for __set and __isset.

}

无论您的帖子变得多么复杂,您都可以使用一个包装器非常轻松地管理其生命周期和所有跟踪。

那么您不必担心谁在吃您的帖子。如果是,他们可能应该是。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多