Customer Panel Data Hooks

5 Aufrufe Markdown

The fifteen data filters of the customer panel: account tabs, home page panels, invoice lists, and the partner and reseller screens.

Overview

The filters over the data the customer panel carries to the screen live here: the account tabs, the home page panels, the invoice lists, and the partner and reseller screens.

Two things recur in this group. First the active account: when a sub-user looks at another account, the id you hold belongs to that account rather than to whoever signed in. Second, amounts arrive formatted: read the raw value separately if you compare.

Reference

Hiding account tabs

filterclient.account.tabs
ClientAccount a visibility map

Runs before the tabs of a customer account appear. Closing a tab takes the work behind it out of sight too.

Parameters 3
$tabsarrayby linkTab against visibility: profile, contacts, activity, messages, notifications, security and verification. ? This is visibility only: closing a tab does not close the operation behind it. To really block access, use the matching gate as well.
$uidintby linkThe id of the active account. It is not the id of whoever signed in: when a sub-user is looking at another account, that account’s id arrives.
$selfboolby linkWhether the active account is the person’s own. A false means a sub-user is looking at another account.
Return 1
voidThe return is ignored; you write over the data.
Listener
Hook::add('filter:client.account.tabs', 10, function (&$tabs, &$uid, &$self) {
    // Visibility ONLY: it does not close the operation.
    if (!$self) $tabs['security'] = false;
});

Widening the data that reaches the template

filterclient.predefined_data
Controllers on every page

Runs before every page of the customer site appears. Every key you add here becomes a template variable.

Parameters 2
$dataarrayby linkThe data bag of the page. ? Overwrite an existing key and the page loses its own data. Give your keys a prefix.
$ctxarrayby linkContext: the active route and controller name. The hook runs on every page, so check which one you are on before doing anything heavy.
Return 1
voidThe return is ignored; you write over the data.
Listener
Hook::add('filter:client.predefined_data', 10, function (&$data, &$ctx) {
    // It runs on EVERY page: check the route first.
    if (($ctx['route'] ?? '') !== 'my-account') return;

    $data['acme_banner'] = Acme::accountBanner();
});

Changing the home page panels

filterclient.homepage_panels
website/home four panels

Runs once the panels of the home page are prepared.

Parameters 1
$panelsarrayby linkThe data of four panels: spotlight extensions, product cards, feature blocks and announcements. All four arrive in one array: change it without breaking the shape, since the template expects all four keys.
Return 1
voidThe return is ignored; you write over the data.
Listener
Hook::add('filter:client.homepage_panels', 10, function (&$panels) {
    // All four keys must stay.
    $panels['product_cards'] = Acme::reorderCards($panels['product_cards'] ?? []);
});

Changing the maintenance decision

filterclient.maintenance
Kernel reads backwards

Runs after the maintenance decision is made and before the page is served. This is how you keep certain addresses out of maintenance.

Parameters 3
$passive_maintenanceboolby linkWhat the core decided. ? It reads backwards: true means maintenance is skipped, false means the maintenance page is shown. Setting it true because the name sounds right takes the site out of maintenance.
$controllerstringThe name of the requested controller.
$foundAdminboolWhether the request is on the admin address.
Return 1
voidThe return is ignored; you write over the data.
Listener
Hook::add('filter:client.maintenance', 10,
    function (&$passive_maintenance, $controller, $foundAdmin) {
        // It reads BACKWARDS: true = maintenance is SKIPPED.
        if ($controller === 'status') $passive_maintenance = true;
    });

Changing the invoice list rows

filterclient.invoice_list_data
ClientInvoices formatted rows

Runs before the customer invoice list reaches the screen.

Parameters 2
$rowsarrayby linkThe invoice rows: number, badge, payment link, amount and due line. The amounts are formatted text: read the invoice separately if you need to compare.
$uidintThe customer whose list is on screen.
Return 1
voidThe return is ignored; you write over the data.
Listener
Hook::add('filter:client.invoice_list_data', 10, function (&$rows, $uid) {
    foreach ($rows as $i => $r) $rows[$i]['acme_note'] = Acme::noteFor($r['id'] ?? 0);
});

Changing the invoice summary

filterclient.invoice_list_summary
ClientInvoices tiles and the notice

Runs once the summary above the invoice list is prepared.

Parameters 2
$summaryarrayby linkTwo parts: the summary tiles (all, paid, unpaid, overdue) and the outstanding notice. If you change the numbers, update the notice text too: the two are read from different places and can part ways.
$uidintThe customer whose summary is on screen.
Return 1
voidThe return is ignored; you write over the data.
Listener
Hook::add('filter:client.invoice_list_summary', 10, function (&$summary, $uid) {
    // If you change the numbers, update the notice text too.
    $summary['outstanding']['show'] = Acme::hideOutstanding($uid) ? false : ($summary['outstanding']['show'] ?? false);
});

Changing the invoice share address

filterclient.invoice_share_url
ClientInvoices access without login

Runs after the address is produced when a customer shares an invoice.

Parameters 3
$shareUrlstringby linkThe share address produced. ? That address needs no sign-in: whoever sees it can open the invoice and the payment page. Writing it into your own store copies the access too.
$idintThe invoice id.
$ownerIdintThe owner of the invoice.
Return 1
voidThe return is ignored; you write over the data.
Listener
Hook::add('filter:client.invoice_share_url', 10, function (&$shareUrl, $id, $ownerId) {
    // The address needs no sign-in: keep it out of your own store.
    $shareUrl = Acme::shorten($shareUrl);
});

Changing the invoice transaction list

filterclient.invoice_transactions
ClientInvoices refunds included

Runs before the payment movements of an invoice reach the screen.

Parameters 3
$rowsarrayby linkThe movement rows: method, reference, date, whether it is a refund, and the amount. Refunds are in this list too: mind the flag when totalling.
$idintThe invoice id.
$invCidintThe currency of the invoice.
Return 1
voidThe return is ignored; you write over the data.
Listener
Hook::add('filter:client.invoice_transactions', 10, function (&$rows, $id, $invCid) {
    // Refunds are in this list too.
    foreach ($rows as $i => $r)
        if ($r['refund'] ?? false) $rows[$i]['method'] = 'Acme refund';
});

Changing the bulk payment list

filterclient.bulk_pay_rows
ClientInvoices the active account

Runs on the screen where a customer pays several invoices together.

Parameters 2
$rowsarrayby linkThe invoice rows that can be paid. An invoice you remove becomes unpayable here: the customer has to pay it separately.
$uidintby linkThe id of the active account. It is not the id of whoever signed in: when a sub-user is looking at another account, that account’s id arrives.
Return 1
voidThe return is ignored; you write over the data.
Listener
Hook::add('filter:client.bulk_pay_rows', 10, function (&$rows, &$uid) {
    // An invoice you remove becomes unpayable here.
    $rows = array_values(array_filter($rows, fn ($r) => !Acme::onHold($r['id'] ?? 0)));
});

Changing the commission list

filterclient.affiliate_commissions
ClientAffiliate three states

Runs before a partner’s commission list reaches the screen.

Parameters 2
$commissionsarrayby linkThe commission rows; each carries a state: available, clearing or rejected. Keep the three apart when totalling: adding them all shows the partner money they will never receive.
$commissionsCtxarrayContext: the account id, the partner record and the currency.
Return 1
voidThe return is ignored; you write over the data.
Listener
Hook::add('filter:client.affiliate_commissions', 10,
    function (&$commissions, $commissionsCtx) {
        // Three states: do not total them all.
        $commissions = array_values(array_filter($commissions,
            fn ($c) => ($c['flag'] ?? '') !== 'rejected'));
    });

Changing the payout channel list

filterclient.affiliate_gateways
ClientAffiliate a list of labels

Runs once the payout channels a partner may pick are prepared.

Parameters 2
$outarrayby linkThe channel labels. It is a list of plain text, not ids, and the choice is stored as that text. Changing a label can break the match with older records.
$gatewaysCtxarrayContext: the language the labels were resolved in.
Return 1
voidThe return is ignored; you write over the data.
Listener
Hook::add('filter:client.affiliate_gateways', 10, function (&$out, $gatewaysCtx) {
    // Changing a label can break the match with older records.
    $out[] = 'Acme Wallet';
});

Changing the referral destination

filterclient.affiliate_referral_redirect
ClientAffiliate invalid codes arrive too

Runs when a visitor clicks a partner link, before the redirect happens.

Parameters 2
$redirectstringby linkThe redirect destination.
$redirectCtxarrayContext: the raw code in the address, the resolved partner and whether the code is valid. ? The hook runs on an invalid code too: a listener using the partner id without checking the valid flag works with a zero.
Return 1
voidThe return is ignored; you write over the data.
Listener
Hook::add('filter:client.affiliate_referral_redirect', 10,
    function (&$redirect, $redirectCtx) {
        // It runs on an invalid code too: check the flag first.
        if (!($redirectCtx['valid'] ?? false)) return;

        $redirect = Acme::landingFor((int) ($redirectCtx['owner_id'] ?? 0)) ?: $redirect;
    });

Changing the payout request amount

filterclient.affiliate_withdraw_amount
ClientAffiliate the partner currency

Runs while a partner requests a payout, before the amount is saved. What you write is what gets recorded.

Parameters 4
$amountfloatby linkThe amount requested.
$uidintThe account requesting.
$cidintThe partner’s currency. It is not the currency selected in the store: use this one if you convert.
$amountCtxarrayContext information.
Return 1
voidThe return is ignored; you write over the data.
Listener
Hook::add('filter:client.affiliate_withdraw_amount', 10,
    function (&$amount, $uid, $cid, $amountCtx) {
        // The currency is the PARTNER'S, not the store's.
        $amount = Acme::roundToPayoutStep($amount, $cid);
    });

Changing the reseller statistics

filterclient.reseller_stats
ClientReseller worked out from invoices

Runs once the figures on the reseller board are worked out.

Parameters 2
$statsarrayby linkThe reseller figures: total sales, turnover and discounts, each with today’s counterpart.
$statsCtxarrayContext: the account id of the reseller.
Return 1
voidThe return is ignored; you write over the data.
Listener
Hook::add('filter:client.reseller_stats', 10, function (&$stats, $statsCtx) {
    $stats['acme_target'] = Acme::monthlyTarget((int) ($statsCtx['uid'] ?? 0));
});

Changing the reseller tiers

filterclient.reseller_tiers
ClientReseller two separate surfaces

Runs once the reseller tier list is prepared. The hook is used on two separate screens.

Parameters 2
$tiersarrayby linkThe tier rows.
$tiersCtxarrayContext: which screen and the account id. ? On the programme page the account id is zero (the visitor may not be signed in); on the board the reseller’s id arrives. A rule depending on the id must behave differently on the two.
Return 1
voidThe return is ignored; you write over the data.
Listener
Hook::add('filter:client.reseller_tiers', 10, function (&$tiers, $tiersCtx) {
    // On the programme page the account id arrives as ZERO.
    if (($tiersCtx['scope'] ?? '') === 'program') return;

    $tiers = Acme::highlightCurrent($tiers, (int) ($tiersCtx['uid'] ?? 0));
});

Pitfalls

The maintenance flag reads backwards

The value in the maintenance filter answers not "is maintenance on" but "will maintenance be skipped". A listener setting it true because the name sounds right opens the site to visitors while you meant it closed. Confirm the direction before changing it.

Hiding a tab does not close access

The account tab filter governs visibility only. Closing a tab does not close the operation behind it: somebody who knows the address can still request it directly. Use the matching gate to really block access.

War das hilfreich?

Vielen Dank für Ihre Rückmeldung!

Brauchen Sie weitere Hilfe?

Unser Support-Team ist rund um die Uhr für Sie da, wenn Sie oben nicht fündig werden.