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:
- Your child theme’s
functions.php— Good for theme-specific customizations - 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]
| Attribute | Default | Description |
|---|---|---|
product | main | Product slug to display (comma-separated for multiple) |
template | minimal | Display template: board, timeline, list, cards, minimal |
mode | view | view 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 |
limit | 20 | Maximum items to display |
orderby | date | Sort field: date, votes, priority, title |
order | DESC | Sort direction: ASC or DESC |
allow<em>frontend</em>edit | false | Enable frontend item editing UI |
class | (none) | Custom CSS class added to the wrapper div |
[roadmap_changelog]
| Attribute | Default | Description |
|---|---|---|
product | (all) | Filter by product slug |
version | (all) | Show a specific version only |
id | (none) | Show a single entry by post ID |
limit | 10 | Number of entries to display |
show_date | true | Show or hide the release date |
collapsible | false | Make version sections collapsible with toggle buttons |
class | (none) | Custom CSS class added to the wrapper div |
[roadmap<em>user</em>profile]
| Attribute | Default | Description |
|---|---|---|
user_id | Current user | WordPress 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
| Template | Theme File | Fallback |
|---|---|---|
| Single item | single-roadmap_item.php | Plugin templates/single-roadmap_item.php |
| Product archive | archive-roadmap<em>product.php or taxonomy-roadmap</em>product.php | Plugin templates/archive-roadmap-product.php |
| All-products archive | archive-roadmap_item.php | Plugin templates/archive-roadmap_item.php |
| Single changelog | single-roadmap_changelog.php | Plugin templates/single-roadmap_changelog.php |
| Changelog archive | archive-roadmap_changelog.php | Plugin 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:
| Capability | Admin | Editor | Author | Contributor | Subscriber |
|---|---|---|---|---|---|
roadmap_vote | Yes | Yes | Yes | Yes | Yes |
roadmap_comment | Yes | Yes | Yes | Yes | Yes |
roadmap_suggest | Yes | Yes | Yes | Yes | Yes |
roadmap<em>edit</em>items | Yes | Yes | — | — | — |
roadmap<em>delete</em>items | Yes | Yes | — | — | — |
roadmap<em>edit</em>own_items | — | — | Yes | — | — |
roadmap<em>manage</em>settings | Yes | — | — | — | — |
roadmap<em>view</em>analytics | Yes | — | — | — | — |
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:
| Value | Meaning |
|---|---|
1 | Upvote |
0 | Remove vote |
-1 | Downvote |
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 Key | Type | Description |
|---|---|---|
<em>roadmap</em>votes | int | Total vote count (cached — the actual votes are in the {prefix}<em>roadmap</em>votes database table) |
<em>roadmap</em>priority | string | Priority level: low, medium, high, or critical |
<em>roadmap</em>progress | int | Completion progress percentage (0-100) |
<em>roadmap</em>target_date | string | Target completion date (YYYY-MM-DD format) |
<em>roadmap</em>assignee | int | WordPress user ID of the assigned team member |
<em>roadmap</em>completion_notes | string | Notes visible when item is marked complete |
<em>roadmap</em>external_link | string | URL to an external tracker (GitHub, Jira, etc.) |
<em>roadmap</em>start_date | string | Start date for timeline view (YYYY-MM-DD) |
<em>roadmap</em>end_date | string | End date for timeline view (YYYY-MM-DD) |
<em>roadmap</em>effort_estimate | string | Effort estimate (story points, hours, etc.) |
<em>roadmap</em>github_issue | string | GitHub issue URL |
<em>roadmap</em>dependencies | array | Array of roadmap item IDs this item depends on |
<em>roadmap</em>order | int | Display 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 Key | Type | Description |
|---|---|---|
<em>guest</em>suggestion_id | int | Original guest suggestion post ID (set via REST API approval) |
<em>original</em>guest_id | int | Original guest suggestion post ID (set via admin row action) |
<em>guest</em>name | string | Name provided by the guest |
<em>guest</em>email | string | Email provided by the guest |
Plugin Architecture
Understanding the plugin’s file structure helps when extending it.
| File | Purpose |
|---|---|
roadmap-pro-addon.php | Main plugin file, bootstraps all modules |
class-roadmap-pro-api.php | REST API endpoint registration |
class-roadmap-pro-settings.php | Pro settings UI and registration |
class-roadmap-pro-analytics.php | Analytics tracking and reporting |
class-roadmap-pro-custom-fields.php | Custom field definitions and meta box |
class-roadmap-pro-guest-suggestions.php | Guest suggestion system |
class-roadmap-pro-webhooks.php | Webhook dispatch and management |
class-roadmap-pro-filters.php | Advanced query filtering |
class-roadmap-pro-templates.php | Template registration and management |
class-roadmap-pro-products.php | Multi-product support |
class-roadmap-pro-changelog.php | Changelog with product filtering |
class-roadmap-pro-export.php | CSV import and export |
class-roadmap-pro-merge.php | Item merging functionality |
All classes use the singleton pattern. Access an instance with:
$analytics = Roadmap_Pro_Analytics::get_instance();
Next Steps
- Hooks & Filters Reference — Complete hook documentation
- REST API Reference — All API endpoints
- Webhooks & Integrations — External service connections
← REST API Reference | Getting Started →
