{"id":267,"date":"2026-05-13T12:00:35","date_gmt":"2026-05-13T15:00:35","guid":{"rendered":"http:\/\/neodoor.neo\/?p=267"},"modified":"2026-05-21T09:03:05","modified_gmt":"2026-05-21T12:03:05","slug":"dashboard-custom-feed","status":"publish","type":"post","link":"https:\/\/www.portanova.com.br\/notebook\/dashboard-custom-feed\/","title":{"rendered":"[MU] Dashboard Custom Feed"},"content":{"rendered":"<h2>Aula: Feed RSS Personalizado no Dashboard com MU-Plugin \u2013 Substituindo o Dashboard Custom Feed<\/h2>\n<p><strong>Objetivo:<\/strong> Substituir o plugin <code>dashboard-custom-feed<\/code> por um MU-Plugin enxuto, que adiciona um widget personalizado ao painel administrativo do WordPress exibindo not\u00edcias ou atualiza\u00e7\u00f5es a partir de um feed RSS, sem sobrecarga e com total controle sobre a exibi\u00e7\u00e3o.<\/p>\n<p><strong>Contexto:<\/strong> Muitos sites utilizam o <code>dashboard-custom-feed<\/code> para criar um canal de comunica\u00e7\u00e3o com o cliente ou equipe diretamente no admin, ou para promover conte\u00fado relevante. No entanto, trata-se de um plugin desatualizado (n\u00e3o testado nas vers\u00f5es recentes do WordPress) que frequentemente depende de um plugin irm\u00e3o (<code>dashboard-custom-feed-admin<\/code>) para criar o feed. Vamos consolidar essa funcionalidade em um \u00fanico MU-Plugin simples, que l\u00ea qualquer feed RSS externo (ou interno) e o exibe no dashboard com formata\u00e7\u00e3o elegante.<\/p>\n<h3>Funcionalidades implementadas no nosso MU-Plugin<\/h3>\n<ul>\n<li>Adiciona um widget personalizado \u00e0 tela inicial do painel administrativo.<\/li>\n<li>Exibe itens de qualquer feed RSS (URL configur\u00e1vel diretamente no c\u00f3digo).<\/li>\n<li>Controla n\u00famero de itens, exibi\u00e7\u00e3o de resumo, data e autor.<\/li>\n<li>Utiliza sistema de cache nativo do WordPress (<code>fetch_feed<\/code>), que armazena o feed por 12 horas para reduzir requisi\u00e7\u00f5es externas.<\/li>\n<li>Inclui tratamento de erro amig\u00e1vel caso o feed n\u00e3o esteja acess\u00edvel.<\/li>\n<li>Design responsivo e integrado ao estilo padr\u00e3o do dashboard.<\/li>\n<\/ul>\n<h3>C\u00f3digo do MU-Plugin<\/h3>\n<p>Crie a pasta <code>wp-content\/mu-plugins\/neodoor-dashboard-feed\/<\/code> e dentro dela o arquivo <code>neodoor-dashboard-feed.php<\/code> com o conte\u00fado abaixo:<\/p>\n<pre><code>&lt;?php\n\/**\n * Plugin Name:  Neodoor Dashboard Custom Feed\n * Description:  Adiciona um widget personalizado ao dashboard com feed RSS (not\u00edcias, atualiza\u00e7\u00f5es).\n * Version:      1.0\n * Author:       Reinaldo (Neodoor.neo)\n *\/\n\nif ( ! defined( 'ABSPATH' ) ) {\n    exit;\n}\n\nclass Neodoor_Dashboard_Feed {\n\n    private static $instance = null;\n\n    \/\/ Configura\u00e7\u00e3o do feed \u2013 edite os valores conforme sua necessidade\n    private $feed_url = 'https:\/\/wordpress.org\/news\/feed\/'; \/\/ URL do feed RSS\n    private $widget_title = 'Neodoor &ndash; Not\u00edcias e Atualiza\u00e7\u00f5es'; \/\/ T\u00edtulo do widget\n    private $items = 5;          \/\/ N\u00famero de itens a exibir\n    private $show_summary = 1;   \/\/ Exibir resumo? 1 = sim, 0 = n\u00e3o\n    private $show_author = 0;    \/\/ Exibir autor? 1 = sim, 0 = n\u00e3o\n    private $show_date = 1;      \/\/ Exibir data? 1 = sim, 0 = n\u00e3o\n\n    public static function get_instance() {\n        if ( null === self::$instance ) {\n            self::$instance = new self();\n        }\n        return self::$instance;\n    }\n\n    private function __construct() {\n        add_action( 'wp_dashboard_setup', [ $this, 'add_dashboard_widget' ] );\n    }\n\n    \/**\n     * Registra o widget no dashboard\n     *\/\n    public function add_dashboard_widget() {\n        wp_add_dashboard_widget(\n            'neodoor_dashboard_feed_widget', \/\/ ID \u00fanico do widget\n            $this-&gt;widget_title,             \/\/ T\u00edtulo exibido\n            [ $this, 'render_widget_output' ] \/\/ Fun\u00e7\u00e3o que exibe o conte\u00fado\n        );\n    }\n\n    \/**\n     * Renderiza o conte\u00fado do widget: exibe o feed RSS\n     *\/\n    public function render_widget_output() {\n        \/\/ Utiliza a fun\u00e7\u00e3o nativa fetch_feed (com cache de 12 horas)\n        $rss = fetch_feed( $this-&gt;feed_url );\n\n        if ( is_wp_error( $rss ) ) {\n            \/\/ Exibe mensagem amig\u00e1vel em caso de erro (feed offline, URL inv\u00e1lida)\n            echo '&lt;div class=\"error\"&gt;&lt;p&gt;N\u00e3o foi poss\u00edvel carregar o feed de not\u00edcias. Verifique a URL ou tente novamente mais tarde.&lt;\/p&gt;&lt;\/div&gt;';\n            return;\n        }\n\n        \/\/ Limita o n\u00famero de itens conforme configurado\n        $max_items = $rss-&gt;get_item_quantity( $this-&gt;items );\n        $rss_items = $rss-&gt;get_items( 0, $max_items );\n\n        if ( empty( $rss_items ) ) {\n            echo '&lt;p&gt;Nenhum item encontrado no feed.&lt;\/p&gt;';\n            return;\n        }\n\n        \/\/ Abre o container com a classe padr\u00e3o do WordPress para widgets RSS\n        echo '&lt;div class=\"rss-widget\"&gt;';\n\n        \/\/ Itera sobre os itens e exibe cada um\n        foreach ( $rss_items as $item ) {\n            $item_link = esc_url( $item-&gt;get_link() );\n            $item_title = esc_html( $item-&gt;get_title() );\n            $item_date = $item-&gt;get_date( 'U' );\n            $item_author = $item-&gt;get_author();\n            $author_name = $item_author ? esc_html( $item_author-&gt;get_name() ) : '';\n\n            echo '&lt;div class=\"rss-widget-item\"&gt;';\n            echo '&lt;h4&gt;&lt;a href=\"' . $item_link . '\" target=\"_blank\"&gt;' . $item_title . '&lt;\/a&gt;&lt;\/h4&gt;';\n\n            if ( $this-&gt;show_date &amp;&amp; $item_date ) {\n                echo '&lt;p class=\"rss-date\"&gt;' . date_i18n( get_option( 'date_format' ), $item_date ) . '&lt;\/p&gt;';\n            }\n\n            if ( $this-&gt;show_author &amp;&amp; ! empty( $author_name ) ) {\n                echo '&lt;p class=\"rss-author\"&gt;Por ' . $author_name . '&lt;\/p&gt;';\n            }\n\n            if ( $this-&gt;show_summary ) {\n                $description = $item-&gt;get_description();\n                if ( $description ) {\n                    \/\/ Limita o resumo a 120 palavras (pode ajustar)\n                    $excerpt = wp_trim_words( $description, 120, ' [...]' );\n                    echo '&lt;p class=\"rss-summary\"&gt;' . esc_html( $excerpt ) . '&lt;\/p&gt;';\n                }\n            }\n\n            echo '&lt;\/div&gt;';\n        }\n\n        echo '&lt;\/div&gt;';\n    }\n}\n\nNeodoor_Dashboard_Feed::get_instance();\n<\/code><\/pre>\n<h3>Instru\u00e7\u00f5es de instala\u00e7\u00e3o<\/h3>\n<ol>\n<li>Certifique-se de que o autoloader <code>loader.php<\/code> esteja presente em <code>\/wp-content\/mu-plugins\/<\/code> (conforme aula anterior).<\/li>\n<li>Crie a pasta <code>neodoor-dashboard-feed<\/code> dentro de <code>\/wp-content\/mu-plugins\/<\/code>.<\/li>\n<li>Dentro dela, crie o arquivo <code>neodoor-dashboard-feed.php<\/code> e cole o c\u00f3digo acima.<\/li>\n<li>Desative e remova o plugin <code>dashboard-custom-feed<\/code> da lista de plugins (bem como qualquer plugin complementar como <code>dashboard-custom-feed-admin<\/code>).<\/li>\n<\/ol>\n<h3>Configura\u00e7\u00e3o do feed<\/h3>\n<p>Para personalizar o feed e a apar\u00eancia do widget, edite as propriedades privadas no in\u00edcio da classe:<\/p>\n<pre><code>private $feed_url = 'https:\/\/wordpress.org\/news\/feed\/';   \/\/ URL do feed RSS\nprivate $widget_title = 'Neodoor \u2013 Not\u00edcias e Atualiza\u00e7\u00f5es'; \/\/ T\u00edtulo do widget\nprivate $items = 5;          \/\/ N\u00famero de itens a exibir\nprivate $show_summary = 1;   \/\/ Exibir resumo? 1 = sim, 0 = n\u00e3o\nprivate $show_author = 0;    \/\/ Exibir autor? 1 = sim, 0 = n\u00e3o\nprivate $show_date = 1;      \/\/ Exibir data? 1 = sim, 0 = n\u00e3o\n<\/code><\/pre>\n<p>Por exemplo, para exibir os \u00faltimos 3 posts do seu pr\u00f3prio site (cujo feed geralmente est\u00e1 em <code>https:\/\/seudominio.com\/feed\/<\/code>), basta alterar as configura\u00e7\u00f5es acima.<\/p>\n<h3>Cache e performance<\/h3>\n<p>O WordPress utiliza a fun\u00e7\u00e3o <code>fetch_feed()<\/code>, que armazena o feed em cache por padr\u00e3o durante <strong>12 horas<\/strong>, evitando requisi\u00e7\u00f5es repetitivas ao servidor de origem e melhorando a performance do dashboard[reference:0]. Para alterar esse intervalo (por exemplo, para for\u00e7ar atualiza\u00e7\u00e3o a cada hora), voc\u00ea pode adicionar o seguinte filtro em um MU-Plugin separado ou no pr\u00f3prio arquivo:<\/p>\n<pre><code>add_filter( 'wp_feed_cache_transient_lifetime', function( $seconds ) {\n    return 3600; \/\/ 1 hora em segundos\n} );\n<\/code><\/pre>\n<h3>Tratamento de erros e fallback<\/h3>\n<p>Se o feed estiver indispon\u00edvel (servidor fora do ar, URL incorreta), o widget exibe uma mensagem amig\u00e1vel em vez de quebrar o layout do dashboard. O mesmo ocorre se o feed estiver vazio ou se houver qualquer outro erro.<\/p>\n<h3>Teste<\/h3>\n<ol>\n<li>Ap\u00f3s criar o MU-Plugin, acesse o dashboard administrativo do WordPress (Painel \u2192 In\u00edcio).<\/li>\n<li>Voc\u00ea ver\u00e1 um novo widget, geralmente posicionado na coluna da esquerda ou direita, com o t\u00edtulo configurado (padr\u00e3o: &#8220;Neodoor \u2013 Not\u00edcias e Atualiza\u00e7\u00f5es&#8221;).<\/li>\n<li>O widget deve listar os \u00faltimos 5 posts do feed do WordPress.org, com t\u00edtulo, data e resumo (conforme sua configura\u00e7\u00e3o).<\/li>\n<li>Teste a altera\u00e7\u00e3o da URL do feed para o feed RSS de outro site (ex: seu pr\u00f3prio site).<\/li>\n<li>Para simular um erro, altere temporariamente a URL do feed para um endere\u00e7o inv\u00e1lido \u2013 o widget exibir\u00e1 a mensagem de erro.<\/li>\n<\/ol>\n<h3>Poss\u00edveis melhorias e varia\u00e7\u00f5es<\/h3>\n<ul>\n<li><strong>Suporte a m\u00faltiplos feeds:<\/strong> Para exibir feeds de v\u00e1rias fontes, adapte o c\u00f3digo para iterar sobre um array de URLs, chamando <code>fetch_feed()<\/code> para cada uma e mesclando os itens.<\/li>\n<li><strong>Link &#8220;Ver mais&#8221; ao final:<\/strong> Adicione um link para o site de origem do feed.<\/li>\n<li><strong>Permitir que o usu\u00e1rio configure a URL via tela de op\u00e7\u00f5es:<\/strong> Em vez de fixar no c\u00f3digo, crie uma p\u00e1gina de configura\u00e7\u00f5es usando a API de Op\u00e7\u00f5es do WordPress.<\/li>\n<li><strong>\u00cdcone ou imagem destacada:<\/strong> Se o feed incluir imagens, voc\u00ea pode exibi-las usando express\u00f5es regulares ou bibliotecas de parsing.<\/li>\n<\/ul>\n<h3>Compara\u00e7\u00e3o com o plugin original<\/h3>\n<p>Nosso MU-Plugin substitui as principais fun\u00e7\u00f5es do <code>dashboard-custom-feed<\/code>, com as seguintes vantagens:<\/p>\n<ul>\n<li><strong>Sem depend\u00eancias externas:<\/strong> N\u00e3o requer um plugin separado para criar\/gerenciar o feed.<\/li>\n<li><strong>Leve e transparente:<\/strong> O c\u00f3digo \u00e9 curto e vis\u00edvel, sem sobrecarga de CSS\/JS desnecess\u00e1rios.<\/li>\n<li><strong>Atualizado:<\/strong> Funciona perfeitamente nas vers\u00f5es mais recentes do WordPress (6.x).<\/li>\n<li><strong>Controle total:<\/strong> Voc\u00ea decide exatamente o que exibir e como formatar.<\/li>\n<\/ul>\n<h3>Observa\u00e7\u00f5es finais<\/h3>\n<ul>\n<li><strong>Feed deve estar ativo:<\/strong> O site de origem do feed precisa ter o RSS habilitado; caso contr\u00e1rio, o widget n\u00e3o conseguir\u00e1 recuperar os dados[reference:1].<\/li>\n<li><strong>Cache inicial:<\/strong> Ao instalar ou alterar a URL do feed, o WordPress pode demorar at\u00e9 12 horas para exibir os novos itens (a menos que voc\u00ea limpe o cache de transients). Para for\u00e7ar a atualiza\u00e7\u00e3o imediata, utilize um plugin de limpeza de cache ou execute o seguinte comando WP-CLI: <code>wp transient delete --all<\/code>.<\/li>\n<li><strong>Seguran\u00e7a:<\/strong> As fun\u00e7\u00f5es <code>esc_url()<\/code>, <code>esc_html()<\/code> e <code>wp_trim_words()<\/code> garantem que o conte\u00fado exibido seja seguro, prevenindo inje\u00e7\u00e3o de c\u00f3digo malicioso atrav\u00e9s do feed.<\/li>\n<li><strong>Personaliza\u00e7\u00e3o CSS:<\/strong> Voc\u00ea pode adicionar estilos personalizados para o widget usando o gancho <code>admin_head<\/code> ou editando o arquivo <code>admin.css<\/code> do tema, caso queira alterar cores, fontes ou espa\u00e7amentos.<\/li>\n<\/ul>\n<h3>Registro no caderno<\/h3>\n<p>Data: <\/p>\n<p>Funcionalidade: Feed RSS personalizado no painel administrativo<\/p>\n<p>Plugins substitu\u00eddos: dashboard-custom-feed (e dashboard-custom-feed-admin, se instalado)<\/p>\n<p>Tempo de implementa\u00e7\u00e3o: ~10 minutos (configura\u00e7\u00e3o e testes)<\/p>\n<p>Observa\u00e7\u00e3o: O feed padr\u00e3o aponta para wordpress.org\/news; lembre-se de alterar para a URL desejada antes de colocar em produ\u00e7\u00e3o.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Aula: Feed RSS Personalizado no Dashboard com MU-Plugin \u2013 Substituindo o Dashboard Custom Feed Objetivo: Substituir o plugin dashboard-custom-feed por um MU-Plugin enxuto, que adiciona um widget personalizado ao painel administrativo do WordPress exibindo not\u00edcias ou atualiza\u00e7\u00f5es a partir de um feed RSS, sem sobrecarga e com total controle sobre a exibi\u00e7\u00e3o. Contexto: Muitos sites [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,4],"tags":[],"class_list":["post-267","post","type-post","status-publish","format-standard","hentry","category-lessons","category-pluginsmu"],"_links":{"self":[{"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/posts\/267","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/comments?post=267"}],"version-history":[{"count":0,"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/posts\/267\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/media?parent=267"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/categories?post=267"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/tags?post=267"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}