Skip to content

Cookbook (Developers)

Task-oriented recipes combining the helpers, filters, and actions from the other developer docs. Each is a copy-paste starting point. Drop them in a mu-plugin, child theme functions.php, or an extension.

Recipes hooked on a dms_* action or filter need no "is DMS active?" guard - those hooks only fire when DMS is active. Add a function_exists() check only for code that runs outside a DMS hook (e.g. the standalone DMS_Query loop below).


Change the SRP query

Add or override listing query arguments before the search results run.

add_filter( 'dms_query_args', function ( $args ) {
    // Show 24 per page and hide listings older than 2 years.
    $args['posts_per_page'] = 24;
    $args['date_query']     = [
        [ 'after' => '2 years ago', 'column' => 'post_date' ],
    ];
    return $args;
} );

See dms_query_args.


Customize a form notification email

These filters affect the notification email for every DMS form submission (lead capture, contact, trade-in, any form built with the DMS form builder), not just lead forms. The recipient, subject, and body all come from per-form settings; the filters override them for all forms, or use $form_id to target a specific one. They do not affect non-form emails such as stock-alert notifications, which have their own hooks.

// Reroute every DMS form's notification email.
add_filter( 'dms_form_mail_to', function ( $to, $form_id, $post ) {
    return 'sales@example.com, manager@example.com';
}, 10, 3 );

// Override the subject for one specific form only.
add_filter( 'dms_form_mail_subject', function ( $subject, $form_id, $post ) {
    return $form_id === 42 ? 'New website lead: ' . get_the_title( $post ) : $subject;
}, 10, 3 );

// Runs before each DMS form email is sent - inspect, log, or short-circuit.
add_action( 'dms_before_mail_send', function ( $mail_data ) {
    // $mail_data: post, form_fields, mail_to, mail_subject, mail_content, attachments, mail_type
}, 10, 1 );

See the dms_form_mail_* filters.


Trigger custom action on a saved listing (sync to an external system)

dms_on_listing_save fires on manual edits, imports, and programmatic saves.

add_action( 'dms_on_listing_save', function ( $listing_id, $post, $update ) {
    $listing = dms_get_listing( $listing_id );

    if ( ! $listing->exists() || ! $listing->is_published() ) {
        return;
    }

    $payload = [
        'id'    => $listing->get_id(),
        'title' => $listing->get_title(),
        'price' => $listing->get_final_price(),
        'url'   => $listing->get_permalink(),
    ];

    // wp_remote_post( 'https://feed.example.com/listings', [ 'body' => wp_json_encode( $payload ) ] );
}, 10, 3 );

See dms_on_listing_save.


Trigger custom action on a status change

add_action( 'dms_listing_status_changed', function ( $new_status, $old_status, $listing_id ) {
    if ( $new_status === 'sold' ) {
        $listing = dms_get_listing( $listing_id );
        // e.g. remove from an external feed, notify accounting
    }
}, 10, 3 );

See dms_listing_status_changed.


Sync new leads to a CRM

add_action( 'dms_add_lead', function ( $lead_data, $listing_id, $form_data ) {
    $listing = $listing_id ? dms_get_listing( $listing_id ) : null;

    // Push $lead_data (+ optional $listing context) to your CRM API.
}, 10, 3 );

See dms_add_lead.


Adjust displayed prices

Filter the numeric base price everywhere it's shown.

// Add a mandatory $299 prep fee to every base price.
add_filter( 'dms_listing_price', function ( $price, $listing ) {
    return $price + 299;
}, 10, 2 );

For fees/discounts modelled properly (so they appear as line items), configure them under the type's Fees & Discounts settings and read them via get_fees_discounts(). See Listings API - pricing.


Add a custom listing field and read it back

Register a metabox on dms_init, then read the value off the Listing.

add_action( 'dms_init', function () {
    dms_register_metabox( [
        'id'           => 'dealer_notes',
        'title'        => __( 'Dealer Notes', 'my-plugin' ),
        'object_types' => dms_get_types( true ),
        'context'      => 'side',
        'fields'       => [
            [ 'id' => 'internal_note', 'name' => 'Internal Note', 'type' => 'textarea_small' ],
        ],
    ] );
} );

// Read it anywhere:
add_action( 'dms_after_single_listing', function () {
    $listing = dms_get_current_listing();

    if ( $listing && $listing->exists() && current_user_can( 'edit_posts' ) ) {
        echo esc_html( $listing->get_meta( 'internal_note' ) );
    }
} );

See Building Extensions - metabox.


Modify export output

Add a column and populate it for every exported row.

add_filter( 'dms_export_columns', function ( $columns, $type ) {
    $columns['final_price'] = __( 'Final Price', 'my-plugin' );
    return $columns;
}, 10, 2 );

add_filter( 'dms_export_data', function ( $data, $export ) {
    foreach ( $data as $i => $row ) {
        if ( ! empty( $row['ID'] ) ) {
            $data[ $i ]['final_price'] = dms_get_listing( (int) $row['ID'] )->get_final_price();
        }
    }
    return $data;
}, 10, 2 );

Inject markup into the SRP and VDP

// A ribbon on each sold result card.
add_action( 'dms_after_sri', function ( $listing, $classes ) {
    if ( $listing->is_sold() ) {
        echo '<div class="sold-ribbon">Sold</div>';
    }
}, 10, 2 );

// A block at the bottom of every VDP.
add_action( 'dms_vdp_footer', function () {
    $listing = dms_get_current_listing();
    if ( $listing && $listing->exists() ) {
        printf( '<p>Days on lot: %d</p>', $listing->get_days_on_lot() );
    }
} );

See the front-end render hooks.


Build a custom listing loop outside DMS pages

Use DMS_Query so category meta keys and price ordering behave like the SRP.

$type = dms_get_type( 'vehicles' );

$query = new DMS_Query( [
    'type_id'        => $type->get_id(),
    'posts_per_page' => 6,
    'fields'         => 'ids',
] );

foreach ( $query->get_posts() as $listing_id ) {
    $listing = dms_get_listing( $listing_id );
    printf(
        '<a href="%s">%s - %s</a>',
        esc_url( $listing->get_permalink() ),
        esc_html( $listing->get_title() ),
        esc_html( $listing->get_formatted_final_price() )
    );
}

See Listings API - querying.


See also