Account Restriction Hooks

1 views Markdown

The six hooks over blacklisting, bulk suspension, dormant accounts and bulk messages.

Overview

The operations that narrow what an account may do live here: blacklisting, suspending or cancelling every service, and deleting an account left unused.

All of them reach wide and are hard to undo. That is what makes the gates valuable: they are the only place a wrong click can still be stopped.

Reference

Stopping a blacklisting

gateuser.blacklist_add
AdminUsers before the write

Runs before a customer is put on the blacklist.

Parameters 3
$user_idintThe customer to be blacklisted.
$reasonstringThe reason code: payment fraud, chargeback, abuse, spam, terms breach, false information or other.
$restrictionsarrayThe restrictions to apply: new orders, renewals, tickets and suspending services.
Return 1
string|nullA non-empty text blocks the operation and is shown as the error. An empty return lets it carry on.
Listener
Hook::add('gate:user.blacklist_add', 10, function ($user_id, $reason, $restrictions) {
    // Ask for a second approval on an enterprise account.
    if (Acme::isEnterprise($user_id)) return 'An enterprise account needs manager approval.';

    return null;
});

Following a blacklist change

actionuser.blacklist_changed
AdminUsers three states

Runs after the blacklist state of a customer changes.

Parameters 4
$user_idintThe customer affected.
$statusstringWhat happened: add, add-2 or remove. There are two separate adding values; a listener watching only one misses the other.
$reasonstringThe reason.
$admin_idintThe administrator who did it.
Return 1
voidThe return is ignored.
Listener
Hook::add('action:user.blacklist_changed', 10,
    function ($user_id, $status, $reason, $admin_id) {
        // There are two separate adding values.
        if ($status !== 'remove') Acme::flagRisk($user_id, $reason);
    });

Stopping a bulk service cancellation

gateuser.services_bulk_cancel
AdminUsers all at once

Runs before every service of a customer is cancelled. It is one click, and hard to undo.

Parameters 1
$user_idintThe customer whose services would be cancelled.
Return 1
string|nullA non-empty text blocks the operation and is shown as the error. An empty return lets it carry on.
Listener
Hook::add('gate:user.services_bulk_cancel', 10, function ($user_id) {
    // One click takes every service.
    if (Acme::hasActiveContract($user_id)) return 'An account under contract cannot be cancelled in bulk.';

    return null;
});

Following a bulk suspension

actionuser.services_bulk_suspended
AdminUsers all at once

Runs after every service of a customer is suspended.

Parameters 1
$user_idintThe customer whose services were suspended.
Return 1
voidThe return is ignored.
Listener
Hook::add('action:user.services_bulk_suspended', 10, function ($user_id) {
    Acme::notifyAccountFrozen($user_id);
});

Stopping a dormant account being deleted

gateuser.delete_dormant
cronjobs per account

Runs before an account left unused for a long time is deleted. The hook fires per candidate: one round can call it hundreds of times.

Parameters 2
$userIdintThe account up for deletion.
$uarrayThe candidate row: name, address and how long it has been dormant.
Return 1
string|nullA non-empty text skips this account and the reason reaches the result report. Unlike other gates nothing is thrown: the round carries on with the remaining candidates.
Listener
Hook::add('gate:user.delete_dormant', 10, function ($userId, $u) {
    // It runs per account: keep it light.
    if (Acme::hasRetentionHold($userId)) return 'under a retention obligation';

    return null;
});

Changing the bulk message recipients

filteruser.bulk_recipients
AdminUsers count and list together

Runs once the recipient pool for a bulk email or text message is built.

Parameters 4
$resultarrayby linkThe recipient pool: a count and the contacts. ? Keep the two in step: dropping a contact without adjusting the count shows a wrong recipient total on screen.
$dbTypestringWho it goes to: customers or staff.
$notifTypestringWhich channel: email or text message.
$filtersarrayThe filters applied.
Return 1
voidThe return is ignored; you write over the data.
Listener
Hook::add('filter:user.bulk_recipients', 10,
    function (&$result, $dbType, $notifType, $filters) {
        // The COUNT and the LIST must stay in step.
        $result['contacts'] = Acme::dropOptedOut($result['contacts'] ?? []);
        $result['count']    = count($result['contacts']);
    });

Pitfalls

Blacklisting has two separate adding values

The status field carries three values and two of them mean adding. A listener watching only one misses a customer blacklisted through the other path. Testing for removal and treating the rest as adding is safer.

Update the recipient list and the count together

The bulk recipient filter carries both the contacts and the count. Dropping a contact and leaving the count alone shows the administrator a wrong recipient total and skews the decision to send.

Was this helpful?

Thanks for your feedback!

Still Need Help?

Our support team is here around the clock for anything you can't find above.