Código

Puede usar o descargar la carpeta en GitHub

Archivo "arp-admin.js"

jQuery(document).ready(function($){
    // Al pulsar Quick Edit: rellenar campos con los datos actuales
    var wp_inline_edit = inlineEditPost.edit;
    inlineEditPost.edit = function( post_id ) {
        wp_inline_edit.apply(this, arguments);
        var id = 0;
        if (typeof(post_id) == 'object') {
            id = parseInt(this.getId(post_id));
        }
        if (id > 0) {
            var row = $('#post-' + id);
            var prefijo = row.find('td.column-arp_ubicacion').data('arp-prefijo') || '';
            // Pero podemos obtener el texto mostrado y tratarlo:
            var text = row.find('td.column-arp_ubicacion').text().trim();
            // Rellenar los campos del quick edit
            var $edit_row = $('#edit-' + id);
            // Si no encontramos el zone, rellenamos el area del quick edit global
            $('#edit-' + id).find('select[name="arp_ubicacion_prefijo_qe"]').val('');
            $('#edit-' + id).find('input[name="arp_ubicacion_lugar_qe"]').val('');
            // Alternativa simple: si text tiene espacio, separar primer palabra como prefijo y resto lugar
            if (text && text !== '—') {
                var parts = text.split(' ');
                // Buscamos si el primer token coincide con una de las opciones
                var opciones = ['Reportando','Reportó','Reportaron','En','Desde'];
                var first = parts[0];
                var pref = '';
                var lugar = text;
                // Buscar coincidencia prefijo exacta o "En vivo desde"
                var known = ['Reportando','Reportó','Reportaron','En vivo desde','Desde'];
                for (var i=0;i<known.length;i++){
                    if (text.indexOf(known[i]) === 0) {
                        pref = known[i];
                        lugar = text.replace(known[i],'').trim();
                        break;
                    }
                }
                if (pref) {
                    $('#edit-' + id).find('select[name="arp_ubicacion_prefijo_qe"]').val(pref);
                    $('#edit-' + id).find('input[name="arp_ubicacion_lugar_qe"]').val(lugar);
                } else {
                    $('#edit-' + id).find('input[name="arp_ubicacion_lugar_qe"]').val(text);
                }
            }
        }
    };

    // Cuando se abre quick edit en la lista desde el botón "Quick Edit" estándar,
    // WordPress clona la fila .inline-edit-row; por eso usamos evento click
    $(document).on('click', '.editinline', function(){
        var row = $(this).closest('tr');
        var post_id = row.attr('id').replace('post-','');
        var text = row.find('td.column-arp_ubicacion').text().trim();
        var $inline = $('#edit-'+post_id);
        if (!$inline.length) {
            // quick edit global
            var $qe = $('#the-list').find('tr.inline-edit-row');
            $qe.find('select[name="arp_ubicacion_prefijo_qe"]').val('');
            $qe.find('input[name="arp_ubicacion_lugar_qe"]').val('');
            if (text && text !== '—') {
                // intentar separar
                var known = ['Reportando','Reportó','Reportaron','En vivo desde','Desde'];
                var pref = '';
                var lugar = text;
                for (var i=0;i<known.length;i++){
                    if (text.indexOf(known[i]) === 0) {
                        pref = known[i];
                        lugar = text.replace(known[i],'').trim();
                        break;
                    }
                }
                if (pref) {
                    $qe.find('select[name="arp_ubicacion_prefijo_qe"]').val(pref);
                    $qe.find('input[name="arp_ubicacion_lugar_qe"]').val(lugar);
                } else {
                    $qe.find('input[name="arp_ubicacion_lugar_qe"]').val(text);
                }
            }
        }
    });
});

Archivo "autor-ubicacion-elementor.php"

<?php
/*
Plugin Name: Información de Autor y Ubicación para Elementor
Description: Widget de Elementor para mostrar autor, foto, cargo, ubicación (prefijo + lugar) y fecha en reportajes. Incluye metabox, quick-edit y compatibilidad con Elementor.
Version: 3.0
Author: Marcos para El Ambientalista Post
*/

if (!defined('ABSPATH')) exit;

// -------------------------
// Encolar estilos frontend
// -------------------------
add_action('wp_enqueue_scripts', function() {
    wp_enqueue_style('arp-elementor-style', plugin_dir_url(__FILE__) . 'style.css');
});

// -------------------------
// Registrar el widget en Elementor
// -------------------------
add_action('elementor/widgets/register', function($widgets_manager) {
    require_once(__DIR__ . '/widget-autor.php');
    $widgets_manager->register(new \ARP\Widgets\Autor_Ubicacion_Widget());
});

// -------------------------
// Añadir categoría de Elementor
// -------------------------
add_action('elementor/elements/categories_registered', function($elements_manager) {
    $elements_manager->add_category(
        'elambientalista',
        [
            'title' => esc_html__('El Ambientalista', 'arp-elementor'),
            'icon'  => 'fa fa-leaf',
        ]
    );
});

// -------------------------
// Metabox: Solo UN campo: prefijo + lugar
// -------------------------
add_action('add_meta_boxes', function() {
    add_meta_box(
        'arp_autor_ubicacion',
        'Agregar ubicación del autor',
        'arp_autor_ubicacion_metabox',
        ['post'],
        'side',
        'default'
    );
});

function arp_autor_ubicacion_metabox($post) {
    // Prefijo guardado y lugar
    $prefijo = get_post_meta($post->ID, '_arp_ubicacion_prefijo', true);
    $lugar = get_post_meta($post->ID, '_arp_ubicacion_lugar', true);

    // Opciones sugeridas
    $opciones = [
        '' => '-- Ninguno --',
        'Reportando' => 'Reportando',
        'Reportó' => 'Reportó',
        'Reportaron' => 'Reportaron',
        'En vivo desde' => 'En vivo desde',
        'Desde' => 'Desde'
    ];
    ?>
    <p>
        <label for="arp_ubicacion_prefijo"><strong>Tipo</strong></label>
        <select name="arp_ubicacion_prefijo" id="arp_ubicacion_prefijo" class="widefat">
            <?php foreach ($opciones as $k => $v): ?>
                <option value="<?php echo esc_attr($k); ?>" <?php selected($prefijo, $k); ?>><?php echo esc_html($v); ?></option>
            <?php endforeach; ?>
        </select>
    </p>

    <p>
        <label for="arp_ubicacion_lugar"><strong>Ciudad / País</strong></label>
        <input type="text" name="arp_ubicacion_lugar" id="arp_ubicacion_lugar" class="widefat"
               placeholder="Ej: Ciudad de México, México" value="<?php echo esc_attr($lugar); ?>">
    </p>

    <p style="font-size:12px;color:#666;margin-top:6px;">Si dejas ambos en blanco, no se mostrará la ubicación en el widget.</p>
    <?php
}

// -------------------------
// Guardar metadatos
// -------------------------
add_action('save_post', function($post_id) {
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
    if (!current_user_can('edit_post', $post_id)) return;

    // Prefijo y lugar
    if (isset($_POST['arp_ubicacion_prefijo'])) {
        update_post_meta($post_id, '_arp_ubicacion_prefijo', sanitize_text_field($_POST['arp_ubicacion_prefijo']));
    }
    if (isset($_POST['arp_ubicacion_lugar'])) {
        update_post_meta($post_id, '_arp_ubicacion_lugar', sanitize_text_field($_POST['arp_ubicacion_lugar']));
    }
});

// -------------------------
// Helper: obtener ubicación completa (prefijo + lugar)
// -------------------------
function arp_get_post_ubicacion($post_id = null) {
    if (!$post_id) $post_id = get_the_ID();
    $prefijo = get_post_meta($post_id, '_arp_ubicacion_prefijo', true);
    $lugar = get_post_meta($post_id, '_arp_ubicacion_lugar', true);
    if (empty($prefijo) && empty($lugar)) return '';
    $parts = [];
    if (!empty($prefijo)) $parts[] = $prefijo;
    if (!empty($lugar)) $parts[] = $lugar;
    return implode(' ', $parts); // ej: "Reportando Ciudad de México"
}

// -------------------------
// Quick Edit: agregar columna y quick edit para ubicación
// -------------------------
add_filter('manage_posts_columns', function($columns) {
    $columns['arp_ubicacion'] = __('Ubicación', 'arp-elementor');
    return $columns;
});

add_action('manage_posts_custom_column', function($column, $post_id) {
    if ($column === 'arp_ubicacion') {
        $prefijo = get_post_meta($post_id, '_arp_ubicacion_prefijo', true);
        $lugar = get_post_meta($post_id, '_arp_ubicacion_lugar', true);
        if ($prefijo || $lugar) {
            echo esc_html(trim($prefijo . ' ' . $lugar));
        } else {
            echo '—';
        }
    }
}, 10, 2);

// Añadir contenido al quick edit (caja invisible, estilo admin)
add_action('quick_edit_custom_box', function($column_name, $post_type) {
    if ($column_name !== 'arp_ubicacion') return;
    ?>
    <fieldset class="inline-edit-col-left">
        <div class="inline-edit-col">
            <label>
                <span class="title">Tipo</span>
                <select name="arp_ubicacion_prefijo_qe" class="arp-quick-prefijo">
                    <option value="">-- Ninguno --</option>
                    <option value="Reportando">Reportando</option>
                    <option value="Reportó">Reportó</option>
                    <option value="Reportaron">Reportaron</option>
                    <option value="En vivo desde">En vivo desde</option>
                    <option value="Desde">Desde</option>
                </select>
            </label>
            <label>
                <span class="title">Ciudad / País</span>
                <input type="text" name="arp_ubicacion_lugar_qe" class="arp-quick-lugar" value="">
            </label>
        </div>
    </fieldset>
    <?php
}, 10, 2);

// Guardar Quick Edit (hook en save_post ya captura cambios de quick edit si hay datos)
// Para interceptar desde la lista necesitamos usar 'save_post' y valores que vienen por POST con names del quick edit.
add_action('save_post', function($post_id) {
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
    if (!current_user_can('edit_post', $post_id)) return;

    if (isset($_POST['arp_ubicacion_prefijo_qe'])) {
        update_post_meta($post_id, '_arp_ubicacion_prefijo', sanitize_text_field($_POST['arp_ubicacion_prefijo_qe']));
    }
    if (isset($_POST['arp_ubicacion_lugar_qe'])) {
        update_post_meta($post_id, '_arp_ubicacion_lugar', sanitize_text_field($_POST['arp_ubicacion_lugar_qe']));
    }
}, 20, 1);

// -------------------------
// Encolar scripts admin para Quick Edit y media uploader (si quieres editar/avatar desde admin)
// -------------------------
add_action('admin_enqueue_scripts', function($hook) {
    // Solo en listado de posts y editor
    wp_enqueue_script('arp-admin-js', plugin_dir_url(__FILE__) . 'arp-admin.js', ['jquery'], false, true);
    // Localizar texto y nonce si se requiere
    wp_localize_script('arp-admin-js', 'arpAdmin', [
        'ajax_url' => admin_url('admin-ajax.php'),
    ]);
});

Archivo "style.css"

/* Estilos para el widget Autor y Ubicación - responsive y alineación */

/* contenedor */
.arp-autor-widget { font-family: Georgia, 'Times New Roman', serif; color: #111; }

/* layout: foto izquierda, texto derecha */
.arp-autor-inner { display:flex; align-items:flex-start; gap:14px; }
.arp-autor-left { flex: 0 0 auto; }
.arp-autor-right { display:flex; flex-direction:column; justify-content:center; }

/* Ubicación arriba del nombre — alineada con el texto principal */
.arp-ubicacion { font-size:13px; color:#666; margin-bottom:2px; line-height:1.1; }

/* Línea del nombre */
.arp-por-nombre { font-size:15px; color:#111; }

/* Fecha debajo del nombre, con transición */
.arp-fecha { font-size:13px; color:#666; margin-top:6px; height:auto; transition: transform .45s ease, opacity .45s ease; }

/* Responsive */
@media (max-width:768px) {
    .arp-autor-inner { gap:10px; align-items:center; }
    .arp-ubicacion { font-size:12px; }
    .arp-por-nombre { font-size:14px; }
    .arp-fecha { font-size:12px; margin-top:4px; }
}

/* Móvil estrecho: apilar */
@media (max-width:420px) {
    .arp-autor-inner { flex-direction:row; align-items:center; gap:8px; }
    .arp-autor-right { min-width:0; }
    .arp-por-nombre { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
}

Archivo "widget-autor.php"

<?php
namespace ARP\Widgets;

use Elementor\Widget_Base;
use Elementor\Controls_Manager;

if (!defined('ABSPATH')) exit;

class Autor_Ubicacion_Widget extends Widget_Base {

    public function get_name() {
        return 'autor_ubicacion_widget';
    }

    public function get_title() {
        return __('Autor y Ubicación', 'arp-elementor');
    }

    public function get_icon() {
        return 'eicon-person';
    }

    public function get_categories() {
        return ['elambientalista'];
    }

    protected function register_controls() {
        $this->start_controls_section('content_section', [
            'label' => __('Contenido (override opcional)', 'arp-elementor'),
            'tab' => Controls_Manager::TAB_CONTENT,
        ]);

        // Foto independiente
        $this->add_control('foto', [
            'label' => __('Foto del autor (opcional)', 'arp-elementor'),
            'type' => Controls_Manager::MEDIA,
            'default' => ['url' => ''],
        ]);

        // Nombre independiente (si quieres forzar otro nombre)
        $this->add_control('nombre_forzado', [
            'label' => __('Nombre del autor (opcional)', 'arp-elementor'),
            'type' => Controls_Manager::TEXT,
            'placeholder' => __('Ej: María López'),
        ]);

        // Ubicación independiente (override)
        $this->add_control('ubicacion_forzada', [
            'label' => __('Ubicación (opcional - override)', 'arp-elementor'),
            'type' => Controls_Manager::TEXT,
            'placeholder' => __('Ej: Reportando desde Ciudad de México'),
        ]);

        // Fecha independiente
        $this->add_control('fecha_forzada', [
            'label' => __('Texto de fecha (opcional)', 'arp-elementor'),
            'type' => Controls_Manager::TEXT,
            'placeholder' => __('Ej: Publicado el 25 de enero de 2025 a las 12:45 am'),
        ]);

        // Ajustes responsivos: imagen tamaño
        $this->add_control('foto_size', [
            'label' => __('Tamaño de la foto (px)', 'arp-elementor'),
            'type' => Controls_Manager::NUMBER,
            'default' => 55,
        ]);

        $this->end_controls_section();
    }

    protected function render() {
        global $post;
        if (!$post) return;

        $settings = $this->get_settings_for_display();

        // Datos base: autor WP
        $author_id = $post->post_author;
        $author_name_wp = get_the_author_meta('display_name', $author_id);
        $author_avatar_wp = get_avatar_url($author_id, ['size' => 120]);

        // Ubicación desde metadatos (prefijo + lugar)
        $ubicacion_meta = function_exists('arp_get_post_ubicacion') ? arp_get_post_ubicacion($post->ID) : '';

        // Valores finales (prioridad: Elementor override > WP post data)
        $foto = !empty($settings['foto']['url']) ? $settings['foto']['url'] : $author_avatar_wp;
        $author_name = !empty($settings['nombre_forzado']) ? $settings['nombre_forzado'] : $author_name_wp;
        $ubicacion = !empty($settings['ubicacion_forzada']) ? $settings['ubicacion_forzada'] : $ubicacion_meta;
        $fecha_override = !empty($settings['fecha_forzada']) ? $settings['fecha_forzada'] : '';

        // --- INICIO DE LA LÓGICA DE FECHA MODIFICADA ---
        if ($fecha_override) {
            $texto_fecha = $fecha_override;
        } else {
            // Usamos timestamps (formato 'U') para cálculos precisos.
            $pub_ts = get_the_time('U', $post->ID);
            $mod_ts = get_the_modified_time('U', $post->ID);
            $current_ts = current_time('U');

            // Se considera 'modificado' si hay más de 60 segundos de diferencia.
            if ($mod_ts - $pub_ts > 60) {
                $diff_seconds = $current_ts - $mod_ts;

                if ($diff_seconds < HOUR_IN_SECONDS) {
                    // 1. Actualización menor a 1 hora
                    $texto_fecha = sprintf(__('Actualizado hace %s'), human_time_diff($mod_ts, $current_ts));
                } elseif (date('Ymd', $mod_ts) === date('Ymd', $current_ts)) {
                    // 2. Actualización hoy (hace más de una hora)
                    $texto_fecha = "Actualizado hoy a las " . get_the_modified_time('g:i a', $post);
                } elseif (date('Ymd', $mod_ts) === date('Ymd', $current_ts - DAY_IN_SECONDS)) {
                    // 3. Actualización ayer
                    $texto_fecha = "Actualizado ayer a las " . get_the_modified_time('g:i a', $post);
                } else {
                    // 4. Actualización hace más de un día (y no fue ayer)
                    $texto_fecha = "Actualizado el " . get_the_modified_date('j \d\e F \a \l\a\s g:i a', $post);
                }
            } else {
                // No hay modificación real, mostrar fecha de publicación.
                $texto_fecha = "Publicado el " . get_the_date('j \d\e F \d\e Y \a \l\a\s g:i a', $post);
            }
        }
        // --- FIN DE LA LÓGICA DE FECHA MODIFICADA ---

        // Tamaño foto responsive
        $foto_size = intval($settings['foto_size']) ?: 55;
        $foto_size_style = esc_attr($foto_size);

        // Si no hay nada para mostrar, salir
        if (empty($author_name)) return;

        ?>

        <div class="arp-autor-widget" style="margin-top:20px;">
            <div class="arp-autor-inner">
                <div class="arp-autor-left">
                    <img src="<?php echo esc_url($foto); ?>"
                         alt="<?php echo esc_attr($author_name); ?>"
                         style="width:<?php echo $foto_size_style; ?>px;height:<?php echo $foto_size_style; ?>px;object-fit:cover;border-radius:50%;border:1px solid #ddd;">
                </div>

                <div class="arp-autor-right">
                    <?php if ($ubicacion): ?>
                        <div class="arp-ubicacion" aria-hidden="true"><?php echo esc_html($ubicacion); ?></div>
                    <?php endif; ?>

                    <div class="arp-por-nombre">Por <strong><?php echo esc_html($author_name); ?></strong></div>

                    <?php if ($texto_fecha): ?>
                        <div class="arp-fecha" aria-live="polite"><?php echo esc_html($texto_fecha); ?></div>
                    <?php endif; ?>
                </div>
            </div>
        </div>

        <?php
    }
}

Última actualización

¿Te fue útil?