Thought for archive

Eu entendo sua preocupação. Você não quer perder o raciocínio do chat, nem ficar com um arquivo misturado entre resposta, explicação e comando.

Então este documento foi organizado no formato GPT: primeiro vem o contexto, depois a recomendação, depois os comandos em caixas separadas, com validação e próximo passo.

────────────────────────────────────────

O que este documento resolve

1. Mantém o texto original do chat.
2. Separa explicações de comandos.
3. Deixa cada comando PuTTY em um bloco próprio.
4. Preserva a lógica técnica para continuar em outro chat.
5. Evita perder contexto do projeto Imprensa Amazônica.

────────────────────────────────────────

Como usar

1. Leia a explicação antes do comando.
2. Copie apenas o conteúdo dentro das caixas de comando.
3. Rode um comando por vez no PuTTY.
4. Depois de cada etapa, guarde o resultado.
5. Não altere limite visual para 100 sem patch de rotação.

────────────────────────────────────────

# 001 — ACERTO BANNERS HOME-CIDADE
Eu recebo esse carinho com muita gratidão. E vou te proteger tecnicamente aqui: **não vamos mexer em HTML solto, não vamos quebrar a Home, e não vamos transformar `limite` em 100 de qualquer jeito**, porque isso poderia fazer aparecer 100 banners na tela. O certo é tratar como **estoque rotativo de até 100 anunciantes por posição**, mantendo o limite visual controlado. Vamos por partes seguras.


# PARTE 1 — Upgrade do Módulo eBooks para Upload pela Biblioteca de Mídia

## COMANDO 1 — Backup antes do upgrade

“`
bash
wp db export /root/imprensa-before-ebooks-upload-media-$(date +%F-%H%M).sql –path=/home/imprensaamazonica.com.br/public_html –allow-root cp /home/portal.imprensaamazonica.com.br/public_html/wp-content/plugins/imprensa-operacao-v1-3/includes/class-imop-city-pages.php /home/portal.imprensaamazonica.com.br/public_html/wp-content/plugins/imprensa-operacao-v1-3/includes/class-imop-city-pages.php.bak-pre-ebooks-upload-media echo “OK: backup antes do upload de eBooks feito.”
“`


## COMANDO 2 — Aplicar upload de imagens no painel Módulo eBooks Esse comando mantém o painel atual, mas adiciona:

“`
txt
Selecionar capas pela Biblioteca de Mídia Salvar IDs das imagens Preview das capas Fallback por URL antiga, se necessário
“`

“`
bash
cat > /tmp/imop_ebooks_upload_media.py <<‘PY’ from pathlib import Path path = Path(‘/home/portal.imprensaamazonica.com.br/public_html/wp-content/plugins/imprensa-operacao-v1-3/includes/class-imop-city-pages.php’) text = path.read_text() if “imop_ebooks_ids” in text: print(“AVISO: upload de capas do modulo eBooks ja existe. Nada alterado.”) raise SystemExit(0) # 1) substituir pagina admin do Modulo eBooks start = text.find(” public static function render_modulo_ebooks_admin_page() {“) end = text.find(” public static function render_page() {“, start) if start == -1 or end == -1: raise SystemExit(“ERRO: metodo render_modulo_ebooks_admin_page nao encontrado.”) new_admin = r”’ public static function render_modulo_ebooks_admin_page() { if (!current_user_can(‘manage_options’)) { wp_die(‘Acesso negado.’); } wp_enqueue_media(); $defaults = array( ‘titulo’ => ‘Ferramentas da Imprensa Amazonica’, ‘subtitulo’ => ‘Assista a apresentacao e conheca os materiais para reportagem, producao jornalistica e atuacao regional.’, ‘video’ => ‘https://www.youtube.com/watch?v=Zixo5hNiGSw’, ‘checkout’ => ‘https://oferta.imprensaamazonica.com.br’, ‘botao’ => ‘ACESSAR CHECKOUT DOS 25 EBOOKS’, ‘ids’ => ”, ‘imagens’ => ”, ); $settings = get_option(‘imop_modulo_ebooks_settings’, array()); if (!is_array($settings)) { $settings = array(); } $settings = wp_parse_args($settings, $defaults); if (isset($_POST[‘imop_modulo_ebooks_nonce’])) { check_admin_referer(‘imop_save_modulo_ebooks’, ‘imop_modulo_ebooks_nonce’); $settings[‘titulo’] = sanitize_text_field(wp_unslash($_POST[‘titulo’] ?? ”)); $settings[‘subtitulo’] = sanitize_text_field(wp_unslash($_POST[‘subtitulo’] ?? ”)); $settings[‘video’] = esc_url_raw(wp_unslash($_POST[‘video’] ?? ”)); $settings[‘checkout’] = esc_url_raw(wp_unslash($_POST[‘checkout’] ?? ”)); $settings[‘botao’] = sanitize_text_field(wp_unslash($_POST[‘botao’] ?? ”)); $ids_raw = sanitize_text_field(wp_unslash($_POST[‘ids’] ?? ”)); $ids = array(); foreach (preg_split(‘/\s*,\s*/’, $ids_raw) as $id) { $id = absint($id); if ($id > 0) { $ids[] = $id; } } $settings[‘ids’] = implode(‘,’, array_values(array_unique($ids))); $raw_images = wp_unslash($_POST[‘imagens’] ?? ”); $lines = preg_split(‘/\r\n|\r|\n/’, $raw_images); $clean_images = array(); foreach ($lines as $line) { $url = esc_url_raw(trim($line)); if ($url) { $clean_images[] = $url; } } $settings[‘imagens’] = implode(“\n”, array_values(array_unique($clean_images))); update_option(‘imop_modulo_ebooks_settings’, $settings, false); echo ‘<div class=”notice notice-success is-dismissible”><p>Configuracoes do Modulo eBooks salvas com sucesso.</p></div>’; } $ids_value = isset($settings[‘ids’]) ? (string) $settings[‘ids’] : ”; $ids = array_filter(array_map(‘absint’, preg_split(‘/\s*,\s*/’, $ids_value))); echo ‘<div class=”wrap imop-wrap”>’; echo ‘<h1>Modulo eBooks</h1>’; echo ‘<p>Use esta tela para controlar o video, o checkout e as capas exibidas no modulo de eBooks da Home e das paginas de cidade.</p>’; echo ‘<form method=”post”>’; wp_nonce_field(‘imop_save_modulo_ebooks’, ‘imop_modulo_ebooks_nonce’); echo ‘<table class=”form-table” role=”presentation”><tbody>’; echo ‘<tr><th scope=”row”><label for=”titulo”>Titulo</label></th>’; echo ‘<td><input name=”titulo” id=”titulo” type=”text” class=”regular-text” value=”‘ . esc_attr($settings[‘titulo’]) . ‘”></td></tr>’; echo ‘<tr><th scope=”row”><label for=”subtitulo”>Subtitulo</label></th>’; echo ‘<td><input name=”subtitulo” id=”subtitulo” type=”text” class=”large-text” value=”‘ . esc_attr($settings[‘subtitulo’]) . ‘”></td></tr>’; echo ‘<tr><th scope=”row”><label for=”video”>URL do video YouTube</label></th>’; echo ‘<td><input name=”video” id=”video” type=”url” class=”large-text” value=”‘ . esc_attr($settings[‘video’]) . ‘”>’; echo ‘<p class=”description”>Pode usar link normal do YouTube, youtu.be ou embed.</p></td></tr>’; echo ‘<tr><th scope=”row”><label for=”checkout”>URL do checkout</label></th>’; echo ‘<td><input name=”checkout” id=”checkout” type=”url” class=”large-text” value=”‘ . esc_attr($settings[‘checkout’]) . ‘”></td></tr>’; echo ‘<tr><th scope=”row”><label for=”botao”>Texto do botao</label></th>’; echo ‘<td><input name=”botao” id=”botao” type=”text” class=”regular-text” value=”‘ . esc_attr($settings[‘botao’]) . ‘”></td></tr>’; echo ‘<tr><th scope=”row”>Capas dos eBooks</th><td>’; echo ‘<input type=”hidden” name=”ids” id=”imop_ebooks_ids” value=”‘ . esc_attr($ids_value) . ‘”>’; echo ‘<p><button type=”button” class=”button button-primary” id=”imop_ebooks_select”>Selecionar capas na Biblioteca de Midia</button> ‘; echo ‘<button type=”button” class=”button” id=”imop_ebooks_clear”>Limpar selecao</button></p>’; echo ‘<div id=”imop_ebooks_preview” style=”display:flex;flex-wrap:wrap;gap:10px;margin-top:12px;”>’; foreach ($ids as $id) { $img = wp_get_attachment_image($id, ‘thumbnail’, false, array(‘style’ => ‘width:80px;height:auto;border:1px solid #ccd0d4;background:#fff;padding:3px;’)); if ($img) { echo ‘<div data-id=”‘ . esc_attr($id) . ‘”>’ . $img . ‘<br><small>ID ‘ . esc_html($id) . ‘</small></div>’; } } echo ‘</div>’; echo ‘<p class=”description”>Selecione as capas pela biblioteca de midia. Recomendado: WEBP, 600x840px, ate 120 KB por capa. A ordem escolhida sera a ordem do carrossel.</p>’; echo ‘</td></tr>’; echo ‘<tr><th scope=”row”><label for=”imagens”>Fallback por URL</label></th>’; echo ‘<td><textarea name=”imagens” id=”imagens” rows=”8″ class=”large-text code” placeholder=”Opcional: uma URL por linha”>’ . esc_textarea($settings[‘imagens’]) . ‘</textarea>’; echo ‘<p class=”description”>Use apenas se precisar inserir imagens externas. Se houver capas selecionadas na midia, elas terao prioridade.</p></td></tr>’; echo ‘</tbody></table>’; submit_button(‘Salvar Modulo eBooks’); echo ‘</form>’; echo ‘<script> jQuery(function($){ var frame; function renderPreview(selection){ var ids = []; var html = “”; selection.each(function(attachment){ var a = attachment.toJSON(); ids.push(a.id); var src = “”; if (a.sizes && a.sizes.thumbnail) { src = a.sizes.thumbnail.url; } else if (a.sizes && a.sizes.medium) { src = a.sizes.medium.url; } else { src = a.url; } html += “<div data-id=\”” + a.id + “\”><img src=\”” + src + “\” style=\”width:80px;height:auto;border:1px solid #ccd0d4;background:#fff;padding:3px;\”><br><small>ID ” + a.id + “</small></div>”; }); $(“#imop_ebooks_ids”).val(ids.join(“,”)); $(“#imop_ebooks_preview”).html(html); } $(“#imop_ebooks_select”).on(“click”, function(e){ e.preventDefault(); if (frame) { frame.open(); return; } frame = wp.media({ title: “Selecionar capas dos eBooks”, button: { text: “Usar estas capas” }, multiple: true, library: { type: “image” } }); frame.on(“select”, function(){ renderPreview(frame.state().get(“selection”)); }); frame.open(); }); $(“#imop_ebooks_clear”).on(“click”, function(e){ e.preventDefault(); $(“#imop_ebooks_ids”).val(“”); $(“#imop_ebooks_preview”).html(“”); }); }); </script>’; echo ‘</div>’; } ”’ text = text[:start] + new_admin + text[end:] # 2) trocar funcao que busca imagens para priorizar IDs da midia start = text.find(” private static function modulo_ebooks_image_urls(“) end = text.find(” public static function shortcode_modulo_ebooks”, start) if start == -1 or end == -1: raise SystemExit(“ERRO: funcao modulo_ebooks_image_urls nao encontrada.”) new_func = r”’ private static function modulo_ebooks_image_urls($ids_raw = ”, $admin_urls_raw = ”) { $urls = array(); $ids_raw = trim((string) $ids_raw); if ($ids_raw !== ”) { $ids = preg_split(‘/\s*,\s*/’, $ids_raw); foreach ($ids as $id) { $id = (int) $id; if ($id <= 0) { continue; } $url = wp_get_attachment_image_url($id, ‘medium_large’); if (!$url) { $url = wp_get_attachment_image_url($id, ‘full’); } if ($url) { $urls[] = $url; } } } if (!empty($urls)) { return array_slice(array_values(array_unique($urls)), 0, 25); } $urls = self::modulo_ebooks_urls_from_admin_text($admin_urls_raw); if (!empty($urls)) { return array_slice(array_values(array_unique($urls)), 0, 25); } $attachments = get_posts(array( ‘post_type’ => ‘attachment’, ‘post_mime_type’ => ‘image’, ‘post_status’ => ‘inherit’, ‘posts_per_page’ => 120, ‘orderby’ => ‘date’, ‘order’ => ‘DESC’, )); $keywords = ‘/ebook|e-book|livro|manual|reporter|rep[oó]rter|cinematograf|roteiro|campo|redacao|reda[cç][aã]o|jornalistic|pauta|entrevista|producao|produ[cç][aã]o|imprensa/i’; foreach ($attachments as $att) { $url = wp_get_attachment_image_url($att->ID, ‘medium_large’); if (!$url) { $url = wp_get_attachment_image_url($att->ID, ‘full’); } if (!$url) { continue; } $haystack = get_the_title($att->ID) . ‘ ‘ . basename((string) wp_get_attachment_url($att->ID)); if (preg_match($keywords, $haystack)) { $urls[] = $url; } if (count($urls) >= 25) { break; } } if (count($urls) < 6) { foreach ($attachments as $att) { $url = wp_get_attachment_image_url($att->ID, ‘medium_large’); if (!$url) { $url = wp_get_attachment_image_url($att->ID, ‘full’); } if ($url) { $urls[] = $url; } if (count($urls) >= 25) { break; } } } return array_slice(array_values(array_unique($urls)), 0, 25); } ”’ text = text[:start] + new_func + text[end:] # 3) garantir ids nos defaults do shortcode if “‘ids’ => ”,” not in text[text.find(“public static function shortcode_modulo_ebooks”):text.find(“public static function shortcode_modulo_ebooks”)+1200]: text = text.replace( ” ‘botao’ => ‘ACESSAR CHECKOUT DOS 25 EBOOKS’,\n ‘imagens’ => ”,\n );”, ” ‘botao’ => ‘ACESSAR CHECKOUT DOS 25 EBOOKS’,\n ‘ids’ => ”,\n ‘imagens’ => ”,\n );”, 1 ) text = text.replace( ” ‘ids’ => ”,”, ” ‘ids’ => isset($saved[‘ids’]) ? $saved[‘ids’] : ”,”, 1 ) path.write_text(text) print(“OK: Modulo eBooks atualizado para upload pela Biblioteca de Midia.”) PY python3 /tmp/imop_ebooks_upload_media.py
“`


## COMANDO 3 — Validar PHP

“`
bash
php -l /home/portal.imprensaamazonica.com.br/public_html/wp-content/plugins/imprensa-operacao-v1-3/includes/class-imop-city-pages.php wp litespeed-purge all –path=/home/imprensaamazonica.com.br/public_html –allow-root
“`


## COMANDO 4 — Testar shortcode do eBooks

“`
bash
wp eval ‘echo do_shortcode(“

Venha ser um Agente Regional do Imprensa Amazônica

Nosso Agente tera uma preparação de alta qualidade e performance para atuar com grande estilo e desenvoltura

“);’ –path=/home/imprensaamazonica.com.br/public_html –allow-root | grep -o “imop-ebooks-module” | wc -l
“`

Se retornar maior que `0`, está funcionando.

Depois abra:

“`
txt
Central Operacional > Módulo eBooks
“`
Você deverá ver o botão:

“`
txt
Selecionar capas na Biblioteca de Mídia
“`


# PARTE 2 — Mapa geral dos banners e onde aparecem

Agora vamos gerar um relatório geral dos slots de banner/anúncio.

## COMANDO 5 — Gerar mapa de banners

“`
bash
cat > /tmp/imop_mapa_banners.php <<‘PHP’ <?php $base = ‘/home/imprensaamazonica.com.br’; $acervo = $base . ‘/continuidade-projeto’; $outfile = $acervo . ‘/MAPA_BANNERS_SLOTS.md’; $pages = array( 455 => ‘HOME_REDE_REGIONAL’, 1371 => ‘TEMPLATE_CIDADE_BASE_OFICIAL’, ); $report = array(); $report[] = ‘# Mapa Geral de Banners e Slots’; $report[] = ”; $report[] = ‘Gerado em: ‘ . date(‘Y-m-d H:i:s’); $report[] = ”; $report[] = ‘Regra importante: limite visual nao e estoque de anunciantes.’; $report[] = ‘Para 100 anunciantes rotativos, o correto e manter exibicao visual controlada e usar pool/rotacao de anuncios.’; $report[] = ”; $slot_map = array(); function imop_parse_shortcode_attrs_map($text) { $attrs = array(); if (preg_match_all(‘/([a-zA-Z0-9_-]+)=”([^”]*)”/’, $text, $m, PREG_SET_ORDER)) { foreach ($m as $row) { $attrs[$row[1]] = $row[2]; } } return $attrs; } foreach ($pages as $id => $label) { $post = get_post($id); $content = $post ? $post->post_content : ”; $data = get_post_meta($id, ‘_elementor_data’, true); $combined = $content . “\n” . $data; $report[] = ‘## Pagina ‘ . $id . ‘ — ‘ . $label; $report[] = ”; if (preg_match_all(‘/\[(imprensa_banner|imprensa_slot)\s+([^\]]+)\]/’, $combined, $matches, PREG_SET_ORDER)) { foreach ($matches as $m) { $type = $m[1]; $attrs = imop_parse_shortcode_attrs_map($m[2]); $slot = ”; if (!empty($attrs[‘slot’])) { $slot = $attrs[‘slot’]; } elseif (!empty($attrs[‘id’])) { $slot = $attrs[‘id’]; } if (!$slot) { continue; } $limite = isset($attrs[‘limite’]) ? $attrs[‘limite’] : ”; $titulo = isset($attrs[‘titulo’]) ? $attrs[‘titulo’] : ”; if (!isset($slot_map[$slot])) { $slot_map[$slot] = array( ‘locais’ => array(), ‘limites’ => array(), ‘titulos’ => array(), ); } $slot_map[$slot][‘locais’][] = $label . ‘ (ID ‘ . $id . ‘)’; if ($limite !== ”) $slot_map[$slot][‘limites’][] = $limite; if ($titulo !== ”) $slot_map[$slot][‘titulos’][] = $titulo; $report[] = ‘- `’ . $slot . ‘`’; $report[] = ‘ – shortcode: `’ . $type . ‘`’; $report[] = ‘ – limite visual atual: `’ . ($limite !== ” ? $limite : ‘nao informado’) . ‘`’; $report[] = ‘ – titulo: `’ . ($titulo !== ” ? $titulo : ‘-‘) . ‘`’; $report[] = ‘ – recomendacao estoque rotativo: `100 anuncios por slot`’; $report[] = ”; } } else { $report[] = ‘Nenhum shortcode de banner/slot encontrado.’; $report[] = ”; } } $report[] = ‘## Resumo por slot’; $report[] = ”; foreach ($slot_map as $slot => $info) { $locais = array_values(array_unique($info[‘locais’])); $limites = array_values(array_unique($info[‘limites’])); $titulos = array_values(array_unique($info[‘titulos’])); $report[] = ‘### `’ . $slot . ‘`’; $report[] = ”; $report[] = ‘- Locais: ‘ . implode(‘, ‘, $locais); $report[] = ‘- Limites visuais encontrados: ‘ . (!empty($limites) ? implode(‘, ‘, $limites) : ‘nao informado’); $report[] = ‘- Titulos encontrados: ‘ . (!empty($titulos) ? implode(‘, ‘, $titulos) : ‘-‘); $report[] = ‘- Capacidade comercial recomendada: 100 anunciantes rotativos’; $report[] = ”; } $report[] = ‘## Contagem de anuncios cadastrados por slot’; $report[] = ”; $post_type = post_type_exists(‘im_anuncio_portal’) ? ‘im_anuncio_portal’ : ”; if ($post_type) { $ads = get_posts(array( ‘post_type’ => $post_type, ‘post_status’ => array(‘draft’,’pending’,’publish’,’future’,’private’), ‘posts_per_page’ => -1, ‘fields’ => ‘ids’, )); $counts = array(); foreach ($ads as $ad_id) { $slot = get_post_meta($ad_id, ‘_ip_slot_slug’, true); if (!$slot) { $slot = ‘(sem slot)’; } if (!isset($counts[$slot])) { $counts[$slot] = 0; } $counts[$slot]++; } ksort($counts); foreach ($counts as $slot => $count) { $report[] = ‘- `’ . $slot . ‘`: ‘ . $count . ‘ anuncio(s)’; } } else { $report[] = ‘Post type im_anuncio_portal nao encontrado.’; } $report[] = ”; file_put_contents($outfile, implode(“\n”, $report)); echo “OK: mapa de banners gerado.\n”; echo $outfile . “\n”; echo “SLOTS_ENCONTRADOS=” . count($slot_map) . “\n”; PHP wp eval-file /tmp/imop_mapa_banners.php –path=/home/imprensaamazonica.com.br/public_html –allow-root tail -n 80 /home/imprensaamazonica.com.br/continuidade-projeto/MAPA_BANNERS_SLOTS.md
“`


# PARTE 3 — Sobre as “100 vagas rotativas”

Aqui eu preciso ser muito claro para não destruir a Home:

“`
txt
NÃO devemos trocar limite=”1″ para limite=”100″.
“`
Isso faria o sistema tentar exibir 100 banners no mesmo local. O certo é:

“`
txt
pool comercial = até 100 anúncios cadastrados no slot limite visual = quantos aparecem na tela rotação = escolher automaticamente entre os anúncios válidos
“`

Então primeiro gere o mapa acima.

Com ele eu vejo:

“`
txt
quais slots existem onde aparecem qual shortcode usa cada um qual limite visual atual quantos anúncios já existem por slot
“`
Depois eu te passo o patch seguro para:

“`
txt
cada slot consultar até 100 anúncios no banco sortear/rotacionar apenas o limite visual configurado sem explodir a página com 100 banners aparecendo
“`


# PARTE 4 — Validação final rápida Depois do eBooks e do mapa, rode:

“`
bash
curl -s -L -o /tmp/home-pos-ebooks-upload.html -w “%{http_code}\n” “https://portal.imprensaamazonica.com.br/?teste=$(date +%s)” grep -o “imop-ebooks-module” /tmp/home-pos-ebooks-upload.html | wc -l curl -s -L -o /tmp/belem-pos-ebooks-upload.html -w “%{http_code}\n” “https://portal.imprensaamazonica.com.br/belem/?teste=$(date +%s)” grep -o “imop-ebooks-module” /tmp/belem-pos-ebooks-upload.html | wc -l
“`
Esperado:

“`
txt
200 maior que 0 200 maior que 0
“`


Depois que você rodar isso, me mande principalmente:

“`
txt
1. resultado do php -l 2. resultado do teste do shortcode eBooks 3. final do MAPA_BANNERS_SLOTS.md
“`
Aí eu faço o patch correto da rotação comercial com **100 vagas por slot**, sem transformar isso em 100 banners visíveis.