Wordpress插件3

過濾器 Filters

  • 過濾器鉤子和動作鉤子有很大的區別。它讓你可以控制代碼的輸出。
apply_filters() 函數
<?php
 
apply_filters( $tag, $value );
 
?>
  • $tag – 過濾器鉤子的名字。
  • $value – 傳遞給任何添加到這個鉤子的過濾器的參數。這個函數可以添加任意個額外的 $value 參數傳遞給過濾器。
  • 注意:在寫一個過濾器的時候 $value 必須返回給 WordPress。

過濾器鉤子的例子:

<?php
 
apply_filters( 'template_include', $template );
 
?>

template_include 是一個過濾器鉤子的名字,
$template 是一個可以通過注冊到這個過濾器鉤子的過濾器改變的文件名。

什么是過濾器?

一個過濾器是一個注冊到過濾器鉤子的函數。這個函數最少接受一個參數并在執行完代碼后返回那個參數。沒有過濾器的過濾器鉤子沒有任何作用。插件開發者可以通過過濾器鉤子改變不同的變量 – 從字符串到多位數組。

當一個過濾器鉤子被 apply_filters() 函數調用時,所有注冊到這個鉤子的過濾器都會被執行。要添加一個過濾器,使用

add_filter() 函數。

下面看看 wp_title 過濾器鉤子,它是負責頁面的 <title> 元素的過濾器鉤子。

<?php
 
apply_filters( 'wp_title', $title, $sep, $seplocation );
 
?>

wp_title – 鉤子名。
$title – 一個字符串,要過濾并返回給 WordPress 的值。
$sep – 說明 <title> 元素之間的分隔符是什么。
$seplocation – 分隔符的位置。下一個例子中要用到。
現在寫一個函數來過濾 $title 的輸出 – 在頁面的 title 后面附加站點的名字:

<?php
 
add_filter( 'wp_title', 'boj_add_site_name_to_title', 10, 2 );
 
function boj_add_site_name_to_title( $title, $seq ) {
 
/* 得到網站名稱 */
 
$name = get_bloginfo( 'name' );
 
/* 附加到 $title 變量。 */
 
$title .= $sqp.' '.$name;
 
/* 返回 $title */
 
return $title;
 
}
 
?>

boj_add_site_name_to_title() 函數修改 $title 參數并返回給 WordPress。$sep 參數在函數中使用,但沒有返回。

過濾器鉤子函數

apply_filters_ref_array

類似于動作鉤子里面的do_action_ref_array) 函數。

<?php
 
apply_filters_ref_array( $tag, $args );
 
?>

假設你要執行一個一般的 WordPress 沒有的復雜的數據庫查詢來加載首頁的 posts。WordPress 提供了一個叫做 posts_results 的過濾器鉤子使得你可以改變它。下面是 WordPress 核心中的代碼:

<?php
 
$this -> posts = apply_filters_ref_array(
 
'posts_results', array( $this -> posts, & $this )
 
);
 
?>

這個過濾器鉤子向所有注冊到它的過濾器傳遞一個 post 對象的數組。下面的例子,你完全重寫這個 post 對象的數組并用自定義的內容代替。默認情況下,WordPress 查詢 post 類型的 posts。下面改成查詢 page 類型的 psots 并顯示在首頁。

這段代碼使用了 wpdb 類,在 part-6 “插件安全” 中將詳細介紹。

<?php
add_filter( 'posts_result', 'boj_custom_home_page_posts');
 
function boj_cumstom_home_page_posts( $result ) {
    global $wpdb,$wp_query;
    /* 檢查是否在首頁 */
    if( is_home() ) {
        /* 每頁的 post 個數 */
        $per_page= get_option('posts_per_page');
        /* 得到當前頁 */
        $paged= get_query_var('paged');
        /* 設置 $page 變量 */
        $page= ( ( 0 ==$paged|| 1 ==$paged ) ? 1 : absint($paged ) );
        /* 設置偏移的 posts 的個數 */
        $offset= ($page- 1 ) * $per_page.',';
        /* 通過 $offset 和 要顯示的 posts 數量來設置 limit */
        $limits='LIMIT'.$offset.$per_page;
        /* 從數據庫查詢結果 */
        $result=$wpdb-> get_results("
                            SELECT SQL_CALC_FOUND_ROWS$wpdb-> posts. *
                            FROM $wpdb-> posts
                            WHERE 1 = 1
                            AND post_type ='page'
                            AND post_status ='publish'
                            ORDER BY post_title ASC$limits"
                        );
    }
    return $result;
}
?>

remove_filter

<?php
remove_filter( $tag, $function_to_remove,$priority,$accepted_args);
?>

這和前面的 remove_action 類似。

下面看看 WordPress 定義在 wp-includes/default-filters.php 頁面中的默認的過濾器。其中一個有意思的過濾器叫做 wpautop(),它將雙換行轉換成 HTML 的 <p> &lt/p>。這也就是我們在 HTML 發布內容時,直接回車便可在最終前端顯示的時候換行的原因。它在核心代碼中的幾個鉤子中都執行。下面是其中一個實例:

<?php
add_filter( 'the_content', 'wpautop');
?>

這將 wpautop() 過濾器應用到 post 的內容中,把每個換行都轉換成段落( <p> )。但是也許有的客戶不希望他的內容自動變成段落。那么你就可以使用 remove_filter() 函數從 the_content 鉤子中刪除這個過濾器。

<?php
remove_filter( 'the_content', 'wpautop');
?>

因為在 add_filter 的時候沒有定義優先級,所以這里也不需要。

remove_all_filters

和前面的remove_all_actions類似。

<?php
remove_all_filters($tag,$priority);
?>

has_filter

和前面的 has_action 類似。

current_filter

同樣類似于 did_action。不過它不僅僅對過濾器鉤子有效,同樣對動作鉤子也有效,所以它返回的是當前的 action 或者 filter 鉤子。這個函數在你對多個鉤子使用單個函數,但是需要依賴不同的鉤子執行不同的內容的時候非常的有用。例如,客戶希望在 post 標題 和內容中限制一些內容,但是這兩個限制的minganci的集合是不同的。使用 current_filter() 函數來根據鉤子設置不同的minganci表就可以實現用一個函數同時過濾 the_content 和 the_title。使用下面的代碼,你可以把minganci替換成**。

<?php
add_filter( 'the_content', 'boj_replace_unwanted_words');
add_filter( 'the_title', 'boj_replace_unwanted_words');
 
function boj_replace_unwanted_words( $text ) {
    /* 如果過濾器鉤子是 the_content */
    if('the_content'== current_filter() )
        $words=array('min','gan','ci');
    /* 如果鉤子是 the_title */
    elseif('the_title'== current_filter() )
        $words=array('zhen','de','hen','min','gan');
    /* 替換minganci */
    $text=str_replace($words,'**',$text);
    return$text;
}
?>

快速返回函數

你經常需要寫一個函數返回一個常用的值給一個過濾器鉤子,例如 true,false,或者一個空數組。你甚至嘗試使用 PHP 的 create_function() 函數來快速返回一個值。

WordPress 提供幾個函數處理這種情況。

下面是例子禁用了 user contact 方法 – 在 WordPress 的個人用戶管理頁面中的一系列 &ltinput>。要禁用這些表單項,你需要返回一個空數組。通常,你必須添加過濾器鉤子調用和函數。

<?php
add_filter( 'user_contactmethods', 'boj_return_empty_array' );
function boj_return_empty_array() {
    returnarray();
}
?>

寫這樣的代碼一兩次并沒什么。但是寫一個返回空數組的函數太傻了。WordPress 使之簡單化了。因為要禁用這些表單項,你只需要使用 WordPress 的 __return_empty_array() 函數作為過濾器來快速返回一個空數組。如下:

add_filter( 'user_contactmethods', '__return_empty_array' )

還有幾個類似的快速返回函數:

  • __return_false
  • __return_true
  • __return_zero
    如果上面的函數不符合你的要求,你還可以創建自己的快速返回函數。

常用的過濾器鉤子

WordPress 上百種過濾去鉤子提供給插件開發者。下面介紹一些常用的過濾器鉤子。

the_content

the_content 可以說是用的最多的過濾器鉤子了。沒有內容,一個網站一點用處也沒有。內容是一個網站上最重要的東子,插件使用這個鉤子為網站添加許多特色。

the_content 鉤子向所有注冊給它的過濾器傳遞一個 post 的內容。之后由過濾器來控制內容,通常添加一些格式化或者附加而外的一些信息。下面的例子根據 post 分類,當用戶閱讀一篇 post 時顯示一個附加的相關 post 列表到 the_content。

<?php
add_filter( 'the_content', 'boj_add_related_posts_to_content');
 
function boj_add_related_posts_to_content( $content) {
    /* 如果不是單篇文章,直接返回 content */
    if( !is_singular('post') )
        return$content;
    /* 得到當前 post 的分類 */
    $terms= get_the_terms( get_the_ID(),'category');
    /* 循環分類,并將它們的 ID 放到一個數組中 */
    $categories=array();
    foreach($termsas$term )
        $categories[] =$term-> term_id;
    /* 從數據庫查詢相同分類的 posts */
    $loop=newWP_Query(
       array(
            'cat__in'=>$categories,
            'posts_per_page'=> 5,
            'post__not_in'=>array( get_the_ID() ),
            'orderby'=>'rand'
        )
    );
 
    /* 是否有相關 posts 存在 */
    if($loop-> have_posts() ) {
        /* 開始 ul */
        $content.='<ul class="related-posts">';
        while($loop-> have_posts() {
            $loop-> the_post();
            /* 添加 post 標題 */
            $content.= the_title (
                '<li><a href="'.get_permalink().'">',
                '</a></li>',
                false
            );
        }
        /* 結束 ul */
        $content.='</ul>';
        /* 重置 query */
        wp_reset_query();
    }
    /* 返回 content */
    $return $content;
}
?>

the_title

文章的標題幾乎和內容一樣重要,所以 the_title 也是一個常用的過濾器鉤子。你可以使用這個鉤子添加信息,或者直接重寫。

應用給 the_title 鉤子的一個有用的過濾器就是去除標題中 HTML 標簽的過濾器函數。用戶有時會添加一些標簽到標題中,這可能會破壞正常的格式。使用下面的代碼,你可以過濾掉所有用戶可能添加到標簽。

<?php
add_filter( 'the_title', 'boj_strip_tags_from_titles');
 
function boj_strip_tags_from_title( $title ) {
    $title=strip_tags($title);
    $return $title;
}
?>

同樣 comment_text 也很常用。

下面的例子中,檢查一條評論是否是網站的注冊用戶發表的。如果是注冊用戶,你可以附加一段用戶信息的說明( 詳見:Part-8,”用戶” )

<?php
add_filter( 'comment_text', 'boj_add_role_to_comment_text');
 
function boj_add_role_to_comment_text( $text ) {
    global$comment;
    /* 檢查是否是注冊用戶 */
    if($comment-> user_id > 0 ) {
        /* 新建一個用戶對象 */
        $user=newWP_User( $comment-> user_id );
        /* 如果用戶有一個角色,添加到評論內容中 */
        if(is_array($user-> roles ) )
            $text.='<p>User Role: '.$user-> roles[0]. '</p>';
    }
    return$text;
}
?>

template_include

template_include 是其他一些更特殊的過濾器鉤子的一類”雜物包”( catchall )過濾器鉤子。

  • front_page_template
  • home_template
  • single_template
  • page_template
  • attachment_template
  • archive_template
  • category_template
  • tag_template
  • author_template
  • date_template
  • search_template
  • 404_template
  • index_template
    它用在 theme template 過濾器后面,當當前頁被選中后。WordPress 根據讀者當前瀏覽的頁面來選擇一個模板。你可以為每一個獨立的過濾器鉤子添加一個過濾器,也可以在最后使用 template_include 鉤子一起過濾他們。

比如你想按照你的插件的標準構造一個模板層級結構,而不是使用 WordPress 默認的模板層級。template_include 和上面列表中的鉤子可以滿足你。

下面的例子中,根據分類判斷一個 posts 的模板是否存在。默認情況下,WordPress 先檢查 single.php,如果不存在,再檢查 index.php文件。而你的函數查找一個叫做 single-category-$slug.php ( $slug 是分類的別名 )的文件。所以如果用戶有一個叫 art 的分類,同時一個模板的名字叫做 single-category-art.php,那么這個文件會被用來代替 single.php。

<?php
add_filter( 'single_template', 'boj_single_template' );
 
function boj_single_template( $template ) {
    global$wp_query;
    /* 檢查是否在瀏覽單個 post */
    if( is_singular('post') ) {
        /* 獲得 post ID */
        $post_id=$wp_query-> get_queried_object_id();
        /* 獲得 post 的分類 */
        $terms= get_the_terms($post_id,'category');
        /* 循環分類,添加別名作為文件名的一部分 */
        $template=array();
        foreach($termsas$term )
            $templates[] ="single-category-{$term->slug}.php";
        /* 檢查模板是否存在 */
        $locate= locate_template($templates);
        /* 如果找到,讓它成為新模板 */
        if( !empty($locate) )
            $template=$locate;
    }
    /* 換回模板文件名 */
    return$template;
}
?>

使用一個類中的鉤子

前面已經講了許多通過 PHP 函數來使用動作鉤子和過濾器鉤子的例子。在類中添加一個方法作為一個動作或者過濾器的時候,格式和 add_action() 和 add_filter() 略微有些不同。

一般來說,插件使用函數而不是類中的方法作為動作或者過濾器。但是,可能有些時候使用類更適合,所以你要知道如何類在類中將方法注冊到鉤子。

前面已經提到的注冊函數到一個動作鉤子的方法:

<?php
add_action( $tag, $function_to_add);
?>

當在類中將方法作為 $function_to_add 參數時,你必須把 $function_to_add 變成一個數組,其中 & $this 作為第一個參數,方法名作為第二個參數:

<?php
add_action( $tag, array( &$this,$method_to_add) );
?>

對于過濾器鉤子也是一樣。一般的將函數添加到一個過濾器鉤子類似于:

<?php
add_filter( $tag, $function_to_add);
?>

當使用類的方法的時候,要改成:

<?php
add_filter( $tag, array( &$this,$method_to_add) );
?>

下面的例子中,創建了一個類,包含一個構造函數,一個作為動作的方法,和一個作為過濾器的方法。add_filters() 方法檢查用戶是否在瀏覽單篇 post。如果是 content() 方法附加最后的修改時間到 post 的內容中

<?php
class BOJ_My_Plugin_Loader {
    /* 類的構造函數 */
    functionBOJ_My_Plugin_Loader() {
        /* 為 'template_redirect' 鉤子添加 'singular_check' 方法 */
        add_action('template_redirect',array( & $this,'singular_check') );
    }
 
    /* 作為動作的方法 */
    functionsingular_check() {
        /* 如果在看單個文章,過濾內容 */
        if( is_singular() )
            add_filter('the_content',array( & $this,'content') );
    }
 
    /* 作為過濾器的方法 */
    functioncontent($content) {
        /* 得到 post 的最后修改時間 */
        $date= get_the_modified_time( get_option('date_format') );
        /* 附加修改時間到 content */
        $content.='<p> 最后修改于:'.$date.'</p>';
        return$content;
    }
}
 
$boj_myplugin_loader=newBOJ_My_Plugin_Loader();
?>

創建自定義鉤子
插件不但可以使用內核的內置鉤子,他們也可以創建自定義的鉤子供其他插件和模板使用。

插件可以使用4個可用函數中的一個來創建自定義鉤子。

  • do_action()
  • do_action_ref_array()
  • apply_filters()
  • apply_filters_ref_array()
    前兩個創建自定義動作鉤子,后兩個創建自定義過濾器鉤子。
創建自定義鉤子的優點

自定義鉤子使得你的插件更靈活,使其可以被其他插件擴展,讓你可以鉤到你的整個插件自己的其他執行過程中。

使用自定義鉤子還可以防止用戶直接修改你的插件。這一點的重要性在于,當你更新你的插件時,用戶不會失去他們修改的內容。

自定義動作鉤子實例

在這個例子中,建立了一個插件安裝函數。這個函數定義了一個可以更換的常量。別的插件也可以在這個鉤子上執行任何代碼。因為你在那一點上提供了鉤子。

<?php
add_action( 'plugins_loaded', 'boj_myplugin_setup' );
 
function boj_myplugin_setup() {
    /* 允許動作最先觸發 */
    do_action('boj_myplugin_setup_pre');
    /* 檢查 root slug 是否定義 */
    if( !defined('BOJ_MYPLUGIN_ROOT_SLUG') )
        define('BOJ_MYPLUGIN_ROOT_SLUG','articles');
}
?>

其他插件或者模板可以鉤到 boj_myplugin_setup_pre 來執行任何函數。

比如你想把 BOJ_MYPLUGIN_ROOT_SLUG 常量從 ‘articles’ 改為 ‘papers’ ,你可以建立一個動作并添加到這個鉤子中:

<?php
add_action( 'boj_myplugin_setup_pre','boj_define_myplugin_constants');
function boj_define_myplugin_constants() {
    define('BOJ_MYPLUGIN_ROOT_SLUG','papers');
}
?>

自定義過濾器鉤子實例

假設有一個函數顯示一個具有一個特定闡述的文章列表。你也許希望其他人能夠過濾那個參數或者過濾最終結果。

下面的例子中,寫一個函數根據收到的評論條數列取了前10的文章。這個函數讓用戶可以在從數據庫獲取數據前過濾這個參數,并且可以過濾最終輸出的 HTML 列表

<?php
function boj_posts_by_comments() {
    /* 默認參數 */
    $args=array(
        'post_type'=>'post',
        'posts_per_page'=> 10,
        'order'=>'DESC',
        'oerderby'=>'comment_count'
    );
    /* 應用過濾器 */
    $args= apply_filters('boj_posts_by_comments_args',$args);
    /* 設置輸出變量 */
    $out='';
    /* 由給定的參數從數據庫查詢文章 */
    $loop = newWP_Query( $args );
    /* 檢查是否返回結果 */
    if($loop-> have_posts() ) {
        $out.='<ul class="posts-by-comments" >';
        while($loop-> have_posts() ) {
            $loop-> the_post();
            $out.= the_title('<li>','</li>', false );
        }
        $out.='</ul>';
    }
    $out= apply_filters('boj_posts_by_comments',$out);
    echo $out;
}
?>

要過濾參數,給 boj_posts_by_comments_args 添加一個過濾器。比如你希望把數量從默認的10變成15,添加下面的過濾器:

<?php
add_filter( 'boj_posts_by_comments_args','boj_change_posts_by_comments_args');
 
function boj_change_posts_by_comments_args( $args) {
    $args['posts_per_page'] = 15;
    return $args;
}
?>

要過濾最后的 HTML 輸出,添加一個過濾器到 boj_posts_by_comments。比如你想把 ul 改成 ol。

<?php
add_filter( 'boj_posts_by_comments', 'boj_change_posts_by_comments' );
 
function boj_change_posts_by_comments( $out ) {
    $out=str_replace('<ul','<ol',$out);
    $out=str_replace('</ul>','</ol>',$out);
    return$out;
}
?>

上哪找鉤子?
要給出 WordPress 中所有鉤子的列表幾乎是不可能的。前面我們討論了一些常用的動作和過濾器鉤子,這一節僅僅討論一小部分 WordPress 提供的鉤子。

WordPress 的新版本會加入新的鉤子。最終查看不同版本的內核可以讓你找到可以用在插件中的新鉤子。

在內核中搜索鉤子

作為一個插件開發這,你應該熟悉 WordPress 的內核。尋找鉤子能很好的幫助你熟悉 WordPress 內核是如何工作的。沒有更好的方法來搞明白 PHP 代碼在內核中是如何工作的了。

要尋找鉤子的一個簡單的方法是在編輯器中打開一個 WordPress 文件然后搜索下面的四個詞:

  • do_action
  • do_action_ref_array
  • apply_filters
  • apply_filters_ref_array
    這四個函數,每一個都創建一個鉤子。
變量鉤子

在 WordPress 的內核中找鉤子的時候,你會遇到變量鉤子。通常鉤子的名字是一個靜態的字符串。但是變量鉤子的名字跟著特定的變量而改變。

一個很好的例子就是 load-$pagenow 動作鉤子。變量 $pagenow 根據 WordPress 中當前瀏覽的 admin 頁面而改變。這個鉤子如下:

<?php
do_action( "load-$pagenow" );
?>

變量 $pagenow 會變成當前訪問頁面的名字。例如 new post 頁面的鉤子是 load-post-new.php,而編輯頁面的是 load-post.php。這就使得插件僅僅對特定的 admin 頁面執行代碼。WordPress 有幾個動作和過濾器鉤子的名稱里面是含有變量的。

通常,這些鉤子的名字變成給定的內容,使得插件開發者可以在特定的環境下執行代碼。

鉤子參考列表

雖然在核心里面搜索鉤子有助于你增長經驗,但是有時你需要一些網上的參考列表。

WordPress 在 Codex 中有官方的鉤子參考列表。

在 Part-18,開發人員工具箱,將介紹更多幫助插件開發者的工具。

總結

鉤子是創建 WordPress 插件的最重要的一環了。每次你開始創建一個插件,你都要把你的插件鉤到 WordPress 的動作鉤子和過濾器鉤子中。鉤子是插件開發中必不可少的工具。在了解了鉤子之后,就是時候開始創建插件了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,406評論 6 538
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,034評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,413評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,449評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,165評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,559評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,606評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,781評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,327評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,084評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,278評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,849評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,495評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,927評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,172評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,010評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,241評論 2 375

推薦閱讀更多精彩內容

  • 動作鉤子 ( actions ) 動作鉤子讓你可以在 WordPress 加載過程中或者當某個事件發生的特定時刻觸...
    StevenQin閱讀 498評論 0 0
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,807評論 18 139
  • 全文鏈接 第一章 創建一個blog應用第二章 使用高級特性來增強你的blog第三章 擴展你的blog應用第四章上 ...
    夜夜月閱讀 8,908評論 27 31
  • 醫護本是一體連,此消彼長為哪般? 鷸蚌相爭漁翁笑,唇亡焉能齒不寒。 仁心堪濟世,妙手能回春。 白衣且不易,相商共進...
    西樂樂閱讀 687評論 0 2
  • 每個人都有最鐘愛的食物,而我一生卻對豆腐情有獨鐘,那里飽含著我對故鄉的一份情。 我生在農村,長在山...
    念奴嬌88閱讀 190評論 8 14