Tearing down your own working code is a specific kind of pain. Version one of MaidsMe worked, two login systems, two dashboards, a chat, all functional, all tested, all mine. And I deleted half of it deliberately, because the counts from the last post would not leave me alone. This post is the teardown, what went, what replaced it, and the redesign that made the platform simpler and better at the same time.
The insight that unlocked it was about the employer. I had assumed a marketplace needs both sides to have accounts, but walk the employer’s actual need, they want to see available workers and say I want this one. That is it. Browsing needs no account, profiles are public by design once approved. And the hiring signal needs no account either, it needs a form. So the entire employer side of the account system, registration, login, dashboard, password resets, was scaffolding around a need that a single public form could serve:
// The new flow, whole:
// Browse (no login) -> View profile -> "Hire Now" -> contact form -> admin
add_shortcode('mm_hire_form', array($this, 'render_hire_form'));
public function render_hire_form() {
$profile_id = isset($_GET['profile']) ? absint($_GET['profile']) : 0;
$worker = $this->get_approved_profile($profile_id); // approved_visible only
// employer fields: name, email, phone, message
// worker reference auto-filled from $worker (never the phone)
}
The Hire Now button on every profile links to the contact page with the profile’s id, the form auto-fills the chosen worker’s details as reference, name, profession, experience, skills, summary, and the employer adds their own contact details and message. Submission lands as a hiring inquiry in the admin dashboard, and the admin connects the two sides, exactly the mediated flow the platform promised from post one. Note the guard even here, the auto-fill fetches through a function that only returns approved_visible profiles, a rejected or hidden profile cannot be hired by URL guessing.
The chat went entirely, not because it was broken, but because admin mediation was the design and the chat bypassed it. And then the part that felt most like surgery, the database. The employers table, the accounts, the messages, all dropped, replaced by one lean inquiries table:
CREATE TABLE {$prefix}mm_inquiries (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
profile_id BIGINT UNSIGNED NOT NULL,
employer_name VARCHAR(120) NOT NULL,
employer_email VARCHAR(190) NOT NULL,
employer_phone VARCHAR(40) NOT NULL,
message TEXT,
status VARCHAR(20) DEFAULT 'new',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
KEY profile_id (profile_id)
)
Anonymous inquiries, tied to a profile, tracked by status, new, contacted, closed, so the admin works a queue instead of moderating conversations. Half the login code, half the tables, one fewer dashboard, and the employer’s walk went from seven steps to three. The platform got smaller and did its job better, which taught me which direction good redesigns usually point.
A few things people ask me about this
Is it safe to let people submit hiring forms without accounts? Yes, with the standard guards, a nonce on the form, sanitisation on every field, and rate limiting if spam appears. The admin queue is itself a filter, junk inquiries die there without ever reaching a worker.
How do you delete tables without losing data you might want? Export first, then drop. I kept a JSON export of the v1 employer and message data before removing the tables, deletion should be reversible for exactly as long as you might regret it.
Next
The teardown left one rule standing above all others, the one privacy decision that shaped every screen and every query on the platform, no worker’s phone number is ever public. That rule, and its implementation, is the next post.
