このサイトは、只今WEB業界で活躍中のデザイナー、プログラマーの方々の情報を集めたweb統合情報サイトです。

web帳

記事詳細

2017.03.26

Vue.js が予想以上に良かったので、既存WordPressに導入。Vue.js (vue-class-component) + TypeScript + WordPress で作る、記事読み込み component 「実装編」

こちらの続きとなります。

Vue.js が予想以上に良かったので、既存WordPressに導入。Vue.js (vue-class-component) + TypeScript + WordPress で作る、記事読み込み component 「環境構築編」

では、前回の続きから、

components/post-more-btn.html

<div class="moreBtnBox">
  <a @click="onClick">他の記事を読み込む</a>
</div>

componentsである、「post-more-btn.html」をクリックすると、その対となる 「post-more-btn.ts」の「PostMoreBtn」 のonClickが実行される流れでした。

components/post-more-btn.ts

import Vue = require('vue');
import Component from 'vue-class-component';
import PostMoreService from '../service/post-more.service';
import bus from '../bus'

@Component({
  props: ['nowPostNum'],
  template: require('./post-more-btn.html')
})
export class PostMoreBtn extends Vue {
  private nowPostNum: number;
  private postMoreService: PostMoreService = new PostMoreService();

  onClick (): void {
    this.postMoreService.fetchData(this.nowPostNum)
      .then((response: any) =>; {
        bus.$emit('update-post', response.data);

        this.nowPostNum += 10;
      }, (error: any) => {
        console.error(error);
      });
  }
}

onClick関数を見てみると、postMoreServicefetchDataを行っているのが確認できます。

そのpostMoreServiceを見てみると、このようになっています。

service/post-more.service.ts

const axios = require('axios'),
      wpAjaxUrl = window['wpAjaxUrl'];

export default class PostMoreService {
  private formData = new FormData();

  constructor() {
    this.formData.append('action', 'get_more_post');
  }

  public fetchData(nowPostNum: number): any {
    this.formData.append('now_post_num', nowPostNum);

    return axios({
      method: 'post',
      url: wpAjaxUrl,
      data: this.formData
    });
  }
}

formDataオブジェクトのインスタンスをprivateで保持しているのは、wordpressでAjax通信する(POSTでリクエストする)際、
RequestHeaderのcontent-typeが「application/x-www-form-urlencoded」である必要であるためです。

jQueryなどを使用していて、$.ajax()を用いてAjax通信する際は、jQuery側がよしなにやってくれているかもですが、今回は、特に、jQuery等も使わず「axios」を用いてAjax通信しているので、formDataオブジェクトのインスタンスを作っています。

PostMoreServiceのインスタンスが生成される際に実行されるconstructor関数に書かれている

this.formData.append('action', 'get_more_post');

は、formDataオブジェクトに action名である「get_more_post」をappendし、Ajax通信後のwordpress側の関数を実行するためのものです。

axiosはAjax通信後、Promiseが返却されますので、axios関数自体をreturnしております。

service/post-more.service.ts

return axios({
  method: 'post',
  url: wpAjaxUrl,
  data: this.formData
});

APIのエンドポイントである、「wpAjaxUrl」は、tml側でグローバル変数として受け取っている形となります。

これは、wordpressで用意されているAjaxの経路となります。

該当のファイル(エンドポイント)は、「wp-admin/admin-ajax.php」となり、そちらにリクエストを送る形となります。

この経路が一般的に、「wordpressでのAjax経路」として知られている形となります。

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

admin_url関数に「’admin-ajax.php‘」の引数を渡すことで、wordpressのAjaxのpathを取得することができます。

wordpress側

Ajax用のアクションフックに登録

function.php

add_action( 'wp_ajax_get_more_post', 'get_more_post' );
add_action( 'wp_ajax_nopriv_get_more_post', 'get_more_post' );

この関数をアクションフックに登録する必要があります。

アクションフック処理をするadd_actionメソッドが二つありますが、一つ目はログイン状態での登録で、二つ目は非ログイン状態での登録となります。

function.php

function get_more_post() {
  global $wpdb;

  $now_post_num = $_POST['now_post_num'];
  $get_post_num = 10;

  $sql = "SELECT 
            $wpdb->posts.ID,
            $wpdb->posts.post_title,
            $wpdb->posts.post_content
          FROM 
            $wpdb->posts 
          WHERE 
            $wpdb->posts.post_type = 'post' 
          AND 
            $wpdb->posts.post_status = 'publish' 
          ORDER BY
            $wpdb->posts.post_date 
          DESC 
            LIMIT $now_post_num, $get_post_num";

  echo create_post_json($wpdb->get_results($sql));

  die();
}

function create_post_json($posts) {
  $post_list = array();

  foreach($posts as $post) {
    $postId = $post->ID;

    $post_list[] = array(
      "title"        => $post->post_title,
      "date"         => get_the_date("Y年n月j日 l", $postId),
      "imageUrl"     => get_post_image_src($postId),
      "postUrl"      => get_permalink($postId),
      "postDetail"   => mb_substr(strip_tags($post->post_content), 0, 160).'…',
      "tagList"      => create_post_tag_list(get_the_tags($post->ID)),
      "categoryList" => create_post_category_list(get_the_category($postId))
    );
  }

  return json_encode($post_list);
}

 

get_more_post関数は、アクションフックと結びついており呼び出されます。

何件目から記事データを取得するかを、「now_post_num」をpostデータで受け取ります。

global変数である「$wpdb」を使用し、SQL文を発行します。

コードでreturnを使っていないのは、returnを使用するとレスポンスに0が返ってしまう為、die()で処理を終わらせています。

create_post_json関数は、フロント用にjsonデータとして加工する関数です。

これでVueJS側のリクエストである、「postMoreService」と、レスポンス側のwordpressのfunction.phpの準備が整いました。

最後は、レスポンスが返って来た後の、pub/subの役割を持つbusについてです。

親子間以外の通信を行う 「bus」

親子関係ではない2つのコンポーネントの通信を行う場合は、「bus」を利用します。

これは、空の Vue インスタンスを中心のイベントバスとして使用することができます。

公式ガイドページより

親子間以外の通信

bus.ts

var bus = new Vue();
// コンポーネント A のメソッドの中で
bus.$emit('id-selected', 1)
// コンポーネント B の created フックで
bus.$on('id-selected', function (id) {
  // ...
})

と、公式ガイドページとあまり説明もなく、実際にもあまり説明することもないのですが。。

とりあえず、ざっくり言うと、「EventEmitter的な振る舞いが、空の Vueインスタンスで実現できますよ」と、いった感じです。

ちょっと、前回の記事に振り返り、「Vue.js が予想以上に良かったので、既存WordPressに導入。Vue.js (vue-class-component) + TypeScript + WordPress で作る、記事読み込み component 「環境構築編」」で、作成した post-list.tsを見てみましょう。

components/post-list.ts

created() {
  bus.$on('update-post', this.onUpdatePost)
}
 
destroyed() {
  bus.$off('update-post', this.onUpdatePost)
}

post-list.tsで定義されている「created関数」は、component生成されたタイミングで実行され、destroyed関数はその逆で、componentsが破棄されたタイミングで実行されます。

なので、component生成されると同時に、「bus.$on」でupdate-postを購読登録し、this.onUpdatePostを実行するようにしております。

また、componentsが破棄されると同時に、「bus.$off」でupdate-postを購読解除を行っております。

なので、post-more.serviceでは、レスポンスが返ると、update-postがemitされ、components/post-list.ts
側のthis.onUpdatePost関数が呼び出され、記事リストである componentsの、「components/post-list.html」が更新される流れとなります。

service/post-more.service.ts

bus.$emit('update-post', response.data);

と、簡単ではありましたが、「wordpress」と「Vue Class component」を使った、「もっと記事を読み込む」の流れでした。

なんとなく、「Angular」に近い感じではありますが、「Angular」を使うとなると、ガッツリ「SPA」になってしまうので、今回の様な、ちょっとした機能には、手軽にすぐに実装できる「Vue Class component」が良い気がしました。

実は、「カテゴリ」とかに全く考慮していないので、工夫して作ってみると良いかもしれませんね。

それでは、またぁまたぁ。

公式ガイドページ

TypeScript のサポート

  • RSSを登録する

  • follow us in feedly

Graphical FrontEnd Engineer
- Daisuke Takayama

MAD CITY 北九州市で生まれ育つ。20代はバンド活動に明け暮れ、ふと「webデザイナーになりたい。」と思い、デジタルハリウッド福岡校入学。卒業後、数々の賞を受賞、web業界をざわつかせる。
現在、港区六本木で活動中。

WEBデザイナーの、WEBデザイナーによる、WEBデザイナーの為のサイト。「みんなで書こう!」と仲間を募ってみたが、結局書くのは自分だけとなってしまいました。日々のメモを綴っていきます。