TodoMVC with WordPress and intercooler.js 02

A first intercooler.js and WordPress interaction.

Todo post type

Aside for some code refactoring I’ve done little beside adding a first route and handler in the version of the theme current to this post.
As a first step, in the function/post-type.php file, I’m registering a new post type and relevant stati

<?php
add_action( 'init', function () {
    register_post_type( 'todo' );
    register_post_status( 'active' );
    register_post_status( 'completed' );
} );

Markup modifications

The second step is a small modification of the HTML to allow me to use intercooler.js and its attributes.
The relevant parts are those in the part of the index that’s in charge of rendering the todo list

<section class="todoapp">
<header class="header">
    <h1>todos</h1>
    <input class="new-todo" placeholder="What needs to be done?" autofocus="" ic-post-to="/tasks" name="task-title"
           ic-target="#todo-list">
</header>
<div id="todo-list">
    <?php todomvc_the_list() ?>
</div>
</section>

Since I will re-render the list when a new todo is added I’ve delegated the todomvc_the_list function the task to render the list initial state.
Defined in the functions/output.php file it’s just a rewriting of the static markup to allow for PHP-driven dynamics to kick in

function todomvc_the_list( $status = [ 'active', 'completed' ] ) {
    $todos = get_posts( [
        'post_type'   => 'task',
        'post_status' => $status,
        'nopaging'    => true
    ] );
    ?>
    <section class="main">
        <input class="toggle-all" type="checkbox">
        <label for="toggle-all">Mark all as complete</label>
        <ul class="todo-list">
            <?php foreach ( $todos as $todo ): ?>
                <?php $status = $todo->post_status == '' ? '' : 'class = "completed"'; ?>
                <li <?php echo $status ?>>
                    <div class="view">
                        <input class="toggle" type="checkbox">
                        <label><?php echo $todo->post_title ?></label>
                        <button class="destroy"></button>
                    </div>
                    <input class="edit" value="<?php echo $todo->post_title ?>">
                </li>
            <?php endforeach; ?>
        </ul>
    </section>
    <footer class="footer">
        <span class="todo-count"><strong>1</strong> item left</span>
        <ul class="filters">
            <li>
                <a class="selected" href="#/">All</a>
            </li>
            <li>
                <a href="#/active">Active</a>
            </li>
            <li>
                <a href="#/completed">Completed</a>
            </li>
        </ul>

        <button class="clear-completed">Clear completed</button>
    </footer>
    <?php
}

A first objective

From the code of the function above it’s clear I’m outputting fixed numbers and strings in a lot of places where dynamic values should show and any form of security is missing.
That’s intentional: I will add the required functions in small steps and will worry about one at a time.
The first step is being able to add todos to the list.

intercooler.js attributes

In the index.php file I’ve modified the input used to insert a new todo to this

        <input class="new-todo" 
        placeholder="What needs to be done?"
        autofocus="" 
        name="task-title"
        ic-post-to="/tasks" 
        ic-target="#todo-list">

Beside the usual attributes what’s relevant is:
1. I’ve added the name attribute: intercooler.js will not send along data if the input has no name
2. the ic-post-to attribute tells intercooler.js to make a POST request to the /tasks path when the user presses Enter
3. the ic-target attribute, a valid jQuery selector, tells intercooler.js to replace the HTML code of the list with the new returned content

A first route

Point 2 of the list above specifies a /tasks path as the destination of the POST request.
Since I’m using the wp-routes plugin to handle the routing I’ve defined that route in the functions/routes.php file

add_action( 'wp-routes/register_routes', function () {
    // Add a new todo
    respond( 'POST', '/tasks', function ( $request, $response ) {
        if ( empty( $_REQUEST['task-title'] ) ) {
            return;
        }
        $id = wp_insert_post( [
            'post_title'  => $_REQUEST['task-title'],
            'post_type'   => 'task',
            'post_status' => 'active'
        ] );

        if ( empty( $id ) ) {
            return;
        }
        $response->header( 'X-IC-Trigger', 'todomvc/new-task-added' );
        todomvc_the_list();
    } );
} );

In the function handling the route I’m inserting a new active todo in the database and re-rendering the list.
intercooler.js will use any output I return to replace the list or will do nothing if nothing echoes back.

Clean the input

After a todo insertion I will clean the input using an event handler specified in the assets/js/todomvc.js file

/*global jQuery:false */
jQuery( document ).ready( function ( $ ) {
    'use strict';

    $( 'body' ).on( 'todomvc/new-task-added', function () {
        $( 'input[name="task-title"]' ).val( '' );
    } );
} );

The event that’s triggering the input cleaning is the todomvc/new-task-added one.
Looking at the code above I’m triggering that event in the X-IC-Trigger header that I’m returning.
Caveat: intercooler.js seems to trigger the events specified in the X-IC-Trigger header on the body element of the document; that makes sense thinking about events triggered this way as global events but might not be the best course of action in more complicated applications.

Next

I will add the possibility to mark a todo as complete next.

3 thoughts on “TodoMVC with WordPress and intercooler.js 02

  1. Rather than cleaning the input with javascript, you might want to target the entire UI and rerender a blank input. If you set ic-transtion=”none” you won’t get an annoying fade effect.

    In the next version of intercooler transitions are done via CSS, giving you much finer control.

    Thanks for doing this!

    1. You are right regarding the input. I admit I’ve tried to use any feature I came across and saw that as a good point to use the headers.
      I took the “challenge” of porting the TodoMVC app over to intercooler.js and WordPress trying to modify the original markup as little as possible and that’s why I’ve not gone for efficiency.

      Again thanks for the comment and the library: I really appreciate it.

      1. No problem, intercooler is designed to be an open toolkit, rather than an opinionated framework. Trying to modify the original HTML as little as possible is a pragmatic and even noble goal in many cases!

        Thanks again for going through this exercise and putting it out there. 🙂

I appreciate your input