Tabla SEO de tu web con WordPress

Este snippet crea el shortcode [seoweb], que genera una tabla con los datos SEO (keyword, title y meta description) de diferentes tipos de contenido de WordPress —entradas, páginas, categorías, productos, categorías de producto o tipos personalizados— obteniendo automáticamente la información desde Rank Math o Yoast.

Permite elegir qué mostrar mediante parámetros como post=si, page=si, category=si, cpt="nombre_cpt" o tax="nombre_taxonomia".

// Shortcode: [seoweb post=si page=si category=si product=no product_cat=no cpt="proyectos,oferta_trabajo" tax="categorias"]
add_shortcode('seoweb', function ($atts = []) {

    // ---------- Helpers ----------
    $bool = function ($v, $default = false) {
        if ($v === null) return $default;
        $v = strtolower(trim((string)$v));
        return in_array($v, ['si','sí','1','true','on','yes'], true);
    };

    $csv = function ($v) {
        if (!$v) return [];
        if (is_array($v)) return array_values(array_filter(array_map('trim', $v)));
        return array_values(array_filter(array_map('trim', explode(',', $v))));
    };

    $esc = function ($str) {
        return esc_html(is_string($str) ? $str : (string)$str);
    };

    $get_path = function ($url) {
        $path = wp_parse_url($url, PHP_URL_PATH);
        if (!$path) $path = '/';
        if ($path[0] !== '/') $path = '/' . $path;
        return $path;
    };

    // Rank Math / Yoast fallback para POSTS
    $get_post_seo = function ($post_id) {
        // Rank Math
        $rm_title = get_post_meta($post_id, 'rank_math_title', true);
        $rm_desc  = get_post_meta($post_id, 'rank_math_description', true);
        $rm_kw    = get_post_meta($post_id, 'rank_math_focus_keyword', true);

        // Yoast (legacy keys incluidas)
        $yo_title = get_post_meta($post_id, '_yoast_wpseo_title', true);
        $yo_desc  = get_post_meta($post_id, '_yoast_wpseo_metadesc', true);
        $yo_kw    = get_post_meta($post_id, 'yoast_wpseo_focuskw', true);

        return [
            'kw'    => $rm_kw ?: $yo_kw,
            'title' => $rm_title ?: $yo_title,
            'desc'  => $rm_desc ?: $yo_desc,
        ];
    };

    // Rank Math / Yoast fallback para TÉRMINOS
    $get_term_seo = function ($term_id) {
        // Rank Math
        $rm_title = get_term_meta($term_id, 'rank_math_title', true);
        $rm_desc  = get_term_meta($term_id, 'rank_math_description', true);
        $rm_kw    = get_term_meta($term_id, 'rank_math_focus_keyword', true);

        // Yoast en términos
        $yo_title = get_term_meta($term_id, 'wpseo_title', true);
        $yo_desc  = get_term_meta($term_id, 'wpseo_desc', true);
        // Nota: Yoast no guarda siempre focus kw en términos de forma estándar

        return [
            'kw'    => $rm_kw,
            'title' => $rm_title ?: $yo_title,
            'desc'  => $rm_desc ?: $yo_desc,
        ];
    };

    // ---------- Atributos ----------
    $atts = shortcode_atts([
        // básicos WP
        'post'           => 'no',
        'page'           => 'no',
        'category'       => 'no',
        // WooCommerce
        'product'        => 'no',
        'product_cat'    => 'no',
        // personalizados
        'cpt'            => '',      // ej: "proyectos,oferta_trabajo"
        'tax'            => '',      // ej: "categorias,brand"
        // opciones de consulta posts
        'limit'          => '-1',
        'orderby'        => 'date',
        'order'          => 'DESC',
        // opciones de términos
        'hide_empty_terms' => 'no',
    ], $atts, 'seoweb');

    $show_post        = $bool($atts['post']);
    $show_page        = $bool($atts['page']);
    $show_category    = $bool($atts['category']);
    $show_product     = $bool($atts['product']);
    $show_product_cat = $bool($atts['product_cat']);
    $cpt_list         = $csv($atts['cpt']);
    $tax_list         = $csv($atts['tax']);

    $posts_per_page   = intval($atts['limit']);
    if ($posts_per_page === 0) $posts_per_page = -1;

    $orderby          = sanitize_text_field($atts['orderby']);
    $order            = strtoupper(sanitize_text_field($atts['order'])) === 'ASC' ? 'ASC' : 'DESC';

    $hide_empty_terms = $bool($atts['hide_empty_terms'], false);

    // ---------- CSS ----------
    ob_start();
    ?>
    <style>
      .seo-web-wrap{margin:16px 0;}
      .seo-web-title{font-weight:700;font-size:20px;margin:24px 0 12px;}
      .seo-web-table{width:100%;border-collapse:collapse;font-size:14px;}
      .seo-web-table th,.seo-web-table td{border:1px solid #000;padding:8px 10px;vertical-align:top}
      .seo-web-table thead th{background:#71c7cb;color:#fff;font-weight:700;text-align:left}
      .seo-web-table tbody tr:nth-child(odd){background:#fff}
      .seo-web-table tbody tr:nth-child(even){background:#f3feff}
      .seo-web-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}
      .seo-web-edit a{text-decoration:none}
    </style>
    <?php

    // ---------- Render genérico de tabla de POSTS ----------
    $render_posts_table = function ($title, $posts) use ($esc, $get_path, $get_post_seo) {
        ?>
        <div class="seo-web-wrap">
          <div class="seo-web-title"><?php echo $esc($title); ?></div>
          <table class="seo-web-table">
            <thead>
              <tr>
                <th>Nombre</th>
                <th>Slug</th>
                <th>Keyword</th>
                <th>Title</th>
                <th>Meta Description</th>
              </tr>
            </thead>
            <tbody>
            <?php if (!empty($posts)) :
                foreach ($posts as $p) :
                    $permalink = get_permalink($p);
                    $slug      = $get_path($permalink);
                    $seo       = $get_post_seo($p->ID);
                    $edit_link = get_edit_post_link($p->ID);
                    ?>
                    <tr>
                      <td class="seo-web-edit">
                        <?php if ($edit_link): ?>
                          <a href="<?php echo esc_url($edit_link); ?>" target="_blank" rel="noopener noreferrer">
                            <?php echo $esc(get_the_title($p)); ?>
                          </a>
                        <?php else: ?>
                          <?php echo $esc(get_the_title($p)); ?>
                        <?php endif; ?>
                      </td>
                      <td class="seo-web-mono"><?php echo $esc($slug); ?></td>
                      <td><?php echo $esc($seo['kw']); ?></td>
                      <td><?php echo $esc($seo['title']); ?></td>
                      <td><?php echo $esc($seo['desc']); ?></td>
                    </tr>
                <?php endforeach;
            else: ?>
              <tr><td colspan="5">No se han encontrado elementos.</td></tr>
            <?php endif; ?>
            </tbody>
          </table>
        </div>
        <?php
    };

    // ---------- Render genérico de tabla de TÉRMINOS ----------
    $render_terms_table = function ($title, $terms, $tax_name) use ($esc, $get_path, $get_term_seo) {
        ?>
        <div class="seo-web-wrap">
          <div class="seo-web-title"><?php echo $esc($title); ?></div>
          <table class="seo-web-table">
            <thead>
              <tr>
                <th>Nombre</th>
                <th>Slug</th>
                <th>Keyword</th>
                <th>Title</th>
                <th>Meta Description</th>
              </tr>
            </thead>
            <tbody>
            <?php if (!empty($terms) && !is_wp_error($terms)) :
                foreach ($terms as $t) :
                    $link = get_term_link($t);
                    if (is_wp_error($link)) { $link = ''; }
                    $slug      = $link ? $get_path($link) : '';
                    $seo       = $get_term_seo($t->term_id);
                    $edit_link = get_edit_term_link($t->term_id, $tax_name);
                    ?>
                    <tr>
                      <td class="seo-web-edit">
                        <?php if ($edit_link): ?>
                          <a href="<?php echo esc_url($edit_link); ?>" target="_blank" rel="noopener noreferrer">
                            <?php echo $esc($t->name); ?>
                          </a>
                        <?php else: ?>
                          <?php echo $esc($t->name); ?>
                        <?php endif; ?>
                      </td>
                      <td class="seo-web-mono"><?php echo $esc($slug); ?></td>
                      <td><?php echo $esc($seo['kw']); ?></td>
                      <td><?php echo $esc($seo['title']); ?></td>
                      <td><?php echo $esc($seo['desc']); ?></td>
                    </tr>
                <?php endforeach;
            else: ?>
              <tr><td colspan="5">No se han encontrado términos.</td></tr>
            <?php endif; ?>
            </tbody>
          </table>
        </div>
        <?php
    };

    // ---------- BLOQUES SEGÚN PARÁMETROS ----------

    // 1) PÁGINAS
    if ($show_page) {
        $pages = get_posts([
            'post_type'      => 'page',
            'post_status'    => 'publish',
            'posts_per_page' => $posts_per_page,
            'orderby'        => $orderby,
            'order'          => $order,
        ]);
        $render_posts_table('SEO PÁGINAS', $pages);
    }

    // 2) ENTRADAS
    if ($show_post) {
        $posts = get_posts([
            'post_type'      => 'post',
            'post_status'    => 'publish',
            'posts_per_page' => $posts_per_page,
            'orderby'        => $orderby,
            'order'          => $order,
        ]);
        $render_posts_table('SEO ENTRADAS', $posts);
    }

    // 3) CATEGORÍAS DE ENTRADAS
    if ($show_category) {
        $blog_cats = get_terms([
            'taxonomy'   => 'category',
            'hide_empty' => $hide_empty_terms,
            'orderby'    => 'name',
            'order'      => 'ASC',
        ]);
        $render_terms_table('SEO CATEGORÍAS DE ENTRADAS', $blog_cats, 'category');
    }

    // 4) PRODUCTOS (WooCommerce)
    if ($show_product && post_type_exists('product')) {
        $products = get_posts([
            'post_type'      => 'product',
            'post_status'    => 'publish',
            'posts_per_page' => $posts_per_page,
            'orderby'        => $orderby,
            'order'          => $order,
        ]);
        $render_posts_table('SEO PRODUCTOS (WooCommerce)', $products);
    }

    // 5) CATEGORÍAS DE PRODUCTO (WooCommerce)
    if ($show_product_cat && taxonomy_exists('product_cat')) {
        $terms = get_terms([
            'taxonomy'   => 'product_cat',
            'hide_empty' => $hide_empty_terms,
            'orderby'    => 'name',
            'order'      => 'ASC',
        ]);
        $render_terms_table('SEO CATEGORÍAS DE PRODUCTO (WooCommerce)', $terms, 'product_cat');
    }

    // 6) CPTs personalizados (lista)
    if (!empty($cpt_list)) {
        foreach ($cpt_list as $cpt) {
            if (!post_type_exists($cpt)) continue;
            $items = get_posts([
                'post_type'      => $cpt,
                'post_status'    => 'publish',
                'posts_per_page' => $posts_per_page,
                'orderby'        => $orderby,
                'order'          => $order,
            ]);
            $titulo = 'SEO ' . strtoupper($cpt);
            $render_posts_table($titulo, $items);
        }
    }

    // 7) Taxonomías personalizadas (lista)
    if (!empty($tax_list)) {
        foreach ($tax_list as $tax) {
            if (!taxonomy_exists($tax)) continue;
            $terms = get_terms([
                'taxonomy'   => $tax,
                'hide_empty' => $hide_empty_terms,
                'orderby'    => 'name',
                'order'      => 'ASC',
            ]);
            $titulo = 'SEO TAXONOMÍA: ' . $tax;
            $render_terms_table($titulo, $terms, $tax);
        }
    }

    // Si no se pidió nada explícito, mostramos un aviso
    if (
        !$show_page && !$show_post && !$show_category &&
        !$show_product && !$show_product_cat &&
        empty($cpt_list) && empty($tax_list)
    ) {
        echo '<p>No has seleccionado ningún contenido. Usa parámetros como <code>page=si</code>, <code>post=si</code>, <code>category=si</code>, <code>product=si</code>, <code>product_cat=si</code>, <code>cpt="proyectos,oferta_trabajo"</code> o <code>tax="categorias,brand"</code>.</p>';
    }

    return ob_get_clean();
});

 

Ejemplos:

Solo quieres usar las entradas del blog y las páginas usa:
[seoweb post=si page=si category=si ]

Si quieres usar además los productos y sus categorías usa:
[seoweb post=si page=si category=si product=si product_cat=si ]

Si quieres usar algún cpt a medida usa:
[seoweb post=si page=si category=si product=si product_cat=si cpt=»proyectos» tax=»categorias_proyectos»]

¡Más Snippets, Más Opciones!

Al compartir, motivamos a más desarrolladores a contribuir. Ayúdanos a hacer de este directorio un punto de referencia en snippets.

Facebook
Twitter
LinkedIn
Telegram
WhatsApp

¿Cómo implementar este snippet en la web?

Tienes 2 opciones, una de ellas es mediante plugin y la otra pegando el código en tu web.

1. Añadir snippet con plugin

code-snippets

Code Snippets

Por Code Snippets Pro

  1. Descarga el plugin o búscalo en el repositorio de plugins de Wordpress e instálalo en tu web.
  2. En el menú lateral del Escritorio verás un nuevo enlace (Fragmetos de código). Ves a Fragmentos de código > Añadir nuevo.
  3. Se abrirá una página con un título, bloque de código, descripción y etiquetas, rellena el título con el que quieras guardarlo, ejemplo: Añadir Google Analytics.
  4. En la parte código verás que está activo PHP, ahí pega el código del snippet
  5. La descripción y las etiquetas solo son para tu información y para que luego encuentres más fácil los snippets.
  6. Publicar y activar el snippet.

2. Añadir snippet en el functions.php

Diseño web con WordPress

Accede al archivo functions.php de tu tema o tema hijo, pega el snippet y guarda el archivo.

Lo encontrarás en Apariencia > Editor de archivos de tema, pinchas sobre el enlace  functions.php y pegas el código al final del archivo.

Relacionados: