Contents
Hooks - Plugixa Car Rental
Every hook the plugin fires starts with plugixa_car_rental_. This page lists
the ones you are likely to use from a theme’s functions.php or a small plugin
of your own. Hooks that exist only to connect the plugin’s own modules to each
other are left out.
Hooks fired only by a Pro module are marked PRO. Everything else fires in both editions. Several Pro features (pricing rules, tax, driver age, delivery) are ordinary listeners on the pricing filters below, so your code can do what they do.
The ones you are most likely to want
| Hook | Type | What it is for |
|---|---|---|
plugixa_car_rental_booking_created |
action | React to a new booking |
plugixa_car_rental_booking_status_changed |
action | React to a booking being confirmed, picked up, returned, cancelled and so on |
plugixa_car_rental_booking_cancelled_by_customer |
action | React to a customer cancelling from the booking page |
plugixa_car_rental_payment_recorded |
action | React to money coming in or going out |
plugixa_car_rental_wizard_config |
filter | Change how one booking form starts, such as the desk it opens on |
plugixa_car_rental_quote_lines |
filter | Add a charge to every quote |
plugixa_car_rental_quote |
filter | Change a finished quote, or refuse a car for a request |
plugixa_car_rental_email |
filter | Rewrite or stop a booking email |
plugixa_car_rental_confirm_refusal |
filter | Stop a booking being confirmed |
plugixa_car_rental_public_request_captcha |
filter | Add an anti-spam check to the public routes |
plugixa_car_rental_public_request_refusal |
filter | Refuse a public search or hold that is missing an answer |
plugixa_car_rental_client_ip |
filter | Tell the rate limiter the real visitor address behind a proxy |
plugixa_car_rental_user_can |
filter | Narrow or widen what a staff member may do |
plugixa_car_rental_privacy_keep_booking |
filter | Keep a finished booking out of the personal data eraser |
Booking statuses
Status hooks pass these values.
| Status | Meaning |
|---|---|
pending |
Made, not yet confirmed. A booking from the site holds its car until the hold time runs out. |
confirmed |
Confirmed. The customer and your desk are emailed. |
picked_up |
The car is out. |
returned |
The car is back. |
completed |
Closed. The invoice is issued at this point. |
cancelled |
Cancelled by the customer or by your desk. |
no_show |
The customer did not come. |
expired |
The hold ran out before the booking was finished. |
Bookings and payments
| Action | Arguments | When it fires |
|---|---|---|
plugixa_car_rental_booking_created |
array $booking |
A booking was created, as pending, from the site or the desk. The booking includes its price lines. |
plugixa_car_rental_booking_status_changed |
int $id, string $from, string $to, array $booking |
A booking moved from one status to another. $booking is the booking as it now is. |
plugixa_car_rental_booking_cancelled_by_customer |
array $booking, array $terms |
A customer cancelled their own booking from the booking page. $terms holds fee, refund and free. |
plugixa_car_rental_payment_recorded |
array $booking, float $paid |
A payment or a refund was recorded and the booking’s paid state worked out again. $paid is what it now holds in total. |
plugixa_car_rental_payment_unplaced |
array $booking, WP_Error $error |
Money arrived for a booking that could no longer be confirmed: its hold ran out and the car went to somebody else, or a plugixa_car_rental_confirm_refusal listener refused it. (A used-up coupon does not: a paid booking keeps its discount.) The payment is recorded; your desk refunds or rebooks. |
plugixa_car_rental_payment_notice |
string $notice, array $booking, string $gateway, array $data |
A payment provider reported something that moves no money, such as checkout_expired, payment_processing, payment_failed, dispute_opened, dispute_closed or refund_failed. Fired by the Stripe and PayPal modules. |
plugixa_car_rental_invoice_issued |
array $invoice, array $booking |
An invoice was issued. This happens when a booking is completed. |
plugixa_car_rental_message_sent PRO |
true|WP_Error $result, string $channel, string $status, array $booking |
A text message or Telegram alert was sent, or failed to be. |
plugixa_car_rental_inspection_signed PRO |
array $inspection, array $booking |
A pickup or return inspection was signed and its agreement stored. |
Send every confirmed booking to another system:
add_action( 'plugixa_car_rental_booking_status_changed', function ( $id, $from, $to, $booking ) {
if ( 'confirmed' !== $to ) {
return;
}
wp_remote_post( 'https://example.com/hooks/rentals', array(
'body' => array(
'reference' => $booking['reference'],
'pickup' => $booking['pickup_at'],
'return' => $booking['return_at'],
),
) );
}, 10, 4 );
Warn your desk when a payment could not be placed:
add_action( 'plugixa_car_rental_payment_unplaced', function ( $booking, $error ) {
wp_mail(
get_option( 'admin_email' ),
'Payment needs attention: ' . $booking['reference'],
$error->get_error_message()
);
}, 10, 2 );
Refusing a confirmation
| Filter | Value | Other arguments | What it is for |
|---|---|---|---|
plugixa_car_rental_confirm_refusal |
null|WP_Error $refusal |
array $booking |
Asked just before a pending booking is confirmed, whoever confirms it: the booking form, an online payment, or your desk. Return null to let it go ahead, or a WP_Error to refuse it. $booking is the booking about to be confirmed, with its price lines in line_items. A refusal changes nothing: the booking stays pending and the error goes back to whoever asked. |
It is for a condition that was true when the car was held and may have stopped
being true since. The Coupons app uses it to refuse a booking whose coupon was
used up while it was held. Pass on a refusal you were given, so you do not
undo another module’s answer. Put the form field the message is about in the
error’s data as field, and the booking form shows it there.
Refuse to confirm a rental of more than 28 days without a deposit paid:
add_filter( 'plugixa_car_rental_confirm_refusal', function ( $refusal, $booking ) {
if ( null !== $refusal ) {
return $refusal;
}
if ( (int) $booking['billable_days'] > 28 && (float) $booking['amount_paid'] <= 0 ) {
return new WP_Error(
'my_long_rental_unpaid',
'Rentals of more than four weeks must be paid in part before they are confirmed.',
array( 'status' => 409 )
);
}
return null;
}, 10, 2 );
The booking form
| Filter | Arguments | What it is for |
|---|---|---|
plugixa_car_rental_wizard_config |
array $config |
What one booking form is handed when its page is drawn, by the block or the shortcode. Runs once for each form on the page. |
$config holds:
| Key | Holds |
|---|---|
apiUrl |
The address of the plugin’s REST routes, with a trailing slash |
locale |
The visitor’s language, such as pt-PT, for dates and money |
currency |
Your main currency code |
location |
The ID of the desk the form opens on: the location attribute, else the ?pcr_location= link, else 0 for the first desk that takes pickups |
i18n |
The form’s words, by key |
locationPicker PRO |
Added by the Map at the default priority, when the form shows the map of desks. Remove it to leave the map out of one form. |
The form is drawn in the visitor’s browser from this array, so whatever you return is written into the page. Put nothing private in it. A page cache keeps the result, so base it on the page, not on the visitor.
Open the form on the desk with ID 3, without the map, on the page with the slug cascais:
add_filter( 'plugixa_car_rental_wizard_config', function ( array $config ): array {
if ( is_page( 'cascais' ) ) {
$config['location'] = 3;
unset( $config['locationPicker'] );
}
return $config;
}, 20 );
Use a priority above 10, as here, so your filter runs after the map has added
its part. Removing locationPicker this way hides the map, but Google’s script
has already been asked for on that page. To keep Google off the page entirely,
turn off Show a map to choose the pickup desk in the booking form under
Settings -> Map.
Prices
A quote is built in four steps, and each has a filter. The three line filters
work in the site’s currency. When a customer books in another currency
PRO, the quote has already been converted by the time
plugixa_car_rental_quote runs, and its currency says which.
| Filter | Value | Other arguments | What it is for |
|---|---|---|---|
plugixa_car_rental_quote_lines |
array $lines |
array $context |
Charges added before any discount: extras, a surcharge, a delivery fee. |
plugixa_car_rental_quote_discounts |
array $lines (empty) |
float $subtotal, array $context |
Discounts. Only lines with a negative total are kept, and the discount never goes past the subtotal. |
plugixa_car_rental_quote_lines_after_discount |
array $lines (empty) |
float $net, array $context |
Charges on the discounted amount, such as tax. A line with 'included' => true is tax already inside the price: it is shown, and not added a second time. |
plugixa_car_rental_quote |
array $quote |
array $context |
The finished quote. |
Each line needs type, label and a numeric total. You may also give
quantity and unit_price. Anything without the three required keys is
dropped.
$context holds window (the rental: pickup and return locations and times,
and days, the number of days charged), model (the vehicle model’s row),
request and currency.
Add a cleaning fee to every rental of a Premium model:
add_filter( 'plugixa_car_rental_quote_lines', function ( $lines, $context ) {
if ( 4 === (int) $context['model']['category_id'] ) { // Your Premium category's id.
$lines[] = array(
'type' => 'cleaning',
'label' => 'Premium valet',
'total' => 25,
);
}
return $lines;
}, 10, 2 );
Refusing a car
On the finished quote, set refusal to a sentence to stop a car being booked
for this request. The car is still listed and priced, with your sentence beside
it, and holding it is refused in the same words. Add refusal_field to name
the form field the reason is about. With 'refusal_scope' => 'request' the
reason applies to the whole search instead, and the form shows that one
message at the named field instead of a list of refused cars.
add_filter( 'plugixa_car_rental_quote', function ( $quote, $context ) {
if ( $context['window']->days > 21 && 'Mercedes V-Class' === $context['model']['name'] ) {
$quote['refusal'] = 'The V-Class can be rented for three weeks at most.';
}
return $quote;
}, 10, 2 );
Change totals only together with the lines that explain them. The customer sees the lines.
Narrowing the cars
| Filter | Value | Other arguments | What it is for |
|---|---|---|---|
plugixa_car_rental_availability_units |
array $candidates |
int $model_id, RentalWindow $window |
The cars that could serve a rental, before bookings and blocks are checked. You may remove cars from the list. A car of another model is dropped whatever you return. |
Emails
| Hook | Type | Arguments | What it is for |
|---|---|---|---|
plugixa_car_rental_email |
filter | array $email, string $type, array $booking |
Rewrite a booking email. $email has to, subject and body (HTML). Return an empty to to stop it. $type is customer_confirmed, customer_cancelled, desk_confirmed, or customer_invoice PRO. |
plugixa_car_rental_booking_payment_instructions |
filter | string $text, array $booking |
The payment paragraph of the confirmation email. |
plugixa_car_rental_booking_manage_url |
filter | string $url, array $booking |
The link to the customer’s booking page, used in emails and messages. Empty when the customer portal is off or no page shows it. |
plugixa_car_rental_before_send_mail |
action | string|string[] $to, string $subject, array $options |
Just before the plugin hands an email to wp_mail(). Useful for logging. |
Send the desk email to a second address and stop the cancellation email:
add_filter( 'plugixa_car_rental_email', function ( $email, $type, $booking ) {
if ( 'desk_confirmed' === $type ) {
$email['to'] = $email['to'] . ',fleet@example.com';
}
if ( 'customer_cancelled' === $type ) {
$email['to'] = '';
}
return $email;
}, 10, 3 );
Public routes and abuse protection
The booking form and the customer booking page talk to routes under
/wp-json/plugixa-car-rental/v1/public/. Visitors use them without signing in,
so each one is rate limited per visitor address.
| Filter | Value | Other arguments | What it is for |
|---|---|---|---|
plugixa_car_rental_public_request_captcha |
true |
string $token, string $action |
Refuse a public request. Return false, or a WP_Error to choose the status and message. $token is the request’s captcha_token, cleaned, or an empty string. $action names the route, such as public_search, public_hold, public_checkout or public_manage_find. |
plugixa_car_rental_public_request_refusal |
null|WP_Error $refusal |
array $fields |
Asked before a public search and before a public hold. Return null to let it go ahead, or a WP_Error to refuse it. Not asked for desk bookings. See below. |
plugixa_car_rental_client_ip |
string $ip |
none | The address a public request is counted against. By default REMOTE_ADDR only. |
plugixa_car_rental_public_options |
array $options |
none | What the booking form loads before the visitor types anything: locations, gateways and more. Add only what any visitor may see. |
plugixa_car_rental_portal_view |
array $view |
array $booking, string $token |
What the customer booking page shows for a booking. Add only what the holder of the booking’s link may see. |
Behind a proxy or Cloudflare, every visitor arrives from the proxy’s address and they would all share one rate-limit counter. Read the trusted header instead, and only when your site really is behind that proxy, because anyone can send the header otherwise:
add_filter( 'plugixa_car_rental_client_ip', function ( $ip ) {
$forwarded = $_SERVER['HTTP_CF_CONNECTING_IP'] ?? '';
return filter_var( $forwarded, FILTER_VALIDATE_IP ) ? $forwarded : $ip;
} );
The booking form does not send a captcha_token itself, so the CAPTCHA filter
is for checks that need no token from the browser, or for your own front end
that sends one.
Refusing a public search or hold
plugixa_car_rental_public_request_refusal is for an answer a visitor must
give before cars are searched or held, when the browser’s “required” is not
enough. The Driver age app PRO uses it to refuse a request without
an age from 16 to 99.
$fields is not the request body. It holds only the fields the plugin’s
modules claim for pricing, such as extras, coupon, driver_age
PRO, currency PRO, delivery_address PRO
and collection_address PRO, each already cleaned by the module
that owns it. A field the visitor did not send is absent. Dates and locations
are not in it. Pass on a refusal you were given, and put the form field in the
error’s data as field so the form shows the message beside it.
With the Driver age app PRO on, turn away drivers under 21 before any car is searched, instead of showing every car with a minimum-age message:
add_filter( 'plugixa_car_rental_public_request_refusal', function ( $refusal, $fields ) {
if ( null !== $refusal ) {
return $refusal;
}
$age = (int) ( $fields['driver_age'] ?? 0 );
if ( $age > 0 && $age < 21 ) {
return new WP_Error(
'my_driver_too_young',
'We rent to drivers aged 21 and over.',
array( 'status' => 422, 'field' => 'driver_age' )
);
}
return null;
}, 10, 2 );
Payments
| Hook | Type | Arguments | What it is for |
|---|---|---|---|
plugixa_car_rental_payment_gateways |
filter | Gateway[] $gateways |
The payment methods on offer. Pay at pickup and bank transfer are built in; Stripe and PayPal add themselves here in Pro. A new gateway implements the plugin’s Gateway interface. |
plugixa_car_rental_stripe_checkout_params PRO |
filter | array $params, array $booking |
The parameters of the Stripe Checkout session before it is created. The mode, metadata, amounts and return addresses are put back as they were, so change only other options such as the locale. |
add_filter( 'plugixa_car_rental_stripe_checkout_params', function ( $params, $booking ) {
$params['locale'] = 'pt';
return $params;
}, 10, 2 );
Permissions
| Filter | Value | Other arguments | What it is for |
|---|---|---|---|
plugixa_car_rental_user_can |
bool $allowed |
string $action, string $entity_type, array|null $record, int $user_id |
Whether a user may do something to a kind of record. $action is read, create, edit, delete or export. $allowed is the answer from the user’s capabilities. |
plugixa_car_rental_capabilities |
array $map |
none | The capability map handed to the admin app, which decides what it draws. |
Let a staff member read bookings but never export them:
add_filter( 'plugixa_car_rental_user_can', function ( $allowed, $action, $entity_type, $record, $user_id ) {
if ( 'booking' === $entity_type && 'export' === $action && ! user_can( $user_id, 'manage_options' ) ) {
return false;
}
return $allowed;
}, 10, 5 );
The capabilities themselves are plugixa_car_rental_manage,
plugixa_car_rental_view, plugixa_car_rental_create,
plugixa_car_rental_edit, plugixa_car_rental_delete,
plugixa_car_rental_export and plugixa_car_rental_manage_settings. Grant
them with any role editor.
Privacy
The plugin adds a Car rental bookings exporter and eraser to WordPress’s Export Personal Data and Erase Personal Data tools. The eraser anonymises finished bookings (completed, cancelled, expired, no-show) and keeps open ones. See Privacy and uninstall.
| Filter | Value | Other arguments | What it is for |
|---|---|---|---|
plugixa_car_rental_privacy_keep_booking |
string|null $reason |
array $booking |
Asked for each finished booking before it is anonymised. Return null to let it be anonymised, or a sentence saying why it is kept. The sentence is shown to the administrator after the booking’s reference. The Invoices app uses it to keep invoiced bookings. |
Keep bookings with an open damage claim, marked in a notes line of your own:
add_filter( 'plugixa_car_rental_privacy_keep_booking', function ( $reason, $booking ) {
if ( null !== $reason ) {
return $reason;
}
if ( str_contains( (string) $booking['notes'], '[damage claim]' ) ) {
return 'kept because a damage claim is still open.';
}
return null;
}, 10, 2 );
Records
These fire for every kind of record the plugin stores. The first argument is
the record’s slug: booking, payment, invoice, vehicle_category,
vehicle_model, vehicle_unit, location, location_closure, rate_plan,
extra, coupon and form_field, plus pricing_rule, tax_rate,
inspection and calendar_import PRO.
| Hook | Type | Arguments | When it fires |
|---|---|---|---|
plugixa_car_rental_before_insert |
filter | array $data, string $entity |
Just before a record is created. |
plugixa_car_rental_entity_created |
action | string $entity, int $id, array $data |
After a record is created. |
plugixa_car_rental_before_update |
filter | array $data, string $entity, int $id, array $old |
Just before a record is changed. |
plugixa_car_rental_entity_field_changed |
action | string $entity, int $id, string $field, mixed $new, mixed $old |
Once for each field whose value changed. |
plugixa_car_rental_entity_updated |
action | string $entity, int $id, array $data, array $old |
After a record is changed. |
plugixa_car_rental_can_delete |
filter | bool $allowed, string $entity, int $id, array $old |
Before a record goes to the trash. Return anything but true to refuse. |
plugixa_car_rental_entity_deleted |
action | string $entity, int $id, array $old |
After a record is moved to the trash. It can still be restored. |
plugixa_car_rental_entity_restored |
action | string $entity, int $id, array $row |
After a record is restored from the trash. |
plugixa_car_rental_can_purge |
filter | bool $allowed, string $entity, int $id, array $row |
Before a record is deleted for good. Return anything but true to refuse. |
plugixa_car_rental_entity_purged |
action | string $entity, int $id, array $row |
After a record is deleted for good. |
A refusal from can_delete or can_purge carries no message. To explain why a
car, a model or a location cannot be trashed, use the blocker filters instead.
Each takes a list of sentences, and any sentence in the list stops the trash
and is shown to the user.
| Filter | Arguments |
|---|---|
plugixa_car_rental_vehicle_model_delete_blockers |
string[] $blockers, int $id, array $model |
plugixa_car_rental_vehicle_unit_delete_blockers |
string[] $blockers, int $id, array $unit |
plugixa_car_rental_location_delete_blockers |
string[] $blockers, int $id, array $location |
Lifecycle
| Action | Arguments | When it fires |
|---|---|---|
plugixa_car_rental_loaded |
Container $container |
Once the plugin has started, on plugins_loaded, after every module has registered its hooks. |
plugixa_car_rental_register_rest_routes |
string $namespace, Container $container |
On rest_api_init, after the plugin’s own routes. $namespace is plugixa-car-rental/v1. |
plugixa_car_rental_settings_saved |
array $settings |
After the settings are saved. |
plugixa_car_rental_activated |
none | On activation, after the tables exist. |
plugixa_car_rental_deactivated |
none | On deactivation, before scheduled events are cleared. |
plugixa_car_rental_uninstall |
none | During an uninstall that erases data, before the tables are dropped. See Privacy and uninstall. |
Scheduled events
| Event | Runs | What it does |
|---|---|---|
plugixa_car_rental_expire_holds |
Hourly | Marks pending bookings whose hold ran out as expired. A lapsed hold stops blocking its car at once; this only tidies the status. |
plugixa_car_rental_send_message PRO |
Once per message | Sends one text message or Telegram alert, just after the status change that asked for it. |
plugixa_car_rental_calendar_import PRO |
Hourly | Reads the calendar feeds you added under calendar sync. |
All three rely on WordPress’s scheduler, which runs when somebody visits the
site. On a quiet site, or one with DISABLE_WP_CRON set, run wp-cron.php from
a real server cron job.