obtener metaboxes registrados por tipo de publicación o ID de publicación

4

Estoy buscando un método para obtener los metaboxes registrados para un tipo de publicación específico (o ID de publicación) cuando estoy en un tipo de publicación independiente y no relacionada. Estoy trabajando para hacer un tipo de publicación de "edición" personalizada para una necesidad específica del cliente y quiero la capacidad de cargar los metaboxes sin tener que registrarlos en ese tipo "editable".

Clarificación:

Lo que estoy tratando de lograr es la visualización real de los metaboxes de otro tipo de publicación. Por lo tanto, si mi tipo de publicación de "eventos" tiene un metabox con fecha, hora y ubicación, me gustaría mostrar esos mismos cuadros en un tipo de publicación independiente sin volver a registrar el metabox.

    
pregunta Norcross 18.06.2015 - 19:33

4 respuestas

3

Suposiciones erróneas

Las respuestas de

@Rarst o @ Dan-Cameron pueden funcionar, pero supongamos que cuando está viendo una página de edición de tipo de publicación, los metaboxes para el otro tipo de publicación son todos registrado.

Hay diferentes casos en los que eso no sucederá:

  • Si los metaboxes se registran con "add_meta_boxes_{$post_type}" gancho, en lugar del más común, "add_meta_boxes" genérico no estarán disponibles en la página de administración para el tipo de publicación ladrón
  • Incluso el enlace del mensaje genérico "add_meta_boxes" pasa a enlazar devoluciones de llamada al tipo de mensaje actual y al mensaje actual objeto como argumentos. Esto significa que el registro de devoluciones de llamada puede utilizar esos argumentos en algunas condiciones if , por lo que es posible que estemos en la misma situación del punto anterior

En resumen, a menos que tenga control sobre cómo se registran los metaboxes para algún tipo de publicación A , no puede estar seguro de que puedan en la página de edición de publicación para algún tipo de publicación B .

En caso de que tengas ese control, entonces @Rarst answer hará el truco.

En caso de que no tengas ese control, la única manera sería un poco difícil.

OMI, su única oportunidad, en ese caso, es enviar una solicitud HTTP (AJAX o vía WP HTTP API) a la página de edición posterior del CPT del que desea robar las cajas. Tiene que agregar alguna variable de solicitud que hará que la página devuelva la matriz de cuadros (probablemente serializada o incluida en JSON).

Después de eso, puedes combinar las casillas devueltas con las casillas para la publicación actual, y listo.

El punto es que dicho código

  • es lento (porque la solicitud adicional)
  • no es trivial

Por lo tanto, si tiene control sobre cuáles son todos los cuadros registrados para publicar un determinado tipo de publicación, es mucho más simple y rápido, simplemente registre esas cajas nuevamente para el tipo de publicación ladrón .

Si no puede estar seguro de cuáles son todas las casillas para ese tipo de publicación, entonces la solicitud HTTP adicional es su única oportunidad.

Publicaré aquí una clase, que implementa ese flujo de trabajo ( aquí como Gist para una mejor legibilidad):

class MetaboxStealer
{
    private static $stealing;

    private $post_type;
    private $boxes = [];

    /**
     * When the request contain special variable, this function will make it
     * return a serialized version of $wp_meta_boxes array and die.
     */
    public static function init()
    {
        add_filter('post_updated_messages', function ($messages) {
            if (MetaboxStealer::stealing()) {
                ob_start();
                return [];
            }
            return $messages;
        });

        add_action('do_meta_boxes', function () {
            if (MetaboxStealer::stealing()) {
                ob_end_clean();
                global $wp_meta_boxes;
                echo serialize($wp_meta_boxes);
                die();
            }
        });
    }

    /**
     * Checks that the request contain a special variable that will make request
     * return a serialized version of $wp_meta_boxes array and die.
     *
     * @return bool
     */
    public static function stealing()
    {
        if (is_null(self::$stealing)) {
            $screen = function_exists('get_current_screen') ? get_current_screen() : null;
            $stealing = filter_input(INPUT_GET, 'stealing-boxes', FILTER_SANITIZE_STRING);
            self::$stealing =
                $screen instanceof \WP_Screen
                && $stealing
                && wp_verify_nonce($stealing, $screen->post_type);
        }
        return self::$stealing;
    }

    /**
     * @param string $post_type Current post type
     */
    public function __construct($post_type)
    {
        $this->post_type = $post_type;
    }

    /**
     * Send a HTTP request to post edit page of a given CPT setting a special
     * variable that will make that page return serialized $wp_meta_boxes array.
     * After that, so obtained boxes are merged with the boxes for current post type.
     *
     * @param string $cpt CPT to steal metaboxes from
     */
    public function steal($cpt)
    {
        $vars = [
            'post_type'      => $cpt,
            'stealing-boxes' => wp_create_nonce($cpt),
        ];
        $url = add_query_arg($vars, admin_url('/post-new.php'));
        $cookies = [];
        foreach ($_COOKIE as $name => $value) {
            if ('PHPSESSID' !== strtoupper($name)) {
                $cookies[] = new \WP_Http_Cookie([
                    'name'  => $name,
                    'value' => $value,
                ]);
            }
        }
        $response = wp_remote_get($url, ['cookies' => $cookies]);
        if (! is_wp_error($response)) {
            $body = wp_remote_retrieve_body($response);
            if (is_serialized($body)) {
                $boxes = unserialize($body);
                $this->boxes = isset($boxes[$cpt]) ? $boxes[$cpt] : [];
                empty($this->boxes) or $this->merge();
            }
        }
    }

    /**
     * Merge metaboxes for current post type with boxes obtained with 
     * a HTTP request to another CPT post edit page.
     */
    private function merge()
    {
        global $wp_meta_boxes;
        isset($wp_meta_boxes[$this->post_type]) or $wp_meta_boxes[$this->post_type] = [];
        foreach ($this->boxes as $context => $priorities) {
            foreach ($priorities as $priority => $boxes) {
                if (! isset($wp_meta_boxes[$this->post_type][$context])) {
                    $wp_meta_boxes[$this->post_type][$context] = [];
                }
                if (! isset($wp_meta_boxes[$this->post_type][$context][$priority])) {
                    $wp_meta_boxes[$this->post_type][$context][$priority] = [];
                }
                $wp_meta_boxes[$this->post_type][$context][$priority] = array_merge(
                    $wp_meta_boxes[$this->post_type][$context][$priority],
                    $boxes
                );
            }
        }
    }
}

Notas:

  • el método merge() se deriva altamente de Rarst answer
  • He utilizado la API HTTP de WP para enviar solicitudes adicionales para mantener todo en un solo lugar, pero una implementación AJAX sería mejor

Cómo usar

Bastante simple.

// init the class
add_action('admin_init', ['MetaboxStealer', 'init']);

// use the class to merge boxes for current CPT with boxes for another CPT
add_action('edit_form_after_editor', function ($post) {
    $stealer_cpt = 'stealer-cpt';
    $steal_from = 'events';
    if ($post->post_type === $stealer_cpt) {
        $stealer = new MetaboxStealer($post->post_type);
        $stealer->steal($steal_from);
        // note that you can steal from different CPTs
        // $stealer->steal($another_steal_from);
    }
});

El problema de ahorro

No importa cómo logre mostrar cuadros de un CPT en la página de edición posterior de otro CPT, es posible que la rutina de guardado compruebe el tipo de publicación antes de guardar el metadatos posterior.

En ese caso, los metaboxes del otro CPT, incluso si se muestran, no se guardarán y probablemente necesitará escribir otra rutina de guardado, si no tiene acceso en el original uno.

    
respondido por el gmazzap 19.06.2015 - 03:17
0

Crear un metabox adicional (casilla de verificación, estoy pensando) que ofrece la opción de crear un tipo de publicación "editar" a partir de esta publicación. Por el bien de este código, lo llamaremos 'transferencia_datos'.

Cambie el valor de $ post_type al tipo de publicación de la publicación original de la que recuperaremos los datos.

He agregado la funcionalidad para guardar la ID de la publicación original en un valor meta para el tipo de publicación 'editar'. Para guardar los metaboxes de 'edición' en la publicación original, deberías poder usar ese valor y esta función (con update_post_meta() en su lugar, por supuesto) para aplicar ingeniería inversa a otra función para enlazar.

function create_edit_page($data){
    $post_type = 'the_post_type_to_work_with';
    // Grab this post's ID
    $orig_id = $_POST['post_ID'];
    // Grab the value of the 'transfer_data' field
    $is_transfer_val = get_post_meta( $orig_id, 'transfer_data');
    if($data['post_type'] == $post_type && $is_transfer_val == TRUE && 
            isset($data['guid']) && strlen($data['guid'])>0 ){

        $post_id = wp_insert_post(
          array(
            'comment_status'  => 'closed',
            'ping_status'   => 'closed',
            'post_author'   => $data['post_author'],
            'post_name'   => $slug,
                'post_content'  =>  $data['post_content'],
            'post_title'    => $data['post_title'],
            'post_status'   => 'publish',
                // The custom post type 'editing'
            'post_type'   => 'editing'
          )
        );

        // create the meta fields
        $all_meta_boxes = get_post_meta( $orig_id );
        if(isset( $all_meta_boxes ) && is_array( $all_meta_boxes )){
            foreach($all_meta_boxes as $metakey => $metavalue){
                add_post_meta($post_id, $metakey, $metavalue);
            }
        }
        // add a meta field that points to original post (for editing purposes, etc.)
        add_post_meta($post_id, 'original_post_id', $orig_id);

        // If you want to redirect the user after saving use the filter below
        // add_filter('redirect_post_location', 'my_post_redirect_filter', '99');

        return $data;
    }
    return $data;
}
add_action( 'wp_insert_post', 'create_edit_page', '99' );
// Or, call BEFORE updating the database with below action
//add_action( 'wp_insert_post_data', 'create_edit_page', '99' );
    
respondido por el Mickey 18.06.2015 - 21:12
0

No haré ninguna afirmación de que esto sea confiable, pero se trata de lo lejos que llegué:

add_action( 'add_meta_boxes', function () {
    global $wp_meta_boxes;

    foreach ( $wp_meta_boxes['steal-from'] as $context => $priorities ) {

        foreach ( $priorities as $priority => $boxes ) {

            if ( ! isset( $wp_meta_boxes['metabox-stealer'][ $context ] ) ) {
                $wp_meta_boxes['metabox-stealer'][ $context ] = [ ];
            }

            if ( ! isset( $wp_meta_boxes['metabox-stealer'][ $context ][ $priority ] ) ) {
                $wp_meta_boxes['metabox-stealer'][ $context ][ $priority ] = [ ];
            }

            $wp_meta_boxes['metabox-stealer'][ $context ][ $priority ] = array_merge(
                $wp_meta_boxes['metabox-stealer'][ $context ][ $priority ],
                $boxes
            );
        }
    }
}, 11 );

Donde steal-from y metabox-stealer son tipos de publicación para operar.

    
respondido por el Rarst 18.06.2015 - 22:59
0

Esto insertará los metaboxes manualmente en lugares lo suficientemente cercanos como para que vayan los meta boxes. El problema es que se insertarán antes que los mboxes estándar para ese tipo de publicación.

Estoy seguro de que podrías piratearlo más si fuera necesario, pero al menos obtendrás lo básico que necesitas.

function monkey_advanced_meta_boxes() {
    $post = get_post( 2457 );
    do_meta_boxes( 'post_type_to_take_mboxes_from', 'normal', $post );
    do_meta_boxes( 'post_type_to_take_mboxes_from', 'advanced', $post );
}
add_action( 'edit_form_advanced', 'monkey_advanced_meta_boxes' );

function monkey_sidebar_meta_boxes() {
    $post = get_post( 2457 );
    do_meta_boxes( 'post_type_to_take_mboxes_from', 'side', $post );
}
add_action( 'submitpost_box', 'monkey_sidebar_meta_boxes' );

Por supuesto, deberás revisar el ID de pantalla > y asegurarte de que estás agregando los mboxes a la pantalla correcta. Esto tampoco registrará las metacuadros del mismo modo, por lo que no funcionarán las opciones como eliminarlas de la pantalla.

ACTUALIZACIÓN: Después de pensar un poco en esto, parece que esto no es tan fácil como lo he descrito anteriormente. Supongo que querrá que las cajas de metadatos guarden la metáfora que es posible que tenga que hacer manualmente si la acción de guardar original está verificando el tipo_post (que debería) y luego está el problema de que la caja de metadatos no es compatible.

Me imagino que debe haber una forma de evitar esto, como mencioné originalmente al modificar la variable global.

respondido por el Dan Cameron 19.06.2015 - 00:20

Lea otras preguntas en las etiquetas