FEATURE Adding core block variations and styles for enhanced customization

This commit is contained in:
Antoine M 2025-12-11 15:23:56 +01:00
parent f049f853f0
commit 1ad86e7880
16 changed files with 352 additions and 28 deletions

View File

@ -22,23 +22,21 @@ if (! defined('ABSPATH')) {
##### REGISTER BLOCKS #####
function create_block_carhop_blocks_block_init()
{
##### REGISTER ACF BLOCKS #####
// ##### REGISTER ACF BLOCKS #####
register_block_type(__DIR__ . '/acf-blocks/gallery');
register_block_type(__DIR__ . '/acf-blocks/social-networks');
register_block_type(__DIR__ . '/acf-blocks/custom-video');
register_block_type(__DIR__ . '/acf-blocks/team-carhop');
if (function_exists('wp_register_block_types_from_metadata_collection')) {
wp_register_block_types_from_metadata_collection(__DIR__ . '/build', __DIR__ . '/build/blocks-manifest.php');
return;
}
// if (function_exists('wp_register_block_types_from_metadata_collection')) {
// wp_register_block_types_from_metadata_collection(__DIR__ . '/build', __DIR__ . '/build/blocks-manifest.php');
// return;
// }
if (function_exists('wp_register_block_metadata_collection')) {
wp_register_block_metadata_collection(__DIR__ . '/build', __DIR__ . '/build/blocks-manifest.php');
}
// if (function_exists('wp_register_block_metadata_collection')) {
// wp_register_block_metadata_collection(__DIR__ . '/build', __DIR__ . '/build/blocks-manifest.php');
// }
$manifest_data = require __DIR__ . '/build/blocks-manifest.php';
foreach (array_keys($manifest_data) as $block_type) {
@ -85,10 +83,6 @@ function carhop_register_blocks()
if (!function_exists('register_block_type')) {
return;
}
register_block_type(__DIR__ . '/acf-blocks/gallery');
register_block_type(__DIR__ . '/acf-blocks/social-networks');
register_block_type(__DIR__ . '/acf-blocks/custom-video');
register_block_type(__DIR__ . '/acf-blocks/team-carhop');
// Enregistrer le script pour le bloc gallery
wp_register_script(
@ -98,6 +92,12 @@ function carhop_register_blocks()
filemtime(__DIR__ . '/acf-blocks/gallery/view.js'),
true
);
wp_enqueue_style(
'carhop-blocks-variations',
plugins_url('build/variations.css', __FILE__),
);
}
add_action('init', 'carhop_register_blocks');
@ -105,23 +105,29 @@ add_action('init', 'carhop_register_blocks');
##### EDITOR EXTENSIONS
------------------------------------------------------------------*/
/**
* Étend le bloc Titre (core/heading) avec un attribut "carhopVariant"
* et ajoute une interface pour choisir une variante (ajoute une classe CSS).
* Enqueue plusieurs extensions éditeur (variantes/styles pour blocs core).
*/
function carhop_enqueue_editor_assets()
{
$script_path = __DIR__ . '/src/core-heading-variant/editor.js';
if (!file_exists($script_path)) {
return;
}
$asset_file = include __DIR__ . '/build/variations.asset.php';
wp_enqueue_script(
'carhop-heading-variant',
plugins_url('src/core-heading-variant/editor.js', __FILE__),
array('wp-blocks', 'wp-element', 'wp-dom-ready', 'wp-components', 'wp-compose', 'wp-data', 'wp-hooks', 'wp-i18n', 'wp-block-editor', 'wp-edit-post'),
filemtime($script_path),
true
'carhop-variants',
plugins_url('build/variations.js', __FILE__),
);
}
add_action('enqueue_block_editor_assets', 'carhop_enqueue_editor_assets');
function carhop_enqueue_variants_admin_scripts()
{
$css = __DIR__ . '/build/variations.css';
if (file_exists($css)) {
wp_enqueue_style(
'carhop-variants',
plugins_url('build/variations.css', __FILE__),
array(),
filemtime($css)
);
}
}
add_action('admin_enqueue_scripts', 'carhop_enqueue_admin_scripts');

View File

@ -23,4 +23,4 @@
"@wordpress/icons": "^11.2.0",
"url-loader": "^4.1.1"
}
}
}

View File

@ -0,0 +1,4 @@
wp.blocks.registerBlockStyle("core/embed", {
name: "stacked-background",
label: "Fond empilé",
});

View File

@ -0,0 +1,4 @@
wp.blocks.registerBlockStyle("core/heading", {
name: "stroked-after",
label: "Titre + trait ",
});

View File

@ -0,0 +1,10 @@
wp.blocks.registerBlockStyle("core/image", {
name: "framed",
label: "Encadré",
isDefault: true,
});
wp.blocks.registerBlockStyle("core/image", {
name: "stacked",
label: "Empilé",
isDefault: false,
});

Binary file not shown.

View File

@ -0,0 +1,168 @@
import { registerBlockVariation } from "@wordpress/blocks";
import { __ } from "@wordpress/i18n";
import {
InspectorControls,
BlockControls,
AlignmentToolbar,
} from "@wordpress/block-editor";
import { ToolbarGroup, ToolbarDropdownMenu } from "@wordpress/components";
import { Fragment } from "@wordpress/element";
import { addFilter } from "@wordpress/hooks";
import { createHigherOrderComponent } from "@wordpress/compose";
import { check, arrowRight, starFilled } from "@wordpress/icons";
// Variation du bloc "Liste" pour ajouter une classe spéciale
registerBlockVariation("core/list", {
name: "iconed-list",
title: "Liste avec icônes",
description: "Liste dont chaque élément peut avoir une icône personnalisée.",
attributes: {
className: "is-iconed-list",
},
scope: ["inserter", "transform"],
isActive: (blockAttributes) => {
const cls = (blockAttributes && blockAttributes.className) || "";
return cls.split(" ").includes("is-iconed-list");
},
});
// -----------------------------
// 1. On étend les attributs de core/list-item
// -----------------------------
addFilter(
"blocks.registerBlockType",
"am/iconed-list-item-attributes",
(settings, name) => {
if (name !== "core/list-item") {
return settings;
}
return {
...settings,
attributes: {
...settings.attributes,
icon: {
type: "string",
default: "",
},
},
};
}
);
// -----------------------------
// 2. On ajoute un panneau de réglages pour choisir l'icône
// -----------------------------
addFilter(
"editor.BlockEdit",
"am/iconed-list-item-controls",
(BlockEdit) => (props) => {
if (props.name !== "core/list-item") {
return <BlockEdit {...props} />;
}
const { attributes, setAttributes } = props;
const { icon } = attributes;
const ICONS = [
{
title: __("Loupe"),
value: "loupe",
},
{
title: __("Sablier"),
value: "sablier",
},
{ title: __("Cadenas"), value: "cadenas" },
{ title: __("Check"), value: "check" },
{ title: __("Loupe Alt"), value: "loupe-alt" },
{ title: __("Pendule"), value: "pendule" },
];
return (
<Fragment>
<BlockEdit {...props} />
<BlockControls>
<ToolbarGroup>
<ToolbarDropdownMenu
label={__("Icône du bullet")}
className="iconed-list-item-icon-dropdown"
icon={
<div
className={`iconed-list-item-backend-icon-square iconed-list-item-backend-icon-square--${icon}`}
></div>
}
controls={ICONS.map(({ title, value }) => ({
title,
icon: (
<div
className={`iconed-list-item-backend-icon-square iconed-list-item-backend-icon-square--${value}`}
></div>
),
isActive: icon === value,
onClick: () => setAttributes({ icon: value }),
}))}
/>
</ToolbarGroup>
<AlignmentToolbar
value={attributes.align}
onChange={(value) => setAttributes({ align: value })}
/>
</BlockControls>
</Fragment>
);
}
);
// -----------------------------
// 3. On ajoute des props au HTML sauvegardé pour chaque <li>
// -----------------------------
addFilter(
"blocks.getSaveContent.extraProps",
"carhop/iconed-list-item-save-props",
(extraProps, blockType, attributes) => {
if (blockType.name !== "core/list-item") {
return extraProps;
}
if (attributes.icon) {
extraProps = {
...extraProps,
className:
(extraProps.className || "") +
" has-custom-icon has-custom-icon--" +
attributes.icon,
};
}
return extraProps;
}
);
// -----------------------------
// 4. Applique les mêmes classes en mode éditeur (BlockListBlock)
// -----------------------------
addFilter(
"editor.BlockListBlock",
"carhop/iconed-list-item-editor-classes",
createHigherOrderComponent((BlockListBlock) => {
return (props) => {
if (props.name !== "core/list-item") {
return <BlockListBlock {...props} />;
}
const slug = props.attributes?.icon || "";
const className = [
props.className || "",
slug ? "has-custom-icon" : "",
slug ? `has-custom-icon--${slug}` : "",
]
.filter(Boolean)
.join(" ");
return <BlockListBlock {...props} className={className} />;
};
}, "withIconedListItemEditorClasses")
);

View File

@ -0,0 +1,5 @@
<svg width="15" height="23" viewBox="0 0 15 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.6885 8.83801H1V21.2814H13.6885V8.83801Z" stroke="white" stroke-width="2"/>
<path d="M3.37407 8.83887V5.94519C3.07899 3.24489 5.13145 0.965857 7.40686 1.00039C9.64293 1.03492 11.6036 3.29323 11.3085 5.94519V8.83887" stroke="white" stroke-width="2"/>
<path d="M7.40625 14.7007V18.6786" stroke="white" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 434 B

View File

@ -0,0 +1,4 @@
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.3835 19.7949C15.5659 19.7949 19.767 15.5875 19.767 10.3975C19.767 5.20739 15.5659 1 10.3835 1C5.20114 1 1 5.20739 1 10.3975C1 15.5875 5.20114 19.7949 10.3835 19.7949Z" stroke="white" stroke-width="2"/>
<path d="M6.25781 10.8245L8.64858 13.2189L14.5077 7.34546" stroke="white" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 411 B

View File

@ -0,0 +1,11 @@
<svg width="19" height="20" viewBox="0 0 19 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1628_17988)">
<path d="M13.9238 14.8484L18.4761 19.4684" stroke="white" stroke-width="2"/>
<path d="M8.51269 17.1621C12.8064 17.1621 16.2871 13.4879 16.2871 8.95544C16.2871 4.42303 12.8064 0.748779 8.51269 0.748779C4.219 0.748779 0.738281 4.42303 0.738281 8.95544C0.738281 13.4879 4.219 17.1621 8.51269 17.1621Z" stroke="white" stroke-width="2" stroke-miterlimit="10"/>
</g>
<defs>
<clipPath id="clip0_1628_17988">
<rect width="19" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 607 B

View File

@ -0,0 +1,4 @@
<svg width="14" height="21" viewBox="0 0 14 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.75704 12.7611C9.93656 12.7611 12.5141 10.1283 12.5141 6.88057C12.5141 3.63282 9.93656 1 6.75704 1C3.57751 1 1 3.63282 1 6.88057C1 10.1283 3.57751 12.7611 6.75704 12.7611Z" stroke="white" stroke-width="2"/>
<path d="M6.75781 12.7537V20.8623" stroke="white" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 390 B

View File

@ -0,0 +1,4 @@
<svg width="22" height="21" viewBox="0 0 22 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.5781 20C15.868 20 20.1562 15.7467 20.1562 10.5C20.1562 5.25329 15.868 1 10.5781 1C5.28827 1 1 5.25329 1 10.5C1 15.7467 5.28827 20 10.5781 20Z" stroke="white" stroke-width="2"/>
<path d="M10.4805 4.38086V11.0797H15.006" stroke="white" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 369 B

View File

@ -0,0 +1,13 @@
<svg width="15" height="20" viewBox="0 0 15 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1628_17830)">
<path d="M2.27681 0.670654C2.11412 1.51572 1.89286 3.25281 2.62171 5.15087C2.6998 5.34537 4.41781 9.6445 7.68462 9.63108C10.4699 9.61767 12.279 6.48554 12.8647 4.49359C13.3267 2.91747 13.1835 1.50902 13.0208 0.670654H2.27681Z" stroke="white" stroke-width="2"/>
<path d="M13.0213 19.3294C13.184 18.4843 13.4053 16.7472 12.6764 14.8491C12.5983 14.6546 10.8803 10.3555 7.61353 10.3689C4.82828 10.3823 3.01917 13.5145 2.43348 15.5064C1.97144 17.0825 2.11461 18.491 2.2773 19.3294H13.0213Z" stroke="white" stroke-width="2"/>
<path d="M0 0.670654H15" stroke="white" stroke-width="2"/>
<path d="M0 19.3293H15" stroke="white" stroke-width="2"/>
</g>
<defs>
<clipPath id="clip0_1628_17830">
<rect width="15" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 888 B

View File

@ -0,0 +1,6 @@
import "./core-heading-variant/editor.js";
import "./core-image-variant/editor.js";
import "./core-embed-variant/editor.js";
import "./core-list-variant/editor.js";
import "./variants.scss";

View File

@ -0,0 +1,74 @@
.wp-block-list.is-iconed-list {
display: block;
li.has-custom-icon {
padding-left: 0;
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 20px;
&::before {
content: " ";
position: static;
display: inline-block;
padding: 20px;
width: 40px;
height: 40px;
background-color: var(--wp--preset--color--primary);
background-size: 20px auto;
background-repeat: no-repeat;
background-position: center;
}
&--sablier::before {
background-image: url("../core-variants/core-list-variant/icons/carhop-sablier.svg");
}
&--loupe::before {
background-image: url("../core-variants/core-list-variant/icons/carhop-loupe.svg");
}
&--cadenas::before {
background-image: url("../core-variants/core-list-variant/icons/carhop-cadenas.svg");
}
&--check::before {
background-image: url("../core-variants/core-list-variant/icons/carhop-check.svg");
}
&--loupe-alt::before {
background-image: url("../core-variants/core-list-variant/icons/carhop-loupe-alt.svg");
}
&--pendule::before {
background-image: url("../core-variants/core-list-variant/icons/carhop-pendule.svg");
}
}
}
.iconed-list-item-icon-dropdown {
}
.iconed-list-item-backend-icon-square {
display: inline-block;
width: 20px;
height: 20px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
color: currentColor;
filter: invert(1);
&--sablier {
background-image: url("../core-variants/core-list-variant/icons/carhop-sablier.svg");
}
&--loupe {
background-image: url("../core-variants/core-list-variant/icons/carhop-loupe.svg");
}
&--cadenas {
background-image: url("../core-variants/core-list-variant/icons/carhop-cadenas.svg");
}
&--check {
background-image: url("../core-variants/core-list-variant/icons/carhop-check.svg");
}
&--loupe-alt {
background-image: url("../core-variants/core-list-variant/icons/carhop-loupe-alt.svg");
}
&--pendule {
background-image: url("../core-variants/core-list-variant/icons/carhop-pendule.svg");
}
}

View File

@ -0,0 +1,11 @@
// Import the original config from the @wordpress/scripts package.
const defaultConfig = require("@wordpress/scripts/config/webpack.config");
// Add any a new entry point by extending the webpack config.
module.exports = {
...defaultConfig,
entry: {
...defaultConfig.entry(),
variations: "./src/core-variants/variants.js",
},
};