Добавление дополнительных данных к объекту WP_Post в WordPress

21 сент. 2016 г., 12:58:14
Просмотры: 13.9K
Голосов: 7

Я хочу добавить дополнительные элементы к данным, возвращаемым как WP_Post. Чтобы для каждой функции/запроса, возвращающего объект WP_Post, мои дополнительные данные добавлялись автоматически.

Пример возвращаемого результата:

WP_Post (object) => [
    // Стандартные данные, возвращаемые WP_Post
    ID                  => int,
    post_author         => string,
    post_name           => string,
    post_type           => string,
    post_title          => string,
    post_date           => string,
    post_date_gmt       => string,
    post_content        => string,
    post_excerpt        => string,
    post_status         => string,
    comment_status      => string,
    ping_status         => string,
    post_password       => string,
    post_parent         => int,
    post_modified       => string,
    post_modified_gmt   => string,
    comment_count       => string,
    menu_order          => string,

    // Дополнительные данные, которые я хочу добавить
    extra_data_1        => array,
    more_data_key       => string,
    another_added       => string
]

Например, когда функции get_post() или get_page_by_path() выполняются, они должны возвращать объект WP_Post вместе с моими дополнительными данными.

Я пытался найти подходящий хук/фильтр, но это не увенчалось успехом.

Я надеюсь, что смогу сделать что-то вроде:

// Это концептуальный код
add_action('pre_wp_post_return', function($data) {
    $data->extra_data_1     = get_post_meta($data->ID, 'extra_data');
    $data->more_data_key    = get_post_meta($data->ID, 'more_data', true);
    $data->another_added    = get_post_meta($data->ID, 'another_data', true);

    return $data;
});

Моя логика в том, что я создаю кастомный API для WordPress, который использует различные основные функции, возвращающие объекты WP_Post. Возможность добавить дополнительные данные в одном месте позволит избежать дублирования кода.

Надеюсь, мое объяснение достаточно понятно. Любая помощь будет очень полезна!

7
Комментарии

Есть ли причина, по которой вы не хотите использовать post_meta?

cjbj cjbj
21 сент. 2016 г. 13:13:03

@cjbj У меня уже применяется post meta для записей, но объект WP_Post по умолчанию не включает эти данные. Я обновил свой вопрос, чтобы избежать путаницы. Моя идея в том, что я создаю кастомный API для WP, который использует множество различных базовых функций, возвращающих объекты WP_Post. Возможность добавлять дополнительные данные в одном месте позволит избежать дублирования кода.

Levi Cole Levi Cole
21 сент. 2016 г. 13:21:53

Понял вашу точку зрения. Удалю свой ответ. Только что просмотрел post.php и class-wp-post и не нашел ни одного хука действий или фильтров. Это плохая новость для идеи, которую вы пытаетесь реализовать.

Ahmed Fouad Ahmed Fouad
21 сент. 2016 г. 13:23:29

Чтобы избежать дублирования кода, почему бы не написать свои собственные функции-обёртки, которые возвращают значения как из объекта поста, так и из его метаданных? Это кажется более простым подходом.

Andy Macaulay-Brook Andy Macaulay-Brook
21 сент. 2016 г. 13:49:10

@AndyMacaulay-Brook В данный момент я делаю именно так, но мне было интересно, существует ли лучшее решение.

Levi Cole Levi Cole
21 сент. 2016 г. 13:50:57

Зависит от того, что вы понимаете под "лучшим" :-) На мой взгляд, решение, которое предоставляет вам необходимые функции без вмешательства во внутренности WP, кажется довольно хорошим. Уже существуют функции для получения поля поста и метаполя поста, поэтому обернуть их парой строк кода - быстро и просто, ничего не ломает и также использует любое кэширование, которое уже реализовано во встроенных функциях.

Andy Macaulay-Brook Andy Macaulay-Brook
21 сент. 2016 г. 13:54:42

Теоретически можно использовать the_post хук для добавления дополнительных свойств. Однако вопрос, стоит ли так делать, остается спорным.

Howdy_McGee Howdy_McGee
7 янв. 2021 г. 17:17:22
Показать остальные 2 комментариев
Все ответы на вопрос 4
0
11

Если ваши дополнительные данные напрямую ссылаются на метаданные записи, вам не нужно ничего делать, потому что WP_Post реализует "волшебные" методы __isset() и __get(), которые напрямую запрашивают ключи метаданных записи (за исключением следующих четырёх ключей: page_template, post_category, tags_input и ancestors). Вот краткий пример, демонстрирующий это поведение:

<?php
$post_id = 42;
$meta_key = 'extra_data_1';
add_post_meta( $post_id, $meta_key, [ 'some', 'value' ], TRUE );
$post = get_post( $post_id );
var_dump( $post->{$meta_key} ); // (array) ['some', 'value']

В любом другом случае используйте фильтр posts_results:

<?php
add_filter(
    'posts_results',
    function( array $posts, WP_Query $query ) {
        foreach ( $posts as $post ) {
            $post->extra_data_1 = get_post_meta( $post->ID, 'extra_data' );
            // и так далее …
        }

        return $posts;
    },
    10,
    2
);

Однако я бы предложил использовать объектно-ориентированный подход и создать собственные интерфейсы сущностей, которые соответствуют вашей предметной области. Реализации затем будут оборачивать экземпляры WP_Post в качестве зависимости. Например, предположим, что вы работаете с книгами:

<?php

namespace Wpse240042\Type;

use WP_Post;

interface Book {

    /**
     * @return string
     */
    public function title();

    /**
     * @return string
     */
    public function publisher();

    /**
     * @return int
     */
    public function year();
}

class WpPostBook implements Book {

    /**
     * @var WP_Post
     */
    private $post;

    /**
     * @param WP_Post $post
     */
    public function __construct( WP_Post $post ) {

        $this->post = $post;
    }

    /**
     * @return string
     */
    public function title() {

        return $this->post->post_title;
    }

    /**
     * @return string
     */
    public function publisher() {

        return get_post_meta( $this->post->ID, '_book_publisher', TRUE );
    }

    /**
     * @return int
     */
    public function year() {

        return get_post_meta( $this->post->ID, '_book_publisher', TRUE );
    }
}

Ваша бизнес-логика может затем полагаться на структуру книги, указывая тип Book в каждой зависимости. Для получения списка книг вы можете реализовать фабрику на первом этапе, которая обернет WP_Query или получит аргументы WP_Query и вернет список экземпляров книг. В этом случае не следует использовать фильтр posts_results для замены WP_Query::posts списком экземпляров Type\Book, чтобы не нарушить согласованность типов в ядре WordPress.

21 сент. 2016 г. 13:37:26
3

TLDR; Вы не можете и не должны этого делать.

Это невозможно расширить класс WP_post дополнительными полями, потому что он объявлен как 'final'. Возможно, вы могли бы обойти это, обернув класс в другой класс (руководство), но это всё равно не рекомендуется.

Все виды тем и плагинов полагаются на то, что метаданные хранятся как метаданные. Может быть, сейчас у вас получится заставить это работать, но, скорее всего, вы пожалеете об этом в будущем, когда обнаружите, что какой-то плагин, который вы хотите использовать, не может обработать способ хранения ваших метаданных.

21 сент. 2016 г. 13:36:47
Комментарии

Он просто хочет добавить публичные свойства к произвольному объекту. Это возможно независимо от расширяемости объявления класса. Также есть фильтр posts_result.

David David
21 сент. 2016 г. 13:43:16

@David Я проверил в комментариях к вопросу, OP явно хочет расширить класс wp_post, а не использовать add_post_meta.

cjbj cjbj
21 сент. 2016 г. 13:46:31

Насколько я понимаю, он/она хочет расширить именно объекты постов, а не объявление класса.

David David
21 сент. 2016 г. 13:53:23
0

Я знаю, что это старый пост, но решил поделиться рабочим решением. Это можно реализовать следующим образом:

$posts = get_posts( 
    array(
        "post_type" => $post_type->name,
        "numberposts" => -1 
    )
);
foreach($posts as &$post)
{
    $custom_fields = (array)$post;
    // добавляем дополнительные поля, например так
    $custom_fields["posttype_link"] = get_permalink($post->ID);
    $post = (object)$custom_fields;
}
7 янв. 2021 г. 15:36:38
0

Используйте хук the_post: https://developer.wordpress.org/reference/hooks/the_post/

Вы будете изменять глобальный объект $post, поэтому не нужно возвращать его, как в случае с фильтром. Два параметра $post и $query передаются по ссылке.

26 авг. 2021 г. 00:02:54