Añadir datos adicionales al objeto WP_Post
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!

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.

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.

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 Verifiqué eso en los comentarios de la pregunta, OP explícitamente quiere extender la clase wp_post
, no usar add_post_meta
.

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

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.
