|
1 | 1 | # CLAUDE.md |
2 | 2 |
|
3 | | -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 3 | +WordPress plugin that extends the native Gutenberg `core/code` block with Prism.js syntax highlighting. The editor integration is implemented by replacing the `core/code` block edit/save behaviour via a JS block filter, while frontend output is normalized and enhanced through the `render_block_core/code` PHP filter. |
4 | 4 |
|
5 | 5 | ## Commands |
6 | 6 |
|
7 | 7 | ```bash |
8 | | -npm install # Install dependencies (includes prismjs + prism-themes) |
9 | | -npm run build # Production build → build/ (compiles index.js + frontend.js) |
10 | | -npm run build:assets # Copy Prism theme CSS from node_modules → assets/ |
11 | | -npm run start # Development watch mode |
12 | | -npm run lint:js # Lint JS source |
13 | | -npm run lint:css # Lint CSS/SCSS source |
14 | | -npm run format # Auto-format source files |
15 | | -npm run zip # Build distributable zip |
16 | | -``` |
17 | | - |
18 | | -First-time setup requires both: `npm install && npm run build && npm run build:assets` |
19 | | - |
20 | | -PHP linting (requires phpcs + WordPress Coding Standards): |
21 | | -```bash |
| 8 | +# PHP |
22 | 9 | composer install |
23 | | -vendor/bin/phpcs |
| 10 | +composer test |
| 11 | +composer phpcs |
| 12 | +composer phpstan |
| 13 | + |
| 14 | +# JS |
| 15 | +npm install |
| 16 | +npm run build # Production build -> includes/blocks/build/ |
| 17 | +npm run build:prism # Copy Prism themes -> includes/assets/ |
| 18 | +npm run build:assets # Minify generated CSS/JS assets |
| 19 | +npm run start # Watch mode for block/editor/frontend bundles |
| 20 | +npm run zip # Plugin zip |
24 | 21 | ``` |
25 | 22 |
|
| 23 | +## Current feature scope |
| 24 | + |
| 25 | +The current implementation follows the active plan in `PLAN.md`, not the broader experimental ideas in `OLD-FEATURE-PLAN.md`. |
| 26 | + |
| 27 | +- Extends `core/code` with per-block attributes: |
| 28 | + - `language` |
| 29 | + - `lineNumbers` |
| 30 | + - `lineNumbersStart` |
| 31 | + - `wordWrap` |
| 32 | + - `title` |
| 33 | + - `highlightLines` — maps to `data-line` on `<pre>`, consumed by Prism line-highlight plugin |
| 34 | + - `maxHeight` — inline `style="max-height:{n}px;overflow-y:auto"` on `<pre>` (CSS only, no Prism) |
| 35 | +- Adds Inspector Controls for: |
| 36 | + - language selection |
| 37 | + - file name/title |
| 38 | + - line numbers toggle + start line |
| 39 | + - word wrap |
| 40 | + - highlight lines (e.g. `1,3-5`) |
| 41 | + - max height in px |
| 42 | + - save current settings as defaults |
| 43 | +- Saves defaults through the REST route `wz-cbh/v1/default-settings` |
| 44 | +- Frontend integrates Prism plugins for: |
| 45 | + - line numbers |
| 46 | + - line highlight |
| 47 | + - toolbar |
| 48 | + - show language |
| 49 | + - copy to clipboard |
| 50 | +- Registers a custom Prism toolbar label that reads from `data-title` |
| 51 | +- Registers a `wz-cbh-expand` Prism toolbar button that appears when `max-height` is set; toggles the block between collapsed (original inline style) and expanded (inline style cleared), updating `aria-expanded` on each toggle |
| 52 | +- Supports global settings for: |
| 53 | + - color scheme |
| 54 | + - copy to clipboard |
| 55 | + - show language label |
| 56 | + - default language |
| 57 | +- Ships with `One Dark` as the default theme slug: `prism-onedark` |
| 58 | + |
| 59 | +Do not assume features from `OLD-FEATURE-PLAN.md` exist unless they are implemented in code. |
| 60 | + |
26 | 61 | ## Architecture |
27 | 62 |
|
28 | | -This is a WordPress plugin that **extends** the native Gutenberg `core/code` block with Prism.js syntax highlighting. It does not replace the block — it uses filters to avoid block validation errors on existing posts. |
| 63 | +**Namespace:** `WebberZone\Code_Block_Highlighting` |
29 | 64 |
|
30 | | -### PHP namespace & autoloader |
| 65 | +**Autoloader:** `includes/autoloader.php` |
31 | 66 |
|
32 | | -All classes live under the `WebberZone\Code_Block_Highlighting` namespace. A custom PSR-4-style autoloader (`includes/autoloader.php`) maps the namespace to `includes/`, converting class names to files: |
| 67 | +**Bootstrap flow:** |
33 | 68 |
|
34 | | -- `Main` → `includes/class-main.php` |
35 | | -- `Admin\Settings` → `includes/admin/class-settings.php` |
36 | | -- `Frontend\Blocks` → `includes/frontend/class-blocks.php` |
37 | | -- `Frontend\Styles_Handler` → `includes/frontend/class-styles-handler.php` |
| 69 | +- Main plugin file loads the autoloader. |
| 70 | +- `wz_cbh()` resolves the `Main` singleton on `plugins_loaded`. |
| 71 | +- `Main` loads `includes/options-api.php`. |
| 72 | +- `Main` instantiates: |
| 73 | + - `Frontend\Blocks` |
| 74 | + - `Frontend\Styles_Handler` |
| 75 | +- `Admin\Admin` is created on `init` only when `is_admin()`. |
38 | 76 |
|
39 | | -Underscores in class names become dashes in filenames; all lowercase. |
| 77 | +**Key PHP classes:** |
40 | 78 |
|
41 | | -### Bootstrap flow |
| 79 | +- `includes/class-main.php` — plugin bootstrap and object wiring |
| 80 | +- `includes/frontend/class-blocks.php` — editor asset registration, REST route, `render_block_core/code` |
| 81 | +- `includes/frontend/class-styles-handler.php` — conditional frontend Prism asset loading |
| 82 | +- `includes/admin/class-settings.php` — settings registration, theme resolution, language autocomplete wiring |
42 | 83 |
|
43 | | -`webberzone-code-block-highlighting.php` defines constants (`WZ_CBH_VERSION`, `WZ_CBH_PLUGIN_FILE`, `WZ_CBH_PLUGIN_DIR`, `WZ_CBH_PLUGIN_URL`), loads the autoloader, then calls `Main::get_instance()` on the `plugins_loaded` action. |
| 84 | +**JS entry points:** |
44 | 85 |
|
45 | | -`Main` (singleton) instantiates `Frontend\Blocks` and `Frontend\Styles_Handler` immediately, and `Admin\Settings` only inside `is_admin()`. |
| 86 | +- `includes/blocks/src/js/index.js` — replaces `core/code` edit/save and adds Inspector Controls |
| 87 | +- `includes/blocks/src/js/frontend.js` — Prism core, supported grammars, toolbar/copy/show-language plugins, frontend toolbar behaviour |
46 | 88 |
|
47 | | -### Three-layer highlighting strategy |
| 89 | +**Build output:** |
48 | 90 |
|
49 | | -| Layer | Where | What it does | |
50 | | -|---|---|---| |
51 | | -| `blocks.registerBlockType` JS filter | Editor | Adds `language`, `lineNumbers`, `title` attributes to `core/code` | |
52 | | -| `editor.BlockEdit` JS filter (HOC) | Editor | Adds InspectorControls panel with language picker, line number toggle, title field | |
53 | | -| `blocks.getSaveContent.extraProps` JS filter | Editor save | Adds `language-*` and `line-numbers` classes to the serialized `<pre>` | |
54 | | -| `render_block_core/code` PHP filter | Frontend | Injects `language-*` class onto `<code>` element in rendered HTML | |
| 91 | +- `includes/blocks/build/index.js` |
| 92 | +- `includes/blocks/build/frontend.js` |
| 93 | +- corresponding `.asset.php` manifests and extracted CSS files |
55 | 94 |
|
56 | | -### Attribute storage |
| 95 | +Always `require` the generated `.asset.php` file before enqueueing block scripts. |
57 | 96 |
|
58 | | -Selected language is stored in the block comment: |
59 | | -```html |
60 | | -<!-- wp:code {"language":"javascript","lineNumbers":true,"title":"index.js"} --> |
61 | | -<pre class="wp-block-code language-javascript line-numbers" data-label="index.js"> |
62 | | - <code class="language-javascript">...</code> |
63 | | -</pre> |
64 | | -<!-- /wp:code --> |
65 | | -``` |
| 97 | +## Data flow |
| 98 | + |
| 99 | +- Language list is provided by `Frontend\Blocks::get_languages()` |
| 100 | +- Editor globals are injected with `wp_add_inline_script()`: |
| 101 | + - `cbhLanguages` |
| 102 | + - `cbhDefaultLang` |
| 103 | + - `cbhDefaultSettings` |
| 104 | +- Frontend globals are injected with `wp_add_inline_script()`: |
| 105 | + - `cbhSettings` |
| 106 | +- Block attributes are saved in block markup and normalized again in `render_code_block()` |
| 107 | +- Default settings are stored in plugin options through the REST endpoint |
| 108 | + |
| 109 | +## Asset loading |
| 110 | + |
| 111 | +`Frontend\Styles_Handler::enqueue_assets()` only loads Prism on the frontend when at least one `core/code` block is present in the current queried posts. |
| 112 | + |
| 113 | +Use `wz_cbh_force_load_assets` to bypass conditional loading. |
| 114 | + |
| 115 | +The editor canvas styling is handled separately in `Frontend\Blocks::enqueue_editor_canvas_styles()`, which: |
| 116 | + |
| 117 | +- enqueues editor CSS into the block editor iframe |
| 118 | +- extracts only `background` and `color` declarations from the active Prism theme |
| 119 | +- re-injects them with stronger selectors so the editor canvas matches the chosen frontend theme without breaking editor layout |
| 120 | + |
| 121 | +## Key filters, options, and routes |
| 122 | + |
| 123 | +- `wz_cbh_languages` — filter supported Prism languages (`slug => label`) |
| 124 | +- `wz_cbh_color_scheme_css_url` — filter the resolved Prism theme CSS URL |
| 125 | +- `wz_cbh_force_load_assets` — force frontend Prism assets to load |
| 126 | +- REST route: `wz-cbh/v1/default-settings` |
| 127 | +- Settings option key: `wz_cbh_settings` |
| 128 | +- Settings prefix: `wz_cbh` |
| 129 | +- Settings page slug: `wz_cbh_settings` |
| 130 | + |
| 131 | +## Current option IDs |
| 132 | + |
| 133 | +These option IDs are registered in `includes/admin/class-settings.php`: |
| 134 | + |
| 135 | +- `color-scheme` |
| 136 | +- `copy-to-clipboard` |
| 137 | +- `show-language-label` |
| 138 | +- `show-file-name` |
| 139 | +- `default-lang` |
| 140 | +- `default-line-numbers` |
| 141 | +- `default-line-numbers-start` |
| 142 | +- `default-word-wrap` |
| 143 | +- `font-size` |
| 144 | + |
| 145 | +The default color scheme is `prism-onedark`. |
| 146 | + |
| 147 | +## Frontend rendering rules |
66 | 148 |
|
67 | | -### JS build |
| 149 | +`Frontend\Blocks::render_code_block()` currently: |
68 | 150 |
|
69 | | -Two entry points, both built by `wp-scripts build`: |
70 | | -- `includes/blocks/js/index.js` → `build/index.js` + `build/index.asset.php` — editor block filters |
71 | | -- `includes/frontend/js/frontend.js` → `build/frontend.js` + `build/frontend.css` + `build/frontend.asset.php` — Prism core, all language grammars, line-numbers plugin (CSS extracted by webpack) |
| 151 | +- adds `language-{slug}` to `<code>` |
| 152 | +- adds `line-numbers` to `<pre>` when enabled |
| 153 | +- adds `data-start` to `<pre>` when line numbering starts from a value other than `1` |
| 154 | +- adds `word-wrap` to `<pre>` when enabled |
| 155 | +- adds `data-title` to `<pre>` for the custom toolbar label |
| 156 | +- adds `data-line` to `<pre>` from `highlightLines` attribute (consumed by Prism line-highlight plugin) |
| 157 | +- `maxHeight` is CSS-only: serialized as inline `style` by the block save function, not touched by PHP |
72 | 158 |
|
73 | | -Always `require` the `.asset.php` manifest in PHP before calling `wp_enqueue_script` — it provides the correct dependency array and cache-busting version. |
| 159 | +If you change block attributes in JS, update the PHP rendering logic and defaults flow as well. |
74 | 160 |
|
75 | | -Language list is passed from PHP → JS via `wp_add_inline_script` as globals `cbhLanguages` (object) and `cbhDefaultLang` (string) before the editor script loads. |
| 161 | +## Accessibility notes |
76 | 162 |
|
77 | | -### Frontend asset loading |
| 163 | +The active plan targets strong accessibility support. Current frontend code already includes: |
78 | 164 |
|
79 | | -`Styles_Handler` uses `array_reduce` over `$posts` with `has_block( 'core/code', $post )` to only enqueue Prism assets when code blocks are present. Override with the `wz_cbh_force_load_assets` filter. |
| 165 | +- decorative toolbar language labels marked `aria-hidden` |
| 166 | +- a custom title label in the toolbar |
| 167 | +- Prism copy-to-clipboard integration controlled by plugin settings |
| 168 | +- expand/collapse button with `aria-expanded` state management |
80 | 169 |
|
81 | | -### Key filters & options |
| 170 | +If you extend toolbar behaviour, preserve keyboard access and screen reader behaviour. |
82 | 171 |
|
83 | | -- `wz_cbh_languages` — filter the language list array (`slug => label`) |
84 | | -- `wz_cbh_color_scheme_css_url` — override the Prism theme CSS URL |
85 | | -- `wz_cbh_force_load_assets` — force Prism to load on every page |
86 | | -- `wz-cbh-color-scheme` WP option — active theme slug (default: `prism-a11y-dark`) |
87 | | -- `wz-cbh-default-lang` WP option — auto-applied language on new code block inserts |
| 172 | +## Adding a Prism theme |
88 | 173 |
|
89 | | -### Assets (not committed, generated by npm scripts) |
| 174 | +1. Add the theme mapping in `build-prism.js` |
| 175 | +2. Ensure the generated CSS file is copied to `includes/assets/` |
| 176 | +3. Register the theme slug in `includes/admin/class-settings.php` |
| 177 | +4. Run `npm run build:prism` |
90 | 178 |
|
91 | | -- `build/frontend.js` — Prism core + all languages + line-numbers plugin (via `npm run build`) |
92 | | -- `build/frontend.css` — line-numbers plugin CSS (extracted from `src/frontend.js` by webpack) |
93 | | -- `assets/prism-*.css` — color scheme theme files copied from `prism-themes` package (via `npm run build:assets`) |
| 179 | +## Notes for future work |
94 | 180 |
|
95 | | -Bundled themes (defined in `build-assets.js`): `prism-a11y-dark`, `prism-atom-dark`, `prism-darcula`, `prism-dracula`, `prism-ghcolors`, `prism-gruvbox-dark`, `prism-gruvbox-light`, `prism-material-dark`, `prism-material-oceanic`, `prism-night-owl`, `prism-nord`, `prism-onedark`, `prism-one-light`, `prism-shades-of-purple`, `prism-solarized-dark-atom`, `prism-synthwave84`, `prism-vs`, `prism-vsc-dark-plus`. To add a new theme, add an entry to `build-assets.js`, register it in `includes/admin/class-settings.php`, then run `npm run build:assets`. |
| 181 | +- Prefer `PLAN.md` as the source of truth for current implementation direction |
| 182 | +- Treat `OLD-FEATURE-PLAN.md` as backlog/reference only |
| 183 | +- Before adding new per-block controls, verify: |
| 184 | + - the JS attribute schema |
| 185 | + - the save output |
| 186 | + - the PHP render filter |
| 187 | + - frontend Prism plugin support |
0 commit comments