
Today's function creates an access from /Tools to export a list of tags in .txt format with these four options:
Export tags in Spanish. Generates a list of tags in Spanish with the number of posts in which they were added and the total amount.
Export tags without Posts. Returns the list of tags not assigned to any post with language information, e.g. /ES/ /EN/ /DE/ etc.
Export tags with a single post. Creates the list of tags assigned to a single post with language information.
Export All Tags. Here you can download the complete list with all associated languages, the number of posts where they were added and the total amount.

You may be wondering how useful this is if you can see the list of tags filtered by different parameters from the WordPress administration area.
Well, it will be very useful in a scenario where you discover that you have hundreds or thousands of orphan tags or tags with only one associated post accumulated due to neglect and you decide to reorganise them to delete empty tags, merge them or move them to posts that only have one tag and redirect those that are receiving traffic.
Yes, although much of the staff recommends not indexing categories and tags, if you optimise them well they can be a stable source of organic traffic. If you have a real interest in this topic, leave a comment here and I'll try to add a note with the details at some point.
At that point where you have an excessive pile-up of tags, causing an unnecessary bloat of tables in your database and slowing down queries, the administration area will become increasingly slower. This can cause anything from 503 errors to CPU overloads that prevent you from browsing the list.
By working locally with the downloaded lists in .txt you will avoid this and you can always have updated lists of the status of your tags for quick reference and resume the tedious work of reorganisation at any time. If you have a lot of them, take it easy. As a long term project.
In September 2024 I started the task of reorganising categories and tags and I'm not finished yet. The goal is to at least halve the accumulated tags and labels associated with a single post or two in order to regroup, delete and merge them into a more logical structure.
Code (compatible with WPML and Polylang plugins)
The use is the same as always. You add the code in thefunctions.php of your template and you will find the access to the buttons to download the lists from the admin in Tools/ Export Advanced Tags.
// Exportar lista de tags en .txt compatible VPML y Polylang
add_action('admin_menu', 'agregar_menu_exportar_tags_avanzado');
function agregar_menu_exportar_tags_avanzado() {
add_submenu_page(
'tools.php',
'Exportar Tags Avanzado',
'Exportar Tags Avanzado',
'manage_options',
'exportar-tags-avanzado',
'pagina_exportar_tags_avanzado'
);
}
function generar_archivo_tags($tipo) {
if (!current_user_can('manage_options')) {
wp_die(__('No tienes permisos suficientes para acceder a esta página.'));
}
if (ob_get_level()) {
ob_end_clean();
}
$all_tags = get_tags(array(
'orderby' => 'name',
'order' => 'ASC',
'hide_empty' => false
));
$tags_filtradas = array();
$nombre_archivo = '';
$titulo = '';
switch ($tipo) {
case 'espanol':
if (function_exists('pll_get_term_language')) {
foreach ($all_tags as $tag) {
if (pll_get_term_language($tag->term_id) == 'es') {
$tags_filtradas[] = $tag;
}
}
}
$nombre_archivo = 'lista-tags-espanol';
$titulo = 'Etiquetas en Español';
break;
case 'sin_posts':
foreach ($all_tags as $tag) {
if ($tag->count == 0) {
$tags_filtradas[] = $tag;
}
}
$nombre_archivo = 'lista-tags-sin-posts';
$titulo = 'Etiquetas sin Posts';
break;
case 'un_post':
foreach ($all_tags as $tag) {
if ($tag->count == 1) {
$tags_filtradas[] = $tag;
}
}
$nombre_archivo = 'lista-tags-un-post';
$titulo = 'Etiquetas con un solo Post';
break;
default:
$tags_filtradas = $all_tags;
$nombre_archivo = 'lista-tags-completa';
$titulo = 'Todas las Etiquetas';
}
if (empty($tags_filtradas)) {
wp_die(__('No se encontraron etiquetas que coincidan con el criterio seleccionado.'));
}
$contenido = "Lista de {$titulo}\n";
$contenido .= str_repeat("=", strlen($titulo) + 6) . "\n\n";
$contenido .= "Total de etiquetas: " . count($tags_filtradas) . "\n\n";
foreach ($tags_filtradas as $tag) {
$idioma = '';
if (function_exists('pll_get_term_language')) {
$idioma = pll_get_term_language($tag->term_id);
$idioma = $idioma ? strtoupper($idioma) : 'ND';
}
$contenido .= sprintf("%-50s %-8s %s\n",
$tag->name,
"(Usos: {$tag->count})",
$idioma ? "IDIOMA: /{$idioma}/" : "");
}
header('Content-Description: File Transfer');
header('Content-Type: text/plain; charset=utf-8');
header('Content-Disposition: attachment; filename="' . $nombre_archivo . '-' . date('Y-m-d') . '.txt"');
header('Content-Length: ' . strlen($contenido));
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
echo $contenido;
exit;
}
function pagina_exportar_tags_avanzado() {
if (!current_user_can('manage_options')) {
wp_die(__('No tienes permisos suficientes para acceder a esta página.'));
}
if (isset($_GET['tipo_exportacion'])) {
generar_archivo_tags(sanitize_text_field($_GET['tipo_exportacion']));
return;
}
?>
<div class="wrap">
<h1>Exportar Etiquetas Avanzado</h1>
<p>Selecciona el tipo de etiquetas que deseas exportar:</p>
<div style="margin: 20px 0;">
<a href="<?php echo esc_url(add_query_arg('tipo_exportacion', 'espanol')); ?>" class="button button-primary">
Exportar Tags en Español
</a>
<span class="description">Lista de etiquetas en español con información de idioma</span>
</div>
<div style="margin: 20px 0;">
<a href="<?php echo esc_url(add_query_arg('tipo_exportacion', 'sin_posts')); ?>" class="button button-primary">
Exportar Tags sin Posts
</a>
<span class="description">Etiquetas no asignadas a ningún post con información de idioma</span>
</div>
<div style="margin: 20px 0;">
<a href="<?php echo esc_url(add_query_arg('tipo_exportacion', 'un_post')); ?>" class="button button-primary">
Exportar Tags con un solo Post
</a>
<span class="description">Etiquetas asignadas a un solo post con información de idioma</span>
</div>
<div style="margin: 20px 0;">
<a href="<?php echo esc_url(add_query_arg('tipo_exportacion', 'todas')); ?>" class="button button-primary">
Exportar Todas las Tags
</a>
<span class="description">Lista completa con todos los idiomas asociados</span>
</div>
</div>
<style>
.description {
margin-left: 10px;
color: #666;
font-style: italic;
}
.wrap > div {
padding: 10px;
border-bottom: 1px solid #eee;
}
.button-primary {
min-width: 220px;
text-align: left;
}
</style>
<?php
}