Migrating from WP Human Resource Management to Punchwell

This is the technical migration guide for moving from the abandoned WP Human Resource Management plugin (original slug hrm, last shipped around 2019, removed from WordPress.org in 2025) to Punchwell.

The important thing to understand up front: this is a migration, not a rebuild. Punchwell is a maintained fork of the same codebase, so it uses the same data model — your employees are still WordPress users, and your records still live in the same wp_hrm_* database tables. Your employees, attendance, and leave records carry over in place. You are not re-entering staff or rebuilding history.

Most of the schema upgrades itself the moment Punchwell runs. A small number of older tables use different column names than the current code, so the fork ships two SQL files that copy that data into the new columns and confirm the result. That’s the only part that isn’t automatic.

Time: roughly 30–60 minutes on a typical site.
Skill level: comfortable taking a full backup and running a couple of SQL files (phpMyAdmin or WP-CLI).
Current build: Punchwell base 2.14.1, database schema version 3.3.

The single most important step is the backup. With a verified backup in hand, every step below is reversible.


What carries over (and what doesn’t)

Carries over automatically — same lineage, same database:

  • Employees — they are WordPress users; nothing to re-import.
  • Attendance / punch records (wp_hrm_attendance).
  • Leave records (wp_hrm_leave) — after the column copy in Step 5.
  • Leave type names, departments, designations/job titles, shifts, work-experience entries (after the copy).
  • Roles — the legacy hrm_employer role is auto-renamed to hrm_employee on first admin load.

You must re-enter manually — these can’t be auto-migrated:

  • Office IP allowlist — the legacy wp_hrm_whitelist table is dropped during migration, and the current code reads office IPs from a different place. Save your existing values first (Step 2), then re-enter them in Punchwell.
  • Leave-type yearly entitlements — type names survive, but re-enter each type’s annual entitlement under the Leave settings.
  • Payroll / salary — the original wp_hrm_salary structure is a completely different model. Payroll starts fresh in Punchwell’s payroll engine. (For how Punchwell handles pay, see the Payroll export docs.)

Before you start — read this

  • Why a SQL script is needed at all. Most tables upgrade cleanly via Punchwell’s built-in dbDelta reconcile. But a few legacy tables (Leave and Work-Experience especially) store data under old column names. dbDelta adds the new columns but cannot rename or copy your data into them — so the script does that copy. Without it, Leave and Work-Experience records would appear blank.
  • Order is critical. You must let dbDelta run (by loading wp-admin once on Punchwell) before you run the migration SQL — otherwise the new columns don’t exist yet and there’s nothing to copy into.
  • Table prefix. The scripts assume the default wp_ prefix. If your install uses a different prefix (check $table_prefix in wp-config.php), find-and-replace wp_ in both SQL files first.
  • The SQL file headers reference older version numbers (they say “2.4.0” / db version “2.1”). That’s cosmetic — those headers predate the current build. What actually matters is that you load wp-admin once on Punchwell so dbDelta brings the schema all the way up to DB 3.3 before you run the migration. Verification (Step 6) confirms you’re stamped at 2.14.1 / 3.3.
  • Do it on staging first. Strongly recommended: run the whole migration on a staging copy, confirm it works, then repeat on production.

Step 1 — Take a full backup (do not skip)

Back up both the database and the files.

With a backup plugin: UpdraftPlus, BlogVault, Duplicator, or your host’s one-click backup. Take a fresh full backup and confirm it completed.

With WP-CLI:

wp db export pre-punchwell-migration.sql
tar -czf pre-punchwell-files.tgz wp-content/plugins wp-content/uploads

Verify the backup is real — non-zero file size, downloadable, and ideally test-restorable on staging. Do not proceed until you have it.


Step 2 — Record your current state

Before changing anything, write down what you can compare against afterward:

  • Your current plugin version (Plugins screen, or readme.txt).
  • Approximate counts: number of employees, leave records, attendance rows.
  • Your office IP allowlist, if you use the IP/attendance feature — because the legacy whitelist table is dropped during migration. Run this read-only query and save the output:
SELECT id, ip FROM wp_hrm_office_time;   -- save these; you'll re-enter them
-- older installs may instead have:
-- SELECT * FROM wp_hrm_whitelist;

You’ll re-enter these IPs later in Punchwell under Punchwell → Structure → Locations and Punchwell → Settings → IP & Geofence. (For how the allowlist works once you’re on Punchwell — exact IPs, CIDR blocks, address ranges, per-office and per-employee scopes — see IP & Geofence settings.)


Step 3 — Swap the plugin

  1. In Plugins → Installed Plugins, Deactivate the original WP Human Resource Management plugin. Do not delete it yet — keeping it lets you roll back instantly.
  2. Install Punchwell:
    • Upload the Punchwell ZIP via Plugins → Add New → Upload Plugin, or
    • copy the plugin folder into wp-content/plugins/ (keep the folder slug wp-hrm).
  3. Activate Punchwell.

If you used any add-ons (Recruitment, Loan, Attendance Reports, Permission, Front-End), install Punchwell’s matching add-on versions too. The base plugin must be active or add-ons self-deactivate. See Installation for the full add-on list.


Step 4 — Let the database reconcile run (critical ordering)

Simply load wp-admin as an administrator. On the first admin page load, Punchwell runs its idempotent dbDelta reconcile, which adds the new tables and columns — for example, Leave gains status, comments, type, created_at, and updated_at; Work-Experience gains employee_id, title, start, end, and description. It also renames the legacy hrm_employer role to hrm_employee and stamps the version options (hrm_version = 2.14.1, hrm_db_version = 3.3).

(Equivalent alternative: deactivate then reactivate the Punchwell base plugin.)

This step adds, never deletes — no data is touched. But do not run the migration SQL until you have done this, because the script copies into the columns this step creates.


Step 5 — Run UPGRADE-DATA-MIGRATION.sql

Run the file that ships with Punchwell against your database via phpMyAdmin (Import / SQL tab) or WP-CLI:

wp db query < UPGRADE-DATA-MIGRATION.sql

What it does, in order:

  1. Prints your existing IP-config tables to the output (a reference snapshot, since the legacy whitelist table is dropped in step 5 below).
  2. Copies Leave data from the old columns into the new ones (leave_status → status, leave_comments → comments, leave_type_id → type) and seeds created_at / updated_at from each record’s start time.
  3. Copies Work-Experience data from the old OrangeHRM-style eexp_* columns into the new columns. The raw company, comments, and dates are also preserved in description so nothing is lost even if an old free-text date doesn’t parse cleanly.
  4. Normalizes legacy 0000-00-00 timestamps to NULL across several tables — those invalid dates fatal under MySQL 8 strict mode.
  5. Drops three wholly-unused legacy tables: wp_hrm_education, wp_hrm_skill, and wp_hrm_whitelist.

Do NOT run Section 6 of that file yet. Section 6 is the optional drop of the now-redundant old columns (the ones the script just copied from). It is commented out on purpose. Leave it commented until verification (Step 6) confirms the copy succeeded — that’s what makes the migration reversible.

After this step, three things still need to be re-entered by hand (the script can’t map them): payroll/salary (regenerate in the payroll engine), leave-type yearly entitlements (names survive, entitlements don’t), and your office IPs (you saved them in Step 2).


Step 6 — Run UPGRADE-VERIFY.sql and read the results

wp db query < UPGRADE-VERIFY.sql

This is read-only — it changes nothing. Check the output against these expectations:

Check Expected result
New columns present (Leave + Work-Experience) All listed columns appear. If any are missing, you ran the SQL before Step 4 — redo Step 4, then re-run the migration and verify.
Version stamps hrm_version = 2.14.1, hrm_db_version = 3.3. (The SQL file headers cite older numbers — cosmetic. What matters is that wp-admin loaded once so dbDelta reconciled to 3.3.)
Row counts (attendance, leave, work_experience, …) Match your pre-upgrade numbers from Step 2 — nothing vanished.
leave_rows_NOT_copied 0
workexp_rows_NOT_copied 0
Orphan checks (leave / attendance / work-experience pointing at missing users) 0 each
Residual zero-dates in attendance 0
Employee roles hrm_employees / hrm_managers > 0; legacy_employer = 0 (auto-renamed on first admin load)
Legacy tables (education, skill, whitelist) 0 rows returned — they were dropped

If anything is off — a non-zero NOT_copied, missing columns, unexpected orphans — stop and roll back (Step 8). Do not run Section 6.


Step 7 — Smoke-test the admin, then finish up

In wp-admin, confirm the live paths work:

  1. Punchwell Dashboard loads without errors.
  2. Employees list shows your people; open a profile and confirm details are intact.
  3. Add a test employee, then delete it — confirms the old PHP 8 “can’t add employee” hang is gone.
  4. Attendance — punch in and punch out for a test user; confirms punch-out works.
  5. Leave — open an existing leave record and confirm status, type, and comments display (not blank). Blank here means the copy didn’t happen — see Troubleshooting.
  6. Office-IP lock (if you use it) — re-enter your saved IPs under Structure → Locations / Settings → IP & Geofence, flag a test employee as office-only, and confirm enforcement behaves as expected. (See IP & Geofence.)
  7. Leave types — re-enter each type’s yearly entitlement.

When everything checks out:

  • Only now, if you want a clean schema, you may uncomment and run Section 6 of UPGRADE-DATA-MIGRATION.sql to drop the redundant old columns. This is optional — leaving them in place is harmless.
  • Delete the old plugin files once you’re confident. You still have your Step-1 backup.

Step 8 — Rollback plan

If anything goes wrong at any point:

  1. Deactivate Punchwell.
  2. Restore your Step-1 backup (database + files). With a backup plugin, use its restore. With WP-CLI:
    wp db import pre-punchwell-migration.sql
    
  3. Reactivate the original plugin — this is exactly why you didn’t delete it in Step 3.

You’re back to your pre-migration state.

Why rollback stays safe: you never deleted the old plugin until Step 7, and Section 6 (the destructive old-column drop) is gated behind a clean verification. Until you run Section 6, the old columns still hold your original data — so even a partial migration is fully reversible from your backup.


Troubleshooting

  • Leave or Work-Experience records look blank after migrating. You almost certainly ran the SQL before Step 4, so the new columns didn’t exist yet and nothing copied. Restore the backup, then redo Steps 4 → 5 → 6 in order.
  • UPGRADE-VERIFY.sql reports missing new columns. Same cause: dbDelta hadn’t run. Load wp-admin as an administrator (or deactivate/reactivate the base plugin), then re-run the migration and verification.
  • Wrong-table-prefix errors. Your install isn’t using the wp_ prefix. Find-and-replace wp_ in both SQL files with your real prefix (from wp-config.php) and re-run.
  • Orphan checks come back non-zero. Some WordPress user accounts, or the old emp_number → employee_id mapping, didn’t line up. Review the sample rows the verify script prints before proceeding.
  • Still seeing PHP 8 errors after migrating. Confirm you actually activated Punchwell (version 2.14.1) and not the original (2.2.17 or lower). Check the version on the Plugins screen.

FAQ

Will I lose any data?
No. Punchwell shares the original plugin’s data model, so your employees, attendance, and leave records stay in place. The migration script only copies legacy columns into their new names and drops three tables Punchwell never reads. As long as you take a backup first (Step 1), the whole process is reversible.

Do I need to re-create my employees?
No. Employees are WordPress users in both the original and Punchwell — they’re already there. Nothing to re-import.

Why are the version numbers in the SQL file different from 2.14.1?
The SQL file headers were written for an earlier release and reference older numbers. They’re cosmetic. What actually upgrades your schema is dbDelta, which runs when you load wp-admin (Step 4) and brings the database all the way to the current version 3.3. The verify script confirms you end up stamped at 2.14.1 / 3.3.

Can I do this without WP-CLI?
Yes. Run both .sql files through phpMyAdmin (the Import tab, or paste into the SQL tab) instead. The steps and order are identical.

My site uses a custom table prefix. What changes?
Open both SQL files and find-and-replace wp_ with your actual prefix (the $table_prefix value in wp-config.php) before running them. Everything else is the same.

What about my payroll and salary data?
The original salary structure is a different model, so it doesn’t auto-migrate. Punchwell’s payroll engine starts fresh — set per-employee pay type and rate, then generate payout reports and exports. See the Payroll export docs.


Files referenced (they ship with Punchwell): UPGRADE-DATA-MIGRATION.sql and UPGRADE-VERIFY.sql.

Punchwell is an independent, third-party maintained fork of the GPL-licensed “WP Human Resource Management” plugin. Sturdyhaus is not affiliated with, endorsed by, or sponsored by wpspear, weDevs, or the original author. “WP Human Resource Management” is referenced descriptively only, to help affected users find a maintained alternative.