Employee Time Tracking
WordPress plugin: REST API for employee time tracking with cron-style recurring rules and CSV payroll export.
by GeekShop Computers (byron@geekshop.ca) · github.com/bigberryj/employee-time-tracking · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/bigberryj/employee-time-tracking/archive/refs/heads/main.zipA WordPress plugin that exposes a REST API for tracking employee time entries against projects, with cron-style recurring rules and CSV payroll export.
- Author: GeekShop Computers (
byron@geekshop.ca) - Version: 1.0.0
- License: MIT
- Source: https://github.com/bigberryj/employee-time-tracking
- Requires: WordPress 6.0+, PHP 7.4+, WooCommerce is not required.
What you get
- Four custom tables under the WP prefix:
wp_ett_employees,wp_ett_projects,wp_ett_time_entries,wp_ett_recurring_rules. - REST namespace
employee-time-tracking/v1with full CRUD on employees, projects, and time entries, plus list/create/update/delete on recurring rules and aPOST /recurring-rules/runendpoint that manually fires the cron. - Recurring rules (
daily/weekly/biweekly/monthly) that generate time entries automatically viawp_schedule_event(..., hourly, 'ett_run_recurring_rules'). - CSV payroll export at
GET /export?from=YYYY-MM-DD&to=YYYY-MM-DDreturning a header row plus one row per time entry, withgross_paycomputed fromhours × hourly_rate(only when both entry and project are billable). - Admin settings page under Settings → Time Tracking for default cadence, max hours per day, CSV buffer days, and toggle for CSV export.
- Strict sanitiser for every payload — mode whitelists for
status, literal=== 1for booleans,> 0for ID arrays, hours clamped to 0–24, hourly rate clamped to 0–9999.99.
REST endpoints
All write routes require a valid WP REST nonce in the X-WP-Nonce header
and a manage_options (or edit_posts for own-employee POST/PUT) capability.
| Method | Path | Capability | Purpose |
|---|---|---|---|
| GET | /employees |
read |
List employees |
| POST | /employees |
manage_options |
Create employee |
| PUT | /employees/{id} |
manage_options |
Update employee |
| DELETE | /employees/{id} |
manage_options |
Delete employee |
| GET | /projects |
read |
List projects |
| POST | /projects |
manage_options |
Create project |
| PUT | /projects/{id} |
manage_options |
Update project |
| DELETE | /projects/{id} |
manage_options |
Delete project |
| GET | /time-entries |
read |
List time entries (filters: employee_id, project_id, from, to, limit, offset) |
| POST | /time-entries |
manage_options / edit_posts |
Create time entry |
| PUT | /time-entries/{id} |
manage_options / edit_posts |
Update time entry |
| DELETE | /time-entries/{id} |
manage_options |
Delete time entry |
| GET | /recurring-rules |
read |
List recurring rules |
| POST | /recurring-rules |
manage_options |
Create rule |
| PUT | /recurring-rules/{id} |
manage_options |
Update rule |
| DELETE | /recurring-rules/{id} |
manage_options |
Delete rule |
| POST | /recurring-rules/run |
manage_options |
Manually trigger generation (optional ?today=YYYY-MM-DD) |
| GET | /export?from=…&to=… |
manage_options |
JSON wrapper around the CSV body |
Installation
- Copy the
employee-time-tracking/folder intowp-content/plugins/. - Activate the plugin under Plugins → Installed Plugins. The activation hook creates the four tables and schedules the hourly cron.
- (Optional) Grant editors
edit_postsif you want them to log their own time entries throughPOST /time-entries. - Test with
curlor the WordPress REST console under Tools → REST API.
Quick smoke test
# Get a nonce (replace /wp-login.php + creds as needed).
NONCE=$(curl -s -c cookies.txt http://example.com/wp-login.php \
-d 'log=admin&pwd=password&wp-submit=Log+In' \
-b cookies.txt | grep wp-rest | head -1)
# Create an employee.
curl -X POST -H "X-WP-Nonce: $NONCE" \
-H 'Content-Type: application/json' \
-d '{"full_name":"Alice","email":"alice@example.com","hourly_rate":60}' \
http://example.com/wp-json/employee-time-tracking/v1/employees
Local development
cd /home/byron/projects/employee-time-tracking
php qa/lint.php # php -l on every PHP file (14 files, all OK)
php tests/run-tests.php # 72 assertions across CRUD, sanitiser, CSV, recurring
The test runner is plain PHP — no PHPUnit, no MySQL, no WordPress
required. It loads qa/phpstan-wordpress-stubs.php which provides
minimal add_action/get_option/$wpdb/etc. stubs that keep enough
state to assert behaviour.
CSV export format
entry_id,employee_name,employee_email,project_name,client_name,work_date,hours,billable,hourly_rate,gross_pay,notes
1,Alice,alice@example.com,Website Redesign,Acme,2026-09-13,8.00,1,60.00,480.00,"first ""half"" of the day"
Comma, double-quote, and newline characters in any cell are properly
escaped per RFC 4180 (double-quote wrap + double-up internal quotes).
gross_pay is hours × hourly_rate only when both the time entry and
the project are billable; otherwise it's 0.00.
Recurring rules
A rule has: hours, cadence (daily / weekly / biweekly / monthly),
optional weekday (0–6, used with weekly / biweekly), start_date,
optional end_date, and last_generated_date (managed internally).
When the cron fires (every hour) the engine walks each active rule and
inserts a time entry for every due date after last_generated_date (or
start_date on first run) up to today (or end_date if earlier). The
generator is idempotent: re-running it produces no duplicates.
Manual run:
curl -X POST -H "X-WP-Nonce: $NONCE" \
http://example.com/wp-json/employee-time-tracking/v1/recurring-rules/run
Uninstall
Drop the four wp_ett_* tables and the ett_settings option. The
uninstall.php script runs only when the user deletes the plugin from
the Plugins screen (not on simple deactivate).
License
MIT — see LICENSE.