JavaScript >> Javascript 文檔 >  >> jQuery

由 WordPress 提供支持的待辦事項列表應用程序

WordPress 是建立博客的絕佳工具。憑藉其海量的插件和主題,再加上涵蓋系統各個角落的 API,您可以使用它構建幾乎任何類型的 Web 應用程序。這將其從一個內容管理系統推進到一個用於創建 Web 應用程序的成熟平台。

在本教程中,我們將製作一個與 API 掛鉤的 WordPress 插件。然後它將在 /todo 上顯示一個簡單的、AJAX 編輯的待辦事項列表應用程序 您的 WordPress 網站的 URL。最好的是,這是一個插件而不是主題,這意味著您可以在任何 WordPress 網站上使用它,而不管主題如何。讓我們開始吧!

您的第一個 WordPress 插件

如果你之前沒有寫過 WordPress 插件,這裡是你需要知道的:

  • 插件是位於 /wp-content/plugins 文件夾中的 PHP 文件;
  • 插件可以是具有唯一名稱的單個 PHP 文件,也可以是包含該文件的文件夾,以及其他包含和資源(閱讀入門指南);
  • 插件由 PHP 主文件中的註釋頭描述。你需要這個才能讓你的插件被識別;
  • 插件通過與 WordPress 執行中的特定事件掛鉤來開展業務。有一個包含所有可用過濾器和操作的參考;
  • 文檔是你的朋友。

要開發插件,請安裝 WordPress 的本地副本並在 /wp-content/plugins 文件夾中創建一個新的 PHP 文件。在此之後放置您在下面看到的標題註釋,然後從管理面板激活您的插件。

如果您只想測試我們今天編寫的 Todo 應用程序,您可以簡單地獲取下載 zip,然後從 WordPress 的管理面板安裝它(選擇 Plugins->Upload )。

這是我們應用程序的主要插件文件:

tz-todoapp.php

/*
Plugin Name: Todo App
Plugin URI: https://tutorialzine.com
Description: This is a demo plugin for a Tutorialzine tutorial
Version: 1.0
Author: Martin Angelov
Author URI: https://tutorialzine.com
License: GPL2
*/

define('TZ_TODO_FILE', __FILE__);
define('TZ_TODO_PATH', plugin_dir_path(__FILE__));

require TZ_TODO_PATH.'includes/tzTodo.php';

new tzTodo();

您可以在頂部看到標題註釋。這是系統用於在插件激活頁面上呈現的描述。在此之後,我們為插件文件(在某些函數調用中用作標識符)和文件夾路徑定義了兩個常量。在此之後,我們將包含 tzTodo 類並創建一個新對象。

tzTodo 類

此類包含插件的所有功能。在它的構造函數中,我們連接了許多動作:用於初始化、ajax 和我們將定義的自定義帖子類型的佈局。在類的主體中,我們有一些方法可以在這些操作被觸發時執行有用的功能,並且還定義了一個自定義帖子類型'tz_todo '。

包括/tzTodo.php

class tzTodo {

    public function __construct(){

        add_action( 'init', array($this,'init'));

        // These hooks will handle AJAX interactions. We need to handle
        // ajax requests from both logged in users and anonymous ones:

        add_action('wp_ajax_nopriv_tz_ajax', array($this,'ajax'));
        add_action('wp_ajax_tz_ajax', array($this,'ajax'));

        // Functions for presenting custom columns on
        // the custom post view for the todo items

        add_filter( "manage_tz_todo_posts_columns", array($this, 'change_columns'));

        // The two last optional arguments to this function are the
        // priority (10) and number of arguments that the function expects (2):

        add_action( "manage_posts_custom_column", array($this, "custom_columns") , 10, 2 );
    }

    public function init(){

        // When a URL like /todo is requested from the,
        // blog we will directly include the index.php
        // file of the application and exit 

        if( preg_match('/\/todo\/?$/',$_SERVER['REQUEST_URI'])){
            $base_url = plugins_url( 'app/' , TZ_TODO_FILE);
            require TZ_TODO_PATH.'/app/index.php';
            exit;
        }

        $this->add_post_type();
    }

    // This method is called when an
    // AJAX request is made to the plugin

    public function ajax(){
        $id = -1;
        $data = '';
        $verb = '';

        $response = array();

        if(isset($_POST['verb'])){
            $verb = $_POST['verb'];
        }

        if(isset($_POST['id'])){
            $id = (int)$_POST['id'];
        }

        if(isset($_POST['data'])){
            $data = wp_strip_all_tags($_POST['data']);
        }

        $post = null;

        if($id != -1){
            $post = get_post($id);

            // Make sure that the passed id actually
            // belongs to a post of the tz_todo type

            if($post && $post->post_type != 'tz_todo'){
                exit;
            }
        }

        switch($verb){
            case 'save':

                $todo_item = array(
                    'post_title' => $data,
                    'post_content' => '',
                    'post_status' => 'publish',
                    'post_type' => 'tz_todo',
                );

                if($post){

                    // Adding an id to the array will cause
                    // the post with that id to be edited
                    // instead of a new entry to be created.

                    $todo_item['ID'] = $post->ID;
                }

                $response['id'] = wp_insert_post($todo_item);
            break;

            case 'check':

                if($post){
                    update_post_meta($post->ID, 'status', 'Completed');
                }

            break;

            case 'uncheck':

                if($post){
                    delete_post_meta($post->ID, 'status');
                }

            break;

            case 'delete':
                if($post){
                    wp_delete_post($post->ID);
                }
            break;
        }

        // Print the response as json and exit

        header("Content-type: application/json");

        die(json_encode($response));

    }

    private function add_post_type(){

        // The register_post_type function
        // will make a new Todo item entry
        // in the wordpress admin menu

        register_post_type( 'tz_todo',
            array(
                'labels' => array(
                    'name' => __( 'Todo items' ),
                    'singular_name' => __( 'Todo item' )
                ),
                'public' => true,
                'supports' => array('title') // Only a title is allowed for this type
            )
        );
    }

    public function change_columns($cols){

        // We need to customize the columns
        // shown when viewing the Todo items
        // post type to include a status field

        $cols = array(
            'cb'       => '<input type="checkbox" />',
            'title'      => __( 'Task' ),
            'status' => __( 'Status' ),
            'date'     => __( 'Date' ),
        );

        return $cols;
    }

    public function custom_columns( $column, $post_id ) {

        // Add content to the status column

        switch ( $column ) {

            case "status":
                // We are requesting the status meta item

                $status = get_post_meta( $post_id, 'status', true);

                if($status != 'Completed'){
                    $status = 'Not completed';
                }

                echo $status;

                break;
        }
    }

}

最有趣的方法可能是 AJAX 方法。在這裡,我們接收從 jQuery 前端發送的 AJAX 請求。根據需要執行的操作,我們創建或刪除 tz_todo 的項目 自定義帖子類型並附加或刪除元數據以將任務標記為已完成。歸功於 Joost de Valk 的有用片段。

在 init() 方法中,當請求 /todo URL 時,您可以看到我用來從插件的 app 文件夾中提供 index.php 文件的技巧。我正在匹配 $_SERVER['REQUEST_URI'] 帶有圖案的條目。如果請求的 URL 是我們感興趣的 URL,則包含 index.php 文件並停止 WordPress 執行。現在當有人訪問 http://example.com/todo WordPress 驅動的網站,他們將看到該應用程序。

待辦事項列表應用程序

正如你在上面看到的,在訪問 /todo URL,我們的插件包括 /app/index.php .這是呈現您在演示中看到的界面的文件。如下圖所示。

/app/index.php

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Todo App Powered By WordPress | Tutorialzine Demo</title>

        <!-- This is important! It fixes the paths of the css and js files -->
        <base href="<?php echo $base_url ?>"></base>

        <!-- The stylesheets -->
        <link rel="stylesheet" href="assets/css/styles.css" />

        <script>

            // This is the URL where we need to make our AJAX calls.
            // We are making it available to JavaScript as a global variable.

            var ajaxurl = '<?php echo admin_url('admin-ajax.php')?>';
        </script>
    </head>

    <body>

        <div id="todo">
            <h2>Todo List <a href="#" class="add"
                title="Add new todo item!">✚</a></h2>
            <ul>
                <?php

                    $query = new WP_Query(
                        array( 'post_type'=>'tz_todo', 'order'=>'ASC')
                    );

                    // The Loop
                    while ( $query->have_posts() ) :
                        $query->the_post();
                        $done = get_post_meta(get_the_id(), 'status', true) ==
                            'Completed';
                    ?>

                        <li data-id="<?php the_id()?>"
                            class="<?php echo ($done ? 'done' : '')?>">
                            <input type="checkbox"
                                <?php echo ($done ? 'checked="true"' : '')?> />
                            <input type="text"
                                value="<?php htmlspecialchars(the_title())?>"
                                placeholder="Write your todo here" />
                            <a href="#" class="delete" title="Delete">✖</a>
                        </li>

                    <?php endwhile; ?>
            </ul>
        </div>

        <!-- JavaScript includes.  -->
        <script src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
        <script src="assets/js/script.js"></script>

    </body>
</html>

這裡我們使用 WP_Query 類來請求 tz_todo 的所有帖子 從最舊的開始按升序輸入。如果您創建了 WordPress 主題,您可能會識別出一個普通的 while 循環。

在底部,我們有撰寫本文時最新版本的 jQuery 庫,以及驅動應用程序前端的 script.js 文件。

jQuery 代碼

我們的 Todo 應用程序即將完成!我們所要做的就是編寫驅動界面的jQuery代碼:

/app/assets/js/script.js

$(function(){

    var saveTimer;
    var todoHolder = $('#todo');

    // Listen for the input event in the text fields:
    todoHolder.on('input','li input[type=text]', function(e){

        // This callback is run on every key press

        var todo = $(this),
            li = todo.closest('li');

        // We are clearing the save timer, so that
        // sending the AJAX request will only
        // happen once the user has stopped typing

        clearTimeout(saveTimer);

        saveTimer = setTimeout(function(){

            ajaxAction('save', li.data('id'), todo.val()).done(function(r){
                if(r.id != li.data('id')){
                    // The item has been written to the database
                    // for the first time. Update its id.
                    li.data('id', r.id);
                }
            });

        }, 1000);

    });

    // Listen for change events on the checkboxes
    todoHolder.on('change', 'li input[type=checkbox]',function(e){

        var checkbox = $(this),
            li = checkbox.closest('li');

        li.toggleClass('done',checkbox.is(':checked'));

        if(checkbox.is(':checked')){
            ajaxAction('check', li.data('id'));
        }
        else{
            ajaxAction('uncheck', li.data('id'));
        }

    });

    // Listen for clicks on the delete link
    todoHolder.on('click', 'li .delete',function(e){

        e.preventDefault();

        var li = $(this).closest('li');

        li.fadeOut(function(){
            li.remove();
        });

        if(li.data('id') != 0){

            // No need to delete items if they are missing an id.
            // This would mean that the item we are deleting
            // does not exist in the database, so the AJAX
            // request is unnecessary.
            ajaxAction('delete', li.data('id'));
        }

    });

    // Clicks on the add new item button)
    todoHolder.on('click','a.add', function(e){
        e.preventDefault();

        var item = $('<li data-id="0">'+
            '<input type="checkbox" /> <input type="text" val="" placeholder="Write your todo here" />'+
            '<a href="#" class="delete">✖</a>'+
            '</li>');

        todoHolder.find('ul').append(item);

        // We are not running an AJAX request when creating elements.
        // We are only writing them to the database when text is entered.
    });

    // A help function for running AJAX requests
    function ajaxAction(verb, id, data){

        // Notice that we are returning a deferred

        return $.post(ajaxurl, {
            'action': 'tz_ajax',
            'verb':verb,
            'id': id,
            'data': data
        }, 'json');

    }
});

該代碼有大量註釋,因此應該不難掌握。我正在使用一些較新的 jQuery 功能,例如 deferreds 和 on() 語法來註冊事件。

完成!

此應用程序將使您對開發 WordPress 插件的情況有一個很好的了解。正如我一開始所說,WP 正在變成一個開發 Web 應用程序的平台。畢竟它很容易設置,有一個很棒的管理區域,裡面有用戶角色,還有大量高質量的插件和主題。


Tutorial JavaScript 教程
  1. 我用 Next.js 製作了一個 kickass 自動化投資組合網站。這裡是如何。

  2. 個人博客免費

  3. 返回一個沒有刪除元素的數組?使用 splice() 而不更改數組?

  4. React vs Angular:2020 年你應該使用哪一個

  5. typescript + redux:在父組件中排除 redux props

  6. 二分搜索簡介

  7. 如何使用 Nx 輕鬆創建與 ES/AMD/UMD/CJS 模塊系統兼容的 JS 庫

  1. 如果 LI 標籤有一個 active 類,它將轉到最後一個位置

  2. 將 Mastodon 的安全性提升到一個新的水平 - 第 1 部分:加密你的嘟嘟聲

  3. JQuery 不能使用多個元素的同名

  4. 將環境變量與 Powershell 命令一起傳遞

  5. 一次動態加載一個Javascript文件

  6. 事件循環和大圖 — NodeJS 事件循環第 1 部分

  7. Javascript 中的匿名和箭頭函數

  1. 如何在不使用 create-react-app 的情況下設置 React 項目

  2. Javascript的設計模式——建造者模式

  3. 跨平台 Web Speech API(語音合成)按鈕

  4. 使用 peasy-js 編寫可重用的 JavaScript 業務邏輯