fluentcart-extension-architecture
Designs and audits third-party FluentCart extensions against the real 1.6.0 bootstrap, hybrid WordPress-post/custom-table data model, monetary units, Free/Pro boundary, and public helper APIs. Use when starting a FluentCart addon, choosing between hooks, models, Resource APIs, RE
Install
npx skills add https://github.com/Lonsdale201/wp-agent-skills/tree/main/fluentcart/fluentcart-extension-architecture
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install lonsdale201-wp-agent-skills@llmmart
git clone https://github.com/Lonsdale201/wp-agent-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole lonsdale201/wp-agent-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
FluentCart extension architecture
Establish the correct integration boundary before writing business logic. Do not transpose WooCommerce CRUD, cart, session, order, or subscription assumptions onto FluentCart.
Read data-and-lifecycle-map.md when the change touches more than one entity or persists commerce state.
Bootstrap safely
- Declare FluentCart as an integration dependency in the addon's own admin UX.
- Register classes and hooks no earlier than plugins_loaded.
- Use fluentcart_loaded when FluentCart's application object is required.
- Use fluent_cart/init for components that need FluentCart's init-time routes, modules, CPT, taxonomies, or migrated schema.
- Attach listeners for fluent_cart/register_storage_drivers and fluent_cart/register_payment_methods by fluentcart_loaded at the latest. Those registration actions run on init before fluent_cart/init in 1.6.0, so adding their listeners inside fluent_cart/init misses the event.
- Feature-detect Pro with FLUENTCART_PRO_PLUGIN_VERSION or the exact Pro class. Do not infer Pro from a saved option.
- Recheck the minimum core/Pro version pair before using a newly added method.
add_action('fluent_cart/init', static function ($app): void {
if (!defined('FLUENTCART_VERSION')) {
return;
}
// Register this addon's FluentCart hooks here.
});
The two lifecycle names are intentionally inconsistent: fluentcart_loaded has no underscore after fluent; fluent_cart/init does.
Select the right persistence layer
| Data | Canonical layer |
|---|---|
| Product title/content/status | WordPress post APIs or ProductResource |
| Product detail, variants, attributes, stock | FluentCart Resource/service APIs |
| Orders, items, transactions, subscriptions | FluentCart models/resources and lifecycle services |
| Categories and brands | WordPress taxonomy APIs using FluentCart taxonomy names |
| Plugin settings | StoreSettings, ModuleSettings, or fluent_cart_* option helpers |
| Addon-owned state | Addon-owned table/options with explicit foreign identifiers |
Use Resource APIs for coordinated writes. Models are suitable for scoped reads and documented model operations, but a raw model save can bypass validation, secondary rows, counters, stock movements, event dispatch, remote gateway work, or cache invalidation.
Never write fct_* rows with ad hoc SQL in normal request code. Restrict direct SQL to migrations, bounded reports, or repairs that explicitly reproduce all required invariants.
Preserve core invariants
- Treat monetary inputs and totals as integer minor units. In 1.6.0, Helper::toCent('12.34') yields 1234. Use FluentCart formatting helpers only at display boundaries.
- Keep store mode attached to every integration. Never mix test and live transactions, provider objects, cache keys, or reports.
- Treat an order's status, payment_status, and shipping_status as separate state dimensions.
- Treat Customer as a commerce identity distinct from WP_User.
- Treat cart_hash, order UUID, transaction UUID, and subscription UUID as lookup tokens, not authorization by themselves.
- Design callbacks and outbound effects for replay. Webhooks, checkout retries, Action Scheduler, and internal queues can execute more than once.
- Preserve filter inputs and return the documented type. Scope every dynamic hook to the intended product, order, gateway, or integration key.
Extension workflow
- Record the installed Free, Pro, and companion-plugin versions.
- Identify the owning entity and the service that normally mutates it.
- Trace the controller/service to the final event rather than choosing a hook by name alone.
- Confirm callback arguments and timing from source at the installed version.
- Add dependency guards and Free/Pro feature detection.
- Enforce authorization, object ownership, validation, and monetary units at the addon's boundary.
- Test live/test separation, anonymous/authenticated paths, retries, concurrent submission, and an interrupted background job.
Documentation accuracy rule
Treat the installed source and registered runtime routes as authoritative. FluentCart's current developer pages contain some stale v1 URLs, generic cart endpoints, fixed rate-limit claims, and a gateway example that omits metadata required by GatewayManager in 1.6.0. Verify any copied example before shipping.
Cross-references
- Use fluentcart-products-inventory for catalog and stock changes.
- Use fluentcart-orders-transactions for order events and status transitions.
- Use fluentcart-rest-headless for HTTP clients and custom endpoints.
References
- Official developer documentation: https://dev.fluentcart.com/
- Official database documentation: https://dev.fluentcart.com/database/
- Verified Free source paths:
- fluent-cart/fluent-cart.php
- fluent-cart/boot/app.php
- fluent-cart/boot/globals.php
- fluent-cart/api/FluentCartGeneralApi.php
- fluent-cart/api/Resource/
- fluent-cart/app/Models/
- fluent-cart/database/Migrations/
- Verified Pro source path:
- fluent-cart-pro/fluent-cart-pro.php
Files (wp-agent-skills)
-
agents
-
openai.yaml 313 B
interface: display_name: "FluentCart extension architecture" short_description: "Choose safe FluentCart lifecycle and data boundaries" default_prompt: "Use $fluentcart-extension-architecture to design or audit this FluentCart addon against the verified bootstrap, storage, version, and monetary contracts."
-
-
references
-
data-and-lifecycle-map.md 4 KB
# FluentCart 1.6.0 data and lifecycle map ## Bootstrap order ~~~text plugin load -> core hook registrations plugins_loaded -> fluentcart_loaded init priority 9 -> storage drivers + fluent_cart/register_storage_drivers init priority 10 (earlier callback) -> gateways + fluent_cart/register_payment_methods init priority 10 (later callback) -> DB migration + fluent_cart/init ~~~ Attach payment/storage registration listeners at plugin load, plugins_loaded, or fluentcart_loaded. Do not wait for fluent_cart/init for those two actions. Use this map to orient an integration. Re-audit migrations and models after an upgrade; table shape is not a stable public API. ## Runtime 1. fluent-cart.php defines Free constants and loads Composer plus boot/app.php. 2. plugins_loaded fires fluentcart_loaded with the Application instance. 3. ProductDataSetup boots after that hook. 4. Earlier init callbacks register storage drivers and payment methods. 5. The later core init callback runs DBMigrator::maybeMigrateDBChanges(). 6. That callback then fires fluent_cart/init with the Application instance. Pro 1.6.0 requires Free 1.6.0. The companion Migrator 1.0.0 loads only when FLUENTCART_VERSION exists. ## Entity ownership | Entity | Storage | Important relationship | |---|---|---| | Product | wp_posts, post type fluent-products | detail/variants link by post_id | | ProductDetail | fct_product_details | one per product | | ProductVariation | fct_product_variations | many per product; globally unique non-null SKU | | ProductDownload | fct_product_downloads | product plus selected variation IDs | | Cart | fct_carts | primary lookup is cart_hash | | Customer | fct_customers | optional user_id plus email identity | | Order | fct_orders | customer_id; optional parent_id for renewal | | OrderItem | fct_order_items | order_id plus object_id variation | | OrderTransaction | fct_order_transactions | order_id and optional subscription_id | | Subscription | fct_subscriptions | parent_order_id, customer, product, variation | | Coupon | fct_coupons | conditions/settings JSON | | AppliedCoupon | fct_applied_coupons | immutable-ish order-time discount snapshot | | Download permission | fct_order_download_permissions | customer/order/download accounting | | ScheduledAction | fct_scheduled_actions | FluentCart integration queue, not Action Scheduler | Additional tables cover addresses, order/product/customer/subscription meta, tax rates/classes/order snapshots, shipping zones/methods/classes, attributes, activities, labels, webhooks, and reports. Pro licensing adds fct_licenses, fct_license_activations, fct_license_sites, and fct_license_meta. ## Identity rules - Product IDs are WordPress post IDs; variation IDs are custom-table IDs. - Order IDs are internal numeric IDs. uuid is an external-facing lookup value, but its database index is non-unique for legacy compatibility. - Customer ID is not WP user ID. - Subscription and transaction identifiers have their own namespaces. - Never authorize a request solely because it knows a UUID or cart hash. ## Monetary rules Orders, items, transactions, subscriptions, fees, tax, shipping, and coupon allocations use integer minor units in business logic. Some ORM casts and variation schema columns are double for historical reasons; do not introduce floating-point arithmetic because of that implementation detail. Use: - FluentCart\App\Helpers\Helper::toCent() at decimal-input boundaries. - Helper::toDecimal() or CurrencySettings at presentation boundaries. - integers for sums, comparisons, refunds, discounts, shipping, and tax. ## Cache and long-running process rules Some Resources use request-static caches. Reset them between simulated requests, different users, or sites in CLI/tests: - CustomerResource::resetCurrentCustomerRuntimeCache() - Frontend CartResource::resetCartCache() - TaxCalculator::resetCache() when its calculation context changes Do not keep FluentCart model/application state across multisite switch_to_blog() boundaries without re-resolving it.
-
-
SKILL.md 5.8 KB
--- name: fluentcart-extension-architecture description: >- Designs and audits third-party FluentCart extensions against the real 1.6.0 bootstrap, hybrid WordPress-post/custom-table data model, monetary units, Free/Pro boundary, and public helper APIs. Use when starting a FluentCart addon, choosing between hooks, models, Resource APIs, REST, or direct WordPress APIs, checking fluentcart_loaded or fluent_cart/init timing, diagnosing missing classes, or reviewing code that reads or writes fct_* commerce records. metadata: wp-skills-author: "Soczó Kristóf" wp-skills-contact: "mailto:lonsdale201@hotmail.com" wp-skills-plugin: "fluent-cart" wp-skills-plugin-version-tested: "1.6.0" wp-skills-wp-version-tested: "7.0.2" wp-skills-php-min: "7.4" wp-skills-last-updated: "2026-08-06" --- # FluentCart extension architecture Establish the correct integration boundary before writing business logic. Do not transpose WooCommerce CRUD, cart, session, order, or subscription assumptions onto FluentCart. Read [data-and-lifecycle-map.md](references/data-and-lifecycle-map.md) when the change touches more than one entity or persists commerce state. ## Bootstrap safely - Declare FluentCart as an integration dependency in the addon's own admin UX. - Register classes and hooks no earlier than plugins_loaded. - Use fluentcart_loaded when FluentCart's application object is required. - Use fluent_cart/init for components that need FluentCart's init-time routes, modules, CPT, taxonomies, or migrated schema. - Attach listeners for fluent_cart/register_storage_drivers and fluent_cart/register_payment_methods by fluentcart_loaded at the latest. Those registration actions run on init before fluent_cart/init in 1.6.0, so adding their listeners inside fluent_cart/init misses the event. - Feature-detect Pro with FLUENTCART_PRO_PLUGIN_VERSION or the exact Pro class. Do not infer Pro from a saved option. - Recheck the minimum core/Pro version pair before using a newly added method. ~~~php add_action('fluent_cart/init', static function ($app): void { if (!defined('FLUENTCART_VERSION')) { return; } // Register this addon's FluentCart hooks here. }); ~~~ The two lifecycle names are intentionally inconsistent: fluentcart_loaded has no underscore after fluent; fluent_cart/init does. ## Select the right persistence layer | Data | Canonical layer | |---|---| | Product title/content/status | WordPress post APIs or ProductResource | | Product detail, variants, attributes, stock | FluentCart Resource/service APIs | | Orders, items, transactions, subscriptions | FluentCart models/resources and lifecycle services | | Categories and brands | WordPress taxonomy APIs using FluentCart taxonomy names | | Plugin settings | StoreSettings, ModuleSettings, or fluent_cart_* option helpers | | Addon-owned state | Addon-owned table/options with explicit foreign identifiers | Use Resource APIs for coordinated writes. Models are suitable for scoped reads and documented model operations, but a raw model save can bypass validation, secondary rows, counters, stock movements, event dispatch, remote gateway work, or cache invalidation. Never write fct_* rows with ad hoc SQL in normal request code. Restrict direct SQL to migrations, bounded reports, or repairs that explicitly reproduce all required invariants. ## Preserve core invariants - Treat monetary inputs and totals as integer minor units. In 1.6.0, Helper::toCent('12.34') yields 1234. Use FluentCart formatting helpers only at display boundaries. - Keep store mode attached to every integration. Never mix test and live transactions, provider objects, cache keys, or reports. - Treat an order's status, payment_status, and shipping_status as separate state dimensions. - Treat Customer as a commerce identity distinct from WP_User. - Treat cart_hash, order UUID, transaction UUID, and subscription UUID as lookup tokens, not authorization by themselves. - Design callbacks and outbound effects for replay. Webhooks, checkout retries, Action Scheduler, and internal queues can execute more than once. - Preserve filter inputs and return the documented type. Scope every dynamic hook to the intended product, order, gateway, or integration key. ## Extension workflow 1. Record the installed Free, Pro, and companion-plugin versions. 2. Identify the owning entity and the service that normally mutates it. 3. Trace the controller/service to the final event rather than choosing a hook by name alone. 4. Confirm callback arguments and timing from source at the installed version. 5. Add dependency guards and Free/Pro feature detection. 6. Enforce authorization, object ownership, validation, and monetary units at the addon's boundary. 7. Test live/test separation, anonymous/authenticated paths, retries, concurrent submission, and an interrupted background job. ## Documentation accuracy rule Treat the installed source and registered runtime routes as authoritative. FluentCart's current developer pages contain some stale v1 URLs, generic cart endpoints, fixed rate-limit claims, and a gateway example that omits metadata required by GatewayManager in 1.6.0. Verify any copied example before shipping. ## Cross-references - Use fluentcart-products-inventory for catalog and stock changes. - Use fluentcart-orders-transactions for order events and status transitions. - Use fluentcart-rest-headless for HTTP clients and custom endpoints. ## References - Official developer documentation: <https://dev.fluentcart.com/> - Official database documentation: <https://dev.fluentcart.com/database/> - Verified Free source paths: - fluent-cart/fluent-cart.php - fluent-cart/boot/app.php - fluent-cart/boot/globals.php - fluent-cart/api/FluentCartGeneralApi.php - fluent-cart/api/Resource/ - fluent-cart/app/Models/ - fluent-cart/database/Migrations/ - Verified Pro source path: - fluent-cart-pro/fluent-cart-pro.php
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.