docs(01): create phase 1 plans
Phase 01: Foundation & Setup - 3 plans created (all independent, can run parallel) - 7 total tasks defined - Ready for execution Plans: - 01-01: Plugin structure and activation hooks - 01-02: Register job_offer CPT with capabilities - 01-03: Register ddhh_provider role and ACF fields Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
157
.planning/phases/01-foundation-setup/01-01-PLAN.md
Normal file
157
.planning/phases/01-foundation-setup/01-01-PLAN.md
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
---
|
||||||
|
phase: 01-foundation-setup
|
||||||
|
plan: 01
|
||||||
|
type: execute
|
||||||
|
depends_on: []
|
||||||
|
files_modified: [ddhh-job-manager.php, includes/class-ddhh-job-manager.php, includes/class-activator.php, includes/class-deactivator.php]
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
Create WordPress plugin boilerplate with proper structure, activation/deactivation hooks, and autoloading.
|
||||||
|
|
||||||
|
Purpose: Establish the foundation that all other features will build upon.
|
||||||
|
Output: Functional WordPress plugin that can be activated without errors.
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<execution_context>
|
||||||
|
~/.claude/get-shit-done/workflows/execute-plan.md
|
||||||
|
./summary.md
|
||||||
|
</execution_context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
@.planning/PROJECT.md
|
||||||
|
@.planning/ROADMAP.md
|
||||||
|
@.planning/STATE.md
|
||||||
|
|
||||||
|
**Tech stack:** WordPress 6.x, ACF Pro, Formidable Forms Pro, Elementor Pro
|
||||||
|
**Constraints:** Must follow WordPress plugin standards, security best practices
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Create main plugin file with header</name>
|
||||||
|
<files>ddhh-job-manager.php</files>
|
||||||
|
<action>
|
||||||
|
Create main plugin file with WordPress plugin header:
|
||||||
|
- Plugin Name: Digital Dabei Job Manager
|
||||||
|
- Description: Closed job board for provider self-registration and mentor applications
|
||||||
|
- Version: 1.0.0
|
||||||
|
- Author: digital dabei Hamburg
|
||||||
|
- Text Domain: ddhh-job-manager
|
||||||
|
- Domain Path: /languages
|
||||||
|
|
||||||
|
Add security check: `defined('ABSPATH') || exit;`
|
||||||
|
|
||||||
|
Define constants: DDHH_JM_VERSION, DDHH_JM_PLUGIN_DIR, DDHH_JM_PLUGIN_URL
|
||||||
|
|
||||||
|
Include autoloader and main class file.
|
||||||
|
Instantiate main class on plugins_loaded hook (priority 10).
|
||||||
|
|
||||||
|
DO NOT use namespace yet — WordPress plugins traditionally use class prefixes for compatibility.
|
||||||
|
</action>
|
||||||
|
<verify>Plugin appears in WordPress admin plugins list (check Plugin Name: header is valid)</verify>
|
||||||
|
<done>Main plugin file exists with valid header, constants defined, autoloader included</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Create main plugin class with activation/deactivation</name>
|
||||||
|
<files>includes/class-ddhh-job-manager.php, includes/class-activator.php, includes/class-deactivator.php</files>
|
||||||
|
<action>
|
||||||
|
Create `includes/class-ddhh-job-manager.php`:
|
||||||
|
- Singleton pattern (private constructor, getInstance() method)
|
||||||
|
- register_activation_hook() → DDHH_JM_Activator::activate()
|
||||||
|
- register_deactivation_hook() → DDHH_JM_Deactivator::deactivate()
|
||||||
|
- Store version in options on activation
|
||||||
|
|
||||||
|
Create `includes/class-activator.php`:
|
||||||
|
- activate() method
|
||||||
|
- Check WordPress version >= 6.0 (wp_die if older)
|
||||||
|
- Check PHP version >= 7.4 (wp_die if older)
|
||||||
|
- Set option 'ddhh_jm_version' to current version
|
||||||
|
- Flush rewrite rules ONCE (set transient flag, flush on next init if flag exists)
|
||||||
|
|
||||||
|
Create `includes/class-deactivator.php`:
|
||||||
|
- deactivate() method
|
||||||
|
- Flush rewrite rules on deactivation
|
||||||
|
- DO NOT delete data (user may reactivate)
|
||||||
|
|
||||||
|
Use `wp_die()` for version checks, not exceptions. WordPress doesn't handle exceptions well during activation.
|
||||||
|
</action>
|
||||||
|
<verify>Code follows WordPress Coding Standards, no syntax errors</verify>
|
||||||
|
<done>Classes created, activation checks present, rewrite rules flushed properly</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 3: Test plugin activation in Local WP environment</name>
|
||||||
|
<files>N/A</files>
|
||||||
|
<action>
|
||||||
|
IMPORTANT: This task documents the testing steps but CANNOT be automated without access to Local WP environment.
|
||||||
|
|
||||||
|
Manual verification required:
|
||||||
|
1. Copy plugin to Local WP: wp-content/plugins/ddhh-job-manager/
|
||||||
|
2. Activate plugin in WordPress admin
|
||||||
|
3. Check for activation errors
|
||||||
|
4. Check admin notices
|
||||||
|
5. Verify version stored in options table
|
||||||
|
|
||||||
|
This is a DOCUMENTATION task — the actual testing must be done by the user in their Local WP environment.
|
||||||
|
</action>
|
||||||
|
<verify>User confirms plugin activates without errors in Local WP</verify>
|
||||||
|
<done>Plugin structure complete and ready for user testing in Local WP</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Before declaring plan complete:
|
||||||
|
- [ ] All PHP files have `defined('ABSPATH') || exit;` security check
|
||||||
|
- [ ] Plugin header is valid and parseable
|
||||||
|
- [ ] Activation/deactivation hooks are registered
|
||||||
|
- [ ] Version checks prevent activation on incompatible environments
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
|
||||||
|
- All tasks completed
|
||||||
|
- Plugin structure follows WordPress standards
|
||||||
|
- Activation/deactivation hooks functional
|
||||||
|
- Ready for user verification in Local WP environment
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.planning/phases/01-foundation-setup/01-01-SUMMARY.md`:
|
||||||
|
|
||||||
|
# Phase 1 Plan 1: Plugin Structure Summary
|
||||||
|
|
||||||
|
**WordPress plugin boilerplate created with activation/deactivation hooks**
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- Main plugin file with proper header and constants
|
||||||
|
- Singleton pattern for main class
|
||||||
|
- Activation with version/PHP/WP checks
|
||||||
|
- Deactivation with rewrite flush
|
||||||
|
- Security checks on all files
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
- `ddhh-job-manager.php` - Main plugin file with header
|
||||||
|
- `includes/class-ddhh-job-manager.php` - Main singleton class
|
||||||
|
- `includes/class-activator.php` - Activation logic with checks
|
||||||
|
- `includes/class-deactivator.php` - Deactivation logic
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
- Used class prefix instead of namespace for WordPress compatibility
|
||||||
|
- Singleton pattern for main class (WordPress convention)
|
||||||
|
- Flush rewrites via transient to avoid multiple flushes
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
## Next Step
|
||||||
|
|
||||||
|
Ready for 01-02-PLAN.md (can run in parallel)
|
||||||
|
</output>
|
||||||
141
.planning/phases/01-foundation-setup/01-02-PLAN.md
Normal file
141
.planning/phases/01-foundation-setup/01-02-PLAN.md
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
---
|
||||||
|
phase: 01-foundation-setup
|
||||||
|
plan: 02
|
||||||
|
type: execute
|
||||||
|
depends_on: []
|
||||||
|
files_modified: [includes/class-post-types.php]
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
Register custom post type `job_offer` with proper capabilities, labels, and support for Elementor templates.
|
||||||
|
|
||||||
|
Purpose: Create the data structure for job listings that providers will manage and mentors will browse.
|
||||||
|
Output: Functional `job_offer` CPT with correct capabilities and features.
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<execution_context>
|
||||||
|
~/.claude/get-shit-done/workflows/execute-plan.md
|
||||||
|
./summary.md
|
||||||
|
</execution_context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
@.planning/PROJECT.md
|
||||||
|
@.planning/ROADMAP.md
|
||||||
|
@.planning/STATE.md
|
||||||
|
|
||||||
|
**From PROJECT.md:**
|
||||||
|
- Custom role `ddhh_provider` with restricted capabilities
|
||||||
|
- Providers can only edit their own posts
|
||||||
|
- No WP-Admin access for providers (except profile)
|
||||||
|
|
||||||
|
**Security requirement:** Use `map_meta_cap` filter to enforce ownership
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Register job_offer custom post type</name>
|
||||||
|
<files>includes/class-post-types.php</files>
|
||||||
|
<action>
|
||||||
|
Create `DDHH_JM_Post_Types` class with static register() method.
|
||||||
|
|
||||||
|
Register CPT 'job_offer' with register_post_type():
|
||||||
|
- Labels: Singular "Jobangebot", Plural "Jobangebote", menu_name "Jobs" (German, as per PROJECT.md)
|
||||||
|
- public: true
|
||||||
|
- show_ui: true
|
||||||
|
- show_in_menu: true
|
||||||
|
- menu_position: 5 (below Posts)
|
||||||
|
- menu_icon: 'dashicons-businessperson'
|
||||||
|
- supports: ['title', 'editor', 'author', 'thumbnail']
|
||||||
|
- has_archive: true
|
||||||
|
- rewrite: ['slug' => 'jobangebote']
|
||||||
|
- capability_type: 'job_offer' (custom capabilities)
|
||||||
|
- map_meta_cap: true (enables per-post capability checks)
|
||||||
|
- show_in_rest: true (Gutenberg + Elementor support)
|
||||||
|
|
||||||
|
Custom capabilities:
|
||||||
|
- edit_posts: 'edit_job_offers'
|
||||||
|
- edit_others_posts: 'edit_others_job_offers'
|
||||||
|
- publish_posts: 'publish_job_offers'
|
||||||
|
- read_private_posts: 'read_private_job_offers'
|
||||||
|
- delete_posts: 'delete_job_offers'
|
||||||
|
|
||||||
|
Hook register() to 'init' action in main class.
|
||||||
|
|
||||||
|
DO NOT use 'post' as capability_type — this would give providers access to regular posts.
|
||||||
|
</action>
|
||||||
|
<verify>CPT appears in WordPress admin menu, archive URL works (even if empty)</verify>
|
||||||
|
<done>job_offer CPT registered with custom capabilities and Elementor support</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Add capability mapping filter for ownership enforcement</name>
|
||||||
|
<files>includes/class-post-types.php</files>
|
||||||
|
<action>
|
||||||
|
Add static method `map_job_offer_capabilities($caps, $cap, $user_id, $args)` hooked to 'map_meta_cap' filter.
|
||||||
|
|
||||||
|
Logic:
|
||||||
|
- If $cap is 'edit_job_offer' or 'delete_job_offer':
|
||||||
|
- Check if post author == $user_id
|
||||||
|
- If yes: return ['edit_job_offers'] (allow)
|
||||||
|
- If no: return ['edit_others_job_offers'] (deny for providers, allow for admins)
|
||||||
|
- For all other caps: return $caps unchanged
|
||||||
|
|
||||||
|
This ensures providers can ONLY edit/delete their own job_offer posts, never others'.
|
||||||
|
|
||||||
|
WordPress will automatically check these capabilities against user roles.
|
||||||
|
</action>
|
||||||
|
<verify>Logic is sound: non-author providers cannot edit others' posts</verify>
|
||||||
|
<done>Capability mapping enforces post ownership, providers restricted to own posts</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Before declaring plan complete:
|
||||||
|
- [ ] CPT registered with correct labels (German)
|
||||||
|
- [ ] Custom capability_type prevents capability leakage to regular posts
|
||||||
|
- [ ] map_meta_cap filter enforces ownership
|
||||||
|
- [ ] show_in_rest enabled for Elementor compatibility
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
|
||||||
|
- All tasks completed
|
||||||
|
- CPT registered with custom capabilities
|
||||||
|
- Ownership enforcement via map_meta_cap
|
||||||
|
- Ready for ACF field registration in next plan
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.planning/phases/01-foundation-setup/01-02-SUMMARY.md`:
|
||||||
|
|
||||||
|
# Phase 1 Plan 2: Custom Post Type Summary
|
||||||
|
|
||||||
|
**`job_offer` CPT registered with ownership-enforced capabilities**
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- Custom post type 'job_offer' with German labels
|
||||||
|
- Custom capability type prevents access to regular posts
|
||||||
|
- map_meta_cap filter enforces per-post ownership
|
||||||
|
- Elementor support via show_in_rest
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
- `includes/class-post-types.php` - CPT registration and capability mapping
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
- Used custom capability_type 'job_offer' (not 'post') for security
|
||||||
|
- German labels: "Jobangebot" / "Jobangebote"
|
||||||
|
- Archive slug: 'jobangebote'
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
## Next Step
|
||||||
|
|
||||||
|
Ready for 01-03-PLAN.md (can run in parallel)
|
||||||
|
</output>
|
||||||
146
.planning/phases/01-foundation-setup/01-03-PLAN.md
Normal file
146
.planning/phases/01-foundation-setup/01-03-PLAN.md
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
---
|
||||||
|
phase: 01-foundation-setup
|
||||||
|
plan: 03
|
||||||
|
type: execute
|
||||||
|
depends_on: []
|
||||||
|
files_modified: [includes/class-roles.php, includes/class-acf-fields.php]
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
Register custom role `ddhh_provider` with restricted capabilities and ACF field groups for job_offer CPT.
|
||||||
|
|
||||||
|
Purpose: Define provider permissions and job listing data structure.
|
||||||
|
Output: Provider role with correct capabilities, ACF fields for job metadata.
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<execution_context>
|
||||||
|
~/.claude/get-shit-done/workflows/execute-plan.md
|
||||||
|
./summary.md
|
||||||
|
</execution_context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
@.planning/PROJECT.md
|
||||||
|
@.planning/ROADMAP.md
|
||||||
|
@.planning/STATE.md
|
||||||
|
|
||||||
|
**From PROJECT.md:**
|
||||||
|
- ACF fields: job_location (text), job_type (select), job_deadline (date), job_contact_email (email), job_logo (image), job_deactivation_reason (textarea - internal)
|
||||||
|
- Providers: restricted capabilities, no WP-Admin access except profile
|
||||||
|
|
||||||
|
**Tech stack:** ACF Pro available
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Register ddhh_provider role with restricted capabilities</name>
|
||||||
|
<files>includes/class-roles.php</files>
|
||||||
|
<action>
|
||||||
|
Create `DDHH_JM_Roles` class with static add_roles() method.
|
||||||
|
|
||||||
|
Register role 'ddhh_provider' with add_role():
|
||||||
|
- Display name: 'Anbieter' (German for Provider)
|
||||||
|
- Capabilities:
|
||||||
|
- read: true (basic WordPress access)
|
||||||
|
- edit_job_offers: true (can edit own job_offers)
|
||||||
|
- publish_job_offers: false (jobs go to pending, admin publishes)
|
||||||
|
- delete_job_offers: true (can delete own)
|
||||||
|
- upload_files: true (needed for logo upload)
|
||||||
|
|
||||||
|
- Explicitly DENY:
|
||||||
|
- edit_others_job_offers: false (cannot edit others' jobs)
|
||||||
|
- edit_posts: false (no access to regular posts)
|
||||||
|
- edit_pages: false (no access to pages)
|
||||||
|
- manage_categories: false (no admin functions)
|
||||||
|
|
||||||
|
Hook add_roles() to activation (via Activator class), not 'init' (roles persist in DB).
|
||||||
|
|
||||||
|
Also create static remove_roles() method for deactivation cleanup.
|
||||||
|
|
||||||
|
DO NOT give 'edit_posts' capability — this would grant access to regular blog posts.
|
||||||
|
</action>
|
||||||
|
<verify>Role appears in WordPress users > Add New > Role dropdown</verify>
|
||||||
|
<done>ddhh_provider role registered with correct capabilities for job management only</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Register ACF field group for job_offer metadata</name>
|
||||||
|
<files>includes/class-acf-fields.php</files>
|
||||||
|
<action>
|
||||||
|
Create `DDHH_JM_ACF_Fields` class with static register_fields() method.
|
||||||
|
|
||||||
|
Use acf_add_local_field_group() to register field group:
|
||||||
|
- Title: 'Job Details'
|
||||||
|
- Location: post_type == 'job_offer'
|
||||||
|
- Position: 'normal'
|
||||||
|
- Style: 'default'
|
||||||
|
|
||||||
|
Fields:
|
||||||
|
1. job_location (type: text, label: 'Standort', required: true)
|
||||||
|
2. job_type (type: select, label: 'Art', choices: ['vollzeit' => 'Vollzeit', 'teilzeit' => 'Teilzeit', 'ehrenamt' => 'Ehrenamt'], required: true)
|
||||||
|
3. job_deadline (type: date_picker, label: 'Bewerbungsfrist', return_format: 'Y-m-d', required: false)
|
||||||
|
4. job_contact_email (type: email, label: 'Kontakt-E-Mail', required: true)
|
||||||
|
5. job_logo (type: image, label: 'Logo', return_format: 'id', preview_size: 'thumbnail', required: false)
|
||||||
|
6. job_deactivation_reason (type: textarea, label: 'Deaktivierungsgrund (intern)', rows: 3, required: false, conditional_logic: show only when post_status != 'publish')
|
||||||
|
|
||||||
|
Hook register_fields() to 'acf/init' action.
|
||||||
|
|
||||||
|
Use acf_add_local_field_group() not acf_register_field_group() — local fields are code-defined, not DB-stored.
|
||||||
|
</action>
|
||||||
|
<verify>ACF fields appear on job_offer edit screen in WordPress admin</verify>
|
||||||
|
<done>ACF field group registered with all required metadata fields</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Before declaring plan complete:
|
||||||
|
- [ ] Provider role exists with correct capabilities
|
||||||
|
- [ ] Provider CANNOT edit regular posts/pages
|
||||||
|
- [ ] Provider CAN upload files (for logos)
|
||||||
|
- [ ] ACF fields appear on job_offer edit screen
|
||||||
|
- [ ] All required fields marked as required
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
|
||||||
|
- All tasks completed
|
||||||
|
- Provider role restricts access appropriately
|
||||||
|
- ACF fields capture all job metadata
|
||||||
|
- Ready for Formidable form integration in Phase 2
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.planning/phases/01-foundation-setup/01-03-SUMMARY.md`:
|
||||||
|
|
||||||
|
# Phase 1 Plan 3: Roles & Fields Summary
|
||||||
|
|
||||||
|
**Provider role and ACF field group for job metadata registered**
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- Custom role 'ddhh_provider' with job-only capabilities
|
||||||
|
- ACF field group with 6 metadata fields
|
||||||
|
- Proper capability restrictions (no posts/pages access)
|
||||||
|
- Logo upload support
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
- `includes/class-roles.php` - Role registration and cleanup
|
||||||
|
- `includes/class-acf-fields.php` - ACF field group definition
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
- Jobs submit to 'pending' status (admin approval required)
|
||||||
|
- German field labels: Standort, Art, Bewerbungsfrist, etc.
|
||||||
|
- Logo as image ID (not URL) for better media library integration
|
||||||
|
- Deactivation reason field conditional on non-published status
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
## Next Step
|
||||||
|
|
||||||
|
Phase 1 complete — all 3 plans done. Ready for Phase 2.
|
||||||
|
</output>
|
||||||
Reference in New Issue
Block a user