diff --git a/includes/class-formidable.php b/includes/class-formidable.php index a5f48d4..0044366 100644 --- a/includes/class-formidable.php +++ b/includes/class-formidable.php @@ -161,6 +161,9 @@ class DDHH_JM_Formidable { // Hook into Formidable form submission add_action( 'frm_after_create_entry', array( __CLASS__, 'handle_registration_submission' ), 30, 2 ); + add_action( 'frm_after_create_entry', array( __CLASS__, 'handle_job_submission' ), 30, 2 ); + add_action( 'frm_after_create_entry', array( __CLASS__, 'handle_job_edit_submission' ), 30, 2 ); + add_action( 'frm_after_create_entry', array( __CLASS__, 'handle_job_deactivation_submission' ), 30, 2 ); // Add JavaScript redirect for registration form add_action( 'wp_footer', array( __CLASS__, 'add_registration_redirect_script' ) ); @@ -168,6 +171,9 @@ class DDHH_JM_Formidable { // Hook into Formidable form validation for ownership check add_filter( 'frm_validate_entry', array( __CLASS__, 'validate_job_ownership' ), 10, 2 ); add_filter( 'frm_validate_entry', array( __CLASS__, 'validate_job_deactivation_ownership' ), 10, 2 ); + + // Hook to pre-populate edit form fields + add_filter( 'frm_get_default_value', array( __CLASS__, 'prepopulate_edit_form_fields' ), 10, 3 ); } /** @@ -437,6 +443,324 @@ class DDHH_JM_Formidable { do_action( 'ddhh_provider_registered', $user_id, $organization_name ); } + /** + * Handle job submission form entry + * + * @param int $entry_id Entry ID. + * @param int $form_id Form ID. + */ + public static function handle_job_submission( $entry_id, $form_id ) { + // Only process our job submission form + if ( $form_id != self::get_job_submission_form_id() ) { + return; + } + + error_log( 'DDHH Job Submission: Processing form entry ' . $entry_id ); + + // Get entry data + $entry = FrmEntry::getOne( $entry_id, true ); + if ( ! $entry ) { + error_log( 'DDHH Job Submission: Failed to get entry' ); + return; + } + + // Extract field values + $job_title = ''; + $job_description = ''; + $job_location = ''; + $job_type = ''; + $job_deadline = ''; + $job_contact_email = ''; + $job_logo = ''; + + foreach ( $entry->metas as $field_id => $value ) { + $field = FrmField::getOne( $field_id ); + if ( ! $field ) { + continue; + } + + switch ( $field->field_key ) { + case 'job_title': + $job_title = sanitize_text_field( $value ); + break; + case 'job_description': + $job_description = wp_kses_post( $value ); + break; + case 'job_location': + $job_location = sanitize_text_field( $value ); + break; + case 'job_type': + $job_type = sanitize_text_field( $value ); + break; + case 'job_deadline': + $job_deadline = sanitize_text_field( $value ); + break; + case 'job_contact_email': + $job_contact_email = sanitize_email( $value ); + break; + case 'job_logo': + $job_logo = $value; // File ID + break; + } + } + + // Validate required fields + if ( empty( $job_title ) || empty( $job_description ) || empty( $job_location ) || empty( $job_type ) || empty( $job_contact_email ) ) { + error_log( 'DDHH Job Submission: Validation failed - missing required fields' ); + return; + } + + // Create job_offer post + $post_data = array( + 'post_title' => $job_title, + 'post_content' => $job_description, + 'post_type' => 'job_offer', + 'post_status' => 'pending', + 'post_author' => get_current_user_id(), + ); + + $post_id = wp_insert_post( $post_data ); + + // Check for errors + if ( is_wp_error( $post_id ) ) { + error_log( 'DDHH Job Submission: wp_insert_post failed - ' . $post_id->get_error_message() ); + return; + } + + error_log( 'DDHH Job Submission: Post created successfully with ID ' . $post_id ); + + // Save custom fields + update_post_meta( $post_id, 'job_location', $job_location ); + update_post_meta( $post_id, 'job_type', $job_type ); + update_post_meta( $post_id, 'job_contact_email', $job_contact_email ); + + if ( ! empty( $job_deadline ) ) { + update_post_meta( $post_id, 'job_deadline', $job_deadline ); + } + + // Handle logo upload if present + if ( ! empty( $job_logo ) && is_numeric( $job_logo ) ) { + set_post_thumbnail( $post_id, absint( $job_logo ) ); + error_log( 'DDHH Job Submission: Logo set as featured image' ); + } + + error_log( 'DDHH Job Submission: Job offer created successfully' ); + + do_action( 'ddhh_job_submitted', $post_id, $entry_id ); + } + + /** + * Handle job edit form submission + * + * @param int $entry_id Entry ID. + * @param int $form_id Form ID. + */ + public static function handle_job_edit_submission( $entry_id, $form_id ) { + // Only process our job edit form + if ( $form_id != self::get_job_edit_form_id() ) { + return; + } + + // Check if we have a job_id to update + if ( ! isset( $_GET['job_id'] ) ) { + error_log( 'DDHH Job Edit: No job_id provided' ); + return; + } + + $post_id = absint( $_GET['job_id'] ); + error_log( 'DDHH Job Edit: Processing form entry ' . $entry_id . ' for post ' . $post_id ); + + // Verify post exists and user owns it + $post = get_post( $post_id ); + if ( ! $post || 'job_offer' !== $post->post_type ) { + error_log( 'DDHH Job Edit: Invalid post' ); + return; + } + + if ( absint( $post->post_author ) !== get_current_user_id() ) { + error_log( 'DDHH Job Edit: User does not own this post' ); + return; + } + + // Get entry data + $entry = FrmEntry::getOne( $entry_id, true ); + if ( ! $entry ) { + error_log( 'DDHH Job Edit: Failed to get entry' ); + return; + } + + // Extract field values (accounting for "2" suffix) + $job_title = ''; + $job_description = ''; + $job_location = ''; + $job_type = ''; + $job_deadline = ''; + $job_contact_email = ''; + $job_logo = ''; + + foreach ( $entry->metas as $field_id => $value ) { + $field = FrmField::getOne( $field_id ); + if ( ! $field ) { + continue; + } + + switch ( $field->field_key ) { + case 'job_title': + case 'job_title2': + $job_title = sanitize_text_field( $value ); + break; + case 'job_description': + case 'job_description2': + $job_description = wp_kses_post( $value ); + break; + case 'job_location': + case 'job_location2': + $job_location = sanitize_text_field( $value ); + break; + case 'job_type': + case 'job_type2': + $job_type = sanitize_text_field( $value ); + break; + case 'job_deadline': + case 'job_deadline2': + $job_deadline = sanitize_text_field( $value ); + break; + case 'job_contact_email': + case 'job_contact_email2': + $job_contact_email = sanitize_email( $value ); + break; + case 'job_logo': + case 'job_logo2': + $job_logo = $value; // File ID + break; + } + } + + // Validate required fields + if ( empty( $job_title ) || empty( $job_description ) || empty( $job_location ) || empty( $job_type ) || empty( $job_contact_email ) ) { + error_log( 'DDHH Job Edit: Validation failed - missing required fields' ); + return; + } + + // Update job_offer post + $post_data = array( + 'ID' => $post_id, + 'post_title' => $job_title, + 'post_content' => $job_description, + 'post_status' => 'pending', // Reset to pending for admin review + ); + + $result = wp_update_post( $post_data ); + + // Check for errors + if ( is_wp_error( $result ) ) { + error_log( 'DDHH Job Edit: wp_update_post failed - ' . $result->get_error_message() ); + return; + } + + error_log( 'DDHH Job Edit: Post updated successfully with ID ' . $post_id ); + + // Update custom fields + update_post_meta( $post_id, 'job_location', $job_location ); + update_post_meta( $post_id, 'job_type', $job_type ); + update_post_meta( $post_id, 'job_contact_email', $job_contact_email ); + + if ( ! empty( $job_deadline ) ) { + update_post_meta( $post_id, 'job_deadline', $job_deadline ); + } + + // Handle logo upload if present + if ( ! empty( $job_logo ) && is_numeric( $job_logo ) ) { + set_post_thumbnail( $post_id, absint( $job_logo ) ); + error_log( 'DDHH Job Edit: Logo updated' ); + } + + error_log( 'DDHH Job Edit: Job offer updated successfully' ); + + do_action( 'ddhh_job_edited', $post_id, $entry_id ); + } + + /** + * Handle job deactivation form submission + * + * @param int $entry_id Entry ID. + * @param int $form_id Form ID. + */ + public static function handle_job_deactivation_submission( $entry_id, $form_id ) { + // Only process our job deactivation form + if ( $form_id != self::get_job_deactivation_form_id() ) { + return; + } + + // Check if we have a job_id to deactivate + if ( ! isset( $_GET['job_id'] ) ) { + error_log( 'DDHH Job Deactivation: No job_id provided' ); + return; + } + + $post_id = absint( $_GET['job_id'] ); + error_log( 'DDHH Job Deactivation: Processing form entry ' . $entry_id . ' for post ' . $post_id ); + + // Verify post exists and user owns it + $post = get_post( $post_id ); + if ( ! $post || 'job_offer' !== $post->post_type ) { + error_log( 'DDHH Job Deactivation: Invalid post' ); + return; + } + + if ( absint( $post->post_author ) !== get_current_user_id() ) { + error_log( 'DDHH Job Deactivation: User does not own this post' ); + return; + } + + // Get entry data + $entry = FrmEntry::getOne( $entry_id, true ); + if ( ! $entry ) { + error_log( 'DDHH Job Deactivation: Failed to get entry' ); + return; + } + + // Extract deactivation reason + $deactivation_reason = ''; + + foreach ( $entry->metas as $field_id => $value ) { + $field = FrmField::getOne( $field_id ); + if ( ! $field ) { + continue; + } + + if ( 'deactivation_reason' === $field->field_key ) { + $deactivation_reason = sanitize_textarea_field( $value ); + break; + } + } + + // Update post status to draft (deactivated) + $result = wp_update_post( array( + 'ID' => $post_id, + 'post_status' => 'draft', + ) ); + + // Check for errors + if ( is_wp_error( $result ) ) { + error_log( 'DDHH Job Deactivation: wp_update_post failed - ' . $result->get_error_message() ); + return; + } + + error_log( 'DDHH Job Deactivation: Post status updated to draft for post ' . $post_id ); + + // Save deactivation reason (using ACF field name) + if ( ! empty( $deactivation_reason ) ) { + update_post_meta( $post_id, 'job_deactivation_reason', $deactivation_reason ); + update_post_meta( $post_id, 'job_deactivation_date', current_time( 'mysql' ) ); + error_log( 'DDHH Job Deactivation: Saved deactivation reason' ); + } + + error_log( 'DDHH Job Deactivation: Job deactivated successfully' ); + + do_action( 'ddhh_job_deactivated', $post_id, $entry_id ); + } + /** * Create the job submission form programmatically if it doesn't exist */ @@ -777,6 +1101,71 @@ class DDHH_JM_Formidable { } } + /** + * Pre-populate edit form fields with existing post data + * + * @param mixed $default_value The default value. + * @param object $field The field object. + * @param bool $dynamic_default Whether to use dynamic default. + * @return mixed The modified default value. + */ + public static function prepopulate_edit_form_fields( $default_value, $field, $dynamic_default ) { + // Only process for the job edit form + if ( absint( $field->form_id ) !== self::get_job_edit_form_id() ) { + return $default_value; + } + + // Check if we're editing - look for job_id in URL + if ( ! isset( $_GET['job_id'] ) ) { + return $default_value; + } + + $post_id = absint( $_GET['job_id'] ); + $post = get_post( $post_id ); + + if ( ! $post || 'job_offer' !== $post->post_type ) { + return $default_value; + } + + // Map field keys to post data (handle both with and without "2" suffix) + switch ( $field->field_key ) { + case 'job_title': + case 'job_title2': + return $post->post_title; + + case 'job_description': + case 'job_description2': + return $post->post_content; + + case 'job_location': + case 'job_location2': + $value = get_post_meta( $post_id, 'job_location', true ); + return $value ? $value : $default_value; + + case 'job_type': + case 'job_type2': + $value = get_post_meta( $post_id, 'job_type', true ); + return $value ? $value : $default_value; + + case 'job_deadline': + case 'job_deadline2': + $value = get_post_meta( $post_id, 'job_deadline', true ); + return $value ? $value : $default_value; + + case 'job_contact_email': + case 'job_contact_email2': + $value = get_post_meta( $post_id, 'job_contact_email', true ); + return $value ? $value : $default_value; + + case 'job_logo': + case 'job_logo2': + $value = get_post_thumbnail_id( $post_id ); + return $value ? $value : $default_value; + } + + return $default_value; + } + /** * Validate job ownership before allowing edit * diff --git a/includes/class-roles.php b/includes/class-roles.php index d3e688a..f494a5d 100644 --- a/includes/class-roles.php +++ b/includes/class-roles.php @@ -50,6 +50,24 @@ class DDHH_JM_Roles { 'manage_options' => false, ) ); + + // Grant job_offer capabilities to administrator + $admin_role = get_role( 'administrator' ); + if ( $admin_role ) { + $admin_role->add_cap( 'edit_job_offer' ); + $admin_role->add_cap( 'read_job_offer' ); + $admin_role->add_cap( 'delete_job_offer' ); + $admin_role->add_cap( 'edit_job_offers' ); + $admin_role->add_cap( 'edit_others_job_offers' ); + $admin_role->add_cap( 'publish_job_offers' ); + $admin_role->add_cap( 'read_private_job_offers' ); + $admin_role->add_cap( 'delete_job_offers' ); + $admin_role->add_cap( 'delete_private_job_offers' ); + $admin_role->add_cap( 'delete_published_job_offers' ); + $admin_role->add_cap( 'delete_others_job_offers' ); + $admin_role->add_cap( 'edit_private_job_offers' ); + $admin_role->add_cap( 'edit_published_job_offers' ); + } } /** @@ -58,5 +76,23 @@ class DDHH_JM_Roles { */ public static function remove_roles() { remove_role( 'ddhh_provider' ); + + // Remove job_offer capabilities from administrator + $admin_role = get_role( 'administrator' ); + if ( $admin_role ) { + $admin_role->remove_cap( 'edit_job_offer' ); + $admin_role->remove_cap( 'read_job_offer' ); + $admin_role->remove_cap( 'delete_job_offer' ); + $admin_role->remove_cap( 'edit_job_offers' ); + $admin_role->remove_cap( 'edit_others_job_offers' ); + $admin_role->remove_cap( 'publish_job_offers' ); + $admin_role->remove_cap( 'read_private_job_offers' ); + $admin_role->remove_cap( 'delete_job_offers' ); + $admin_role->remove_cap( 'delete_private_job_offers' ); + $admin_role->remove_cap( 'delete_published_job_offers' ); + $admin_role->remove_cap( 'delete_others_job_offers' ); + $admin_role->remove_cap( 'edit_private_job_offers' ); + $admin_role->remove_cap( 'edit_published_job_offers' ); + } } } diff --git a/migrations/completed/2026-01-15-migrate-job-entries.php b/migrations/completed/2026-01-15-migrate-job-entries.php new file mode 100644 index 0000000..75cb6d4 --- /dev/null +++ b/migrations/completed/2026-01-15-migrate-job-entries.php @@ -0,0 +1,193 @@ +id; +echo "Found job submission form with ID: {$form_id}\n"; + +// Get all entries for this form using global $wpdb +global $wpdb; +$entry_table = $wpdb->prefix . 'frm_items'; +$entry_ids = $wpdb->get_col( $wpdb->prepare( + "SELECT id FROM {$entry_table} WHERE form_id = %d ORDER BY created_at ASC", + $form_id +) ); + +if ( empty( $entry_ids ) ) { + die( "No entries found to migrate.\n" ); +} + +// Load full entry objects +$entries = array(); +foreach ( $entry_ids as $entry_id ) { + $entry = FrmEntry::getOne( $entry_id ); + if ( $entry ) { + $entries[] = $entry; + } +} + +echo "Found " . count( $entries ) . " entries to migrate.\n\n"; + +$migrated = 0; +$skipped = 0; +$errors = 0; + +foreach ( $entries as $entry ) { + echo "Processing entry #{$entry->id}...\n"; + + // Get full entry with meta data + $full_entry = FrmEntry::getOne( $entry->id, true ); + if ( ! $full_entry ) { + echo " ERROR: Could not load entry data\n"; + $errors++; + continue; + } + + // Check if this entry has already been migrated by checking if a post exists + // We'll check if there's a post with the same author and created around the same time + $entry_user_id = absint( $entry->user_id ); + if ( empty( $entry_user_id ) ) { + echo " SKIPPED: Entry has no user_id\n"; + $skipped++; + continue; + } + + // Extract field values + $job_title = ''; + $job_description = ''; + $job_location = ''; + $job_type = ''; + $job_deadline = ''; + $job_contact_email = ''; + $job_logo = ''; + + foreach ( $full_entry->metas as $field_id => $value ) { + $field = FrmField::getOne( $field_id ); + if ( ! $field ) { + continue; + } + + switch ( $field->field_key ) { + case 'job_title': + $job_title = sanitize_text_field( $value ); + break; + case 'job_description': + $job_description = wp_kses_post( $value ); + break; + case 'job_location': + $job_location = sanitize_text_field( $value ); + break; + case 'job_type': + $job_type = sanitize_text_field( $value ); + break; + case 'job_deadline': + $job_deadline = sanitize_text_field( $value ); + break; + case 'job_contact_email': + $job_contact_email = sanitize_email( $value ); + break; + case 'job_logo': + $job_logo = $value; // File ID + break; + } + } + + // Validate required fields + if ( empty( $job_title ) ) { + echo " SKIPPED: Missing job title\n"; + $skipped++; + continue; + } + + // Check if a post with this title and author already exists + $existing_post = get_posts( array( + 'post_type' => 'job_offer', + 'post_status' => 'any', + 'author' => $entry_user_id, + 'title' => $job_title, + 'numberposts' => 1, + ) ); + + if ( ! empty( $existing_post ) ) { + echo " SKIPPED: Post already exists (ID: {$existing_post[0]->ID})\n"; + $skipped++; + continue; + } + + // Create job_offer post + $post_data = array( + 'post_title' => $job_title, + 'post_content' => $job_description, + 'post_type' => 'job_offer', + 'post_status' => 'pending', + 'post_author' => $entry_user_id, + 'post_date' => $entry->created_at, + ); + + $post_id = wp_insert_post( $post_data, true ); + + // Check for errors + if ( is_wp_error( $post_id ) ) { + echo " ERROR: Failed to create post - " . $post_id->get_error_message() . "\n"; + $errors++; + continue; + } + + // Save custom fields + if ( ! empty( $job_location ) ) { + update_post_meta( $post_id, 'job_location', $job_location ); + } + if ( ! empty( $job_type ) ) { + update_post_meta( $post_id, 'job_type', $job_type ); + } + if ( ! empty( $job_contact_email ) ) { + update_post_meta( $post_id, 'job_contact_email', $job_contact_email ); + } + if ( ! empty( $job_deadline ) ) { + update_post_meta( $post_id, 'job_deadline', $job_deadline ); + } + + // Handle logo upload if present + if ( ! empty( $job_logo ) && is_numeric( $job_logo ) ) { + set_post_thumbnail( $post_id, absint( $job_logo ) ); + } + + // Store reference to original entry + update_post_meta( $post_id, '_migrated_from_entry_id', $entry->id ); + + echo " SUCCESS: Created post #{$post_id} - \"{$job_title}\"\n"; + $migrated++; +} + +echo "\n=== Migration Complete ===\n"; +echo "Migrated: {$migrated}\n"; +echo "Skipped: {$skipped}\n"; +echo "Errors: {$errors}\n"; +echo "Total: " . count( $entries ) . "\n"; diff --git a/templates/provider-dashboard.php b/templates/provider-dashboard.php index 792b99f..c65349f 100644 --- a/templates/provider-dashboard.php +++ b/templates/provider-dashboard.php @@ -37,12 +37,79 @@ if ( $is_edit_mode ) { $form_id = DDHH_JM_Formidable::get_job_edit_form_id(); if ( $form_id ) { + // Get post data + $post = get_post( $job_id ); + if ( ! $post || 'job_offer' !== $post->post_type || absint( $post->post_author ) !== get_current_user_id() ) { + echo '

Sie haben keine Berechtigung, dieses Stellenangebot zu bearbeiten.

'; + return; + } + + // Get field IDs + $fields = FrmField::getAll( array( 'fi.form_id' => $form_id ), 'field_order' ); + $field_params = array(); + + foreach ( $fields as $field ) { + $field_value = ''; + switch ( $field->field_key ) { + case 'job_title2': + $field_value = $post->post_title; + break; + case 'job_description2': + $field_value = $post->post_content; + break; + case 'job_location2': + $field_value = get_post_meta( $job_id, 'job_location', true ); + break; + case 'job_type2': + $field_value = get_post_meta( $job_id, 'job_type', true ); + break; + case 'job_deadline2': + $field_value = get_post_meta( $job_id, 'job_deadline', true ); + break; + case 'job_contact_email2': + $field_value = get_post_meta( $job_id, 'job_contact_email', true ); + break; + case 'job_logo2': + $field_value = get_post_thumbnail_id( $job_id ); + break; + } + + if ( ! empty( $field_value ) ) { + $field_params[ $field->id ] = $field_value; + } + } + ?>

Stellenangebot bearbeiten

-

← Zurück zur Übersicht

- +

← Zurück zur Übersicht

+ + +

Stellenangebot deaktivieren

-

← Zurück zur Übersicht

+

← Zurück zur Übersicht

@@ -137,12 +204,14 @@ $job_query = new WP_Query( $args ); 'edit_job', - 'job_id' => $post_id, + 'action' => 'edit_job', + 'job_id' => $post_id, + 'id_param' => $post_id, // For Formidable form action ), - get_permalink() + $dashboard_url ); echo 'Bearbeiten'; } @@ -154,12 +223,13 @@ $job_query = new WP_Query( $args ); // Deactivate link - only for published posts if ( 'publish' === $post_status ) { + $dashboard_url = home_url( '/anbieter-dashboard/' ); $deactivate_url = add_query_arg( array( 'action' => 'deactivate_job', 'job_id' => $post_id, ), - get_permalink() + $dashboard_url ); echo ' Deaktivieren'; }