Files
Viktor Miller 369870ef00 docs: add comprehensive CLAUDE.md for future AI assistance
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>
2026-01-23 23:10:44 +09:00

12 KiB
Raw Permalink Blame History

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:

  1. 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() on plugins_loaded hook
  2. includes/class-ddhh-job-manager.php - Singleton orchestrator that initializes all subsystems via init_hooks()

Core Subsystems

The plugin is organized into focused class files in includes/:

Foundation Layer:

  • class-post-types.php - Registers job_offer CPT with custom capabilities
  • class-roles.php - Manages ddhh_provider role with restricted capabilities
  • class-acf-fields.php - Programmatically registers ACF field groups for job metadata
  • class-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 archives
  • class-user-preferences.php - Manages mentor opt-in preferences for job notifications

Job Workflows:

  • class-dashboard.php - Provides [ddhh_provider_dashboard] shortcode displaying provider's jobs
  • class-pages.php - Creates/manages plugin pages (dashboard, login) via option storage
  • class-archive.php - Filters job queries to show only published jobs to appropriate users
  • class-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_offer posts
  • Cannot access WP-Admin (redirected to frontend dashboard)
  • Can edit their own profile (profile.php access allowed)

Capability mapping (in class-post-types.php):

  • edit_job_offer - Owner can edit their own jobs
  • delete_job_offer - Owner can delete their own jobs
  • read_job_offer - Users can read published jobs
  • Standard WordPress map_meta_cap filter enforces ownership

Formidable Forms Integration

The plugin uses 5 Formidable forms, identified by form keys:

  1. provider_registration (F1) - Creates user with ddhh_provider role, auto-login
  2. job_submission (F2) - Creates job_offer post with pending status, maps ACF fields
  3. job_edit (F3) - Updates existing job (ownership validated), preserves submission date
  4. job_deactivation (F4) - Sets status to draft, captures deactivation reason
  5. 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 → fires ddhh_job_submitted action → admin notification
  • Job edit: frm_after_update_entry → fires ddhh_job_edited action → 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_optin meta
  • Batched into groups of 50 to prevent email provider limits
  • Each batch scheduled as separate ddhh_jm_send_mentor_notification_batch action

Access Control Layers

  1. WP-Admin lockout: Providers redirected to dashboard unless accessing profile.php or AJAX
  2. Dashboard protection: template_redirect hook checks user role, redirects non-providers
  3. Archive protection: Jobs require login; only publish status shown to mentors
  4. Single job protection: Login required to view job details
  5. 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_content filter in class-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:

  1. Checking Action Scheduler status: WP Admin → Tools → Scheduled Actions
  2. Monitoring logs: error_log() calls throughout notification classes
  3. 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

  1. Identify triggering event (form submission, status change, custom action)
  2. Add notification method to class-notifications.php
  3. Hook into appropriate action in setup_hooks()
  4. 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

  1. Log in as provider → Submit job → Should create pending post
  2. Admin receives email with job details and moderation links
  3. Admin publishes job → Opted-in mentors receive notification (async batches)
  4. Provider sees published job in dashboard
  5. 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 with date_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.php registering '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 context
  • ROADMAP.md - Phase breakdown and progress
  • STATE.md - Current work and blockers
  • phases/ - Detailed plans and summaries for each phase

Code Standards

  • WordPress Coding Standards: Follow WordPress PHP coding standards
  • Text Domain: Use ddhh-job-manager for 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 sequence
  • class-formidable.php - Form IDs and field mappings
  • class-notifications.php - Email templates and triggering logic
  • class-access-control.php - Security boundaries for providers
  • class-post-types.php - Capability mapping for job_offer posts