Go Back to Parent Doc

Delivery Manager Developer Reference — Hooks, Filters, Templates & Data Model

Both plugins are built to be extended — Delivery Manager Pro layers onto the free plugin through its public hooks.

FreePro
NamespaceDeliveryManagerForWooCommerceDeliveryManagerPro
Prefixdman_ / DMAN_dmanp_ / DMAN_PRO_
Meta prefix_dman__dmanp_
Text domaindelivery-manager-for-woocommercedelivery-manager-pro

All order access goes through wc_get_order() and the CRUD API, so everything below is HPOS-safe. Never use get_post_meta() on an order ID.


Boot order

woocommerce_init (priority 0)
  └─ DeliveryManagerForWooCommerce\Plugin::init()
       ├─ Role, Frontend\Frontend, Frontend\Order
       ├─ Frontend\MyAccount        (only when dman_is_delivery_person())
       ├─ Admin\Admin, Admin\Actions, Admin\Orders   (only when is_admin())
       └─ do_action( 'dman_init', $plugin )
            └─ DeliveryManagerPro\Plugin::init()
                 ├─ Schema::install()   (always)
                 ├─ returns unless licensed
                 ├─ Statuses, DeliveryLog, Assignment, Notes, ProofOfDelivery,
                 │  Tracking, Timeline, Notifications\Emails, Integrations\Webhooks
                 ├─ Frontend\MyAccount (delivery persons), Frontend\Frontend, Frontend\TrackingPage
                 ├─ Admin\Admin, Actions, Orders, Dispatch, Reports  (is_admin())
                 └─ do_action( 'dmanp_init', $plugin )

Add-ons should boot on dman_init (or dmanp_init if they need Pro), not on plugins_loaded.


Free plugin

Constants

DMAN_VERSION       // Plugin version
DMAN_FILE          // Main plugin file path
DMAN_PATH          // Plugin directory path
DMAN_URL           // Plugin directory URL
DMAN_ASSETS_PATH   // Assets directory path
DMAN_ASSETS_URL    // Assets directory URL

Helper functions

delivery_manager_for_woocommerce();          // the plugin instance
dman_is_delivery_person( $user_id = null );  // bool
dman_get_account_deliveries_columns();       // deliveries table columns
dman_get_delivery_view_url( $order );        // My Account view-delivery URL
dman_get_delivery_steps( $order );           // timeline steps, sorted by priority

Actions

// Plugin loaded, all classes instantiated. Add-ons boot here.
do_action( 'dman_init', $plugin );

// A delivery person was assigned from the admin metabox.
do_action( 'dman_delivery_person_assigned', $order, $person_id, $previous_person_id );

// A delivery status flag changed. $context is 'admin' or 'delivery_person'.
do_action( 'dman_delivery_status_changed', $order, $field, $value, $context );

// Admin — after the delivery metabox fields.
do_action( 'dman_admin_after_order_meta_box', $order );

// Settings — after the general settings fields.
do_action( 'dman_after_general_settings_fields' );

// Frontend — before the delivery timeline.
do_action( 'dman_before_delivery_timeline', $order );

// My Account — after the delivery person's status checkboxes.
do_action( 'dman_after_delivery_status_fields', $order );

// My Account — around the deliveries list.
do_action( 'dman_before_account_deliveries', $has_deliveries );
do_action( 'dman_before_account_deliveries_pagination' );
do_action( 'dman_after_account_deliveries', $has_deliveries );

// My Account — per column of the deliveries table.
do_action( "dman_my_account_deliveries_before_column_{$column_id}", $order );
do_action( "dman_my_account_my_deliveries_column_{$column_id}", $order );
do_action( "dman_my_account_deliveries_after_column_{$column_id}", $order );

Filters

// Screens registered with WooCommerce (plugin admin pages).
apply_filters( 'dman_screen_ids', $screen_ids );

// Screens the Delivery Details metabox is registered on.
// Default: [ 'woocommerce_page_wc-orders', 'shop_order' ]
apply_filters( 'dman_metabox_screen_ids', $screen_ids );

// The timeline steps array (keyed, each with icon/title/desc/date/priority).
apply_filters( 'dman_delivery_steps', $steps, $order );

// Expected delivery date shown on the timeline. Return '' to hide it.
apply_filters( 'dman_expected_delivery_date', $expected_delivery, $order );

// Delivery status key used for the badge and the deliveries column.
apply_filters( 'dman_delivery_status', $delivery_status, $order );

// Columns of the My Account deliveries table.
apply_filters( 'dman_account_deliveries_columns', $columns );

// wc_get_orders() args for the delivery person's deliveries list.
apply_filters( 'dman_my_account_my_deliveries_query', $args );

Order meta

KeyValue
_dman_delivery_personAssigned user ID
_dman_is_out_for_deliveryyes / no
_dman_is_deliveredyes / no
_dman_delivery_assigned_dateMySQL datetime
_dman_out_for_delivery_dateMySQL datetime
_dman_delivered_dateMySQL datetime
_dman_delivery_stepsSerialized timeline steps

Options: dman_is_auto_complete_delivery, dman_is_complete_order_on_delivery, dman_deliveries_menu_title. Role: dman_delivery_person (read, manage_delivery).

Templates

Copy into yourtheme/woocommerce/<same path> to override:

  • templates/order/order-delivery-details.php
  • templates/myaccount/deliveries.php
  • templates/myaccount/view-delivery.php

Examples

// Add a column to the delivery person's deliveries table.
add_filter( 'dman_account_deliveries_columns', function ( $columns ) {
    $columns['zone'] = __( 'Zone', 'my-plugin' );
    return $columns;
} );

add_action( 'dman_my_account_my_deliveries_column_zone', function ( $order ) {
    echo esc_html( $order->get_shipping_postcode() );
} );

// Give delivery persons their on-hold orders too.
add_filter( 'dman_my_account_my_deliveries_query', function ( $args ) {
    $args['status'][] = 'on-hold';
    return $args;
} );

// Notify an external system whenever a delivery is assigned.
add_action( 'dman_delivery_person_assigned', function ( $order, $person_id ) {
    wp_remote_post( 'https://example.com/hook', [ 'body' => [
        'order'  => $order->get_id(),
        'person' => $person_id,
    ] ] );
}, 10, 2 );

Delivery Manager Pro

Constants

DMAN_PRO_VERSION, DMAN_PRO_FILE, DMAN_PRO_PATH, DMAN_PRO_URL, DMAN_PRO_ASSETS_URL.

Detect Pro with defined( 'DMAN_PRO_VERSION' ) — the free plugin uses exactly that to hide its upgrade prompts.

Helper functions

dmanp_get_settings();                               // all settings, merged with defaults
dmanp_get_setting( $key, $default = null );
dmanp_update_settings( array $values );

dmanp_get_statuses();                               // configured statuses, in display order
dmanp_get_status_config( $key );
dmanp_get_status_keys_by_group( $groups );          // pending|active|delivered|failed|returned|cancelled
dmanp_get_status( $order );                         // current status key ('' when none)
dmanp_get_status_label( $order );
dmanp_set_status( $order, $status, $args );         // true|WP_Error
dmanp_status_badge( $key );                         // HTML

dmanp_assign_person( $order, $user_id, $args );     // true|WP_Error
dmanp_get_delivery_person( $order );                // WP_User|false
dmanp_get_delivery_persons( $args );                // WP_User[]
dmanp_person_is_on_duty( $user_id );
dmanp_get_person_capacity( $user_id );              // 0 = unlimited
dmanp_count_active_deliveries( $user_id );
dmanp_get_person_delivery_ids( $user_id, $groups );
dmanp_get_person_phone( $user_id );

dmanp_get_expected_delivery( $order );              // [ date, slot, formatted, timestamp, is_custom ]
dmanp_get_time_slots();
dmanp_get_tracking_url( $order );
dmanp_get_delivery_address( $order );
dmanp_get_delivery_name( $order );
dmanp_get_delivery_phone( $order );
dmanp_get_map_url( $order );
dmanp_get_whatsapp_url( $phone, $text = '' );

dmanp_log( array $data );                           // write a delivery log row
dmanp_format_datetime( $utc_datetime, $format = '' );
dmanp_format_duration( $seconds );
dmanp_current_user_can_manage();                    // manage_woocommerce
dmanp_current_user_can_deliver( $order );           // manager, or the assigned person
dmanp_locate_template( $template );
dmanp_get_template( $template, array $args = [] );

$args for dmanp_set_status(): note, is_public, context (admin | delivery_person | system | api), lat, lng, user_id. $args for dmanp_assign_person(): method (manual | bulk | auto | dispatch), context, note, zone_id.

Actions

do_action( 'dmanp_init', $plugin );
do_action( 'dmanp_status_changed', $order, $new_status, $old_status, $args );
do_action( 'dmanp_delivery_assigned', $order, $person_id, $previous_id, $method );
do_action( 'dmanp_note_added', $order, $text, $is_public, $user_id, $log_id );
do_action( 'dmanp_pod_saved', $order, $pod );
do_action( 'dmanp_expected_delivery_changed', $order, $expected );
do_action( 'dmanp_notification', $email_id, $order, $recipient, $context );
do_action( 'dmanp_before_timeline', $order, $context );
do_action( 'dmanp_after_timeline', $order, $context );
do_action( 'dmanp_log_inserted', $id, $data );
do_action( 'dmanp_daily_maintenance_done' );
do_action( "dmanp_settings_tab_{$tab}" );   // render your own settings tab

Filters

apply_filters( 'dmanp_default_settings', $settings );
apply_filters( 'dmanp_settings', $settings );
apply_filters( 'dmanp_settings_tabs', $tabs );

apply_filters( 'dmanp_default_statuses', $statuses );
apply_filters( 'dmanp_statuses', $statuses );
apply_filters( 'dmanp_before_status_change', true, $order, $new, $old, $args ); // WP_Error blocks it
apply_filters( 'dmanp_person_status_choices', $choices, $order, $current );

apply_filters( 'dmanp_auto_assign_candidates', $candidates, $order, $zone_id );
apply_filters( 'dmanp_auto_assign_candidate', $person_id, $candidates, $order );
apply_filters( 'dmanp_matched_zone', $zone, $order, $address );
apply_filters( 'dmanp_dispatch_unassigned_statuses', $statuses );
apply_filters( 'dmanp_delivery_order_statuses', $statuses );

apply_filters( 'dmanp_expected_delivery', $expected, $order );
apply_filters( 'dmanp_time_slots', $slots );
apply_filters( 'dmanp_timeline_steps', $steps, $order, $context );
apply_filters( 'dmanp_deliveries_tabs', $tabs );

apply_filters( 'dmanp_notification_placeholders', $values, $order, $context );
apply_filters( 'dmanp_webhook_events', $events );
apply_filters( 'dmanp_webhook_payload', $payload, $event, $order );

apply_filters( 'dmanp_tracking_page_lookup', $order, $number, $identifier );
apply_filters( 'dmanp_tracking_page_url', $url );

Data model

Tables

{prefix}dmanp_delivery_log — append-only, one row per event. Columns: id, order_id, person_id, event (assigned, reassigned, unassigned, status, note, pod, location, eta), status, note, is_public, lat, lng, created_by (0 = system), created_at (UTC).

{prefix}dmanp_zones — id, name, match_type (postcode, city, state, country, wc_shipping_zone), match_values (JSON), persons (JSON user IDs), priority, is_active.

Order meta — _dmanp_status, _dmanp_status_updated, _dmanp_expected_date, _dmanp_time_slot, _dmanp_zone_id, _dmanp_attempts, _dmanp_pod_photo_id, _dmanp_pod_signature_id, _dmanp_pod_recipient, _dmanp_tracking_token.

The free _dman_* flags are kept in sync by Statuses, so free-plugin code and third-party integrations keep working while Pro is active.

User meta — dmanp_phone, dmanp_vehicle, dmanp_max_active, dmanp_on_duty, dmanp_zones.

Options — dmanp_settings (array), dmanp_statuses, dmanp_round_robin, dmanp_webhook_log, plus the license options.

Templates

Copy into yourtheme/woocommerce/<same path>:

  • templates/order/order-delivery-details.php
  • templates/myaccount/deliveries.php
  • templates/myaccount/view-delivery.php
  • templates/tracking/track-order.php
  • templates/emails/delivery-notification.php
  • templates/emails/plain/delivery-notification.php

Pro swaps the free plugin’s templates through the wc_get_template filter — but a theme override always wins, so if your theme already overrides order/order-delivery-details.php, Pro leaves it alone.

Examples

// Block a status change unless proof of delivery exists.
add_filter( 'dmanp_before_status_change', function ( $ok, $order, $new ) {
    if ( 'delivered' === $new && ! $order->get_meta( '_dmanp_pod_photo_id' ) ) {
        return new WP_Error( 'pod_required', __( 'A delivery photo is required.', 'my-plugin' ) );
    }
    return $ok;
}, 10, 3 );

// Prefer the driver who delivered to this customer last time.
add_filter( 'dmanp_auto_assign_candidate', function ( $person_id, $candidates, $order ) {
    $last = get_user_meta( $order->get_customer_id(), 'my_last_driver', true );
    return in_array( (int) $last, $candidates, true ) ? (int) $last : $person_id;
}, 10, 3 );

// Add your own field to the webhook payload.
add_filter( 'dmanp_webhook_payload', function ( $payload, $event, $order ) {
    $payload['delivery']['zone_id'] = $order->get_meta( '_dmanp_zone_id' );
    return $payload;
}, 10, 3 );

// Send an SMS on every Pro notification.
add_action( 'dmanp_notification', function ( $email_id, $order, $recipient, $context ) {
    if ( 'dmanp_out_for_delivery' === $email_id ) {
        my_sms_send( dmanp_get_delivery_phone( $order ), 'Your order is on its way.' );
    }
}, 10, 4 );

Related

Shopping Cart
  • Your cart is empty.