Customization Guide

Get Started

Customization Guide

Common customization patterns for Product Roadmap Pro. Each recipe shows a practical use case with copy-paste code you can add to your theme’s functions.php file or a custom plugin.

Time to read: 8 minutes


Before You Start

All code examples go in one of two places:

  1. Your child theme’s functions.php — Good for theme-specific customizations
  2. A custom plugin — Better for site-wide customizations that survive theme changes

Create a custom plugin by adding this file to wp-content/plugins/my-roadmap-customizations/my-roadmap-customizations.php:

<?php
/**
 * Plugin Name: My Roadmap Customizations
 * Description: Custom extensions for Product Roadmap Pro
 */

// Your customization code goes here

Activate it under Plugins in WordPress admin.


Shortcode Reference

[roadmap] / [product_roadmap]

AttributeDefaultDescription
productmainProduct slug to display (comma-separated for multiple)
templateminimalDisplay template: board, timeline, list, cards, minimal
modeviewview for read-only, manage for drag-and-drop (requires edit_posts capability)
status(all)Comma-separated status slugs to filter
category(all)Comma-separated category slugs to filter
sort(default)Sort order: votes, recent, comments, priority
limit20Maximum items to display
orderbydateSort field: date, votes, priority, title
orderDESCSort direction: ASC or DESC
allow<em>frontend</em>editfalseEnable frontend item editing UI
class(none)Custom CSS class added to the wrapper div

[roadmap_changelog]

AttributeDefaultDescription
product(all)Filter by product slug
version(all)Show a specific version only
id(none)Show a single entry by post ID
limit10Number of entries to display
show_datetrueShow or hide the release date
collapsiblefalseMake version sections collapsible with toggle buttons
class(none)Custom CSS class added to the wrapper div

[roadmap<em>user</em>profile]

AttributeDefaultDescription
user_idCurrent userWordPress user ID to display

Template Override System

The free plugin supports theme-based template overrides. Place template files in your theme directory to customize the display without modifying plugin files.

Override Hierarchy

TemplateTheme FileFallback
Single itemsingle-roadmap_item.phpPlugin templates/single-roadmap_item.php
Product archivearchive-roadmap<em>product.php or taxonomy-roadmap</em>product.phpPlugin templates/archive-roadmap-product.php
All-products archivearchive-roadmap_item.phpPlugin templates/archive-roadmap_item.php
Single changelogsingle-roadmap_changelog.phpPlugin templates/single-roadmap_changelog.php
Changelog archivearchive-roadmap_changelog.phpPlugin templates/archive-roadmap_changelog.php

To override a template, copy it from the plugin’s templates/ directory into your theme’s root directory and modify as needed. Your theme’s version takes priority over the plugin’s version.


Custom Capabilities

The free plugin registers these custom capabilities on activation:

CapabilityAdminEditorAuthorContributorSubscriber
roadmap_voteYesYesYesYesYes
roadmap_commentYesYesYesYesYes
roadmap_suggestYesYesYesYesYes
roadmap<em>edit</em>itemsYesYes
roadmap<em>delete</em>itemsYesYes
roadmap<em>edit</em>own_itemsYes
roadmap<em>manage</em>settingsYes
roadmap<em>view</em>analyticsYes

Capabilities are dynamically disabled when the corresponding global setting is turned off (e.g., disabling voting revokes roadmap_vote at runtime).


Voting System Details

The voting system supports three vote values:

ValueMeaning
1Upvote
0Remove vote
-1Downvote

Votes are stored in a custom {prefix}<em>roadmap</em>votes database table with unique constraints preventing duplicate votes per user (by user<em>id) or per guest (by guest</em>ip).


Status Change Notifications

When a roadmap item’s status changes, the free plugin notifies not only the admin but also all users who voted on or commented on that item. The notification system queries the votes table and comments table to build the recipient list. Results are cached for 1 hour for performance.


Customizing API Responses

View all customization code: Customization Recipes Gist

Add Custom Data to Item Responses

Use the roadmap<em>api</em>format_item filter to add extra fields to every roadmap item in API responses. This affects the shortcode display and any frontend JavaScript that reads item data.

add_filter( 'roadmap_api_format_item', function( $item_data, $item_id ) {
    // Add the item's featured image URL
    $thumbnail_id = get_post_thumbnail_id( $item_id );
    if ( $thumbnail_id ) {
        $item_data['featured_image'] = wp_get_attachment_url( $thumbnail_id );
    }

    // Add a "days since created" counter
    $created = get_the_date( 'U', $item_id );
    $item_data['days_open'] = floor( ( time() - $created ) / DAY_IN_SECONDS );

    return $item_data;
}, 25, 2 );

The priority is set to 25 so this runs after the built-in custom fields filter (priority 20).

Filter Items by Date Range

Restrict the API to only return items created within a specific date range.

add_filter( 'roadmap_api_query_args', function( $args, $request ) {
    $after = $request->get_param( 'created_after' );
    $before = $request->get_param( 'created_before' );

    if ( $after || $before ) {
        $date_query = array();
        if ( $after ) {
            $date_query['after'] = sanitize_text_field( $after );
        }
        if ( $before ) {
            $date_query['before'] = sanitize_text_field( $before );
        }
        $args['date_query'] = array( $date_query );
    }

    return $args;
}, 10, 2 );

Now you can query: /wp-json/roadmap/v1/items?created<em>after=2026-01-01&created</em>before=2026-03-01


Customizing Email Notifications

Route Emails by Product

Send notification emails to different teams based on which product the item belongs to.

add_filter( 'roadmap_notification_email', function( $email, $item_id ) {
    $products = get_the_terms( $item_id, 'roadmap_product' );

    if ( ! $products || is_wp_error( $products ) ) {
        return $email; // No product assigned, use default
    }

    $routing = array(
        'mobile-app'  => 'mobile@yourcompany.com',
        'web-app'     => 'web@yourcompany.com',
        'desktop-app' => 'desktop@yourcompany.com',
    );

    $slug = $products[0]->slug;
    return isset( $routing[ $slug ] ) ? $routing[ $slug ] : $email;
}, 10, 2 );

Add a Footer to All Notification Emails

add_filter( 'roadmap_email_message', function( $message, $event_type, $item_id ) {
    $settings_url = admin_url( 'admin.php?page=roadmap-settings' );
    $footer = "\n\n---\n";
    $footer .= "Manage your notification preferences: $settings_url\n";
    $footer .= "Sent by Product Roadmap Pro";

    return $message . $footer;
}, 10, 3 );

Customize Digest Content

Add a custom section to the weekly or daily digest email.

add_filter( 'roadmap_digest_content', function( $content, $period ) {
    // Add a "stale items" section for items with no activity in 30 days
    $stale_items = get_posts( array(
        'post_type'      => 'roadmap_item',
        'posts_per_page' => 5,
        'date_query'     => array(
            array( 'before' => '30 days ago', 'column' => 'post_modified' ),
        ),
        'orderby'        => 'modified',
        'order'          => 'ASC',
    ) );

    if ( ! empty( $stale_items ) ) {
        $content .= "\n\nStale Items (no activity in 30 days)\n";
        $content .= str_repeat( '-', 40 ) . "\n";
        foreach ( $stale_items as $item ) {
            $content .= "- {$item->post_title}\n";
        }
    }

    return $content;
}, 10, 2 );

Customizing the Frontend Display

Register a Custom Template

Add your own display template alongside the built-in ones (Kanban, List, Grid, Timeline).

add_filter( 'roadmap_available_templates', function( $templates ) {
    $templates['compact'] = 'Compact View';
    return $templates;
} );

Then create the template file in your theme at roadmap/templates/compact.php.

Add Extra Data to the Shortcode

Pass additional data to the shortcode template for use in custom templates.

add_filter( 'roadmap_shortcode_data', function( $data, $atts ) {
    // Add a "product_list" for template use
    $products = get_terms( array(
        'taxonomy'   => 'roadmap_product',
        'hide_empty' => true,
    ) );
    $data['product_list'] = wp_list_pluck( $products, 'name', 'slug' );

    return $data;
}, 10, 2 );

Modify Shortcode Attributes

Set default attributes or override user-provided ones.

add_filter( 'roadmap_shortcode_atts', function( $atts ) {
    // Always default to timeline template if none specified
    if ( empty( $atts['template'] ) ) {
        $atts['template'] = 'timeline';
    }
    return $atts;
} );

Reacting to Events

Log All Status Changes

add_action( 'roadmap_status_changed', function( $item_id, $old_status, $new_status ) {
    $title = get_the_title( $item_id );
    $user = wp_get_current_user();
    $log_entry = sprintf(
        '[%s] %s changed "%s" from %s to %s',
        current_time( 'mysql' ),
        $user->display_name,
        $title,
        $old_status,
        $new_status
    );
    error_log( $log_entry );
}, 10, 3 );

Auto-Assign Product to Guest Suggestions

When a guest suggestion is submitted, automatically assign it to a default product.

add_action( 'roadmap_guest_suggestion_submitted', function( $suggestion_id ) {
    wp_set_object_terms( $suggestion_id, 'general', 'roadmap_product' );
} );

Notify Slack on High-Vote Items

Send a Slack notification when an item hits 50 votes.

add_action( 'roadmap_vote_submitted', function( $item_id, $user_id ) {
    $vote_count = get_post_meta( $item_id, '_roadmap_votes', true );

    if ( (int) $vote_count === 50 ) {
        $title = get_the_title( $item_id );
        $url = get_permalink( $item_id );

        wp_remote_post( 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL', array(
            'headers' => array( 'Content-Type' => 'application/json' ),
            'body'    => wp_json_encode( array(
                'text' => "Roadmap item \"$title\" just hit 50 votes! $url",
            ) ),
        ) );
    }
}, 10, 2 );

Working with Custom Fields Programmatically

Read Custom Field Values

Custom field values are stored as post meta with the <em>roadmap</em>cf_ prefix.

// Get a specific custom field value
$effort = get_post_meta( $item_id, '_roadmap_cf_effort', true );

// Get all custom fields for an item
$fields = get_post_meta( $item_id );
$custom_fields = array();
foreach ( $fields as $key => $value ) {
    if ( 0 === strpos( $key, '_roadmap_cf_' ) ) {
        $field_key = str_replace( '_roadmap_cf_', '', $key );
        $custom_fields[ $field_key ] = $value[0];
    }
}

Update Custom Field Values

update_post_meta( $item_id, '_roadmap_cf_effort', 8 );
update_post_meta( $item_id, '_roadmap_cf_target_quarter', 'Q2 2026' );

Item Meta Keys Reference

Every roadmap<em>item post stores its data using these post</em>meta keys. Use get<em>post</em>meta() (a WordPress PHP function that retrieves stored metadata for a post) to read them and update<em>post</em>meta() to write them.

Core Meta Keys

These are set by the free plugin and available on every roadmap item.

Meta KeyTypeDescription
<em>roadmap</em>votesintTotal vote count (cached — the actual votes are in the {prefix}<em>roadmap</em>votes database table)
<em>roadmap</em>prioritystringPriority level: low, medium, high, or critical
<em>roadmap</em>progressintCompletion progress percentage (0-100)
<em>roadmap</em>target_datestringTarget completion date (YYYY-MM-DD format)
<em>roadmap</em>assigneeintWordPress user ID of the assigned team member
<em>roadmap</em>completion_notesstringNotes visible when item is marked complete
<em>roadmap</em>external_linkstringURL to an external tracker (GitHub, Jira, etc.)
<em>roadmap</em>start_datestringStart date for timeline view (YYYY-MM-DD)
<em>roadmap</em>end_datestringEnd date for timeline view (YYYY-MM-DD)
<em>roadmap</em>effort_estimatestringEffort estimate (story points, hours, etc.)
<em>roadmap</em>github_issuestringGitHub issue URL
<em>roadmap</em>dependenciesarrayArray of roadmap item IDs this item depends on
<em>roadmap</em>orderintDisplay order within a status column (set by drag & drop)

Custom Field Meta Keys

Custom fields defined through the Pro addon are stored with the <em>roadmap</em>cf<em> prefix. For example, a custom field with key effort is stored as </em>roadmap<em>cf</em>effort.

// Read a custom field
$effort = get_post_meta( $item_id, '_roadmap_cf_effort', true );

// Write a custom field
update_post_meta( $item_id, '_roadmap_cf_effort', 8 );

Guest Suggestion Meta Keys

When a guest suggestion is approved and converted to a roadmap item, these meta keys are added.

Meta KeyTypeDescription
<em>guest</em>suggestion_idintOriginal guest suggestion post ID (set via REST API approval)
<em>original</em>guest_idintOriginal guest suggestion post ID (set via admin row action)
<em>guest</em>namestringName provided by the guest
<em>guest</em>emailstringEmail provided by the guest

Plugin Architecture

Understanding the plugin’s file structure helps when extending it.

FilePurpose
roadmap-pro-addon.phpMain plugin file, bootstraps all modules
class-roadmap-pro-api.phpREST API endpoint registration
class-roadmap-pro-settings.phpPro settings UI and registration
class-roadmap-pro-analytics.phpAnalytics tracking and reporting
class-roadmap-pro-custom-fields.phpCustom field definitions and meta box
class-roadmap-pro-guest-suggestions.phpGuest suggestion system
class-roadmap-pro-webhooks.phpWebhook dispatch and management
class-roadmap-pro-filters.phpAdvanced query filtering
class-roadmap-pro-templates.phpTemplate registration and management
class-roadmap-pro-products.phpMulti-product support
class-roadmap-pro-changelog.phpChangelog with product filtering
class-roadmap-pro-export.phpCSV import and export
class-roadmap-pro-merge.phpItem merging functionality

All classes use the singleton pattern. Access an instance with:

$analytics = Roadmap_Pro_Analytics::get_instance();

Next Steps


← REST API Reference | Getting Started

Last updated: March 4, 2026