Om du någonsin har sett ett block som inte hittats après aggressiv cachning, eller skriptreferensen hittades inte Eftersom din build har ändrat sin hash har du berört det verkliga problemet: ett modernt block, i hood.discount 6.9.4, styrs initialt av block.json och via Block API, inte via en stack av wp_enqueue_script() spridd.

Problemet / Behovet

Du vill spara "moderna" Gutenberg-block (redigering och front-end), med korrekt deklarerade, versionsbaserade, översättningsbara och framför allt underhållbara resurser. Du vill också undvika gamla metoder som bara kastar allt i... functions.phpbryts vid den första refactoringen, och gör felsökning till ett krångel så fort du har två miljöer (dev/prod) och ett caching-plugin.

Detta innehåll riktar sig till avancerade bloggare (och deras utvecklare) som publicerar regelbundet, har prestandakrav och vill kunna utveckla sina block utan rädsla för att förstöra dem. innehåll existerande.

Till slut kommer du att veta:

  • definiera ett block via block.json (metadata, attribut, media, stilar, variationer),
  • spara PHP-sidans block med register_block_type() genom att peka på mappen,
  • Laddaren skript/stilar via wp_register_script()/wp_register_style() + pålitliga beroenden (utan att "gissa"),
  • rendera blocket i dynamisk rendering (PHP) med korrekt hygien och säkerhet (sanering/flykt),
  • testa och felsöka verkliga fall (cache, dålig hook, saknad build, föråldrad PHP, etc.).

Snabb sammanfattning

  • Vi skapar ett plugin (rekommenderas) som exponerar ett block via en mapp build/ innehållande block.json + sammanställda tillgångar.
  • Vi räddar blocket med register_block_type( __DIR__ . '/build/mon-bloc' ), som lyder block.json.
  • JS/CSS-handtag och deras beroenden deklareras explicit (helst via filen). .asset.php genererad av @wordpress/scripts).
  • Vi skapar ett dynamiskt block (PHP) för robust rendering (SEO, prestanda, temakompatibilitet), samtidigt som vi bibehåller en hyfsad förhandsvisning i redigeraren.
  • Vi lägger till en "enkel" variant (statiskt block) och en "avancerad" variant (serverrendering + cache + variationer).

När ska man använda denna lösning

  • Du behöver ett återanvändbart och versionsbart block (t.ex. nyhetsbrevsbilagor, meddelanden, "att komma ihåg"-rutor, sammanfattningar, uppmaning till uppmaning).
  • Du vill ha en serverstyrd frontend-rendering (t.ex. frågor, kontextbaserad anpassning, A/B-testning, externa data).
  • Du arbetar i ett team och vill ha en tydlig källa till sanning (block.json) snarare än fragmenterad kod.
  • Du behöver hantera WordPress JS-beroenden (paket) @wordpress/*) utan att bryta dem med varje uppdatering.
  • Du riktar in dig på WordPress 6.9.4+ och PHP 8.1+ (vilket möjliggör renare kod, lättare skrivning och moderna verktyg).

När man INTE ska använda denna lösning

  • Om du bara vill ha en enkel och stabil layout räcker det ofta med ett nativt block (Core) + globala stilar + mönster. Ta en titt på Blockera mönster et Stilvariationer innan man skriver JS.
  • Du är på en webbplats som använder 100 % Elementor/Divi/Avada, och blockredigeraren används inte för innehåll. I det här fallet är en widget/modul från verktyget mer lämplig för redaktionella team.
  • Du kan inte skapa en byggkedja (eller så vägrar du Node): du kan skapa ett väldigt enkelt block "utan att bygga", men du förlorar snabbt DX och robusthet.
  • Ditt behov härrör från en äldre shortcode som redan används flitigt. Att migrera till ett block är genomförbart, men kräver en strategi (utfasning, konvertering, innehållstestning).

Förutsättningar / innan du börjar

Jag antar att du använder WordPress 6.9.4 (april 2026) och PHP 8.1+. Om du använder en äldre version än så kommer du att stöta på en mängd problem (allvarliga fel, inkonsekventa JS-beroenden, oåterskapbara versioner).

  • Miljö en mellanlagringsplats + säkerhetskopia (databas + wp-content), inga direkta tester i produktionen.
  • Verktyg Node.js LTS (för kompilering), npm/pnpm, och helst @wordpress/scripts.
  • kunskap WordPress-hooks, REST/nonce-bas och byggkoncept (webpack/vite via WP-skript).

Användbara officiella dokument:

Det naiva tillvägagångssättet (och varför man ska undvika det)

Klassikern jag fortfarande ser år 2026: en functions.php (eller ett snippets-plugin) som spelar in ett globalt skript och försöker "skapa ett block" med hjälp av inline JS, utan block.json, utan en fil .asset.php, utan korrekt beroendehantering.

<?php
// Exemple volontairement naïf : à éviter.
add_action('init', function () {
    wp_enqueue_script(
        'mon-bloc-js',
        get_stylesheet_directory_uri() . '/js/mon-bloc.js',
        array('wp-blocks', 'wp-element', 'wp-editor'),
        '1.0.0',
        true
    );
});

Mer specifikt, varför är detta ett problem?

  • Dålig krok : wp_enqueue_script() i init Den riktar sig inte korrekt mot utgivaren (och kan förorena användargränssnittet). Du vill enqueue_block_editor_assets eller, ännu hellre, deklarera via block.json + registrering.
  • Sköra beroenden Du "gissar" handtagen. Med utvecklingen av Block Editor får du fel som wp är inte definierad eller paket laddade två gånger.
  • Cache och versioner Utan byggbaserad versionshantering använder du föråldrad JS (den vanligaste buggen på webbplatser med Cloudflare + cache-plugin).
  • Underhåll Det är omöjligt att förstå blocket utan att gräva igenom flera filer och hooks.
  • Säkerhet När rendering endast görs på JS-sidan injicerar många oescaped data i front-end.

Rätt tillvägagångssätt — steg-för-steg-handledning

Steg 1 — Skapa ett dedikerat plugin (snarare än ett tema)

Ett block är en funktion. Enligt min erfarenhet förhindrar det att innehåll går förlorat när man byter tema om man lägger till det i ett plugin.

# wp-content/plugins/bpcab-blocs/
mkdir -p wp-content/plugins/bpcab-blocs
<?php
/**
 * Plugin Name: BPCAB Blocs
 * Description: Blocs personnalisés modernes via block.json (WP 6.9.4+).
 * Version: 1.0.0
 * Requires at least: 6.9
 * Requires PHP: 8.1
 * Author: Votre Nom
 */

defined('ABSPATH') || exit;

require_once __DIR__ . '/src/Plugin.php';

add_action('plugins_loaded', static function () {
    BPCABBlocksPlugin::instance()->boot();
});

Steg 2 — Lägg till en liten "servicebehållare" (ren och testbar)

Du behöver inte använda DI, men så fort du har 2-3 block lönar det sig. Det undviker också globala funktionskollisioner.

<?php
// wp-content/plugins/bpcab-blocs/src/Plugin.php

namespace BPCABBlocks;

defined('ABSPATH') || exit;

final class Plugin {
    private static ?self $instance = null;

    /** @var array<string, object> */
    private array $services = [];

    public static function instance(): self {
        return self::$instance ??= new self();
    }

    public function boot(): void {
        $this->register_services();
        $this->init_hooks();
    }

    private function register_services(): void {
        $this->services['blocks'] = new ServiceBlocksRegistry(__DIR__ . '/../build');
    }

    private function init_hooks(): void {
        add_action('init', [$this->services['blocks'], 'register_blocks']);
    }
}

Steg 3 — Skapa blockmappen och dess block.json-fil

Vi ska skapa ett block med namnet "Anteckningsruta" (statiskt på redigeringssidan, dynamiskt renderat på användargränssnittet). block.json är sanningens källa.

mkdir -p wp-content/plugins/bpcab-blocs/build/note-box
{
  "$schema": "https://schemas.wp.org/trunk/block.json",
  "apiVersion": 3,
  "name": "bpcab/note-box",
  "version": "1.0.0",
  "title": "Encart Note (BPCAB)",
  "category": "text",
  "icon": "info-outline",
  "description": "Encart éditorial avec titre, contenu et style.",
  "textdomain": "bpcab-blocs",
  "attributes": {
    "title": {
      "type": "string",
      "default": "À retenir"
    },
    "tone": {
      "type": "string",
      "default": "info"
    }
  },
  "supports": {
    "anchor": true,
    "align": ["wide", "full"],
    "html": false,
    "spacing": {
      "margin": true,
      "padding": true
    },
    "color": {
      "background": true,
      "text": true
    },
    "typography": {
      "fontSize": true,
      "lineHeight": true
    }
  },
  "editorScript": "bpcab-note-box-editor",
  "style": "bpcab-note-box-style",
  "render": "file:./render.php"
}

Tekniska anmärkningar:

  • apiVersion: 3 är grunden för moderna block (och överensstämmer med WP 6.9.x).
  • render Pekar på en PHP-fil: detta är ett dynamiskt block. Mycket användbart för att upprätthålla en stabil front-end HTML, även om editorn ändras.
  • editorScript et style hänvisning handtag WordPress. Vi kommer att deklarera dem korrekt.

Steg 4 — Deklarera tillgångarna med .asset.php (betrodda beroenden)

Det robusta mönstret är: bygg JS → genererar en fil index.asset.php som innehåller dependencies + versionDet är just detta som undviker "gissade handtag".

För att hålla det 100 % kopierbart och klistrabart här, ska jag visa dig PHP-sidan som användningar den här filen. (Du kan generera den här versionen via @wordpress/skript.)

Steg 5 — Registrera blocket med register_block_type(), som pekar på mappen

Vi skapar ett register som skannar en mapp build/ och registrerar varje block som innehåller en block.jsonDetta är ett mönster jag ofta använder på webbplatser med flera block.

<?php
// wp-content/plugins/bpcab-blocs/src/Service/BlocksRegistry.php

namespace BPCABBlocksService;

use WP_Error;

defined('ABSPATH') || exit;

final class BlocksRegistry {
    public function __construct(
        private readonly string $build_dir
    ) {}

    public function register_blocks(): void {
        if (!function_exists('register_block_type')) {
            // Sécurité : si l’API n’est pas disponible (cas rarissime), on stoppe.
            return;
        }

        $block_dirs = glob($this->build_dir . '/*', GLOB_ONLYDIR) ?: [];

        foreach ($block_dirs as $dir) {
            $block_json = $dir . '/block.json';
            if (!is_readable($block_json)) {
                continue;
            }

            // 1) Enregistrer les assets référencés par block.json (handles)
            $this->register_assets_for_block_dir($dir);

            // 2) Enregistrer le bloc à partir de son dossier (lit block.json)
            $result = register_block_type($dir);

            if ($result === false) {
                // En prod, évitez de spammer les logs. Ici, c’est volontairement visible.
                error_log('[BPCAB] Échec register_block_type pour: ' . $dir);
            }
        }
    }

    private function register_assets_for_block_dir(string $dir): void {
        // Convention : build/note-box/index.js + index.asset.php + style.css
        $slug = basename($dir);

        $editor_handle = 'bpcab-' . $slug . '-editor';
        $style_handle  = 'bpcab-' . $slug . '-style';

        $editor_js     = $dir . '/index.js';
        $editor_asset  = $dir . '/index.asset.php';
        $style_css     = $dir . '/style.css';

        if (is_readable($editor_js) && is_readable($editor_asset)) {
            $asset = require $editor_asset;

            $deps = isset($asset['dependencies']) && is_array($asset['dependencies'])
                ? $asset['dependencies']
                : [];

            $ver = isset($asset['version']) && is_string($asset['version'])
                ? $asset['version']
                : filemtime($editor_js);

            wp_register_script(
                $editor_handle,
                plugins_url('build/' . $slug . '/index.js', dirname(__DIR__, 2) . '/bpcab-blocs.php'),
                $deps,
                $ver,
                true
            );

            // Optionnel : traductions JS si vous utilisez i18n côté JS.
            // wp_set_script_translations($editor_handle, 'bpcab-blocs', plugin_dir_path(...). 'languages');
        }

        if (is_readable($style_css)) {
            wp_register_style(
                $style_handle,
                plugins_url('build/' . $slug . '/style.css', dirname(__DIR__, 2) . '/bpcab-blocs.php'),
                [],
                filemtime($style_css)
            );
        }
    }
}

Ja den plugins_url() Att använda en "ankare"-sökväg är jobbigt. Jag håller det tydligt eftersom det är en av de buggar jag ser oftast: tillgångs-URL:er som pekar till fel plugin efter en omstrukturering. Alternativ: definiera en konstant BPCAB_BLOCKS_FILE i huvudfilen.

Steg 6 — Skriv serversidans rendering (render.php) med hygien och säkerhet i åtanke.

Serversidesrendering bör behandla attribut som användarinmatning. Även om editorn verkar "säker" kan ett attribut injiceras via REST eller innehållsimport.

<?php
// wp-content/plugins/bpcab-blocs/build/note-box/render.php

defined('ABSPATH') || exit;

/**
 * Rendu serveur du bloc bpcab/note-box.
 *
 * @param array $attributes Attributs du bloc (non fiables).
 * @param string $content Contenu interne (si InnerBlocks).
 * @param WP_Block $block Instance du bloc.
 */
return function (array $attributes, string $content, $block): string {
    $title = isset($attributes['title']) ? sanitize_text_field($attributes['title']) : 'À retenir';
    $tone  = isset($attributes['tone']) ? sanitize_key($attributes['tone']) : 'info';

    $allowed_tones = ['info', 'warning', 'success'];
    if (!in_array($tone, $allowed_tones, true)) {
        $tone = 'info';
    }

    // Récupère des classes générées par WordPress (align, spacing, colors, typography, etc.)
    $wrapper_attributes = get_block_wrapper_attributes([
        'class' => 'bpcab-note-box bpcab-note-box--' . $tone,
    ]);

    ob_start();
    ?>
    <div <?php echo $wrapper_attributes; ?>>
        <div class="bpcab-note-box__title"><?php echo esc_html($title); ?></div>
        <div class="bpcab-note-box__content">
            <?php
            // Ici, on autorise seulement du HTML “post” standard.
            // Si vous n’avez pas besoin de HTML, préférez esc_html().
            echo wp_kses_post($content);
            ?>
        </div>
    </div>
    <?php
    return (string) ob_get_clean();
};

Steg 7 — Minimal och stabil front-end CSS (style.css)

/* wp-content/plugins/bpcab-blocs/build/note-box/style.css */
.bpcab-note-box {
  border-left: 4px solid currentColor;
  padding: 1rem;
  background: rgba(0,0,0,.03);
}

.bpcab-note-box__title {
  font-weight: 700;
  margin-bottom: .5rem;
}

.bpcab-note-box--info { color: #0b5fff; }
.bpcab-note-box--warning { color: #b45309; }
.bpcab-note-box--success { color: #15803d; }

Steg 8 — JS-redigeraren (index.js): redigera enkelt användargränssnitt

Jag ger ett minimalt exempel. I praktiken kommer du att kompilera det (och generera index.asset.php).

// wp-content/plugins/bpcab-blocs/build/note-box/index.js
import { registerBlockType } from '@wordpress/blocks';
import { InspectorControls, RichText, useBlockProps, InnerBlocks } from '@wordpress/block-editor';
import { PanelBody, SelectControl, TextControl } from '@wordpress/components';

registerBlockType('bpcab/note-box', {
	edit({ attributes, setAttributes }) {
		const { title, tone } = attributes;

		const blockProps = useBlockProps();

		return (
			<>
				<InspectorControls>
					<PanelBody title="Réglages">
						<TextControl
							label="Titre"
							value={ title }
							onChange={ (value) => setAttributes({ title: value }) }
						/>
						<SelectControl
							label="Ton"
							value={ tone }
							options={ [
								{ label: 'Info', value: 'info' },
								{ label: 'Avertissement', value: 'warning' },
								{ label: 'Succès', value: 'success' },
							] }
							onChange={ (value) => setAttributes({ tone: value }) }
						/>
					</PanelBody>
				</InspectorControls>

				<div { ...blockProps }>
					<div className="bpcab-note-box__title">
						<RichText
							tagName="span"
							value={ title }
							allowedFormats={ [] }
							onChange={ (value) => setAttributes({ title: value }) }
							placeholder="Titre…"
						/>
					</div>
					<div className="bpcab-note-box__content">
						<InnerBlocks
							template={ [
								['core/paragraph', { placeholder: 'Votre note…' }],
							] }
							templateLock={ false }
						/>
					</div>
				</div>
			</>
		);
	},

	// Bloc dynamique : le HTML front est rendu par render.php
	save() {
		return <InnerBlocks.Content />;
	},
});

Fullständig kod

Här är det minimala funktionspaketet (plugin + register + block). Du måste lägga till själva JS-bygget (eller använda din pipeline) för att generera det. index.asset.phpResten kan kopieras och klistras in som det är.

Trädväxt

wp-content/plugins/bpcab-blocs/
  bpcab-blocs.php
  src/
    Plugin.php
    Service/
      BlocksRegistry.php
  build/
    note-box/
      block.json
      render.php
      style.css
      index.js
      index.asset.php   # généré par build (ex: @wordpress/scripts)

bpcab-block.php

<?php
/**
 * Plugin Name: BPCAB Blocs
 * Description: Blocs personnalisés modernes via block.json (WP 6.9.4+).
 * Version: 1.0.0
 * Requires at least: 6.9
 * Requires PHP: 8.1
 */

defined('ABSPATH') || exit;

define('BPCAB_BLOCKS_FILE', __FILE__);
define('BPCAB_BLOCKS_DIR', __DIR__);

require_once BPCAB_BLOCKS_DIR . '/src/Plugin.php';

add_action('plugins_loaded', static function () {
    BPCABBlocksPlugin::instance()->boot();
});

src/Plugin.php

<?php
namespace BPCABBlocks;

defined('ABSPATH') || exit;

final class Plugin {
    private static ?self $instance = null;

    /** @var array<string, object> */
    private array $services = [];

    public static function instance(): self {
        return self::$instance ??= new self();
    }

    public function boot(): void {
        $this->register_services();
        $this->init_hooks();
    }

    private function register_services(): void {
        $this->services['blocks'] = new ServiceBlocksRegistry(BPCAB_BLOCKS_DIR . '/build');
    }

    private function init_hooks(): void {
        add_action('init', [$this->services['blocks'], 'register_blocks']);
    }
}

src/Tjänst/Blockregister.php

<?php
namespace BPCABBlocksService;

defined('ABSPATH') || exit;

final class BlocksRegistry {
    public function __construct(
        private readonly string $build_dir
    ) {}

    public function register_blocks(): void {
        $block_dirs = glob($this->build_dir . '/*', GLOB_ONLYDIR) ?: [];

        foreach ($block_dirs as $dir) {
            if (!is_readable($dir . '/block.json')) {
                continue;
            }

            $this->register_assets_for_block_dir($dir);

            $result = register_block_type($dir);
            if ($result === false) {
                error_log('[BPCAB] Échec register_block_type pour: ' . $dir);
            }
        }
    }

    private function register_assets_for_block_dir(string $dir): void {
        $slug = basename($dir);

        $editor_handle = 'bpcab-' . $slug . '-editor';
        $style_handle  = 'bpcab-' . $slug . '-style';

        $editor_js     = $dir . '/index.js';
        $editor_asset  = $dir . '/index.asset.php';
        $style_css     = $dir . '/style.css';

        if (is_readable($editor_js) && is_readable($editor_asset)) {
            $asset = require $editor_asset;

            $deps = (isset($asset['dependencies']) && is_array($asset['dependencies']))
                ? $asset['dependencies']
                : [];

            $ver = (isset($asset['version']) && is_string($asset['version']))
                ? $asset['version']
                : (string) filemtime($editor_js);

            wp_register_script(
                $editor_handle,
                plugins_url('build/' . $slug . '/index.js', BPCAB_BLOCKS_FILE),
                $deps,
                $ver,
                true
            );
        }

        if (is_readable($style_css)) {
            wp_register_style(
                $style_handle,
                plugins_url('build/' . $slug . '/style.css', BPCAB_BLOCKS_FILE),
                [],
                (string) filemtime($style_css)
            );
        }
    }
}

bygg/anteckningsruta/block.json

{
  "$schema": "https://schemas.wp.org/trunk/block.json",
  "apiVersion": 3,
  "name": "bpcab/note-box",
  "version": "1.0.0",
  "title": "Encart Note (BPCAB)",
  "category": "text",
  "icon": "info-outline",
  "description": "Encart éditorial avec titre, contenu et style.",
  "textdomain": "bpcab-blocs",
  "attributes": {
    "title": { "type": "string", "default": "À retenir" },
    "tone": { "type": "string", "default": "info" }
  },
  "supports": {
    "anchor": true,
    "align": ["wide", "full"],
    "html": false,
    "spacing": { "margin": true, "padding": true },
    "color": { "background": true, "text": true },
    "typography": { "fontSize": true, "lineHeight": true }
  },
  "editorScript": "bpcab-note-box-editor",
  "style": "bpcab-note-box-style",
  "render": "file:./render.php"
}

build/note-box/render.php

<?php
defined('ABSPATH') || exit;

return function (array $attributes, string $content, $block): string {
    $title = isset($attributes['title']) ? sanitize_text_field($attributes['title']) : 'À retenir';
    $tone  = isset($attributes['tone']) ? sanitize_key($attributes['tone']) : 'info';

    $allowed_tones = ['info', 'warning', 'success'];
    if (!in_array($tone, $allowed_tones, true)) {
        $tone = 'info';
    }

    $wrapper_attributes = get_block_wrapper_attributes([
        'class' => 'bpcab-note-box bpcab-note-box--' . $tone,
    ]);

    ob_start();
    ?>
    <div <?php echo $wrapper_attributes; ?>>
        <div class="bpcab-note-box__title"><?php echo esc_html($title); ?></div>
        <div class="bpcab-note-box__content"><?php echo wp_kses_post($content); ?></div>
    </div>
    <?php
    return (string) ob_get_clean();
};

build/note-box/style.css

.bpcab-note-box {
  border-left: 4px solid currentColor;
  padding: 1rem;
  background: rgba(0,0,0,.03);
}

.bpcab-note-box__title {
  font-weight: 700;
  margin-bottom: .5rem;
}

.bpcab-note-box--info { color: #0b5fff; }
.bpcab-note-box--warning { color: #b45309; }
.bpcab-note-box--success { color: #15803d; }

build/note-box/index.asset.php (exempel)

Den här filen genereras av ditt byggverktyg. Realistiskt exempel (beroenden varierar beroende på din kod).

<?php
// Fichier généré automatiquement par le build.
return array(
    'dependencies' => array(
        'wp-blocks',
        'wp-element',
        'wp-components',
        'wp-block-editor',
        'wp-i18n',
    ),
    'version' => 'b7c1b2d9f1a2',
);

Kodförklaring

Varför block.json är banbrytande

block.json Den centraliserar metadata (namn, ikon, attribut, media) och tillgångsdeklarationer (editorScript/style/render). WordPress kan läsa den här filen och bygga blockposten. Resultatet: mindre "fast" PHP-kod och en struktur som dina verktyg (build, lint, CI) förstår.

Den officiella referensen finns här: Blockera metadata.

Varför är register_block_type($dir) rätt ingångspunkt?

register_block_type() accepterar en mappsökväg. WordPress letar där block.jsonoch härleder blocket. Du undviker enorma PHP-arrayer som duplicerar information.

Dokument: register_block_type().

Varför registrerar vi handles före register_block_type()?

I din block.json, editorScript et style peka på handtag (t.ex. bpcab-note-box-editorWordPress känner inte igen sin URL. Därför är det nödvändigt att... wp_register_script() / wp_register_style() innan du sparar blocket, annars kommer du att ha saknade resurser (eller ett block som redigeras utan ett användargränssnitt).

Dokument: wp_register_script() et wp_register_style().

Varför serversidesrendering (render.php) ofta är mer tillförlitlig

När blocket är dynamiskt "sparas" inte front-end-HTML:en i innehållet. Den beräknas om. Detta hjälper eftersom:

  • corriger en HTML/CSS-bugg utan att "migrera" alla inlägg,
  • lägg till en klass, en wrapper, strukturerad data,
  • hantera kontexter (kategorier, författare, ACF, alternativ) på PHP-sidan.

I gengäld måste du vara uppmärksam på cachen (sidcache, fragmentcache) och markupens stabilitet (för att undvika SEO-överraskningar).

Sanering och flykt (båda, inte det ena eller det andra)

  • sanitization vid posten (här, attribut): sanitize_text_field(), sanitize_key().
  • Validering domän (här, $allowed_tones): du avvisar alla oväntade värden.
  • Flyr utdata (HTML): esc_html()och wp_kses_post() om du tillåter en delmängd av HTML.

Jag har ofta sett "interna" block injiceras med konstiga värden via import/export eller API. Behandla attribut som opålitliga, systematiskt.

Varianter och användningsfall

Variant 1 — Statiskt block (full save()) för webbplatser utan serversidesrendering

Om du vill ha ett block som sparar sin slutliga HTML i inlägget (mindre PHP, enklare att hosta), ta bort "render" i block.json och göra en save() vilket gör strukturen komplett. Obs: om du ändrar markeringen senare måste du hantera deprecated på JS-sidan för att inte förstöra det gamla innehållet.

Variant 2 — Lägga till en stil som endast är för redaktörer

På block med ett kompakt gränssnitt separerar jag ofta editorns CSS (för användbarhet) från front-end CSS (för prestanda). block.json en nyckel editorStyle (handtag) och spara det som style.

{
  "editorStyle": "bpcab-note-box-editor-style"
}

Variant 3 — Rendering av cache (fragmentcache) för dyra dynamiska block

Om din renderingsprocess gör en extern förfrågan eller en tung WP_Query-förfrågan, implementera en tillfällig cache per inlägg + attribut. Ett klassiskt edge-fall: ogiltigförklara cachen när inlägget uppdateras.

<?php
// Exemple de pattern (à adapter) : cache par post ID + hash attributs.
$key = 'bpcab_nb_' . (int) ($block->context['postId'] ?? 0) . '_' . md5(wp_json_encode($attributes));

$cached = get_transient($key);
if (is_string($cached) && $cached !== '') {
    return $cached;
}

$html = '...'; // générez votre HTML

set_transient($key, $html, HOUR_IN_SECONDS);
return $html;

Se upp för ogiltigförklaringar: om du gömmer dig via post, ogiltigförklara den save_post och om modifiering av globala alternativ.

Divi 5 / Elementor / Avada-kompatibilitet

Gutenberg-block fungerar generellt sett bra tillsammans med Divi 5, Elementor och Avada, men det finns några praktiska detaljer.

Avdelning 5

  • Om dina sidor är byggda i Divi kommer blocket att vara mest användbart i WordPress inbyggda redigerare (inlägg, CPT). Håll blockets CSS mycket namnavståndsbaserat (som .bpcab-note-box) för att undvika globala Divi-stilar.
  • Om Divi tillämpar aggressiva globala typografiska stilar, använd stöd typography och låt användaren justera det i redigeraren.

Elementor

  • Elementor kan omsluta innehåll i omslag. Undvik CSS-selektorer som är alltför beroende av den överordnade DOM-strukturen.
  • Om du infogar blocket i ett Elementor-"Shortcode"- eller "HTML"-område via innehållsrendering, testa bredden (alignwide/full): Vissa Elementor-teman begränsar bredden via max-width.

Avada (Fusion Builder)

  • Avada har ofta ett kritiskt CSS- och resurscachningssystem. Efter att du har lagt till/modifierat ett block, rensa Avada-cachen + webbläsarcachen, annars kommer du att tro att style.css Den laddas inte.
  • Om Avada minifierar/sammanfogar, verifiera att dina handles förblir stabila (därav vikten av versionshantering genom filemtime eller hash-bygge).

Kontroller efter installationen

  1. Synligt block Sök efter ”Note Insert (BPCAB)” i redigeraren. Om det inte visas finns det ett registreringsproblem (init, sökvägar, ogiltig block.json).
  2. Tillgångar laddade Öppna nätverksinspektören i redigeraren och kontrollera att build/note-box/index.js et style.css är laddade.
  3. Renderad framsida Publicera ett inlägg, kontrollera den genererade HTML-koden. Du borde se class="bpcab-note-box ...".
  4. Stöder Testa ankaret, färgerna och utfyllnaden/marginalen. Kontrollera att get_block_wrapper_attributes() återspeglar dina val.
  5. Cache Om du har ett cachande plugin, utför en fullständig rensning efter att du har lagt till pluginet och byggt det.

Om det inte fungerar

Procedur jag tillämpar när ett block misslyckas med att ladda (och som undviker att gå av i alla riktningar).

1) Kontrollera PHP-fel (loggar)

  • aktivera WP_DEBUG et WP_DEBUG_LOG på iscensättning.
  • se wp-content/debug.log.
  • Vanliga fel: PHP < 8.1, felaktig sökväg till filen, require av en saknad fil.

2) Kontrollera att init körs

Om du placerar koden på fel ställe (ett kodavsnitt som inte laddas på init(eller ett felplacerat MU-plugin), register_block_type() vänder aldrig. Lägg tillfälligt till en error_log() i register_blocks() att bekräfta.

3) Kontrollera block.json (ogiltig JSON)

Ett extra kommatecken och WordPress ignorerar blocket. Validera JSON. I vissa team har jag sett filer sparade i UTF-8 med BOM som orsakar överraskningar.

4) Kontrollera tillgångshandtagen

Si block.json innehåller "editorScript": "bpcab-note-box-editor"då behöver din PHP registreras exakt Detta användarnamn. En annan bokstav, och redigeraren har inte ditt användargränssnitt.

5) Rensa cacheminnen (på riktigt)

  • cache-plugin (sida/objekt),
  • servercache (Nginx fastcgi, varnish),
  • CDN (Cloudflare),
  • webbläsarens cache (hård omladdning).

Diagnostiskt diagram (snabbt)

Symptôme Trolig orsak verifiering Lösning
Blocket visas inte i infogningen. block.json oläst / JSON-fel / hooken kördes inte PHP-loggar + kontroll build/*/block.json Korrigera JSON, verifiera add_action('init', ...)stigar
Blocket visas, men användargränssnittet är trasigt. Redigeringsskriptet laddades inte (handle/dependencies) Webbläsarkonsol (redigerare) + fliken Nätverk Kontrollera handtag, generera index.asset.php, rensa cacheminnor
Front-end CSS gäller inte style inte registrerad eller Avada/Autooptimize-cache Se HTML-källa + link rel="stylesheet" Kontrollanten wp_register_style, rensning/minifiering
Felet ”Anrop till odefinierad funktion register_block_type” Kod körd för tidigt / trasig miljö Stacktrace Kör vidare init, kontrollera WP Core-laddningen
Frontrenderingen är tom render.php returnerar inte ett giltigt återanrop Aktivera felsökning + testa en return '<div>ok</div>'; Att korrigera return function (...) { ... }, kontrollera behörigheter/fel

Vanliga fallgropar och misstag

Fel Orsak Lösning
Koden är kopierad till fel fil (tema istället för plugin). Temabyte = block borta Lägg inspelningen i ett plugin, behåll temat för designändamål.
Parsefel: syntaxfel, oväntat... Saknar parenteser/semikolon i ett utdrag Kör plugin-programmet i en linter/IDE och aktivera loggning vid staging.
utiliser wp_enqueue_script istället för wp_register_script Skriptet laddas överallt och/eller för tidigt Deklarera handle-filen, låt WordPress ladda den vid behov via block.json
Olämplig krok (plugins_loaded istället för init) API-block är inte klara / ladda order Spara på init (standardprioritet), eller justera vid behov
Cachekonflikt (gammal JS-serverad) Fryst tillgångsversion utiliser .asset.php (hash) eller filemtimerensa CDN
index.asset.php saknas Byggnaden har inte körts, distributionen är ofullständig Lägg till ett CI/CD-steg, eller en reservfunktion (men dokumentera det).
Permanenta länkar genereras inte om (indirekt gemener och skiftläge) Efter migrering, inkonsekventa slutpunkter/omskrivningar Spara permalänkarna igen (Inställningar > Permalänkar > Spara)
Förvirring mellan aktier och filter Att returnera ett värde i en åtgärd är meningslöst. utiliser add_action att utföra, add_filter att förvandla
CSS/JS laddades inte på grund av en felaktig URL plugins_url förankrad till fel fil definiera BPCAB_BLOCKS_FILE och hänvisa till det överallt
Fel relaterat till en föråldrad PHP-version PHP 8.1-syntax (typer, skrivskyddade egenskaper) Uppgradera PHP, eller ta bort moderna funktioner (rekommenderas inte)
Kod från en gammal handledning (pre-block.json) är inkompatibel Äldre metod, osäkra beroenden Återgå till block.json + register_block_type($dir)

Tips för säkerhet, prestanda och underhåll

  • Säkerhet Behandla attribut som opålitliga. Sanering + validering + escape. För rik HTML, wp_kses_post() är ett minimum, men begränsa det om möjligt.
  • Prestanda Undvik att ladda globala skript. Koppling block.json Registrerade handles gör att WordPress kan laddas på rätt plats.
  • stabilitet För ett statiskt block, planera deprecated På JS-sidan, om du ändrar markupen. För ett dynamiskt block, håll frontend-markupen stabil (klasser, struktur), annars skapar du CSS-regressioner.
  • Reproducerbar byggnation Den främsta orsaken till "trasiga" block i produktion är en odistribuerad lokal version. Lägg till ett CI-steg som producerar build/ och arkivet.
  • Framtida kompatibilitet Undvik att använda instabila JavaScript API:er. Håll dig till dokumenterade paket. Följ det officiella arkivet. WordPress/Gutenberg.

För att spåra kärnförändringar (och förstå varför ett beteende förändras) håller jag ett öga på Trac och Gutenberg pull requests. Trac: core.trac.wordpress.org.

Resurser

FAQ

Måste jag absolut använda ett plugin snarare än ett tema?

Om blocket används inom innehållet, ja, i de flesta fall. Annars länkar du ditt innehåll till ett tema. Jag har sett migreringar där 300 artiklar förlorat sina block eftersom temat ändrades.

Varför visas mitt block, men kontrollerna (InspectorControls) visas inte?

Nästan alltid: redigeringsskriptet laddas inte. Kontrollera referensen i block.json och det av wp_register_script()Kontrollera sedan det index.asset.php finns och innehåller korrekta beroenden.

Jag kan lägga file:./index.js direkt i block.json?

Du kan referera till filer via file: I vissa sammanhang, men i praktiken (och i produktion), föredrar jag +-handtagen wp_register_script avec .asset.phpDetta är mer förutsägbart med cachning/CDN och CI-pipelines.

Hur hanterar man översättningar på JS-sidan?

användning wp_set_script_translations() på redigerarens skripthandtag och en textdomain Håll dina filer konsekventa. .po/.mo i en mapp languagesDokument: wp_set_script_translations().

Dynamiskt eller statiskt block: vilket ska man välja?

  • dynamisk om renderingen behöver ändras, eller beror på sammanhanget, eller om du vill göra korrigeringar utan att migrera innehållet.
  • statique om du vill ha en "fryst" HTML i inlägget, enkel att exportera och utan PHP-beroende.

Varför använda get_block_wrapper_attributes() istället för att bygga klassrummen för hand?

Eftersom WordPress automatiskt lägger till attribut/klasser relaterade till elementen (justering, avstånd, färger etc.). Om du bygger om allt manuellt förlorar du funktionalitet och temat fungerar sämre.

Min CSS är laddad, men den åsidosätts av temat (eller Divi/Avada). Vad ska jag göra?

Undvik att öka specificiteten i all oändlighet. Namnrym dina klasser (som .bpcab-note-boxAtt använda CSS-variabler eller stöd för färg/typografi är ofta mer robust. Och testa med temats CSS under verkliga förhållanden.

Kan jag automatiskt skanna alla block i build/ som i exemplet?

Ja, det är praktiskt. För mycket stora plugins föredrar jag ibland en explicit lista (för att kontrollera ordningen, hantera beroenden eller inaktivera ett block). Skanningen fungerar bra så länge man upprätthåller en strikt konvention.

Vad händer om ett minifierings-plugin sammanfogar och stör redigeraren?

Inaktivera minifiering på administratören/redigeraren, eller exkludera dina handles. Jag har ofta sett Autoptimize/LSCache förstöra Block Editor-skript om de är felkonfigurerade.

Hur spårar man ändringar i Block API över tid?

Följ WordPress versionsinformation på utvecklare.wordpress.org/nyheteroch repo WordPress/GutenbergFör kärnändringar är Trac fortfarande den primära källan: core.trac.wordpress.org.