` tag with the exact * FluentCart data-attributes, native hooks, and `%%CHILDREN%%` for its 12 sub-elements. * All render logic lives in `src/Rendering/Checkout/CheckoutWrapperRenderer.php` (this * fork's own rendering layer); this file is metadata + control declarations only. * * Feature flag: `fcbd_atomized_checkout` (default OFF, * `CheckoutAdapter::ATOMIZED_OPTION`). While off, this element renders only the native * `[fluent_cart_checkout]` shortcode -- see `CheckoutWrapperRenderer::render()`. * * `nestingRule()`: `container-excluding-self`, the exact native Breakdance rule already * verified and used by `bd-elements/FC_Product_Builder/element.php` (itself verified * against `subplugins/breakdance-elements/elements/ProductBuilder/element.php:172`) to * stop a container nesting inside its own descendants at the builder-UI level. This is * the FIRST of two independent defenses against "geen geneste checkout" * (V1.1-audit punt 5); `CheckoutStructureValidator::evaluateForPost()` is the second, * server-side one (see that class's own docblock for why a second layer is needed: this * native rule is builder-UI-level only, not enforced against a hand-edited/migrated * tree). * * `defaultChildren()` returns Breakdance ChildElement descriptors for exactly * `CheckoutStructureValidator::ALL_SLUGS` (single source of truth shared with the * validator, architectuurprincipe 14 "geen dubbele bron van waarheid"), reordered into * the same logical sequence FluentCart's own * `CheckoutRenderer::renderCheckoutForm()` uses (name/email, create account, billing, * ship-to-different, shipping address, shipping methods, agree terms, payment methods, * order summary, order notes) with Coupon placed directly after Order Summary (task * instruction 2, "defaultChildren() levert een complete geldige checkout"; Coupon has no * native default position since `fluent_cart_show_coupon` is always a separately-placed * shortcode, this placement is this fork's own choice, flagged in the final report). */ final class FCCheckout extends \Breakdance\Elements\Element { public static function uiIcon() { return '' . '' . ''; } public static function tag() { return 'div'; } public static function tagOptions() { return []; } public static function tagControlPath() { return false; } public static function name() { return 'FC Checkout'; } public static function className() { return 'fcbd-fc-checkout-element'; } public static function category() { return 'fluentcart'; } public static function badge() { return ['label' => 'FC', 'backgroundColor' => '#3157d5', 'textColor' => '#fff']; } public static function slug() { return __CLASS__; } public static function template() { return file_get_contents(__DIR__ . '/html.twig'); } public static function defaultCss() { return file_get_contents(__DIR__ . '/default.css'); } /** * FIXTAAK TAAK 2 (heading audit, v0.6.0+1): CheckoutWrapperRenderer.php's own render * (this element's own markup, not its 12 children) is wrapperStart()/renderNotices()/ * a real `
`/%%CHILDREN%%/wrapperEnd() -- no heading tag anywhere. And even * accounting for CSS cascading down into the children's DOM (`%%SELECTOR%%` here IS * an ancestor of every child's own render output, since they substitute into * %%CHILDREN%%): grepping every FC_Checkout_* section renderer * (CheckoutSectionRenderers.php) and FluentCart's own live CheckoutRenderer/ * FormFieldRenderer/CartSummaryRender/ShippingMethodsRender source shows no node * anywhere in the whole checkout tree carries the literal class "fcbd-heading" (the * builder-only `.fcbd-checkout-heading` and the live `.fct_form_section_header_label` * are both different strings). typographyCssSnippet()'s heading portion is * unreachable from any angle, so it is suppressed via ['text'], matching * designControls()'s own ['text'] filter. This is independent of, and does not touch, * CheckoutControlPresets::sectionPanelSection()'s OWN, already-real "Section Panel > * Heading Color" field one line below, which does correctly reach * `.fcbd-checkout-heading` through that same cascade (out of this task's file area; * unchanged). */ public static function cssTemplate() { return ControlPresets::typographyCssSnippet('%%SELECTOR%%', 'design.typography', ['text']) . ControlPresets::spacingCssSnippet() . CheckoutControlPresets::sectionPanelCssSnippet('%%SELECTOR%%') . file_get_contents(__DIR__ . '/css.twig'); } public static function defaultChildren() { $slugs = [ CheckoutStructureValidator::SLUG_NAME_EMAIL, CheckoutStructureValidator::SLUG_CREATE_ACCOUNT, CheckoutStructureValidator::SLUG_BILLING, CheckoutStructureValidator::SLUG_SHIP_DIFFERENT, CheckoutStructureValidator::SLUG_SHIPPING_ADDRESS, CheckoutStructureValidator::SLUG_SHIPPING_METHODS, CheckoutStructureValidator::SLUG_AGREE_TERMS, CheckoutStructureValidator::SLUG_PAYMENT_METHODS, CheckoutStructureValidator::SLUG_ORDER_SUMMARY, CheckoutStructureValidator::SLUG_COUPON, CheckoutStructureValidator::SLUG_ORDER_NOTES, CheckoutStructureValidator::SLUG_SUBMIT, ]; return array_map( static fn(string $slug): array => ['slug' => $slug], $slugs ); } public static function dependencies() { return false; } public static function settingsControls() { return []; } public static function settings() { return ['proOnly' => false]; } public static function availableIn() { return ['breakdance']; } public static function propertyPathsToSsrElementWhenValueChanges() { return ['content.settings.when_empty']; } public static function defaultProperties() { return ['content' => ['settings' => ['when_empty' => null]]]; } public static function contentControls() { return [c('settings', __('Settings', 'sparkcore-commerce'), [ c('when_empty', __('When cart is empty', 'sparkcore-commerce'), [], ['type' => 'global_block_chooser', 'layout' => 'vertical'], false, false, []), ], ['type' => 'section', 'layout' => 'vertical'], false, false, [])]; } /** * FIXTAAK TAAK 2: no Heading Color/Heading Font Family on the generic Typography * section (['text'] filter); see cssTemplate()'s own matching comment. The Section * Panel section directly above keeps its own, separate, already-real heading field * unchanged. */ public static function designControls() { return [ CheckoutControlPresets::sectionPanelSection(), ControlPresets::typographySection('typography', 'Typography', ['text']), ControlPresets::spacingSection(), ]; } /** * Container-excluding-self: any element may nest inside except FC_Checkout being its * own (direct or indirect) descendant. See class docblock for the two-layer nesting * defense. */ public static function nestingRule() { return ['type' => 'container-excluding-self']; } }