0
15

SHARE

Como Criar um Bloco Dinâmico no WordPress com Renderização PHP

Bloco Dinâmico com Renderização no Servidor

Aprenda a criar um bloco Gutenberg que carrega posts no editor e renderiza via PHP no frontend. Estrutura profissional com render_callback!
Este post é a parte 13 de 13 da Série WordPress Extremo

Neste dia, exploramos como criar um bloco dinâmico que se adapta tanto no editor quanto no frontend, utilizando atributos do Gutenberg e a função render_callback() no PHP para gerar o HTML final — o famoso bloco com renderização via servidor.


✍️ O que você vai aprender:

  • Criar um bloco com lista de posts via REST API no editor.
  • Exibir os posts de forma dinâmica no frontend com PHP.
  • Separar responsabilidades: JS (editor) e PHP (renderização).
  • Evitar erros de conflito de blocos duplicados.
  • Estruturar o código com qualidade de produção.

✅ Pré-requisitos:

  • Plugin wp-arquitetura-extrema já iniciado.
  • Pasta blocks/posts criada.
  • WP-CLI, Composer e @wordpress/scripts funcionando.
  • Webpack configurado no webpack.config.js.

🛠️ Estrutura do bloco posts:

blocks/
└── posts/
    ├── block.json
    ├── edit.js
    ├── save.js
    ├── index.js
    └── components/
        └── PostList.js

🔁 Código do Bloco

📦 block.json

{
  "apiVersion": 2,
  "name": "wp24h/posts",
  "title": "Lista de Posts WP24H",
  "category": "widgets",
  "icon": "list-view",
  "description": "Um bloco que exibe os últimos posts via REST API.",
  "attributes": {
    "quantidade": {
      "type": "number",
      "default": 3
    }
  },
  "supports": {
    "html": false
  }
}

🧠 edit.js

import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, RangeControl } from '@wordpress/components';
import { useState, useEffect } from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';
import PostList from './components/PostList';

export default function Edit({ attributes, setAttributes }) {
  const { quantidade } = attributes;
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    apiFetch({ path: `/wp/v2/posts?per_page=${quantidade}` })
      .then(setPosts);
  }, [quantidade]);

  return (
    <>
      <InspectorControls>
        <PanelBody title="Configurações">
          <RangeControl
            label="Quantidade de posts"
            min={1}
            max={10}
            value={quantidade}
            onChange={(val) => setAttributes({ quantidade: val })}
          />
        </PanelBody>
      </InspectorControls>

      <div {...useBlockProps()}>
        <PostList posts={posts} />
      </div>
    </>
  );
}

💾 save.js

import { useBlockProps } from '@wordpress/block-editor';

export default function save() {
  return null; // Usamos render_callback no PHP
}

🧩 index.js

import { registerBlockType } from '@wordpress/blocks';
import edit from './edit';
import save from './save';
import metadata from './block.json';

registerBlockType(metadata.name, {
  ...metadata,
  edit,
  save,
});

🧷 components/PostList.js

export default function PostList({ posts }) {
  if (!posts.length) return <p>Carregando posts...</p>;

  return (
    <ul className="wp24h-post-list">
      {posts.map(post => (
        <li key={post.id}>
          <strong>{post.title.rendered}</strong>
        </li>
      ))}
    </ul>
  );
}

⚙️ PHP — inc/register/posts.php

<?php

function wp24h_render_block_posts($attributes) {
  $qtd = isset($attributes['quantidade']) ? intval($attributes['quantidade']) : 3;

  $query = new WP_Query([
    'post_type' => 'post',
    'posts_per_page' => $qtd,
  ]);

  if (!$query->have_posts()) {
    return '<p>Sem posts recentes no momento.</p>';
  }

  ob_start();
  echo '<ul class="wp24h-post-list-frontend">';
  while ($query->have_posts()) {
    $query->the_post();
    echo '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>';
  }
  echo '</ul>';

  wp_reset_postdata();
  return ob_get_clean();
}

add_action('init', function () {
  $block_path = plugin_dir_path(__FILE__) . '../../blocks/posts';
  $script_path = plugin_dir_path(__FILE__) . '../../dist/posts.asset.php';

  if (!file_exists($script_path)) return;

  $asset = include $script_path;

  wp_register_script(
    'wp24h-posts',
    plugins_url('../../dist/posts.js', __FILE__),
    $asset['dependencies'],
    $asset['version']
  );

  register_block_type($block_path, [
    'editor_script'   => 'wp24h-posts',
    'render_callback' => 'wp24h_render_block_posts',
  ]);
});

🔁 Encaixe no seu plugin:

No wp-arquitetura-extrema.php:

require_once plugin_dir_path(__FILE__) . 'inc/register/posts.php';

E no Init.php, remova 'posts' da lista de blocos:

$blocks = ['hello', 'card'];

🧱 Webpack

Garanta que o webpack.config.js está configurado para gerar múltiplos blocos:

const path = require('path');
const defaultConfig = require('@wordpress/scripts/config/webpack.config');

module.exports = {
  ...defaultConfig,
  entry: {
    hello: path.resolve(__dirname, 'blocks/hello/index.js'),
    card: path.resolve(__dirname, 'blocks/card/index.js'),
    posts: path.resolve(__dirname, 'blocks/posts/index.js'),
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js',
    clean: false
  },
};

✅ Resultado

Agora você tem um bloco 100% funcional, que:

  • Exibe posts no editor (JS com REST API).
  • Renderiza no frontend com HTML puro via PHP (render_callback).
  • Está separado, modular e pronto pra produção.

📣 CTA final

Se você curtiu esse conteúdo e quer se tornar um desenvolvedor WordPress de elite, conheça:

Navegação<< Conectando Blocos com a REST API do WordPress

Não perca mais nenhuma atualização aqui!

Ative as Notificações!

Clique aqui e, em seguida, clique em Permitir na caixa que aparecerá na parte superior da janela, próximo à barra de endereços.

Torne-se um Assinante e Eleve seu Conhecimento do WordPress!

Acesso Exclusivo, Suporte Especializado e Muito Mais.

Se você está aproveitando nosso conteúdo gratuito, vai adorar os benefícios exclusivos que oferecemos aos nossos assinantes! Ao se tornar um assinante do WP24Horas, você terá acesso a:

Não perca a oportunidade de maximizar seu potencial no WordPress. Clique no botão abaixo para se tornar um assinante e leve suas habilidades ao próximo nível!

Não perca mais nenhuma atualização aqui!

Tabela de Conteúdo
PUBLICIDADE
Últimos Posts
Conectando Blocos Gutenberg à REST API

Conectando Blocos com a REST API do WordPress

Componentes Reutilizáveis e Campos Compostos no Gutenberg

Componentes Reutilizáveis e Atributos Compostos em Blocos Gutenberg

Adicionando Imagem Ícone e Classe CSS Personalizada em Bloco Gutenberg

Ícones, Imagens e Classes Personalizadas no Gutenberg

Atributos Visuais e Estilo Dinâmico com Gutenberg

Cor, Alinhamento e Estilo Dinâmico com Gutenberg + React

Como Estilizar Blocos Gutenberg com CSS e Classes Dinâmicas

Estilizando Blocos Gutenberg com CSS e Classes Dinâmicas

Criando Campos Dinâmicos e InspectorControls no Gutenberg

Campos Dinâmicos e InspectorControls no Gutenberg: Deixe Seu Bloco Interativo

Você precisa estar logado para ver esta informação.

Torne-se um Assinante e Eleve seu Conhecimento do WordPress!

Acesso Exclusivo, Suporte Especializado e Muito Mais.

Se você está aproveitando nosso conteúdo gratuito, vai adorar os benefícios exclusivos que oferecemos aos nossos assinantes! 

Não perca a oportunidade de maximizar seu potencial no WordPress. Clique no botão abaixo para se tornar um assinante e leve suas habilidades ao próximo nível!