Skip to content

Editor integration

Expose theme tokens, breakpoints, and custom icons to the editor.

Provide Tailwind-like config and breakpoints

ts
import { addFilter } from '@wordpress/hooks';

import webentorConfig, { customTypographyKeys } from '../../webentor-config';

addFilter('webentor.core.twBreakpoints', 'theme/bp', (bps) => {
  for (const key in webentorConfig.theme.screens) {
    if (!bps.includes(key)) bps.push(key);
  }
  return bps;
});

addFilter('webentor.core.twTheme', 'theme/tw', () => webentorConfig.theme);

addFilter('webentor.core.customTypographyKeys', 'theme/typo', () => [
  { key: 'none', name: 'None', value: '', __experimentalHint: 'Inherit' },
  ...customTypographyKeys.map((i) => ({
    key: i.key,
    name: i.key,
    value: i.key,
    __experimentalHint: i.size,
  })),
]);

Customize quick layout presets

Register the preset filter in the same editor bootstrap where you already wire breakpoints and theme tokens. Core starts with an empty preset array, so the normal pattern is to return a fresh list for the blocks your theme supports:

ts
addFilter(
  'webentor.core.responsiveSettings.layoutPresets',
  'theme/responsive/presets',
  (_presets, blockName, twTheme) => {
    if (blockName === 'webentor/l-flexible-container') {
      return [
        {
          id: 'content-stack',
          label: 'Content Stack',
          description: 'Vertical flex stack with theme spacing',
          applies: {
            layout: {
              display: { value: { basic: 'flex' } },
            },
            flexbox: {
              'flex-direction': { value: { basic: 'flex-col' } },
              gap: {
                value: {
                  basic: 'gap-8',
                },
              },
            },
          },
        },
        {
          id: 'two-col-grid',
          label: '2 Column Grid',
          description: 'Simple grid for equal-width content',
          applies: {
            layout: {
              display: { value: { basic: 'grid' } },
            },
            grid: {
              'grid-cols': { value: { basic: 'grid-cols-2' } },
              gap: { value: { basic: 'gap-6' } },
            },
          },
        },
      ];
    }

    return [];
  },
);

Returning [] hides the preset UI for blocks that do not have a theme-defined catalog. If you share presets across multiple blocks, extract a helper and return that helper result from the filter.

When a preset needs classes that are not generated by the standard responsive settings modules, add them with customClasses and make sure they exist in theme CSS and in your safelist when the build cannot discover them statically:

ts
addFilter(
  'webentor.core.responsiveSettings.layoutPresets',
  'theme/responsive/custom-classes',
  (_presets, blockName) => {
    if (blockName !== 'webentor/l-flexible-container') {
      return [];
    }

    return [
      {
        id: 'flex-3-col-wrap',
        label: '3 Column Wrap',
        description: 'Wraps into equal-width columns with custom utilities',
        applies: {
          layout: {
            display: { value: { basic: 'flex' } },
          },
          flexbox: {
            'flex-wrap': { value: { basic: 'flex-wrap' } },
          },
        },
        customClasses: ['w-flex-cols', 'w-flex-cols-3', 'w-gap-4'],
      },
    ];
  },
);

Register custom icons for Icon Picker

ts
import { registerIcons } from '@10up/block-components';

const svgFiles = import.meta.glob('../../images/svg/*.svg', {
  eager: true,
  query: '?raw',
  import: 'default',
});
const icons = Object.keys(svgFiles).map((p) => {
  const name = p.split('/').pop().replace('.svg', '');
  return { source: svgFiles[p] as string, name, label: name };
});

registerIcons({ name: 'webentor', label: 'Webentor', icons });

Auto-import block editors

ts
// resources/scripts/editor.ts
import './blocks-filters/_core-init';
import './blocks-filters/_register-icons';

import.meta.glob('../blocks/**/*.block.{ts,tsx}', { eager: true });