Skip to content
  1. Extras
  2. ms3FirstTimeBuyerDiscount
  3. Extension

Extension

How to replace the service, extend it, and use plugins on events.

Replacing the service

The service is registered in bootstrap under ms3ftb_discount. To use your own implementation:

  1. Load your code before the plugin runs (e.g. in a plugin with higher priority or in a package resolver).
  2. Register your factory:
php
$modx->services->add('ms3ftb_discount', function () use ($modx) {
    return new \YourNamespace\YourFtbService($modx);
});

Your class must at least implement apply(array $scriptProperties): ?float; other public methods are optional if you only call them from your own code.

Extending FtbDiscountService

The service is designed so you can override the main logic in a subclass:

  • isEligible(int $userId, ?object $draft): bool — change who is eligible (e.g. by user group or draft field).
  • getPaidOrdersCount(int $userId, int $excludeOrderId = 0): int — change how paid orders are counted (e.g. exclude current order).
  • getGuestContactFromDraft(?object $draft): array — change how guest email/phone is read from the draft.
  • getPaidOrdersCountByContact(string $email, string $phone, int $excludeOrderId = 0): int — change paid-order count for guests.
  • calculateDiscount(float $cost, string $type, float $value): float — change the formula (e.g. minimum order amount).

Example: discount only for the “Partner” group:

php
namespace YourNamespace\Services;

use Ms3FirstTimeBuyerDiscount\Services\FtbDiscountService;

class PartnerFtbService extends FtbDiscountService
{
    public function isEligible(int $userId, ?object $draft = null): bool
    {
        if (!parent::isEligible($userId, $draft)) {
            return false;
        }
        $user = $this->modx->getObject(\MODX\Revolution\modUser::class, $userId);
        if (!$user) {
            return false;
        }
        return $user->isMember('Partner');
    }
}

Register PartnerFtbService instead of the default service (see above).

Plugins on ftbOnBeforeApply

Cancel applying the discount (e.g. for a specific delivery method):

php
if (($modx->event->name ?? '') !== 'ftbOnBeforeApply') {
    return;
}
$draft = $modx->event->params['draft'] ?? null;
if ($draft && is_object($draft) && $draft->get('delivery_id') == 5) {
    $modx->event->returnedValues['apply'] = false;
}

Override the base amount used for the discount:

php
if (($modx->event->name ?? '') !== 'ftbOnBeforeApply') {
    return;
}
$cost = (float) ($modx->event->params['cost'] ?? 0);
$modx->event->returnedValues['cost'] = $cost * 0.95; // 5% base discount, then FTB

Plugins on ftbOnApply

Log or send to analytics:

php
if (($modx->event->name ?? '') !== 'ftbOnApply') {
    return;
}
$params = $modx->event->params;
$modx->log(modX::LOG_LEVEL_INFO, sprintf(
    'FTB applied: user=%s, discount=%s',
    $params['user_id'],
    $params['discount_amount']
), '', 'ftb');
// or send to CRM/analytics via $params['user_id'], $params['discount_amount']

Constants and settings

The service uses internal constants for discount types: percent, fixed. Setting keys: ftb_enabled, ftb_discount_type, ftb_discount_value, ftb_allow_combination. Full list and types: API.

Logging

The plugin writes to the MODX log when the discount is applied:

  • Category: ftb
  • Level: INFO
  • Message: [FTB] Applied: user_id=..., discount=..., cost_before=..., cost_after=...

Errors (e.g. service unavailable) are logged with level ERROR and the same category ftb.