feat(03-04): add custom admin columns for job moderation

Create DDHH_JM_Admin_UI class with custom columns for job_offer admin listing:
- Anbieter (provider org name + contact person from user meta)
- Standort (location from ACF field)
- Art (job type from ACF field)
- Eingereicht am (submission date)

Removed default author/date columns to reduce clutter. Made columns sortable for efficient moderation workflow.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-14 19:48:13 +09:00
parent 9df86a3847
commit a9cb056e7e

255
includes/class-admin-ui.php Normal file
View File

@@ -0,0 +1,255 @@
<?php
/**
* Admin UI Enhancements
*
* @package DDHH_Job_Manager
*/
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;
/**
* Handles admin interface enhancements for job moderation
*/
class DDHH_JM_Admin_UI {
/**
* Setup admin hooks
*/
public static function setup_hooks() {
// Custom columns
add_filter( 'manage_job_offer_posts_columns', array( __CLASS__, 'add_custom_columns' ) );
add_action( 'manage_job_offer_posts_custom_column', array( __CLASS__, 'render_custom_columns' ), 10, 2 );
add_filter( 'manage_edit-job_offer_sortable_columns', array( __CLASS__, 'add_sortable_columns' ) );
// Status filters and views
add_filter( 'views_edit-job_offer', array( __CLASS__, 'add_status_filters' ) );
// Sort query modifications
add_action( 'pre_get_posts', array( __CLASS__, 'handle_column_sorting' ) );
}
/**
* Add custom columns to job_offer admin listing
*
* @param array $columns Existing columns.
* @return array Modified columns.
*/
public static function add_custom_columns( $columns ) {
// Remove default columns we're replacing
unset( $columns['author'] );
unset( $columns['date'] );
// Build new column array with custom columns
$new_columns = array(
'cb' => $columns['cb'],
'title' => $columns['title'],
'provider' => __( 'Anbieter', 'ddhh-job-manager' ),
'location' => __( 'Standort', 'ddhh-job-manager' ),
'job_type' => __( 'Art', 'ddhh-job-manager' ),
'submitted' => __( 'Eingereicht am', 'ddhh-job-manager' ),
);
return $new_columns;
}
/**
* Render custom column content
*
* @param string $column Column name.
* @param int $post_id Post ID.
*/
public static function render_custom_columns( $column, $post_id ) {
switch ( $column ) {
case 'provider':
self::render_provider_column( $post_id );
break;
case 'location':
self::render_location_column( $post_id );
break;
case 'job_type':
self::render_job_type_column( $post_id );
break;
case 'submitted':
self::render_submitted_column( $post_id );
break;
}
}
/**
* Render provider column (organization name + contact person)
*
* @param int $post_id Post ID.
*/
private static function render_provider_column( $post_id ) {
$post = get_post( $post_id );
if ( ! $post ) {
echo '—';
return;
}
// Get author user
$author_id = $post->post_author;
$org_name = get_user_meta( $author_id, 'ddhh_org_name', true );
$contact_person = get_user_meta( $author_id, 'ddhh_contact_person', true );
if ( $org_name ) {
echo esc_html( $org_name );
if ( $contact_person ) {
echo '<br><small>' . esc_html( $contact_person ) . '</small>';
}
} else {
// Fallback to author display name
$author = get_userdata( $author_id );
if ( $author ) {
echo esc_html( $author->display_name );
} else {
echo '—';
}
}
}
/**
* Render location column
*
* @param int $post_id Post ID.
*/
private static function render_location_column( $post_id ) {
$location = get_field( 'job_location', $post_id );
echo $location ? esc_html( $location ) : '—';
}
/**
* Render job type column
*
* @param int $post_id Post ID.
*/
private static function render_job_type_column( $post_id ) {
$job_type = get_field( 'job_type', $post_id );
if ( $job_type ) {
// Get human-readable label
$labels = array(
'vollzeit' => __( 'Vollzeit', 'ddhh-job-manager' ),
'teilzeit' => __( 'Teilzeit', 'ddhh-job-manager' ),
'ehrenamt' => __( 'Ehrenamt', 'ddhh-job-manager' ),
);
$label = isset( $labels[ $job_type ] ) ? $labels[ $job_type ] : $job_type;
echo esc_html( $label );
} else {
echo '—';
}
}
/**
* Render submitted column (post creation date)
*
* @param int $post_id Post ID.
*/
private static function render_submitted_column( $post_id ) {
$date = get_the_date( 'd.m.Y H:i', $post_id );
echo esc_html( $date );
}
/**
* Add sortable columns
*
* @param array $columns Sortable columns.
* @return array Modified sortable columns.
*/
public static function add_sortable_columns( $columns ) {
$columns['submitted'] = 'date';
$columns['location'] = 'job_location';
$columns['job_type'] = 'job_type';
return $columns;
}
/**
* Handle column sorting in admin query
*
* @param WP_Query $query The query object.
*/
public static function handle_column_sorting( $query ) {
if ( ! is_admin() || ! $query->is_main_query() ) {
return;
}
$orderby = $query->get( 'orderby' );
// Handle ACF field sorting
if ( 'job_location' === $orderby ) {
$query->set( 'meta_key', 'job_location' );
$query->set( 'orderby', 'meta_value' );
} elseif ( 'job_type' === $orderby ) {
$query->set( 'meta_key', 'job_type' );
$query->set( 'orderby', 'meta_value' );
}
}
/**
* Add status filter links with counts
*
* @param array $views Existing view links.
* @return array Modified view links.
*/
public static function add_status_filters( $views ) {
// Get post counts by status
$post_counts = wp_count_posts( 'job_offer' );
// Override default views with custom ones
$views = array();
// All
$all_count = $post_counts->publish + $post_counts->pending + $post_counts->draft + $post_counts->private;
$current_class = ( ! isset( $_GET['post_status'] ) ) ? ' class="current"' : '';
$views['all'] = sprintf(
'<a href="%s"%s>%s <span class="count">(%d)</span></a>',
admin_url( 'edit.php?post_type=job_offer' ),
$current_class,
__( 'Alle', 'ddhh-job-manager' ),
$all_count
);
// Pending (with emphasis)
if ( $post_counts->pending > 0 ) {
$pending_class = ( isset( $_GET['post_status'] ) && 'pending' === $_GET['post_status'] ) ? ' class="current"' : '';
$views['pending'] = sprintf(
'<a href="%s"%s>%s <span class="count">(%d)</span></a>',
admin_url( 'edit.php?post_type=job_offer&post_status=pending' ),
$pending_class,
__( 'Ausstehend', 'ddhh-job-manager' ),
$post_counts->pending
);
}
// Published
if ( $post_counts->publish > 0 ) {
$publish_class = ( isset( $_GET['post_status'] ) && 'publish' === $_GET['post_status'] ) ? ' class="current"' : '';
$views['publish'] = sprintf(
'<a href="%s"%s>%s <span class="count">(%d)</span></a>',
admin_url( 'edit.php?post_type=job_offer&post_status=publish' ),
$publish_class,
__( 'Veröffentlicht', 'ddhh-job-manager' ),
$post_counts->publish
);
}
// Draft
if ( $post_counts->draft > 0 ) {
$draft_class = ( isset( $_GET['post_status'] ) && 'draft' === $_GET['post_status'] ) ? ' class="current"' : '';
$views['draft'] = sprintf(
'<a href="%s"%s>%s <span class="count">(%d)</span></a>',
admin_url( 'edit.php?post_type=job_offer&post_status=draft' ),
$draft_class,
__( 'Entwurf', 'ddhh-job-manager' ),
$post_counts->draft
);
}
return $views;
}
}