wordpress-1

Si estamos creando un tema personalizado en WordPress, quizá queramos mostrar sólo unos posts determinados en una zona concreta. Por ejemplo, podemos necesitar mostrar sólo los posts que consideremos importantes en la portada, o quizá tengamos un apartado lateral donde sólo nos interesan mostrar los posts que hablan de nuestra empresa, etc.

Hay varias soluciones, unas que son más sencillas y otras que, aunque más complejas, tiene mayor flexibilidad. Para que sea más fácil de entender, vamos a centrarnos en cómo hacerlo para los posts generados en el index, aunque es fácil trasladar la solución para un sidebar o cualquier otra sección de la web.

1. Seleccionar posts por categorías

En primer lugar deberíamos añadir una categoría en la que incluiremos los posts que queremos mostrar en la portada. Una vez creada, podemos ver su slug en el listado y su ID en el enlace de edición de la categoría (es el valor del parámetro cat_ID de la url).

La función que Worpdress utiliza para seleccionar los posts para mostrar es query_posts. Como vemos en la referencia de wordpress.org, podemos utilizar varios parámetros para definir la selección. En este caso nos interesa uno de los que filtran por categoría. Existen más parámetros que nos permiten realizar filtrados más complejos, pero para este ejemplo utilizaremos el más sencillo:

category_name (string) – el parámetro indica el slug (ojo, no el nombre) de la categoría cuyos posts queremos obtener.

Por tanto, simplemente modificando la función en el archivo de nuestro tema (el index.php o el archivo que utilicemos como plantilla para la portada):

query_posts('category_name=destacados');

obtendremos solamente los posts que pertenezcan a esta categoría.

Aunque es una solución sencilla, la contra es que puede que estemos utilizando una categoría simplemente para filtrar posts, y no para categorizarlos, con lo que ello conlleva.

2. Seleccionar posts por tags

Si no queremos utilizar una categoría, podremos utilizar un tag o etiqueta para marcar los posts que queremos visualizar. La solución es idéntica a la anterior, simplemente la función quedaría:

query_posts('tag=destacado');

Esta es la opción más sencilla, pero de nuevo podemos ver la referencia de la función respecto a tags si necesitamos utilizar filtrados más complejos. Podemos incluso utilizar un filtrado por categoría y por etiqueta simultáneamente.

E igual que en el anterior caso, la solución es sencilla pero puede que estemos utilizando una etiqueta sólo para filtrar posts en un determinado lugar.

3. Marcar explícitamente los posts a través de un checkbox en el backend

La solución más compleja pero funcional y flexible pasa por añadir un checkbox en el panel de edición del post que sirva para establecer una meta_key de Worpdress en los posts que queramos incluír en la portada.

Crear un checkbox en el backend

El archivo del tema functions.php define la configuración de nuestro tema. Podemos incluír en él acciones definidas por WordPress. En este caso, necesitamos ejecutar una función a través de la acción add_meta_boxes, por lo que en nuestro functions.php añadiremos:

add_action('add_meta_boxes', 'add_checkbox_portada');

Con lo que le indicamos a WordPress que en el momento de añadir meta boxes, se acuerde de nuestra función add_checkbox_portada. ¿Y qué queremos que haga? Pues añadir una meta box:

function add_checkbox_portada() {
	add_meta_box('es_portada', 'En portada', 'print_checkbox_portada', 'post', 'side');
}

Puedes consultar la referencia de esta función para ver los parámetros, aunque básicamente son el id del div que aparecerá en el backend, el título del bloque que se mostrará, la función encargada de imprimir el HTML, el tipo de elementos en el que aparecerá, y el lugar en que se mostrará.

Con lo que el siguiente paso será definir la función print_checkbox_portada que tendrá que imprimir el HTML del checkbox. En resumen, todo el código para crear el checkbox:

WP_seleccionar_posts/anadir_checkbox.php

Perfecto, ya tenemos un checkbox en el backend, pero… por ahora no sirve para nada.

Checkbox portada

Asignar el meta_key

Volvemos a utilizar las actions de Worpress para decirle que queremos que haga algo más cuando guardemos nuestro post. De nuevo incluímos una acción en el functions.php, y una función que se ejecute en esa acción:

WP_seleccionar_posts/save_checkbox_portada.php

Simplemente comentar que el tag debe comenzar por “_” para que Worpress entienda que no debe mostrarlo en el listado de tags (ni en frontend ni en backend).

Filtrar posts por nuestro meta_key

Simplemente nos falta indicar a WordPress que sólo queremos obtener los posts que tengan ese meta_key, por lo que, como en los anteriores apartados, cambiamos la función query_posts:

query_posts('meta_key=_portada');

Pero puede que no queramos utilizarlo en nuestro loop principal, y además, si no tenemos ningún post marcado como “portada”, quizá queramos obtener los últimos, en vez de no poner ninguno. Para ello podemos utilizar las funciones get_posts o crea un nuevo objeto WP_query, para no interferir con el loop principal. Personalmente me es más cómoda la segunda opción, por lo que podríamos crear una nueva función:

WP_seleccionar_posts/get_posts_portada.php

que luego llamaríamos en nuestra plantilla, donde quisiéramos que apareciesen esos posts.:q

En resumen, podemos añadir en nuestro functions.php:

WP_seleccionar_posts/seleccionar_posts.php

33 respuestas a “Seleccionar qué posts mostrar en WordPress”

  1. Muy buen artículo, justo lo que necesitaba pero tengo una duda que me impide realizar ninguna de las tres opciones.
    Mi theme es el de TwentyTen de wordpress, modificado. En el index.php no encuentro donde poner lo de “query_posts(‘meta_key=_portada’);”
    ni en el archivo de loop tampoco, ¿sabrias decirme donde o como tengo que añadirlo? Muchas gracias,
    saludos

  2. Hola, Xavi.

    Eso de tener un “TwentyTen modificado” quizá no sea muy buena idea. Date cuenta que una actualización del tema podría borrar los cambios que hayas hecho. Lo más recomendable es un tema hijo, que herede del TwentyTen, y que puedas modificar. Te recomiendo echar un vistazo a http://codex.wordpress.org/Child_Themes

    Respondiendo a tu pregunta, tal y como dices el index.php del TwentyTen no define ninguna búsqueda específica, por lo que obtendrá la búsqueda por defecto, es decir, los últimos posts. Puedes modificarla con la función query_posts, antes de llamar al loop.

    En el caso concreto que me planteas, en el index.php de tu tema hijo (o directamente del TwentyTen, aunque como decía no es recomendable), puedes indicar, antes del get_template_part: query_posts(‘meta_key=_portada’).

    Un saludo.

  3. Hola, gracias por la respuesta.

    He conseguido hacerlo funcionar! de las 2 formas, usando una categoría y con el checkbox de “En Portada”. Personalmente prefiero usar el checkbox, lo veo mas claro y funcional, lo que pasa que me gustaría que cuando el post ha sido seleccionado para mostrarse en portada y guardado, si vuelvo a entrar a editar el post debería ver el checkbox marcado, porque sinó no recuerdo si lo está o no, quiero decir que wordpress lo marca pero el checkbox no guarda el estado de checked cuando vuelves al backend para editar de nuevo ese post y no sabes si lo marcaste o no y eso despista.
    ¿hay forma de arreglarlo? con ese ajuste quedaría fino fino…

    Este es el código completo que tengo ahora en functions.php (por si alguien más le interesa) con esto ya funciona pero sin dejar marcado visualmente el checkbox cuando vuelves a editar el post…

    // FEATURED

    add_action(‘add_meta_boxes’, ‘add_checkbox_featured’);

    function add_checkbox_featured() {
    add_meta_box(‘is_featured’, ‘Featured’, ‘print_checkbox_featured’, ‘post’, ‘side’);
    }

    function print_checkbox_featured() {
    global $post;
    $checked = get_post_meta($post->ID, ‘_featured’, true) ? ‘checked=”checked”‘ : ”;
    echo ‘Show at front page ‘;
    }

    add_action(‘save_post’, ‘save_checkbox_featured’);

    function save_checkbox_featured($post_id){
    if (defined(‘DOING_AUTOSAVE’) && DOING_AUTOSAVE) return $post_id;

    if ( !current_user_can( ‘edit_post’, $post_id ) )
    return $post_id;

    if ($_POST[‘is_featured’]){
    add_post_meta($post_id, ‘_featured’, ‘1’);
    }else{
    delete_post_meta($post_id, ‘_featured’);
    }
    }

    He cambiado la palabra “portada” por un “featured”, soy así de freaky… espero que nos importe!

    Gracias y saludos 😉

  4. Bueno y ahora que lo pienso, también debería poder desmarcarlo, por si algun dia quiero que deje de aparecer ese post en la home.
    Pero con el código que tengo ahora no se puede desmarcar…

  5. Bueno, lo siento por comentar antes de tiempo. Si que se puede desmarcar, checkeando y des-chekeando el checkbox. 🙂
    Ahora solo faltaría que guarde el estado del checkbox visualmente, para saber si esta seleccionado para aprecer en la home o no,

    Saludos!

  6. Hola, Xavi.

    Tal y como defines la función que imprime la checkbox :

    function print_checkbox_featured() {
    global $post;
    $checked = get_post_meta($post->ID, ‘_featured’, true) ? ‘checked=”checked”‘ : ”;
    echo ‘Show at front page ‘;
    }

    no va a funcionar. En primer lugar, y supongo que será porque estabas en proceso de debug, eso no dibuja un checkbox, sino la frase “Show at front page”. La tercera línea debería ser:
    echo ‘Mostrar en portada ‘;

    En segundo lugar, ojo con las comillas al determinar si el ítem debe estar marcado o no. Me refiero a que la segunda línea dentro de la función debería ser:
    $checked = get_post_meta($post->ID, ‘_featured’, true) ? ‘checked=”checked”‘ : ”;

    Básicamente lo que hago ahí es asignar a la variable $checked el valor checked=”checked” si el post tiene el tag _featured, y en caso contrario asignarle un string vacío: ” (dos comillas simples).

    Si este es el error, debería aparecer algo en el log de tu servidor cuando está mal.

  7. Hola Félix, gracias por la ayuda 🙂
    pero uso tu código y no me acaba de funcionar. Las comillas las tengo bien, no se porque no se publicó el trozo de código que imprime el checkbox.
    Pero como te digo el checkbox funciona y los post se muestran correctamente solo los que tocan, es decir que funciona el asunto, el único problema es que el checkbox no se queda marcado como te expliqué, los marcas y funciona el asunto pero luego si vuelves a editar el post no aparecen chequeados visualmente y si que lo estan…

    este es el código:

    add_action(‘add_meta_boxes’, ‘add_checkbox_featured’);

    function add_checkbox_featured() {
    add_meta_box(‘is_featured’, ‘Featured’, ‘print_checkbox_featured’, ‘post’, ‘side’);
    }

    function print_checkbox_featured() {
    global $post;
    $checked = get_post_meta($post->ID, ‘_featured’, true) ? ‘checked=”checked”‘ : ”;
    echo ‘Show at front page ‘;
    }

    add_action(‘save_post’, ‘save_checkbox_featured’);

    function save_checkbox_featured($post_id){
    // Si la llamada es un autosave, no queremos hacer nada
    if (defined(‘DOING_AUTOSAVE’) && DOING_AUTOSAVE) return $post_id;

    // Comprobamos los permisos del usuario
    if ( !current_user_can( ‘edit_post’, $post_id ) )
    return $post_id;

    if ($_POST[‘is_featured’]){
    // Si el checkbox está marcado, añadimos el meta key
    add_post_meta($post_id, ‘_featured’, ‘1’);
    }else{
    // Si no está marcado, borramos el meta key
    delete_post_meta($post_id, ‘_featured’);
    }
    }

  8. He separado las palabras porque no publica la segunda parte de echo

    function print_checkbox_featured() {
    global $post;
    $checked = get_post_meta($post->ID, ‘_featured’, true) ? ‘checked=”checked”‘ : ”;
    echo ‘Show at front page ‘;
    }

  9. label for=”checkbox_is_featured”>Show at front page <input id="checkbox_is_featured" name="is_featured" type="checkbox" value="1"

  10. y lo que abre y cierra label e input lo tengo bien… es que sinó no se posteaba el comentario,
    disculpas

  11. Vale, lo he conseguido, que bien!!
    faltaba esto: ‘.$checked.’
    es que copié el código de la primera parte de la explicación supongo…
    muy contento, mil gracias, super buen aporte.

    Saludos

  12. Ok, Xavi, efectivamente primero determino si el checkbox tiene que estar marcado, y guardo el ‘checked=”checked”‘ en la variable $checked.
    Después hay que pintar esa variable con el input.

    Me alegro que te haya resultado útil.

    Un saludo.

  13. Hola de nuevo,
    tengo otra duda. He creado tipos de post personalizado (custom post type) con una herramienta online, que va de maravilla por cierto
    se llaman “projects” y el singular “project”

    Pues ahora no consigo hacer que los post que se muestren en la home no sean “posts” sinó “projects”
    Sabrias decirme como?

    muchas gracias!
    Saludos

  14. Hola, Xavi.

    Siento no poder ayudarte, pero no conozco esa herramienta. Hay varias formas de hacer lo que me comentas, por lo que en este caso es difícil orientarte.

    Espero que lo resuelvas.

    Un saludo.

  15. primero qu e todo agradezco la atención a mi pregunta que tiene que ver con el tema que estan tratando por acá

    la cuesti´lon es que quisiera que en vez de post en mi index, aparecieran paginas, como hago ese cambio?

  16. Capo. Llevaba 5 horas dándole vueltas al tema. Lo rondaba, casi lo tenía, pero hasta que no he llegado a tu artículo no lo he comprendido…

    ¡Muchas gracias!

  17. Gracias por el artículo. Es estupendo.
    Tengo un problema. Estoy utilizando un meta key para seleccionar entradas de la portada. Funciona bien, pero cuando pulso anteriores me sale las mismas entradas, es decir no pagina.
    ¿Podéis ayudarme?

  18. Hola, Enrique.

    Te recomiendo echar un vistazo a la referencia: http://codex.wordpress.org/Class_Reference/WP_Query#Pagination_Parameters

    Básicamente, habría que comprobar el campo de paginación al crear el WP_Query. Quedaría algo como:

    $paged = get_query_var(‘paged’) ? get_query_var(‘paged’) : 1;
    $args = array(
    ‘meta_key’ => ‘_portada’,
    ‘paged’ => $paged
    );

    $portada = new WP_query($args);

    El código lo escribo de memoria y sin comprobar el funcionamiento, puedes utilizar la referencia para comprobar los errores (si hay).

    Espero que te sirva.

  19. Buenas…he seguido el manual y he ido pegando el código que Félix ha indicado y va todo bien, pero cuando pego el código de la seccion get_posts_portada

    have_posts()) {
    $portada = new WP_query();
    }

    while ( $portada->have_posts() ) : $portada->the_post();
    ?>

    <a href="” title=””>

    <a href="” title=””>Leer entrada

    no me funciona la página….hay algún error en este código?
    Gracias

  20. Bueno….ha salido un churro de código y no se ve bien…¿cómo puedo mandar el archivo functions.php para que lo reviséis.?

  21. ya he visto el error de sintexis:
    if (defined(‘DOING_AUTOSAVE’) && DOING_AUTOSAVE) return $post_id; esta es la correcta

    Por otro lado decir que ahora no da error pero el check box no hace nada….da igual que esté marcada o no….todos los posts se publican en la portada.
    Uso el Theme Rapido

  22. bueno ya he conseguido que funcione pero hay un problema……no pagina!!, quiero decir que siempre salen los mismos mensajes . En la paginación me indica que tengo 5 páginas pero en todas me salen siempre los mismos post. Ideas?

  23. Gracias por la respuesta y por el código que va de cine. Eso va perfecto para un blog nuevo ya que cada vez que creas una entrada decides, marcando el checkbox, si quieres que aparezca en la portada o no…. pero el problema lo tengo en mi blog wordpress al cual he aplicado tu código ya que tengo mas de 1200 entradas y todas ellas no tienen el checkbox marcado ni el meta_key=”_portada” al ser anteriores a la inclusión del codigo. Ahora he de ir editando las entradas una a una para marcar el checkbox ya que quiero que todas las entradas antigüas salgan en la portada paginadas. Es un trabajo de chinos. Se te ocurre alguna forma de añadir el meta_key=”_portada”a todas las entradas de una vez sin tener que ir una a una marcando la casilla?. Gracias

  24. Hola, Mike, y gracias por compartir.

    Quizá en tu caso lo mejor sea invertir la funcionalidad, es decir, que el check no sea para indicar que se quiere el post en portada, sino para indicar que no se quiere en portada.
    Así, por defecto los posts aparecerían en portada, y sólo los que marcases no aparecerían.

    Para esto, deberías cambiar los textos del checkbox, y en vez de “Mostrar en portada” debería decir “No mostrar en portada”, y quizá sería bueno cambiar el meta, en vez de “_portada”, que fuese “_noportada” o similar.

    Por último, la función get_posts_portada() debería cambiar la creación de la WP_Query, de forma que seleccione los posts que no tengan ese meta:

    $portada = new WP_Query( array( ‘meta_key’ => ‘_noportada’, ‘meta_value’ => ‘1’, ‘meta_compare’ => ‘NOT EXISTS’ ) );

    Ojo que NOT EXISTS sólo existe a partir de la versión 3.5 de WordPress.

    Tiene la referencia aquí: http://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_Parameters

    Si de todas formas quieres mantener la funcionalidad original (marcar el check para que sí aparezcan en portada), tendrías que crear un script que para cada post de la tabla wp_posts (suponiendo wp_ tu prefijo de tablas), cree una entrada en wp_posts_meta, si aún no existe. Por ejemplo, para un post con id 123, sería:

    INSERT INTO wp_posts_meta(post_id, meta_key, meta_value) VALUES
    (123, ‘_portada’, 1);

    Espero que te sirva.

  25. ok, esa opcion de revertir la funcion del checkbox la habia pensado pero no sabia como hacerlo. En el caso de que opte por esa solucion, la linea de codigo que puse en el index.php de mi theme la he de dejar tal cual o he de cambiar algo query_posts(‘meta_key=_portada’); ?.
    Y si optara por la segunda opcion….¿cómo se crea ese script y cómo se usa o activa?. gracias

  26. Hola, Mike.

    Como decía en el comentario anterior, los argumentos para la query quedarían:
    query_posts(array( ‘meta_key’ => ‘_noportada’, ‘meta_value’ => ’1′, ‘meta_compare’ => ‘NOT EXISTS’ ) );

    Respecto a la creación del script, podría ser atacando directamente la base de datos o incluso mediante funciones WordPress, pero entiendo que la formulación del mismo escapa del alcance de este post.

    Un saludo.

  27. Buenas, ya he conseguido la solución para meter el meta_key a todos los artículos a la vez usando tu código:
    INSERT INTO wp_postsmeta(post_id, meta_key, meta_value) VALUES (123, ‘_portada’, 1); que fue la clave….

    Modificado por un usuario de forosdelweb.com llamado quimfv:
    INSERT INTO wp_postmeta(post_id, meta_key, meta_value) SELECT ID, ‘_portada’, 1 FROM wp_posts;

    Gracias a los dos por vuestra ayuda, ya tengo los 1200 articulos con el checkbox “mostrar en portada” marcado y con todos los artículos en portada paginados, que por cierto he conseguido paginar con el siguiente código (por si le interesa a alguien) metido en el index.php del theme.

    $paged = (get_query_var(‘paged’)) ? get_query_var(‘paged’) : 1;
    query_posts(‘meta_key=_portada&paged=’ . $paged);

Comentarios cerrados.