0

I have a plugin with two custom post types - Projects and Tasks. In the plugin, you can assign tasks to projects. So, for example you might have a "Website Design" project with Tasks "Purchase Domain Name", "Customize Theme", "Add Content", etc.

What I'm trying to do is create a list of projects, and create a nested list of tasks below each project like this.

  • Project 1
    • Task 1
    • Task 2
  • Project 2
    • Task 3
    • Task 4

In HTML, I know that this works:

<ul>
    <li>Project 1
        <ul>
            <li>Task 1</li>
            <li>Task 2</li>
        </ul>
    </li>
    <li>Project 2
        <ul>
            <li>Task 3</li>
            <li>Task 4</li>
        </ul>
    </li>
</ul>

My plugin generates the list for Projects and Tasks in two separate functions. I include the tasks in the Project list by using do_action( 'my-task-action', $project_id )

Display projects

$project_option .= '<ul class="project-list">';
    foreach( $projects as $project ) {
    $project_id = $project->ID;
    $project_option .= '
        <li class="project" id="project-' . $project_id . '">
            <span class="project-title">' . get_the_title( $project_id ) . ' </span>
            <span class="project-status-title">' . __( 'Project Status: ', 'client-area' ) . '</span>
            <span class="project-status">' .  get_post_meta( $project_id, 'project-status', true ) . '</span>' .
            do_action( 'my-task-action', $project_id ) . '
        </li>';
    }
$project_option .= '</ul>';
echo $project_option;

Display Tasks

The function to display the tasks gets the project ID passed to it through do_action( 'my-task-action', $project_id ), and can display each task assigned to each project.

$task_option .= '<ul class="task-list">';
    foreach( $tasks as $task ) {
        $task_id = $task->ID;
        $task_option .= '
        <li class="task project-' . $project_id . '" id="task-' . $task_id . '">
            <span class="task-title">' . get_the_title( $task_id ) . ' </span>
            <span class="task-status-title">' . __( 'Task Status: ', 'client-area' ) . '</span>
            <span class="task-status">' .  get_post_meta( $task_id, 'task-status', true ) . '</span>
        </li>';
    }
    $task_option .= '</ul>';
}
echo $task_option;

The Problem

Instead of a nested list like I displayed above, I get the Tasks in one list and Projects in a separate list.

  • Task 1
  • Task 2
  • Task 3
  • Task 4

  • Project 1

  • Project 2

Or...

<ul class="task-list">
    <li class="task project-1023" id="task-929">
        <span class="task-title">Task 1 </span>
        <span class="task-status-title">Task Status: </span>
        <span class="task-status">on-hold</span>
    </li>
    <li class="task project-1023" id="task-927">
        <span class="task-title">Task 2 </span>
        <span class="task-status-title">Task Status: </span>
        <span class="task-status">not-started</span>
    </li>
    <li class="task project-930" id="task-931">
        <span class="task-title">Task 3 </span>
        <span class="task-status-title">Task Status: </span>
        <span class="task-status">on-hold</span>
    </li>
    <li class="task project-930" id="task-932">
        <span class="task-title">Task 4 </span>
        <span class="task-status-title">Task Status: </span>
        <span class="task-status">not-started</span>
    </li>
</ul>
<ul class="project-list">
    <li class="project" id="project-1023">
        <span class="project-title">Project 1 </span>
        <span class="project-status-title">Project Status: </span>
        <span class="project-status">in-progress</span>
    </li>
    <li class="project" id="project-930">
        <span class="project-title">Project 2 </span>
        <span class="project-status-title">Project Status: </span>
        <span class="project-status">complete</span>
    </li>
</ul>

Based on where the do_action is in the list, I would think that the task list would simply be output inside the project's <li></li>, and cause a nested list to be used.

Any idea why this isn't working the way I'm expecting it to?

  • 1
    It is because your do_action echo's the output. Instead of using do_action, you should create a function like get_tasks_for_project($project_id) and this function should return a string, like return $task_option – czerspalace Sep 29 '16 at 21:17
  • Yes, if I do it that way, it works correctly. However I'd like to keep the do_action so users can hook into that area if they want to modify the output of tasks. – ScottD Sep 29 '16 at 21:21
  • 2
    Then you should use apply_filters('my-task-action', $project_id ) and then use add_filter('my-task-action', 'my_callback') with function my_callback($value){ return $value; } – czerspalace Sep 29 '16 at 21:48
  • That's what I was missing...I think just a case of staring at it too long. Thanks for your help! – ScottD Sep 29 '16 at 22:12
  • If that worked for you then please write it up as an answer to keep the site format useful for others. After 2 days you can mark your own answer as accepted too. – Andy Macaulay-Brook Sep 30 '16 at 7:30
2

If you want to return a value in your hook, use apply_filters instead of do_action, like:

$project_option .= '<ul class="project-list">';
    foreach( $projects as $project ) {
    $project_id = $project->ID;
    $project_option .= '
        <li class="project" id="project-' . $project_id . '">
            <span class="project-title">' . get_the_title( $project_id ) . ' </span>
            <span class="project-status-title">' . __( 'Project Status: ', 'client-area' ) . '</span>
            <span class="project-status">' .  get_post_meta( $project_id, 'project-status', true ) . '</span>' .
            apply_filters( 'my-task-action', $project_id ) . '
        </li>';
    }
$project_option .= '</ul>';
echo $project_option;

and then have an add_filter like

add_filter('my-task-action', 'wpse241018_getTaskActions');

function wpse241018_getTaskActions($project_id){ 
    $task_option .= '<ul class="task-list">';
    foreach( $tasks as $task ) {
        $task_id = $task->ID;
        $task_option .= '
        <li class="task project-' . $project_id . '" id="task-' . $task_id . '">
            <span class="task-title">' . get_the_title( $task_id ) . ' </span>
            <span class="task-status-title">' . __( 'Task Status: ', 'client-area' ) . '</span>
            <span class="task-status">' .  get_post_meta( $task_id, 'task-status', true ) . '</span>
        </li>';
     }
    $task_option .= '</ul>';
    }
    return $task_option; 
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.