__( 'Tasks', 'admin-hero' ), 'singular_name' => __( 'Task', 'admin-hero' ), 'add_new' => __( 'Add New', 'admin-hero' ), 'add_new_item' => __( 'Add New Task', 'admin-hero' ), 'edit_item' => __( 'Edit Task', 'admin-hero' ), 'new_item' => __( 'New Task', 'admin-hero' ), 'all_items' => __( 'All Tasks', 'admin-hero' ), 'view_item' => __( 'View Task', 'admin-hero' ), 'search_items' => __( 'Search Tasks', 'admin-hero' ), 'not_found' => __( 'No tasks found', 'admin-hero' ), 'not_found_in_trash' => __( 'No tasks found in Trash','admin-hero' ), 'menu_name' => __( 'Admin Hero Tasks', 'admin-hero' ), ]; $args = [ 'labels' => $labels, 'public' => false, 'show_ui' => true, 'show_in_menu' => false, 'capability_type' => 'post', 'supports' => [ 'title' ], 'has_archive' => false, 'hierarchical' => false, 'rewrite' => false, 'query_var' => false, ]; register_post_type( 'admin_hero_task', $args ); }); /** * 2) AJAX handler: return all tasks as JSON. */ add_action( 'wp_ajax_admin_hero_get_tasks', function() { $queried = get_posts( [ 'post_type' => 'admin_hero_task', 'post_status' => 'publish', 'posts_per_page' => -1, 'orderby' => 'date', 'order' => 'DESC', ] ); $response = []; foreach ( $queried as $post ) { // assigned_to $assigned_id = intval( get_post_meta( $post->ID, '_ah_assigned_to', true ) ); $assigned_name = $assigned_id ? get_the_author_meta( 'display_name', $assigned_id ) : ''; // assigned_by + date $assigned_by_id = intval( get_post_meta( $post->ID, '_ah_assigned_by', true ) ); if ( ! $assigned_by_id ) { // fallback to created_by if never explicitly assigned $assigned_by_id = intval( get_post_meta( $post->ID, '_ah_created_by', true ) ); } $assigned_by_name = $assigned_by_id ? get_the_author_meta( 'display_name', $assigned_by_id ) : ''; $raw_assigned_date = get_post_meta( $post->ID, '_ah_assigned_date', true ); $assigned_date_iso = $raw_assigned_date ? ( $ts = strtotime( $raw_assigned_date ) ) ? date( 'Y-m-d', $ts ) : '' : ''; // created_by + date $created_by_id = intval( get_post_meta( $post->ID, '_ah_created_by', true ) ); $created_by_name = $created_by_id ? get_the_author_meta( 'display_name', $created_by_id ) : ''; $raw_created_date = get_the_date( 'Y-m-d', $post ); // other fields $notes = get_post_meta( $post->ID, '_ah_notes', true ); $status = sanitize_text_field( get_post_meta( $post->ID, '_ah_status', true ) ); $priority = sanitize_text_field( get_post_meta( $post->ID, '_ah_priority', true ) ); $raw_due = get_post_meta( $post->ID, '_ah_due_date', true ); $due_iso = $raw_due ? ( $ts = strtotime( $raw_due ) ) ? date( 'Y-m-d', $ts ) : '' : ''; $response[] = [ 'id' => $post->ID, 'title' => $post->post_title, 'assigned' => $assigned_id, 'assignedName' => esc_html( $assigned_name ), 'assignedById' => $assigned_by_id, 'assignedByName' => esc_html( $assigned_by_name ), 'assignedDate' => $assigned_date_iso, 'createdById' => $created_by_id, 'createdByName' => esc_html( $created_by_name ), 'createdDate' => $raw_created_date, 'status' => $status, 'priority' => $priority, 'dueDate' => $due_iso, 'notes' => esc_textarea( $notes ), ]; } wp_send_json_success( $response ); }); /** * 3) AJAX handler: insert OR update a task. */ add_action( 'wp_ajax_admin_hero_save_task', function() { check_ajax_referer( 'admin_hero_task_action', 'nonce' ); $task_id = isset( $_POST['id'] ) ? intval( $_POST['id'] ) : 0; $title = isset( $_POST['title'] ) ? sanitize_text_field( $_POST['title'] ) : ''; $assigned_to = isset( $_POST['assigned_to'] ) ? intval( $_POST['assigned_to'] ) : 0; $assigned_by = isset( $_POST['assigned_by'] ) ? intval( $_POST['assigned_by'] ) : get_current_user_id(); $created_by = isset( $_POST['created_by'] ) ? intval( $_POST['created_by'] ) : get_current_user_id(); $status = isset( $_POST['status'] ) ? sanitize_text_field( $_POST['status'] ) : ''; $due_date = isset( $_POST['due_date'] ) ? sanitize_text_field( $_POST['due_date'] ): ''; $priority = isset( $_POST['priority'] ) ? sanitize_text_field( $_POST['priority'] ): ''; $notes = isset( $_POST['notes'] ) ? sanitize_textarea_field( $_POST['notes']): ''; if ( empty( $title ) || ! $assigned_to || empty( $status ) || empty( $priority ) ) { wp_send_json_error( 'All fields except Due Date are required.' ); } // insert or update if ( $task_id ) { wp_update_post( [ 'ID' => $task_id, 'post_title' => $title, ] ); // update metas update_post_meta( $task_id, '_ah_assigned_to', $assigned_to ); update_post_meta( $task_id, '_ah_assigned_by', $assigned_by ); update_post_meta( $task_id, '_ah_assigned_date', current_time( 'Y-m-d' ) ); update_post_meta( $task_id, '_ah_created_by', $created_by ); update_post_meta( $task_id, '_ah_status', $status ); if ( $due_date ) { update_post_meta( $task_id, '_ah_due_date', $due_date ); } else { delete_post_meta( $task_id, '_ah_due_date' ); } update_post_meta( $task_id, '_ah_priority', $priority ); update_post_meta( $task_id, '_ah_notes', $notes ); wp_send_json_success( [ 'message' => 'Task updated' ] ); } // new task $new_id = wp_insert_post( [ 'post_type' => 'admin_hero_task', 'post_title' => $title, 'post_status' => 'publish', ] ); update_post_meta( $new_id, '_ah_assigned_to', $assigned_to ); update_post_meta( $new_id, '_ah_assigned_by', $assigned_by ); update_post_meta( $new_id, '_ah_assigned_date', current_time( 'Y-m-d' ) ); update_post_meta( $new_id, '_ah_created_by', $created_by ); if ( $due_date ) { update_post_meta( $new_id, '_ah_due_date', $due_date ); } update_post_meta( $new_id, '_ah_status', $status ); update_post_meta( $new_id, '_ah_priority', $priority ); update_post_meta( $new_id, '_ah_notes', $notes ); wp_send_json_success( [ 'message' => 'Task saved' ] ); } ); /** * 4) Enqueue Tasks JS + CSS. */ add_action( 'admin_enqueue_scripts', function() { $assets_dir = ADMIN_HERO_DIR . 'panels/tasks/assets/'; $assets_url = ADMIN_HERO_URL . 'panels/tasks/assets/'; // JS + localized data $js_files = glob( $assets_dir . 'tasks*.js' ); $js_file = ! empty( $js_files ) ? basename( $js_files[0] ) : 'tasks.js'; wp_enqueue_script( 'admin-hero-tasks-js', $assets_url . $js_file, [ 'admin-hero-js', 'jquery' ], ADMIN_HERO_VERSION, true ); wp_localize_script( 'admin-hero-tasks-js', 'AH_TASKS', [ 'ajax_url' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'admin_hero_task_action' ), 'current_user_id' => get_current_user_id(), 'current_user_name' => wp_get_current_user()->display_name, 'today_date' => date( 'Y-m-d' ), ] ); // CSS $css_files = glob( $assets_dir . 'tasks*.css' ); $css_file = ! empty( $css_files ) ? basename( $css_files[0] ) : 'tasks.css'; wp_enqueue_style( 'admin-hero-tasks-css', $assets_url . $css_file, [ 'admin-hero-css' ], ADMIN_HERO_VERSION ); }); // 5) Dashboard widget: always register (free & pro). add_action( 'wp_dashboard_setup', 'admin_hero_register_dashboard_widget' ); function admin_hero_register_dashboard_widget() { if ( ! current_user_can( 'edit_posts' ) ) { return; } wp_add_dashboard_widget( 'admin_hero_my_tasks_widget', __( 'My Tasks', 'admin-hero' ), 'admin_hero_my_tasks_widget_display' ); } function admin_hero_my_tasks_widget_display() { $user_id = get_current_user_id(); // fetch all non-completed tasks created by this user, ordered by due date $tasks = get_posts( [ 'post_type' => 'admin_hero_task', 'post_status' => 'publish', 'posts_per_page' => -1, 'meta_query' => [ [ 'key' => '_ah_created_by', 'value' => $user_id, 'compare' => '=' ], [ 'key' => '_ah_status', 'value' => 'Completed', 'compare' => '!=' ], ], 'orderby' => 'meta_value', 'meta_key' => '_ah_due_date', 'order' => 'ASC', ] ); if ( empty( $tasks ) ) { echo '
' . esc_html__( 'You have no pending tasks.', 'admin-hero' ) . '
'; return; } echo '