Añadir datos adicionales al objeto WP_Post

21 sept 2016, 12:58:14
Vistas: 13.9K
Votos: 7

Quiero añadir elementos adicionales a los datos devueltos como WP_Post. Para cada función/consulta que devuelva un objeto WP_Post, quiero que se incluyan mis datos adicionales.

Ejemplo del resultado devuelto:

WP_Post (object) => [
    // Datos por defecto devueltos por 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,

    // Datos adicionales que quiero añadir
    extra_data_1        => array,
    more_data_key       => string,
    another_added       => string
]

Por ejemplo, cuando se ejecuten las funciones get_post() o get_page_by_path(), devolverán el objeto WP_Post junto con mis datos adicionales.

He intentado encontrar el hook/filter apropiado pero no he tenido éxito.

Espero poder hacer algo como:

// Este es código conceptual
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;
});

Mi razonamiento es que estoy construyendo una API personalizada para WP que utiliza varias funciones principales que devuelven objetos WP_Post. Poder añadir mis datos adicionales en un solo lugar me evitaría duplicar código.

¡Espero que esto sea lo suficientemente claro. Cualquier ayuda sería genial!

7
Comentarios

¿Hay alguna razón por la que no quieras usar post_meta?

cjbj cjbj
21 sept 2016 13:13:03

@cjbj Tengo el post meta aplicado a los posts pero el objeto WP_Post no lo incluye por defecto. He actualizado mi pregunta para evitar confusiones. Mi razonamiento es que estoy construyendo una API personalizada para WP que usa una variedad de funciones principales que devuelven objetos WP_Post. Poder agregar mis datos adicionales en un solo lugar me evitaría duplicar código.

Levi Cole Levi Cole
21 sept 2016 13:21:53

Entiendo tu punto. Eliminaré mi respuesta. Acabo de revisar post.php y class-wp-post y no encontré ningún action hook o filter hook. Esas son malas noticias para la idea que intentas implementar aquí.

Ahmed Fouad Ahmed Fouad
21 sept 2016 13:23:29

Para evitar duplicar código, ¿por qué no escribes tus propias funciones wrapper que devuelvan valores tanto del objeto post como de sus metadatos? Parece un enfoque más simple.

Andy Macaulay-Brook Andy Macaulay-Brook
21 sept 2016 13:49:10

@AndyMacaulay-Brook Actualmente así es como lo estoy haciendo, pero me preguntaba si existía una mejor solución.

Levi Cole Levi Cole
21 sept 2016 13:50:57

Depende de cómo definas "mejor" :-) Desde mi punto de vista, una solución que te proporcione las funciones que necesitas sin alterar los internos de WP parece bastante buena. Ya existen funciones para obtener un campo del post y un campo de metadatos, así que envolverlas con media docena de líneas de código es rápido y fácil, no rompe nada más y también aprovechará cualquier caché que las funciones integradas ya implementen.

Andy Macaulay-Brook Andy Macaulay-Brook
21 sept 2016 13:54:42

En teoría, se podría usar el the_post hook para agregar propiedades adicionales. Sin embargo, si realmente deberías hacer esto es algo discutible.

Howdy_McGee Howdy_McGee
7 ene 2021 17:17:22
Mostrar los 2 comentarios restantes
Todas las respuestas a la pregunta 4
0
11

Si tus datos adicionales hacen referencia directamente a un meta de post, no tienes que hacer nada, porque WP_Post implementa los métodos »mágicos« __isset() y __get() que consultan directamente las claves de meta de post (excepto las siguientes cuatro claves: page_template, post_category, tags_input y ancestors). Aquí un ejemplo rápido que muestra el comportamiento:

<?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']

En cualquier otro caso, usa el filtro 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' );
            // y así sucesivamente …
        }

        return $posts;
    },
    10,
    2
);

Sin embargo, sugiero usar un enfoque orientado a objetos y crear tus propias interfaces de entidad que sigan tu dominio del problema. Las implementaciones luego envolverán instancias de WP_Post como dependencia. Por ejemplo, digamos que estás trabajando con libros:

<?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 );
    }
}

Tu lógica de negocio puede entonces basarse en la estructura de un libro mediante el tipo de sugerencia Book en cada dependencia. Para obtener una lista de libros podrías implementar primero una fábrica que envuelva un WP_Query o reciba argumentos de WP_Query y devuelva una lista de instancias de libros. No deberías usar el filtro posts_results en ese caso para reemplazar WP_Query::posts con una lista de instancias de Type\Book para no romper la consistencia de tipos en todo el núcleo de WP.

21 sept 2016 13:37:26
3

TLDR; No puedes y no deberías hacerlo.

Es imposible extender la clase WP_post con campos adicionales, porque ha sido definida como 'final'. Quizás podrías solucionarlo envolviendo la clase en otra clase (tutorial), pero aún así no es recomendable.

Toda clase de temas y plugins dependen de que los metadatos se almacenen como metadatos. Puede que funcione ahora, pero probablemente te arrepentirás en el futuro, cuando descubras que algún plugin que quieres usar no puede manejar la forma en que has almacenado tus metadatos.

21 sept 2016 13:36:47
Comentarios

Solo quiere agregar propiedades públicas a un objeto arbitrario. Esto es posible independientemente de la extensibilidad de la declaración de la clase. También está el filtro posts_result.

David David
21 sept 2016 13:43:16

@David Verifiqué eso en los comentarios de la pregunta, OP explícitamente quiere extender la clase wp_post, no usar add_post_meta.

cjbj cjbj
21 sept 2016 13:46:31

Por lo que veo, él/ella quiere extender objetos de post, no la declaración de la clase.

David David
21 sept 2016 13:53:23
0

Sé que esta es una publicación antigua pero pensé en compartir una solución funcional Esto se puede lograr haciendo:

$posts = get_posts( 
    array(
        "post_type" => $post_type->name,
        "numberposts" => -1 
    )
);
foreach($posts as &$post)
{
    $custom_fields = (array)$post;
    // añadir campo(s) extra así
    $custom_fields["posttype_link"] = get_permalink($post->ID);
    $post = (object)$custom_fields;
}
7 ene 2021 15:36:38
0

Utiliza el hook the_post: https://developer.wordpress.org/reference/hooks/the_post/

Estarás modificando el objeto global $post, por lo que no es necesario devolverlo como si fuera un filtro. Los 2 parámetros $post y $query se pasan por referencia.

26 ago 2021 00:02:54