Contents
Hooks reference - Plugixa Inventory
Every hook is prefixed plugixa_inventory_. Add listeners from a small plugin or
your theme’s functions.php.
Lifecycle
| Action | Fires |
|---|---|
plugixa_inventory_loaded |
The plugin has booted and the container is built |
plugixa_inventory_activated |
On activation, after the tables exist |
plugixa_inventory_deactivated |
On deactivation |
plugixa_inventory_uninstall |
On uninstall, before anything is removed |
plugixa_inventory_register_rest_routes |
With the namespace and the container, so your own routes can join it |
plugixa_inventory_enqueue_assets |
When the app’s assets are enqueued |
Records
do_action( 'plugixa_inventory_entity_created', $entity, $id, $data );
do_action( 'plugixa_inventory_entity_updated', $entity, $id, $data, $old );
do_action( 'plugixa_inventory_entity_deleted', $entity, $id );
do_action( 'plugixa_inventory_entity_restored', $entity, $id );
do_action( 'plugixa_inventory_entity_purged', $entity, $id );
$entity is the slug: item, category, warehouse, recipient,
stock_movement, transaction, and with Pro transfer, adjustment and unit.
Also plugixa_inventory_entity_assigned when a record’s assigned user changes,
and plugixa_inventory_entity_field_changed for a single field.
The matching filters run before the write, so a listener can change what is saved or stop it:
| Filter | Purpose |
|---|---|
plugixa_inventory_before_insert |
Change the data about to be inserted |
plugixa_inventory_before_update |
Change the data about to be updated |
plugixa_inventory_can_delete |
Refuse a trash |
plugixa_inventory_can_purge |
Refuse a permanent delete |
plugixa_inventory_load_record |
Change a record as it is loaded |
plugixa_inventory_filter_output |
Change what an endpoint returns |
Delete blockers
The mechanism behind “this warehouse still holds stock”:
add_filter( 'plugixa_inventory_warehouse_delete_blockers', function ( $blockers, $id ) {
if ( my_warehouse_is_locked( $id ) ) {
$blockers[] = __( 'This warehouse is locked for the stocktake.' );
}
return $blockers;
}, 10, 2 );
An empty array means “go ahead”. Anything in it is shown to the user and the
trash is refused. There are three: ..._warehouse_delete_blockers,
..._item_delete_blockers and ..._recipient_delete_blockers.
Stock
| Hook | Kind | Fires |
|---|---|---|
plugixa_inventory_document_finalized |
action | A document was finalised: $entity, $id, $document, $applied |
plugixa_inventory_stock_applied |
action | A batch of stock changes was written: $batch, $result |
plugixa_inventory_stock_level_changed |
action | An item’s total changed: $item_id, $total |
plugixa_inventory_stock_error |
action | A stock operation failed |
plugixa_inventory_stock_audited |
action | The reconcile ran: $report |
plugixa_inventory_layers_seeded |
action | Cost layers were opened: $report |
plugixa_inventory_document_finalized is the one most integrations want. It is
the moment stock actually moved, and it fires for every document type.
Notifications
| Hook | Kind | Purpose |
|---|---|---|
plugixa_inventory_alert_types |
filter | Declare a new kind of alert |
plugixa_inventory_alert_audience |
filter | Decide who an alert reaches |
plugixa_inventory_should_notify |
filter | Suppress one notification |
plugixa_inventory_alert_sent |
action | After sending: $type, $payload, $counts |
plugixa_inventory_before_send_mail |
action | Before an email leaves |
plugixa_inventory_email_throttle |
filter | Change the sending rate limit |
Permissions
| Hook | Kind | Purpose |
|---|---|---|
plugixa_inventory_user_can |
filter | The single permission decision, handed the record |
plugixa_inventory_capabilities |
filter | The capability map |
plugixa_inventory_entity_types |
filter | Register an entity, with its fields |
plugixa_inventory_filterable_fields |
filter | What a list may be narrowed by |
plugixa_inventory_user_can is where the Pro Roles module lives - the entire
module is essentially one listener on it. Every one of the plugin’s permission
callbacks routes through the method that fires it, which is why granular
permissions needed no controller changes.
Import and export
| Hook | Kind | Purpose |
|---|---|---|
plugixa_inventory_import_targets |
filter | Add a mappable column |
plugixa_inventory_import_write_extras |
filter | Write extra data per imported row |
plugixa_inventory_import_document_lines |
filter | Change the opening-stock document |
plugixa_inventory_record_writers |
filter | Register a generic writer, which is what makes an entity importable |
plugixa_inventory_record_names |
filter | Human names for records in messages |
The App Manager and settings
| Hook | Kind | Purpose |
|---|---|---|
plugixa_inventory_modules |
filter | The registered modules |
plugixa_inventory_apps |
filter | The App Manager’s cards |
plugixa_inventory_app_toggled |
action | An app was switched: $id, $enabled |
plugixa_inventory_sanitize_settings |
filter | Validate your own setting |
plugixa_inventory_settings_saved |
action | After a save: $settings |
plugixa_inventory_admin_config |
filter | What the admin bundle is given |
plugixa_inventory_bootstrap_payload |
filter | What /bootstrap returns |
The four that hold the seam together
These exist so that a free build is a working plugin rather than a crippled one. Each replaced a place where free code called something that became premium:
| Filter | So that |
|---|---|
plugixa_inventory_alert_types |
A module describes the event it raises, beside the code that raises it |
plugixa_inventory_warehouse_metrics |
A warehouse tile is contributed, so a dashboard does not need two document modules in order to boot |
plugixa_inventory_occurred_at_sources |
A document module names its own table, so a migration cannot join one that is absent |
plugixa_inventory_costing_strategy |
Costing answers with the object, not a name - a name filter could only choose between implementations the free build already knew |
That last distinction is the useful one to copy: a filter returning a name can only select from what the caller already knows about. A filter returning an object lets something the caller has never heard of answer.
Costing
| Hook | Kind | Purpose |
|---|---|---|
plugixa_inventory_costing_strategy |
filter | Supply your own costing implementation |
plugixa_inventory_costing_methods |
filter | The methods offered in settings |
plugixa_inventory_costing_method |
filter | The method in force |
plugixa_inventory_max_layer_walk |
filter | How far a layer walk may go before it gives up |
Front end
| Hook | Kind | Purpose |
|---|---|---|
plugixa_inventory_is_app_page |
filter | Whether this page holds the app |
plugixa_inventory_app_page_keep_styles |
filter | Stylesheets to keep through the style strip |
plugixa_inventory_public_request_captcha |
filter | Add a challenge to a public request |
plugixa_inventory_client_ip |
filter | How the visitor’s address is determined behind a proxy |
Example
Post a message when a document is finalised:
add_action(
'plugixa_inventory_document_finalized',
function ( string $entity, int $id, array $document, array $applied ): void {
if ( 'transfer' !== $entity ) {
return;
}
my_notify_depot( $document, $applied );
},
10,
4
);
Troubleshooting
| Symptom | Usual cause |
|---|---|
| A listener never fires | Register it on plugins_loaded or later, and check the argument count. |
| A filter has no effect | Another listener runs later. Raise the priority number to run after it. |
| A Pro hook does nothing | Its module is absent. The hook fires; nothing listens. |
plugixa_inventory_user_can is called constantly |
It is. Every permission decision goes through it. Keep the listener cheap. |
| A delete blocker is ignored | Return the array. A listener that returns nothing removes every blocker. |
| An entity has no CRUD routes | It needs to be registered through plugixa_inventory_entity_types. |
What to do next
- Call it from outside: REST API.
- Long jobs: WP-CLI.
- What is stored: Privacy and Data.