Initializing
Back to Projects
Year2024
DomainFullstack
AccessOpen Source
Complexity0 / 10
PHPWordPressWordPress PluginProject ManagementCRM
FullstackArchived

Task Management System (WordPress Plugin)

A comprehensive WordPress plugin for task management with priorities, statuses, assignees, due dates, categories, and integration with external systems via webhooks.

# 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:

  1. Custom Post Type — Dedicated task CPT with rich metadata
  2. Status Workflow — Configurable status progression
  3. Priority System — Visual priority indicators
  4. User Assignment — Task assignment to users
  5. Due Date Tracking — Calendar integration
  6. Category Organization — Taxonomy-based grouping
  7. Filtering System — Advanced search and filter
  8. 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

  1. Upload to WordPress plugins directory
  2. Activate via Plugins admin
  3. Create pages with shortcodes:
  • [tms_tasks] - Task list
  • [tms_calendar] - Calendar view
  • [tms_dashboard] - User dashboard
  1. 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.

Submit a Technical Suggestion