# Task Management System (WordPress Plugin)
A complete task management solution for WordPress that provides comprehensive task tracking with priorities, statuses, assignees, due dates, categories, and powerful filtering capabilities. Designed for teams and organizations managing projects and tasks within WordPress.
Purpose and Philosophy
The Problem
WordPress lacks native task management:
- No built-in way to track project tasks
- Need for custom post type solutions
- No unified interface for team task management
- Difficulty tracking task history and updates
The Solution
A full-featured task management system:
- Custom Post Type — Dedicated task CPT with rich metadata
- Status Workflow — Configurable status progression
- Priority System — Visual priority indicators
- User Assignment — Task assignment to users
- Due Date Tracking — Calendar integration
- Category Organization — Taxonomy-based grouping
- Filtering System — Advanced search and filter
- Webhook Integration — External system connectivity
Core Components
Task CPT Registration
php
function tms_register_task_cpt() {
register_post_type('tms_task', [
'labels' => [
'name' => 'Tasks',
'singular_name' => 'Task',
'add_new' => 'Add Task',
'add_new_item' => 'Add New Task',
'edit_item' => 'Edit Task',
'new_item' => 'New Task',
'view_item' => 'View Task',
'search_items' => 'Search Tasks',
],
'public' => false,
'show_ui' => true,
'supports' => ['title', 'editor', 'comments', 'custom-fields'],
'menu_icon' => 'dashicons-clipboard',
'menu_position' => 25,
'show_in_menu' => 'tms-menu',
'hierarchical' => false,
]);
// Task Categories
register_taxonomy('tms_category', ['tms_task'], [
'labels' => [
'name' => 'Task Categories',
'singular_name' => 'Category',
],
'hierarchical' => true,
'show_in_menu' => 'tms-menu',
]);
// Task Tags
register_taxonomy('tms_tag', ['tms_task'], [
'labels' => [
'name' => 'Task Tags',
'singular_name' => 'Tag',
],
'hierarchical' => false,
'show_in_menu' => 'tms-menu',
]);
}
add_action('init', 'tms_register_task_cpt');Task Meta Fields
php
// Task metadata fields
$task_meta_fields = [
'_tms_priority' => 'priority', // high, medium, low
'_tms_status' => 'status', // pending, in-progress, completed, on-hold
'_tms_assignee' => 'assignee', // user ID
'_tms_due_date' => 'due_date', // date
'_tms_start_date' => 'start_date', // date
'_tms_estimated_hours' => 'estimated_hours',
'_tms_actual_hours' => 'actual_hours',
'_tms_client' => 'client', // client name/ID
'_tms_project' => 'project', // project name/ID
'_tms_dependencies' => 'dependencies', // array of task IDs
];
// Add meta boxes
function tms_add_task_meta_boxes() {
add_meta_box('tms_task_details', 'Task Details', 'tms_task_details_callback', 'tms_task', 'normal', 'high');
add_meta_box('tms_task_dates', 'Dates & Hours', 'tms_task_dates_callback', 'tms_task', 'side', 'default');
add_meta_box('tms_task_relations', 'Relations', 'tms_task_relations_callback', 'tms_task', 'side', 'default');
}
add_action('add_meta_boxes', 'tms_add_task_meta_boxes');Task Status Management
php
// Predefined statuses
define('TMS_STATUS_PENDING', 'pending');
define('TMS_STATUS_IN_PROGRESS', 'in_progress');
define('TMS_STATUS_COMPLETED', 'completed');
define('TMS_STATUS_ON_HOLD', 'on_hold');
define('TMS_STATUS_CANCELLED', 'cancelled');
function tms_get_status_options() {
return [
'pending' => ['label' => 'Pending', 'color' => '#ffc107'],
'in_progress' => ['label' => 'In Progress', 'color' => '#2196f3'],
'completed' => ['label' => 'Completed', 'color' => '#4caf50'],
'on_hold' => ['label' => 'On Hold', 'color' => '#9e9e9e'],
'cancelled' => ['label' => 'Cancelled', 'color' => '#f44336'],
];
}Priority System
php
function tms_get_priority_options() {
return [
'urgent' => ['label' => 'Urgent', 'color' => '#f44336', 'icon' => '🔥'],
'high' => ['label' => 'High', 'color' => '#ff9800', 'icon' => '⬆️'],
'medium' => ['label' => 'Medium', 'color' => '#2196f3', 'icon' => '➡️'],
'low' => ['label' => 'Low', 'color' => '#4caf50', 'icon' => '⬇️'],
];
}
function tms_display_priority_indicator($priority) {
$options = tms_get_priority_options();
$p = $options[$priority] ?? $options['medium'];
return '<span class="tms-priority-badge" style="background:' . $p['color'] . ';">' . $p['icon'] . ' ' . $p['label'] . '</span>';
}Filtering System
php
function tms_filter_tasks($args, $filter_params) {
$meta_query = [];
// Filter by status
if (!empty($filter_params['status'])) {
$meta_query[] = [
'key' => '_tms_status',
'value' => $filter_params['status'],
];
}
// Filter by priority
if (!empty($filter_params['priority'])) {
$meta_query[] = [
'key' => '_tms_priority',
'value' => $filter_params['priority'],
];
}
// Filter by assignee
if (!empty($filter_params['assignee'])) {
$meta_query[] = [
'key' => '_tms_assignee',
'value' => $filter_params['assignee'],
];
}
// Filter by due date range
if (!empty($filter_params['due_date_from'])) {
$meta_query[] = [
'key' => '_tms_due_date',
'value' => $filter_params['due_date_from'],
'compare' => '>=',
'type' => 'DATE',
];
}
if (!empty($filter_params['due_date_to'])) {
$meta_query[] = [
'key' => '_tms_due_date',
'value' => $filter_params['due_date_to'],
'compare' => '<=',
'type' => 'DATE',
];
}
if (!empty($meta_query)) {
$args['meta_query'] = $meta_query;
}
return $args;
}Task List Shortcode
php
function tms_task_list_shortcode($atts) {
$atts = shortcode_atts([
'status' => '',
'priority' => '',
'assignee' => '',
'category' => '',
'show_filters' => 'true',
'per_page' => 20,
], $atts);
ob_start();
if ($atts['show_filters'] === 'true') {
echo tms_render_filter_form($atts);
}
$args = [
'post_type' => 'tms_task',
'posts_per_page' => intval($atts['per_page']),
];
$filter_params = [
'status' => $atts['status'],
'priority' => $atts['priority'],
'assignee' => $atts['assignee'],
];
$args = tms_filter_tasks($args, $filter_params);
$query = new WP_Query($args);
echo '<div class="tms-task-list">';
if ($query->have_posts()) {
echo '<table class="tms-table">';
echo '<thead><tr>';
echo '<th>Title</th>';
echo '<th>Status</th>';
echo '<th>Priority</th>';
echo '<th>Assignee</th>';
echo '<th>Due Date</th>';
echo '</tr></thead>';
echo '<tbody>';
while ($query->have_posts()) {
$query->the_post();
$task_id = get_the_ID();
echo '<tr>';
echo '<td><a href="' . get_edit_post_link($task_id) . '">' . get_the_title() . '</a></td>';
echo '<td>' . tms_display_status_badge(get_post_meta($task_id, '_tms_status', true)) . '</td>';
echo '<td>' . tms_display_priority_indicator(get_post_meta($task_id, '_tms_priority', true)) . '</td>';
echo '<td>' . tms_get_assignee_name(get_post_meta($task_id, '_tms_assignee', true)) . '</td>';
echo '<td>' . get_post_meta($task_id, '_tms_due_date', true) . '</td>';
echo '</tr>';
}
echo '</tbody></table>';
} else {
echo '<p>No tasks found.</p>';
}
echo '</div>';
wp_reset_postdata();
return ob_get_clean();
}
add_shortcode('tms_tasks', 'tms_task_list_shortcode');Calendar View
php
function tms_calendar_shortcode($atts) {
$atts = shortcode_atts([
'view' => 'month', // month, week, agenda
'assignee' => '',
], $atts);
// Enqueue calendar scripts
wp_enqueue_script('tms-fullcalendar');
wp_enqueue_style('tms-fullcalendar-css');
// Get tasks with due dates
$tasks = tms_get_tasks_for_calendar($atts['assignee']);
$events = [];
foreach ($tasks as $task) {
$due_date = get_post_meta($task->ID, '_tms_due_date', true);
if ($due_date) {
$events[] = [
'title' => get_the_title($task->ID),
'start' => $due_date,
'url' => get_edit_post_link($task->ID),
'className' => 'tms-event-' . get_post_meta($task->ID, '_tms_priority', true),
];
}
}
ob_start();
?>
<div id="tms-calendar" data-events='<?php echo json_encode($events); ?>'></div>
<script>
jQuery(document).ready(function($) {
$('#tms-calendar').fullCalendar({
events: JSON.parse($('#tms-calendar').data('events')),
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek'
}
});
});
</script>
<?php
return ob_get_clean();
}
add_shortcode('tms_calendar', 'tms_calendar_shortcode');Dashboard Widget
php
function tms_add_dashboard_widget() {
wp_add_dashboard_widget(
'tms_overview_widget',
'Task Overview',
'tms_dashboard_widget_callback'
);
}
add_action('wp_dashboard_setup', 'tms_add_dashboard_widget');
function tms_dashboard_widget_callback() {
$stats = tms_get_task_stats();
?>
<div class="tms-dashboard-stats">
<div class="stat-box">
<span class="stat-number"><?php echo $stats['total']; ?></span>
<span class="stat-label">Total Tasks</span>
</div>
<div class="stat-box pending">
<span class="stat-number"><?php echo $stats['pending']; ?></span>
<span class="stat-label">Pending</span>
</div>
<div class="stat-box in-progress">
<span class="stat-number"><?php echo $stats['in_progress']; ?></span>
<span class="stat-label">In Progress</span>
</div>
<div class="stat-box completed">
<span class="stat-number"><?php echo $stats['completed']; ?></span>
<span class="stat-label">Completed</span>
</div>
</div>
<?php
}Webhook Integration
php
// Webhook triggers
function tms_trigger_webhook($task_id, $action) {
$webhook_url = get_option('tms_webhook_url');
if (!$webhook_url) {
return;
}
$task_data = tms_prepare_task_data($task_id);
$payload = [
'action' => $action,
'task' => $task_data,
'timestamp' => current_time('mysql'),
];
wp_remote_post($webhook_url, [
'body' => json_encode($payload),
'headers' => ['Content-Type' => 'application/json'],
]);
}
// Trigger on task status change
add_action('transition_post_status', 'tms_on_task_status_change', 10, 3);
function tms_on_task_status_change($new_status, $old_status, $post) {
if ($post->post_type !== 'tms_task') {
return;
}
if ($new_status !== $old_status) {
tms_trigger_webhook($post->ID, 'status_changed');
}
}Analytics
php
function tms_get_task_stats() {
$args = ['post_type' => 'tms_task', 'posts_per_page' => -1];
$query = new WP_Query($args);
$stats = [
'total' => 0,
'pending' => 0,
'in_progress' => 0,
'completed' => 0,
'on_hold' => 0,
'overdue' => 0,
];
if ($query->have_posts()) {
$stats['total'] = $query->found_posts;
while ($query->have_posts()) {
$query->the_post();
$task_id = get_the_ID();
$status = get_post_meta($task_id, '_tms_status', true);
$due_date = get_post_meta($task_id, '_tms_due_date', true);
if (isset($stats[$status])) {
$stats[$status]++;
}
// Check overdue
if ($due_date && strtotime($due_date) < time() && $status !== 'completed') {
$stats['overdue']++;
}
}
}
wp_reset_postdata();
return $stats;
}Installation
- Upload to WordPress plugins directory
- Activate via Plugins admin
- Create pages with shortcodes:
[tms_tasks]- Task list[tms_calendar]- Calendar view[tms_dashboard]- User dashboard
- Configure settings in TMS Settings page
Portfolio Context
This plugin demonstrates:
- Custom Post Types — Rich task management CPT
- Meta Fields — Multiple metadata for task properties
- Taxonomies — Categories and tags for organization
- Shortcodes — Multiple UI components
- AJAX Filtering — Real-time task filtering
- Calendar Integration — FullCalendar.js integration
- Webhook System — External system connectivity
- Analytics — Dashboard statistics
- Role Management — User assignment and permissions
Architecture Feedback
Spotted a potential optimization or antipattern? Let me know.