diff --git a/README.md b/README.md index a0d3935f..dd218410 100644 --- a/README.md +++ b/README.md @@ -14,25 +14,513 @@ You need composer to autoload all your classes from the inc folder. -Use the `beapi/composer-scaffold-theme` package that add it automatically to the composer.json file. -You can add it yourself like this : - -```composer.json - "autoload": { - "psr-4": { - "BEA\\Theme\\Framework\\": "content/themes/framework/inc/" - } +Use the `beapi/composer-scaffold-theme` package that adds it automatically to `composer.json`, or declare the PSR-4 mapping yourself. BFF maps the `inc/` directory like this: + +```json +"autoload": { + "psr-4": { + "BEA\\Theme\\Framework\\": "inc/" } +} ``` ### Autoload -The autoload is based on psr-4 and handled by composer. +Autoloading is PSR-4 and handled by Composer. Theme PHP lives under `inc/` (blocks, services, **Formatting helpers**, etc.). ### Node.js You need [the latest stable version of Node.js](https://nodejs.org/). +## Formatting helpers + +Helpers are namespaced functions under `BEA\Theme\Framework\Helpers\Formatting\`. Import them with `use function` (recommended) or call them with a fully qualified name. + +### Image (`Helpers\Formatting\Image`) + +Outputs attachment images with `wp_get_attachment_image()`, optional wrapper markup, and filters for attributes, settings, and final HTML. + +**Featured image in a card** (custom size and class, `data-location` for ARI plugin): + +```php +use function BEA\Theme\Framework\Helpers\Formatting\Image\the_image; + +// Without ARI default image (hidden if no image) +the_image( + (int) get_post_thumbnail_id(), + [ + 'class' => 'card__image', + 'data-location' => 'archive-card', + ], + [ + 'before' => '
', + 'after' => '
', + ] +); + +// With ARI default image +the_image( + (int) get_post_thumbnail_id(), + [ + 'class' => 'card__image', + 'data-location' => 'archive-card', + ], + [ + 'default' => true, + 'before' => '
', + 'after' => '
', + ] +); + +// Without ARI plugin +the_image( + (int) get_post_thumbnail_id(), + [ + 'class' => 'card__image', + ], + [ + 'size' => 'thumbnail', + 'before' => '
', + 'after' => '
', + ] +); +``` + +If `(int) get_post_thumbnail_id()` is `0` and `'default' => false`, the helper outputs nothing. With `'default' => true` and no image, behavior depends on your default-image setup and filters. + +**Decorative image** (empty `alt` is preserved as `alt=""` for accessibility): + +```php +use function BEA\Theme\Framework\Helpers\Formatting\Image\the_image; + +the_image( + $attachment_id, + [ + 'class' => 'hero__bg', + 'alt' => '', + ], + [ + 'size' => 'full' + ] +); +``` + +**Illustrative generated HTML** (`alt=""` is forced when you pass `'alt' => ''`): + +```html + +``` + +**Echo variant:** `get_the_image()` — same arguments as `the_image()`, prints markup. + +**Filters:** `bea_theme_framework_the_image_attributes`, `bea_theme_framework_the_image_settings`, `bea_theme_framework_the_image_markup`. + +--- + +### Link (`Helpers\Formatting\Link`) + +Builds escaped `` or ` +``` + +**CSS classes for navigation** (current page + external host detection): + +```php +use function BEA\Theme\Framework\Helpers\Formatting\Link\get_acf_link_classes; + +$classes = [ + 'menu-item', + 'current' => '', + 'external' => '', +]; + +echo get_acf_link_classes( $acf_link_field, $classes ); +``` + +**Illustrative return value** (a single string of class names passed to `implode(' ')`; empty slots stay empty until matched): + +``` +menu-item current-menu-item external-menu-item +``` + +When the field URL matches the current page URL, `current-menu-item` replaces the `current` slot; when the host differs from the site home, `external-menu-item` replaces `external`. + +**Echo variants:** `the_link()`, `the_acf_link()`. + +**Filters:** `bea_theme_framework_link_attributes`, `bea_theme_framework_link_settings`, `bea_theme_framework_link_markup`, `bea_theme_framework_acf_link_attribute`, `bea_theme_framework_acf_link_settings`. + +--- + +### Share (`Helpers\Formatting\Share`) + +Builds share actions for predefined networks. Each item uses **button mode** from `Link` by default, an icon from `Helpers\Svg\get_the_icon`, and a **screen-reader label** (`sr-only`). Supported names: `facebook`, `x`, `linkedin`, `instagram`, `bluesky`, `email`. + +**Post permalink row** (override list item wrappers if needed): + +```php +use function BEA\Theme\Framework\Helpers\Formatting\Share\get_share_link; + +$url = get_permalink(); +$title = get_the_title(); + +echo ''; +``` + +**Illustrative generated HTML** (each network outputs a ` + +
  • + +
  • + +``` + +**Echo variant:** `the_share_link()`. + +**Filters:** `bea_theme_framework_share_attributes`, `bea_theme_framework_share_settings`. + +--- + +### Term (`Helpers\Formatting\Term`) + +**Term names only** (simple array of strings): + +```php +use function BEA\Theme\Framework\Helpers\Formatting\Term\get_terms_name; + +$names = get_terms_name( $terms ); // WP_Term[] → string[] +``` + +**Illustrative return value** (plain PHP array of term names): + +```php +[ 'News', 'Opinion', 'Sports' ]; +``` + +**Renderable list** (defaults to ``; escaped term names): + +```php +use function BEA\Theme\Framework\Helpers\Formatting\Term\get_terms_list; + +echo get_terms_list( + get_the_terms( get_the_ID(), 'category' ) ?: [], + [ + 'before' => '
    ' . esc_html__( 'Categories:', 'your-textdomain' ) . '
    ', + 'before_item' => '
  • ', + 'after_item' => '
  • ', + 'separator' => '', + ] +); +``` + +**Illustrative generated HTML:** + +```html +
    + Categories: + +
    +``` + +**Inline tags** (comma-separated spans instead of a list): + +```php +echo get_terms_list( + $terms, + [ + 'before' => '

    ', + 'after' => '

    ', + 'before_item' => '', + 'after_item' => '', + 'separator' => ', ', + ] +); +``` + +**Illustrative generated HTML:** + +```html +

    + News, + Sports +

    +``` + +**Echo variant:** `the_terms_list()`. + +**Filters:** `bea_theme_framework_term_list_attributes`, `bea_theme_framework_term_list_settings`. + +--- + +### Text (`Helpers\Formatting\Text`) + +Escapes and wraps arbitrary strings (default escape: `esc_html`). Empty input returns nothing. + +```php +use function BEA\Theme\Framework\Helpers\Formatting\Text\the_text; + +the_text( + (string) get_field( 'subtitle', get_the_ID(), false ), // ACF raw string; use any string source in your project + [ + 'before' => '

    ', + 'after' => '

    ', + 'escape' => 'wp_kses_post', // Your custom escape + ] +); +``` + +**Illustrative generated HTML** (empty string if the subtitle field is empty; otherwise escaped/wrapped): + +```html +

    + Subtitle text after wp_kses_post +

    +``` + +**Echo variant:** `get_the_text()`. + +**Filters:** `bea_theme_framework_text_settings`, `bea_theme_framework_text_value`. + +--- + +### SVG sprites (`Helpers\Svg`) + +Inline SVG markup references compiled sprite sheets under `dist/icons/` via ``. Cache busting uses hashes from `dist/sprite-hashes.asset.php`. The Svg service registers allowed `svg` / `use` tags for `wp_kses`. + +Helpers delegate to `BEA\Theme\Framework\Services\Svg`: + +- **`get_the_icon( string $icon_class, $additionnal_classes = [] )`** — returns HTML. +- **`the_icon( string $icon_class, $additionnal_classes = [] )`** — echoes the same markup. + +Icons are decorative in markup (`aria-hidden="true"`, `focusable="false"`). If the graphic is the only cue, add adjacent visible text or `.sr-only` copy. + +**Identifiers** + +- **`icon-name`** — loads `dist/icons/sprite.svg`, fragment **`#icon-{name}`** (the `icon-` prefix is added when missing). +- **`sprite-name/icon-name`** — loads **`dist/icons/{sprite-name}.svg`** (e.g. `social/facebook` → `social.svg` + `#icon-facebook`). +- **ACF-style** values such as **`social.svg#icon-facebook`** are normalized to the slash form internally. + +**Examples** + +```php +use function BEA\Theme\Framework\Helpers\Svg\get_the_icon; +use function BEA\Theme\Framework\Helpers\Svg\the_icon; + +// Return markup for concatenation or filters +$markup = get_the_icon( 'chevron-down' ); + +// Echo directly in a template +the_icon( 'social/facebook', [ 'share__glyph', 'u-hidden-mobile' ] ); +``` + +**Illustrative generated HTML** + +Default sprite (`chevron-down`): + +```html + +``` + +Named sprite with extra classes (`social/facebook` + `share__glyph`): + +```html + +``` + +If the Svg service is unavailable, both helpers output an empty string. + ## Installation Download the latest release of BFF [here](https://github.com/BeAPI/beapi-frontend-framework/releases) and extract the zip archive into your `themes` WordPress's folder. @@ -80,26 +568,36 @@ You also have the loaders in `loaders.js` file and Webpack's plugin in `plugins. After installing dependencies, you can run some commands which are explained below. -### Start with Browser Sync +Then, run the following command from the theme : + +### Watch -BFF is configured to work with [lando](https://lando.dev/). If you have a `.lando.yml` file in your project's root, set the path to your file in the `browsersync.config.js` file. +```bash +yarn start +``` + +### Build -```js -let fileContents = fs.readFileSync('../../../../.lando.yml', 'utf8') +```bash +yarn build ``` -Then, run the following command from the theme : +### Lint CSS ```bash -yarn start +yarn lint:css ``` -BrowserSync will proxy your lando'server based on the name defined in your `.lando.yml`. +### Lint JS -### Build +```bash +yarn lint:js +``` + +### Lint CSS & JS ```bash -yarn build +yarn lint ``` ### Bundle report @@ -130,4 +628,14 @@ function customize_editor_settings( $settings ) { return $settings; } -``` \ No newline at end of file +``` + +**Illustrative merged settings** passed back to the editor pipeline (same keys your callback assigns; consumers use them to hide styles / restrict variations): + +```php +[ + 'disableAllBlocksStyles' => [ 'core/separator' ], + 'disabledBlocksStyles' => [ 'core/button' => [ 'outline' ] ], + 'allowedBlocksVariations' => [ 'core/embed' => [ 'youtube' ] ], +]; +```