Both plugins are built to be extended — Delivery Manager Pro layers onto the free plugin through its public hooks.
| Free | Pro | |
|---|---|---|
| Namespace | DeliveryManagerForWooCommerce | DeliveryManagerPro |
| Prefix | dman_ / DMAN_ | dmanp_ / DMAN_PRO_ |
| Meta prefix | _dman_ | _dmanp_ |
| Text domain | delivery-manager-for-woocommerce | delivery-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
| Key | Value |
|---|---|
_dman_delivery_person | Assigned user ID |
_dman_is_out_for_delivery | yes / no |
_dman_is_delivered | yes / no |
_dman_delivery_assigned_date | MySQL datetime |
_dman_out_for_delivery_date | MySQL datetime |
_dman_delivered_date | MySQL datetime |
_dman_delivery_steps | Serialized 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.phptemplates/myaccount/deliveries.phptemplates/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.phptemplates/myaccount/deliveries.phptemplates/myaccount/view-delivery.phptemplates/tracking/track-order.phptemplates/emails/delivery-notification.phptemplates/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 );