--- phase: 01-foundation-setup plan: 03 subsystem: auth tags: [acf, roles, capabilities, wordpress] requires: [01-02] provides: [provider-role, job-metadata-fields] affects: [02-form-submission] tech-stack: added: [] patterns: [capability-based-access-control, acf-local-fields] key-files: created: [includes/class-roles.php, includes/class-acf-fields.php] modified: [includes/class-activator.php, includes/class-deactivator.php, includes/class-ddhh-job-manager.php] key-decisions: - Jobs submit to pending status (admin approval required) - German field labels for v1 - Logo stored as image ID (not URL) - Deactivation reason field conditional on non-published status issues-created: [] metrics: duration: 3 min completed: 2026-01-14 --- # Phase 1 Plan 3: Roles & Fields Summary **Provider role and ACF field group for job metadata registered** ## Accomplishments - Custom role 'ddhh_provider' (Anbieter) with job-only capabilities - ACF field group 'Job Details' with 6 metadata fields - Proper capability restrictions (no posts/pages access, no publishing) - Logo upload support via upload_files capability - Role registration integrated with plugin activation/deactivation ## Files Created/Modified **Created:** - `includes/class-roles.php` - Role registration and cleanup (DDHH_JM_Roles class) - `includes/class-acf-fields.php` - ACF field group definition (DDHH_JM_ACF_Fields class) **Modified:** - `includes/class-activator.php` - Added DDHH_JM_Roles::add_roles() call - `includes/class-deactivator.php` - Added DDHH_JM_Roles::remove_roles() call - `includes/class-ddhh-job-manager.php` - Hooked ACF fields to 'acf/init' action ## Technical Details ### Provider Role Capabilities The `ddhh_provider` role has been configured with restricted capabilities: **Granted:** - `read` - Basic WordPress access - `edit_job_offers` - Can edit own job offers - `delete_job_offers` - Can delete own job offers - `upload_files` - Required for logo uploads **Explicitly Denied:** - `publish_job_offers` - Jobs go to pending for admin approval - `edit_others_job_offers` - Cannot edit others' jobs - `edit_posts`, `edit_pages` - No access to regular content - `manage_categories`, `manage_options` - No admin functions ### ACF Fields Structure Field group targets `post_type == 'job_offer'`: 1. **job_location** (text, required) - Standort 2. **job_type** (select, required) - Art - Choices: Vollzeit, Teilzeit, Ehrenamt 3. **job_deadline** (date_picker, optional) - Bewerbungsfrist - Return format: Y-m-d - Display format: d.m.Y (German) 4. **job_contact_email** (email, required) - Kontakt-E-Mail 5. **job_logo** (image, optional) - Logo - Return format: id (attachment ID) - Preview size: thumbnail 6. **job_deactivation_reason** (textarea, optional) - Deaktivierungsgrund (intern) - Conditional logic: Only shows when post_status != 'publish' - For admin use when deactivating jobs ## Decisions Made 1. **Jobs submit to pending status** - Providers cannot publish directly (`publish_job_offers: false`). This enforces admin approval workflow as specified in PROJECT.md core value. 2. **German field labels** - Per PROJECT.md: German only for v1. Labels use German terms: Standort, Art, Bewerbungsfrist, Kontakt-E-Mail, Logo. 3. **Logo as image ID (not URL)** - Using `return_format: 'id'` for better media library integration. Allows access to all image sizes and metadata. 4. **Deactivation reason field conditional** - Uses ACF conditional logic to show `job_deactivation_reason` only when post is not published. Keeps admin interface clean for active jobs. 5. **Capability-based isolation** - Used custom capability_type 'job_offer' (from 01-02) combined with explicit denials to ensure providers cannot access posts/pages even if WordPress roles are modified. ## Commits - Task 1: `79b1389` - feat(01-03): register ddhh_provider role with restricted capabilities - Task 2: `c8fdf39` - feat(01-03): register ACF field group for job_offer metadata ## Verification All verification criteria met: - Provider role exists with correct capabilities - Provider CANNOT edit regular posts/pages (edit_posts: false, edit_pages: false) - Provider CAN upload files (upload_files: true) for logos - ACF fields will appear on job_offer edit screen (hooked to acf/init) - Required fields marked as required (job_location, job_type, job_contact_email) ## Issues Encountered None ## Next Phase Readiness Phase 1 complete - all 3 plans done: - 01-01: Plugin foundation (completed) - 01-02: Custom post type 'job_offer' (completed) - 01-03: Roles & ACF fields (completed) **Ready for Phase 2:** Form submission with Formidable Forms. The foundation is in place: - Custom post type registered with correct capabilities - Provider role ready for assignment - ACF fields ready to receive data from form submissions No blockers or concerns. ## Next Step Phase 1 complete. Ready for Phase 2 (Form Submission).