Claude Skill

fluentcart-customers-portal

Implements and audits FluentCart customer identity, WP_User linkage, addresses, ownership checks, account creation, customer-scoped queries, and custom portal endpoints. Use when working with Customer, CustomerResource, getCurrentCustomer(), fct_customers, customer-profile REST r

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download lonsdale201-wp-agent-skills-fluentcart_fluentcart-customers-portal-52f6020.zip · 3 KB
Part of lonsdale201/wp-agent-skills — 226 skills

Install

skills CLI npx skills add https://github.com/Lonsdale201/wp-agent-skills/tree/main/fluentcart/fluentcart-customers-portal
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install lonsdale201-wp-agent-skills@llmmart
Git 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 customers and portal

Treat Customer as the commerce identity and WP_User as an optional login identity. Enforce ownership for every customer-facing object.

Read customer-identity.md before changing email/user links, moving resources, or exposing customer data.

Resolve identity safely

  • Customer rows live in fct_customers and may link to WP users by user_id.
  • Orders, subscriptions, addresses, licenses, statistics, and labels reference Customer IDs, not WP user IDs.
  • CustomerResource::getCurrentCustomer() first resolves the logged-in WP user by user_id or matching email and may attach that user_id to the existing row.
  • Passing true may create a Customer from the current WP user.
  • Email matching is a linking operation. Validate verified ownership and duplicate/merge consequences before changing an address.

Use Customers/CustomerResource and the normal resource-moving hooks for coordinated changes. Do not update order and subscription customer_id values piecemeal.

Enforce object ownership

CustomerFrontendPolicy only proves that a WP user is logged in. It does not authorize an arbitrary order, subscription, address, download, or license.

For every custom handler:

  1. resolve CustomerResource::getCurrentCustomer();
  2. query the requested object with customer_id equal to that customer;
  3. reject absent/mismatched objects without revealing whether another customer owns them;
  4. authorize the requested mutation separately;
  5. use FluentCart lifecycle methods for the mutation.

Never authorize solely by UUID, license key, address ID, download ID, or portal URL.

Add a portal page

Register at fluent_cart/init or later. Use a unique kebab-case slug that is not dashboard, purchase-history, subscriptions, licenses, downloads, or profile.

fluent_cart_api()->addCustomerDashboardEndpoint('acme-benefits', [
    'title'           => __('Benefits', 'acme-addon'),
    'render_callback' => static function (): void {
        $customer = \FluentCart\Api\Resource\CustomerResource::getCurrentCustomer();
        if (!$customer) {
            return;
        }

        echo '<div>' . esc_html__('Your benefits', 'acme-addon') . '</div>';
    },
]);

The render callback receives no arguments and echoes content inside the logged-in portal shell. Escape output and recheck any resource ownership inside it. A page_id can be supplied instead, but its content must still avoid exposing unscoped customer data.

Keep caches request-scoped

CustomerResource caches the current customer statically. Call resetCurrentCustomerRuntimeCache() between simulated users/requests in PHPUnit, WP-CLI loops, workers, or multisite switches. Do not let one user's cached Customer bleed into another iteration.

Handle account and email changes

  • Do not create duplicate WP users merely because an order is paid; core may create/link an account according to store/order policy.
  • Normalize and validate email, then search both Customer and WP_User collision cases.
  • Move all connected resources through the normal move/change operation.
  • React to fluent_cart/customer_email_changed and fluent_cart/customer_resources_moved only after verifying their payload.
  • Recount customer statistics after repair/import, not on every read.
  • Never include PII in public cache keys, logs, HTML data attributes, or URLs.

Cross-references

  • Use fluentcart-rest-headless for customer-facing endpoints.
  • Use fluentcart-orders-transactions for customer order queries.
  • Use fluentcart-licensing-pro for Pro license ownership.

References

  • Official customer hooks: https://dev.fluentcart.com/hooks/actions/customers-users/
  • Verified Free source paths:
    • fluent-cart/app/Models/Customer.php
    • fluent-cart/api/Customers.php
    • fluent-cart/api/Resource/CustomerResource.php
    • fluent-cart/api/Resource/CustomerAddressResource.php
    • fluent-cart/app/Http/Policies/CustomerFrontendPolicy.php
    • fluent-cart/app/Http/Controllers/FrontendControllers/
    • fluent-cart/api/FluentCartGeneralApi.php
    • fluent-cart/app/Hooks/Handlers/ShortCodes/CustomerProfileHandler.php
    • fluent-cart/app/Hooks/Handlers/UserHandler.php
Files (wp-agent-skills)
  • agents
    • openai.yaml 313 B
      interface:
        display_name: "FluentCart customers and portal"
        short_description: "Protect customer identity, ownership, and portal data"
        default_prompt: "Use $fluentcart-customers-portal to implement or audit this customer or portal feature with correct Customer/WP_User identity, ownership, and cache scope."
      
  • references
    • customer-identity.md 1.9 KB
      # FluentCart 1.6.0 customer identity
      
      ## Identity graph
      
      ~~~text
      WP_User (optional login)
         | user_id or verified email link
      Customer
         |-- CustomerAddress rows
         |-- Orders -> items / transactions / order addresses
         |-- Subscriptions
         |-- Download permissions
         |-- Pro licenses and activations
      ~~~
      
      Order addresses are snapshots. Updating a customer's primary address must not
      silently rewrite historical invoice/order addresses.
      
      ## Current customer resolution
      
      CustomerResource::getCurrentCustomer():
      
      1. returns null for anonymous requests;
      2. loads the current WP_User;
      3. queries Customer where user_id matches OR email matches;
      4. eager-loads billing/shipping addresses;
      5. attaches user_id when an email match has no/different link;
      6. optionally creates a Customer;
      7. stores the result in a static runtime cache.
      
      This makes email uniqueness and account-email changes security-sensitive.
      
      ## Ownership query pattern
      
      Resolve the current customer first, then include customer_id in the same query
      that resolves the opaque identifier. Avoid loading by UUID and checking later
      when a scoped query is possible.
      
      Return the same not-found response for absent and foreign objects. Apply
      capability checks in addition to ownership for privileged/admin functions.
      
      ## Resource moves
      
      A customer merge/change can affect orders, child renewal orders, transactions,
      subscriptions, addresses, labels, download permissions, integrations, and Pro
      licenses. Use source-verified core movement logic and listen to
      customer_resources_moved for addon-owned foreign rows. Make the addon callback
      transactional or resumable and idempotent by from/to customer IDs.
      
      ## Test matrix
      
      Test anonymous, linked WP user, email-only legacy customer, email collision,
      customer with two addresses, resource merge, user email change, deleted WP user,
      two simulated users in one process, foreign UUID access, and multisite switching.
      
  • SKILL.md 4.9 KB
    ---
    name: fluentcart-customers-portal
    description: >-
      Implements and audits FluentCart customer identity, WP_User linkage,
      addresses, ownership checks, account creation, customer-scoped queries, and
      custom portal endpoints. Use when working with Customer, CustomerResource,
      getCurrentCustomer(), fct_customers, customer-profile REST routes,
      fluent_cart_api() customer-dashboard endpoint registration, customer merges or email
      changes, portal menus, order/subscription ownership, or long-running tests
      that switch users.
    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 customers and portal
    
    Treat Customer as the commerce identity and WP_User as an optional login
    identity. Enforce ownership for every customer-facing object.
    
    Read [customer-identity.md](references/customer-identity.md) before changing
    email/user links, moving resources, or exposing customer data.
    
    ## Resolve identity safely
    
    - Customer rows live in fct_customers and may link to WP users by user_id.
    - Orders, subscriptions, addresses, licenses, statistics, and labels reference
      Customer IDs, not WP user IDs.
    - CustomerResource::getCurrentCustomer() first resolves the logged-in WP user by
      user_id or matching email and may attach that user_id to the existing row.
    - Passing true may create a Customer from the current WP user.
    - Email matching is a linking operation. Validate verified ownership and
      duplicate/merge consequences before changing an address.
    
    Use Customers/CustomerResource and the normal resource-moving hooks for
    coordinated changes. Do not update order and subscription customer_id values
    piecemeal.
    
    ## Enforce object ownership
    
    CustomerFrontendPolicy only proves that a WP user is logged in. It does not
    authorize an arbitrary order, subscription, address, download, or license.
    
    For every custom handler:
    
    1. resolve CustomerResource::getCurrentCustomer();
    2. query the requested object with customer_id equal to that customer;
    3. reject absent/mismatched objects without revealing whether another customer
       owns them;
    4. authorize the requested mutation separately;
    5. use FluentCart lifecycle methods for the mutation.
    
    Never authorize solely by UUID, license key, address ID, download ID, or portal
    URL.
    
    ## Add a portal page
    
    Register at fluent_cart/init or later. Use a unique kebab-case slug that is not
    dashboard, purchase-history, subscriptions, licenses, downloads, or profile.
    
    ~~~php
    fluent_cart_api()->addCustomerDashboardEndpoint('acme-benefits', [
        'title'           => __('Benefits', 'acme-addon'),
        'render_callback' => static function (): void {
            $customer = \FluentCart\Api\Resource\CustomerResource::getCurrentCustomer();
            if (!$customer) {
                return;
            }
    
            echo '<div>' . esc_html__('Your benefits', 'acme-addon') . '</div>';
        },
    ]);
    ~~~
    
    The render callback receives no arguments and echoes content inside the logged-in
    portal shell. Escape output and recheck any resource ownership inside it. A
    page_id can be supplied instead, but its content must still avoid exposing
    unscoped customer data.
    
    ## Keep caches request-scoped
    
    CustomerResource caches the current customer statically. Call
    resetCurrentCustomerRuntimeCache() between simulated users/requests in PHPUnit,
    WP-CLI loops, workers, or multisite switches. Do not let one user's cached
    Customer bleed into another iteration.
    
    ## Handle account and email changes
    
    - Do not create duplicate WP users merely because an order is paid; core may
      create/link an account according to store/order policy.
    - Normalize and validate email, then search both Customer and WP_User collision
      cases.
    - Move all connected resources through the normal move/change operation.
    - React to fluent_cart/customer_email_changed and
      fluent_cart/customer_resources_moved only after verifying their payload.
    - Recount customer statistics after repair/import, not on every read.
    - Never include PII in public cache keys, logs, HTML data attributes, or URLs.
    
    ## Cross-references
    
    - Use fluentcart-rest-headless for customer-facing endpoints.
    - Use fluentcart-orders-transactions for customer order queries.
    - Use fluentcart-licensing-pro for Pro license ownership.
    
    ## References
    
    - Official customer hooks: <https://dev.fluentcart.com/hooks/actions/customers-users/>
    - Verified Free source paths:
      - fluent-cart/app/Models/Customer.php
      - fluent-cart/api/Customers.php
      - fluent-cart/api/Resource/CustomerResource.php
      - fluent-cart/api/Resource/CustomerAddressResource.php
      - fluent-cart/app/Http/Policies/CustomerFrontendPolicy.php
      - fluent-cart/app/Http/Controllers/FrontendControllers/
      - fluent-cart/api/FluentCartGeneralApi.php
      - fluent-cart/app/Hooks/Handlers/ShortCodes/CustomerProfileHandler.php
      - fluent-cart/app/Hooks/Handlers/UserHandler.php
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related