Add detailed documentation covering plugin architecture, subsystems, workflows, and development practices. Includes GSD workflow requirement for all code changes. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
12 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Digital Dabei Job Manager is a WordPress plugin providing a closed job board for "digital dabei Hamburg". External organizations (providers) self-register and manage job listings. Mentors (existing subscribers) view and apply to jobs. All jobs require admin moderation before publication.
Core principle: Every job goes through admin approval before mentors see it. The moderation flow is the trust layer protecting mentors from spam.
Development Environment
- Platform: Local WP (WordPress development environment)
- WordPress: 6.0+, PHP 7.4+
- Required Plugins: ACF Pro, Formidable Forms Pro, Elementor Pro
- Email: WP Mail SMTP on production; disabled in Local WP dev environment
Development Workflow with GSD
IMPORTANT: Use /gsd commands for all code-related work in this repository.
The GSD (Get Stuff Done) workflow provides:
- Structured planning and execution phases
- Automatic verification of changes
- State management across sessions
- Parallel execution when possible
Common commands:
/gsd:progress- Check current state and next steps/gsd:plan-phase- Plan implementation for a phase/gsd:execute-phase- Execute all plans in a phase/gsd:help- View all available GSD commands
Architecture
Plugin Entry Point
The plugin follows WordPress singleton pattern with class-based initialization:
-
ddhh-job-manager.php- Main plugin file that:- Loads Action Scheduler vendor library first (required for async operations)
- Defines constants (DDHH_JM_VERSION, DDHH_JM_PLUGIN_DIR, etc.)
- Requires all class files from
includes/ - Initializes via
DDHH_JM_Job_Manager::get_instance()onplugins_loadedhook
-
includes/class-ddhh-job-manager.php- Singleton orchestrator that initializes all subsystems viainit_hooks()
Core Subsystems
The plugin is organized into focused class files in includes/:
Foundation Layer:
class-post-types.php- Registersjob_offerCPT with custom capabilitiesclass-roles.php- Managesddhh_providerrole with restricted capabilitiesclass-acf-fields.php- Programmatically registers ACF field groups for job metadataclass-activator.php/class-deactivator.php- Plugin lifecycle hooks
User Management:
class-formidable.php- Integration layer for all Formidable Forms (registration, job submission, edit, deactivation, application). Uses form keys like 'provider_registration', 'job_submission', etc.class-access-control.php- Blocks providers from WP-Admin, enforces login requirements on job archivesclass-user-preferences.php- Manages mentor opt-in preferences for job notifications
Job Workflows:
class-dashboard.php- Provides[ddhh_provider_dashboard]shortcode displaying provider's jobsclass-pages.php- Creates/manages plugin pages (dashboard, login) via option storageclass-archive.php- Filters job queries to show only published jobs to appropriate usersclass-template.php- Handles single job display and contact form modal
Notifications & Async Processing:
class-notifications.php- Email system triggered by WordPress hooks (ddhh_job_submitted,transition_post_status,frm_after_create_entry)class-scheduler.php- Action Scheduler wrapper for async batch email processing (chunks of 50 users)
Admin Experience:
class-admin-ui.php- Enhances admin screens with custom columns, quick links, status indicators
Custom Roles & Capabilities
ddhh_provider role: Restricted role for external organizations
- Can create/edit/delete only their own
job_offerposts - Cannot access WP-Admin (redirected to frontend dashboard)
- Can edit their own profile (
profile.phpaccess allowed)
Capability mapping (in class-post-types.php):
edit_job_offer- Owner can edit their own jobsdelete_job_offer- Owner can delete their own jobsread_job_offer- Users can read published jobs- Standard WordPress
map_meta_capfilter enforces ownership
Formidable Forms Integration
The plugin uses 5 Formidable forms, identified by form keys:
- provider_registration (F1) - Creates user with
ddhh_providerrole, auto-login - job_submission (F2) - Creates
job_offerpost withpendingstatus, maps ACF fields - job_edit (F3) - Updates existing job (ownership validated), preserves submission date
- job_deactivation (F4) - Sets status to
draft, captures deactivation reason - job_application (F5) - Mentor applies to job, emails provider contact address
Form hooks (class-formidable.php):
- Registration:
frm_after_create_entry→ auto-login → redirect to dashboard - Job submission:
frm_after_create_entry→ firesddhh_job_submittedaction → admin notification - Job edit:
frm_after_update_entry→ firesddhh_job_editedaction → admin notification - Application:
frm_after_create_entry→ emails provider's contact email from ACF field
Email Notification System
Immediate notifications (class-notifications.php):
- Admin receives email on job submission with edit/view links
- Admin receives email on job edit with change summary
- Admin receives email on deactivation with reason
- Provider receives email when mentor applies (via Formidable)
Async batch notifications (class-scheduler.php):
- Mentor notification on job publish uses Action Scheduler
- Users are queried for
ddhh_jm_notification_optinmeta - Batched into groups of 50 to prevent email provider limits
- Each batch scheduled as separate
ddhh_jm_send_mentor_notification_batchaction
Access Control Layers
- WP-Admin lockout: Providers redirected to dashboard unless accessing
profile.phpor AJAX - Dashboard protection:
template_redirecthook checks user role, redirects non-providers - Archive protection: Jobs require login; only
publishstatus shown to mentors - Single job protection: Login required to view job details
- Ownership validation: Forms validate current user owns the job before editing/deactivation
Template System
Frontend templates (templates/):
provider-dashboard.php- Displays provider's jobs in table format with status badges and action links
Elementor integration:
- Job archive uses Elementor Loop Grid (no custom template file)
- Job detail page uses Elementor single post template with ACF dynamic tags
- Contact form modal injected via
the_contentfilter inclass-template.php
Job Lifecycle
Provider submits → pending → Admin reviews → publish → Mentors see + notified
↓
Admin can reject → trash
Provider deactivates → draft (with reason stored in meta)
Status hooks:
ddhh_job_submitted- Fired after new job metadata saved (form entry ID passed)ddhh_job_edited- Fired after job update metadata saved (form entry ID passed)transition_post_status- Used for publish detection and deactivation detection
ACF Field Groups
Programmatically registered in class-acf-fields.php:
- Job Details:
job_location,job_type,job_deadline(date picker),contact_email - Deactivation:
deactivation_reason,deactivation_date - Metadata:
submission_date(preserved during edits)
All fields support German labels matching site language.
Development Workflow
Testing Locally
Since email is disabled in Local WP, test email functionality by:
- Checking Action Scheduler status: WP Admin → Tools → Scheduled Actions
- Monitoring logs:
error_log()calls throughout notification classes - Using a plugin like WP Mail Logging to capture emails during dev
Working with Forms
Formidable forms are managed through the Formidable UI. When referencing forms in code:
- Use form keys (e.g., 'job_submission') not IDs
- Form ID lookup happens via
FrmForm::getOne('form_key') - Field IDs are stored in form configuration, not hardcoded
Modifying Email Templates
Email templates are inline in class-notifications.php:
- Admin emails use
wp_mail()with HTML content - Mentor notification emails use
wp_mail()with plain text - All emails include job title, provider name, and relevant links
- Date formatting: Use
get_field()for ACF dates, format with German locale
Adding New Notifications
- Identify triggering event (form submission, status change, custom action)
- Add notification method to
class-notifications.php - Hook into appropriate action in
setup_hooks() - For batch processing, use
DDHH_JM_Scheduler::schedule_mentor_notification_batch()
Common Tasks
Debugging Action Scheduler
# View scheduled actions in WP CLI
wp action-scheduler list --status=pending
wp action-scheduler list --status=failed
# Run pending actions manually
wp action-scheduler run --batch-size=10
# Clean up old actions
wp action-scheduler clean --days=90
Checking Provider Permissions
Providers should NOT be able to:
- Access WP-Admin (except profile.php)
- Edit other providers' jobs
- Publish jobs directly (must be pending)
- View unpublished jobs by other providers
Verifying Job Moderation Flow
- Log in as provider → Submit job → Should create
pendingpost - Admin receives email with job details and moderation links
- Admin publishes job → Opted-in mentors receive notification (async batches)
- Provider sees published job in dashboard
- Mentors can view and apply to job
Date Field Handling
Job deadlines use ACF date picker:
- Format conversion in Formidable forms: Slashes auto-converted to dots for display
- Before submission: Dots converted back to ISO format (YYYY-MM-DD)
- Display: Use
get_field('job_deadline')returns 'Ymd', format withdate_i18n() - Validation: Date fields are optional (empty string is valid)
Logo Auto-Cropping
Featured images (logos) auto-crop to 200×200px on upload:
- Handled by
class-post-types.phpregistering 'job-logo' image size - Uses WordPress
add_image_size()with hard crop enabled - Images uploaded via Formidable forms trigger standard WP media processing
Project State
Currently: Phase 6 (Email Notifications) is mostly complete. Phase 7 (Testing & Polish) is next.
What's working:
- Provider registration and authentication
- Job submission, editing, deactivation workflows
- Admin moderation and notifications
- Mentor job browsing and applications
- Opt-in preferences for mentor notifications
- Action Scheduler integration for async processing
What's pending:
- Phase 6.3: Async batch email processing on job publish (implementation in progress)
- Phase 7: End-to-end testing and production deployment prep
Documentation: See .planning/ for detailed project documentation:
PROJECT.md- Requirements and contextROADMAP.md- Phase breakdown and progressSTATE.md- Current work and blockersphases/- Detailed plans and summaries for each phase
Code Standards
- WordPress Coding Standards: Follow WordPress PHP coding standards
- Text Domain: Use
ddhh-job-managerfor all translatable strings - German Language: All user-facing text in German
- Security: Validate ownership, escape output, verify nonces in forms
- Hook Naming: Use
ddhh_jm_prefix for custom actions/filters - Class Naming: Use
DDHH_JM_prefix, one class per file - Static Methods: Use static methods for classes that don't maintain state
- Direct Exit: Always include
defined( 'ABSPATH' ) || exit;at top of PHP files
Critical Files to Review Before Major Changes
ddhh-job-manager.php- Plugin initialization order matters (Action Scheduler first)class-ddhh-job-manager.php- Hook registration sequenceclass-formidable.php- Form IDs and field mappingsclass-notifications.php- Email templates and triggering logicclass-access-control.php- Security boundaries for providersclass-post-types.php- Capability mapping forjob_offerposts