スタッフブログ Staff Blog

レンタルサーバーの応答時間について

私が担当した案件で、さくらインターネット・スタンダードプランを利用しているサイトがありますが、どうもサイト全体が重たい様子なので、原因究明の為、調査をしました。

キャッシュの利用とプラグインの停止

当初はキャッシュを使う予定はなかったのですが、何か変わることを期待して導入しました。Wordpressでよく使われるプラグインではなく、.htaccessによる制御です。

mod_expiresというApatchのモジュールを利用するとできます。ついでにmod_deflateというモジュールで圧縮もかけておきます。またよくある原因としてプラグインが重たい可能性があるので、これも怪しい箇所は全て停止させます。

結果・・・特に変わらず。

Debug Bar でパフォーマンスを測定

体感として間違いなく遅いですが、実際数値として見る為に Debug Bar というプラグインを使ってみました。拡張機能でDebug Bar Extender、Debug Bar Slow Actionsという便利で見やすいプラグインもあるので、それも同じく導入しておきます。

パフォーマンス(通常時)

結果として、数値としてかなり遅いものが出ました。
ACTIONS EXECUTION TIME 処理時間はおよそ3.3秒。
Chromeの開発者ツールなどで確認すると、実際のページ全体の読み込み時間はおよそ倍の5~6秒は平均でかかります。

パフォーマンス(遅延時)

昼頃や夕方などの混む時間は、時より悲惨な数値が出ます。
ACTIONS EXECUTION TIME 処理時間はおよそ12秒。
さすがに遅すぎるのでサーバーに原因がある可能性を疑いました。

別サーバーに同環境を構築して比較

さくらスタンダード以外に、CPIのシェアードプランというテスト環境を用意しました。ここでほぼ同じ環境を用意し検証します。

そのためにまずバックアップを取る必要がありますが、ここでプラグインの1つ「All-in-One WP Migration」をお薦めします。
手順等は調べると分かりますが、簡単操作で環境のバックアップ&復元が可能です。移行時にDBの中身を書き換える方法も前はありましたが、そういう手間も不要で、非常に優秀なプラグインだと感じました。

パフォーマンス(CPIサーバー)

そんなこんなで環境を作って計測したところ、案の定の結果が出ました。
ACTIONS EXECUTION TIME 処理時間はおよそ0.5秒。
ページ遷移やリロードをしても不自然な遅延は起こりません。

サーバーには当たり外れがある、かもしれない

検証結果として、異なるサーバー間で明らかな差がでました。こうして見ると、さくらスタンダードが遅いように感じられますが、一概にはそうとは言えません。

実は他の案件でもさくらスタンダードを使っているものがありますが、それらは全く問題ないのです。今回の案件のみ、なぜか強烈に重いので、苦悩していました。
絶対コレという保証はありませんが、当てられた共用サーバーの運が悪かった可能性は十分考えられます。

月額500円のプランですのでこんなものかなと思いつつも、良いパフォーマンスを発揮したければエックスサーバーなどの方がよいかもしれませんね。

WordPressで営業日カレンダーを作成する

個人のお客様を対象としたBtoCサイトでは営業日カレンダーを表示したいといった要望が出ることがあるのですが、既存のWordPressカレンダー系プラグインでは要件を満たすことが出来なかったのでカスタム投稿+REST API+カレンダーJavaScriptで実装しました。

店休日カレンダーの画面キャプチャ。月単位のカレンダーで店休日は日付の背景色を変更して休日を示している。

営業日カレンダーを作成する前提として

  • 定休日は決まっているが定休日が祝日の場合などイレギュラーな営業日がある
  • カレンダーを二つ並べて表示したい
  • 休日だけを示せれば良いのでGoogleカレンダーのようにカレンダーの日付に複数の予定を表示する必要はない(シンプルに表示したい)

以上の条件で営業日カレンダーを作成しました。

カスタム投稿タイプの作成

店休日を登録するカスタム投稿タイプを作成します。今回はWordPressプラグイン Custom Post Type UI を利用してカスタム投稿タイプを作成しました。

作成したカスタム投稿タイプに休日を登録する日付選択型のカスタムフィールドを作成し、1投稿を1店休日として使用します。 この時カスタム投稿タイプの一覧画面でその投稿がどの店休日に該当するか判別しやすいよう一覧画面に先程作成したカスタムフィールドの値を表示するようにしました。

一覧画面にカスタムフィールドの値を表示するサンプルコード

<?php
// 一覧にカラムを追加
function add_event_columns($columns) {
  $new_columns = array();
  foreach ($columns as $column_name => $column_display_name) {
    // 日付カラムの前に追加
    if ($column_name === 'date') {
      $new_columns['カスタムフィールドのフィールド名'] = __('一覧のカラムラベル');
    }
    $new_columns[$column_name] = $column_display_name;
  }
  return $new_columns;
}
add_filter('manage_event_posts_columns', 'add_event_columns');
// 追加したカラムにカスタムフィールド の値を挿入
function custom_event_column($column, $post_id) {
  switch ($column) {
    case 'カスタムフィールドのフィールド名':
      echo get_post_meta($post_id, 'カスタムフィールドのフィールド名', true);
      break;
  }
}
add_action('manage_event_posts_custom_column', 'custom_event_column', 10, 2);
?>

REST APIに店休日を取得するエンドポイントを追加

今回は月単位でJSONを取得したかったので月別で店休日を取得するためのエンドポイントを追加しました。以下のリクエストで2018年4月の店休日をJSONで返します。 https://example.com/wp-json/custom/event/2018-04

月別の店休日を取得するサンプルコード

<?php
add_action('rest_api_init', 'dt_register_api_hooks');
function dt_register_api_hooks() {
  register_rest_route('custom', '/event/(?P\d+\-\d+)', array(
    'methods' => 'GET',
    'callback' => 'get_events'
  ));
}
function get_events($request) {
  $args = array(
    'post_type' => 'カスタム投稿タイプスラッグ',
    'posts_per_page' => 20,
    'meta_query' => array(array(
      'key' => 'カスタムフィールドのフィールド名',
      'value' => $request['yymm'],
      'compare' => 'LIKE',
    )),
    'orderby' => 'meta_value',
    'meta_key' => 'カスタムフィールドのフィールド名',
    'order' => 'ASC',
  );
  $posts = get_posts($args);

  if (empty($posts)) {
    return null;
  } else {
    $events = [];
    foreach ($posts as $post) {
      $event_date = get_post_meta($post->ID, 'カスタムフィールドのフィールド名', true);
      $event = array(
        'title' => $post->post_title,
        'date' => $event_date
      );
      $events[] = $event;
    }
    return $events;
  }
}
?>

カレンダーJavaScriptで店休日を表示

ここまでで月別の店休日をJSONで取得することが出来るようになりましたのでカレンダーJavaScriptで店休日を表示します。カレンダーJavaScriptはお好みで選択していただければ良いですがサンプルでは FullCalendar を利用しています。

FullCalendarで店休日を表示するサンプルコード

FullCalendarのオプションについてはFullCalendarのドキュメントを参照してください。

$('[カレンダーを挿入する要素]').fullCalendar({
  defaultView: 'month',
  defaultDate: moment.format('YYYY-MM-DD'),
  displayEventTime: false,
  fixedWeekCount: false,
  height: 'auto',
  header: {
    left: '',
    center: 'title',
    right: ''
  },
  views: {
    month: {
      titleFormat: 'YYYY年M月'
    }
  },
  events: {
    url: '/wp-json/custom/event/' + moment.format('YYYY-MM'),
    error: function() {
      console.log('REST API request is failured');
    }
  }
});

まとめ

今回紹介した実装方法では店休日毎に投稿して休日を管理する方法をとりましたが自由度が高い反面、投稿する手間があるとも考えられます。

定休日が営業日となるケースが年に数回など稀な場合はカレンダーJavaScriptで定休日を固定で休日とし、定休日が営業となる日付のみを投稿するなど運用方法を変更することも可能です。

WordPressのACFプラグインに独自フィールドタイプを追加して入力しやすい画面を作成する

とある医療機関様のサイトを作成しているのですが、サイトホームや診療案内ページに以下のような診療時間を提示するテーブルを表示することになりました。
画面キャプチャ: 診療時間のテーブル。横方向に曜日、縦方向に午前・午後が並んでおり、○や-で診療時間か否かを示す。

そこで、次のような条件を満たしつつWordPressで管理するにはどのようにすればよいか検討を進めました。

  • WYSIWYGエディタで編集できないサイトホームと、WYSIWYGエディタで編集できる固定ページに表示する必要がある
  • 一度の変更で全ての表にデータを反映したい
  • アクセシブルなテーブルにしたい
  • ユーザーが入力しやすく、失敗しても破綻しない

検討の結果、WordPressの「Advanced Custom Fields(ACF)」プラグインを拡張し、独自のカスタムフィールドタイプを作成することにしました。

独自のフィールドタイプの作成

「Advanced Custom Fields(ACF)を拡張して独自のフィールドタイプを追加」と聞くと難しそうに感じるかもしれませんが、トライしてみると意外と簡単にフィールドタイプを追加することができました。解説が「ACF | Creating a new field type」に、また独自のフィールドタイプを追加するプラグインのテンプレート「ACF Field Type Template」がGithubに用意されています。

テンプレートをダウンロードした後は、NAMESPACEFIELD_NAMEなどのプレースホルダー文字を自分の名前空間やフィールド名に変更すること、そしてcreate_field関数にフィールドに入力フィールドを作成することが主な作業でした。管理画面で値を受け取った場合の処理などを書く必要はなく、フロント側のテンプレートを書く感覚で開発ができました。

入力した値は一つのカスタムフィールドに配列で格納されています。そのため自由にHTMLを組み立てることができたのが便利でした。
画面キャプチャ: カスタムフィールドの内容をvar_dumpで表示した画面。診療時間が配列で格納されている。

プログラムしたコードは一つのプラグインとして完結しているので、WordPress本体やAdvanced Custom Fields(ACF)がアップグレードした場合も特別な対応は不要です。(但し、Advanced Custom Fieldsが5.xにメジャーバージョンアップした場合はプラグインの書き換えが必要です。)

フィールドのサンプルコード

<?php
private function getSavedValue( $field, $fieldname ) {
    if ( isset( $field['value'][$fieldname] ) ) {
        return esc_attr( $field['value'][$fieldname] );
    }

    return '';
}

function create_field( $field ) {
    // create Field HTML
    ?>
    <div class="Timetable">
        <table class="Timetable__table">
            <caption>診療時間</caption>
            <thead>
            <tr>
                <th></th>
                <th>月</th>
                <th>火</th>
                <th>水</th>
                <th>木</th>
                <th>金</th>
                <th>土</th>
                <th>日・祝</th>
            </tr>
            </thead>
            <tbody>
            <tr>
                <td>
                    <?php
                    echo '<input type="text" name="' . esc_attr( $field['name'] ) . '[time_morning]" value="' . $this->getSavedValue( $field, 'time_morning' ) . '">';
                    ?>
                </td>
                <?php
                $names = ['mon_morning', 'tue_morning', 'wed_morning', 'thu_morning', 'fri_morning', 'sat_morning', 'sun_morning'];
                foreach ($names as $name) {
                    echo '<td>';
                    echo '<input type="text" name="' . esc_attr( $field['name'] . '[' . $name . ']' ) . '" value="' . $this->getSavedValue( $field, $name ) . '">';
                    echo '</td>';
                }
                ?>
            </tr>
            <tr>
                <td>
                    <?php
                    echo '<input type="text" name="' . esc_attr( $field['name'] ) . '[time_afternoon]" value="' . $this->getSavedValue( $field, 'time_afternoon' ) . '">';
                    ?>
                </td>
                <?php
                $names = ['mon_afternoon', 'tue_afternoon', 'wed_afternoon', 'thu_afternoon', 'fri_afternoon', 'sat_afternoon', 'sun_afternoon'];
                foreach ($names as $name) {
                    echo '<td>';
                    echo '<input type="text" name="' . esc_attr( $field['name'] . '[' . $name . ']' ) . '" value="' . $this->getSavedValue( $field, $name ) . '">';
                    echo '</td>';
                }
                ?>
            </tr>
            </tbody>
        </table>
    </div><!-- .Timetable -->
    <?php
}

完成した管理画面

追加したACFの独自フィールドタイプは管理画面で以下のキャプチャのように表示されました。実際に表示される画面と同じような形式で入力できること、入力が容易なことが大きな利点と考えています。
画面キャプチャ: 追加したACFの独自フィールドタイプを管理画面で表示した様子。

最終的にはショートコード[timetable]で、本稿の最初に示した画面のHTMLが出力されるようにプログラムいたしました。

まとめ

ビジュアルデザイン(見た目)だけがデザインではなく、入力しやすい画面をデザインすること等も非常に重要なデザインと考えています。今後もAdvanced Custom Fields(ACF)を拡張して使うことなど試行錯誤を重ね、より使いやすいCMS(WordPress)にしていきたいと考えています。

補足: PowerCMSでは...

ちなみにPowerCMSでは今回のようにPHP等でプログラミングを行いプラグインを書く必要はなく、管理画面からHTMLとMTタグを使用してフィールドを書くだけで実現できます。製品サポートもあり安心です。ご興味のある方は「カスタムフィールド Pro | PowerCMSの機能 | PowerCMS」をご覧ください。

PowerCMS 5の管理画面のみにスタイルを適用したい

現在当社にて開発をお手伝いしているPowerCMS / Movable Type向けのモバイルアプリ作成アドオン「Apliko」をPowerCMS 5(2018年4月2日リリース予定)に対応させる作業を実施しております。PowerCMS 5の新機能に「新しい管理画面デザイン」が含まれることから、作業の過程でPowerCMS 5の管理画面のみにスタイルを適用したい(PowerCMS 4 / Movable Type 6の管理画面には適用しない)というケースが発生しました。

レアケースかもしれませんが具体的例を挙げますと、アドオンで追加している管理画面に含まれるinput type=colorのテイストをinput type=textに合わせたいというものです。

Movable Type 6でエラーを発生させることなくPowerCMS 5を判別する方法を検討したのですが(つまりMTPowerCMSVersionは利用できない)、管理画面のテンプレートに以下のコードを追加して対応することとしました。これによりPowerCMS 5の場合はbodyにclass属性値pack-powercms5が付与され、PowerCMS 5のみに適用されるスタイルを容易に記述できるようになります。

<mt:If name="powercms_version" ge="5"><$mt:SetVar name="screen_class" value=" pack-powercms5" append="1"$></mt:If>

なお、変数powercms_versionはPowerCMS 5から設定されているようです。PowerCMS 4.33では変数powercms_versionは設定されていませんでしたが、仮にpowercms_version => 4.33が設定された場合でも上記コードは意図した動作になりました。

CSSの記述例は以下の通りです。

.color {
    width: 100%;
    max-width: 100px;
    border: 1px solid #a9a9a9;
    border-top-color: #323232;
    border-radius: 2px;
    background-color: #fff;
}

.pack-powercms5 .color {
    border: 1px solid #666;
    border-radius: 0;
    height: 1.875rem;
}

スタイル調整例

キャプチャ画像内の上部にあるテキスト入力フィールドと下部にある色選択フィールドを見比べて下さい。

スタイル調整前
画面キャプチャ: スタイル調整前のinput要素のcolorの表示例
スタイル調整後
画面キャプチャ: スタイル調整後のinput要素のcolorの表示例

※本稿は2018年3月15日より提供されております「PowerCMS 5 ベータ2」を基に執筆しております。

広島市で「Webアクセシビリティの学校 in 広島」が開催されます

来る2018年5月19日(土)、株式会社インフォアクシア様主催、アイエーアイ様開催協力で「Webアクセシビリティの学校 in 広島」が開催されます。隣県の岡山県・山口県では既に開催されており、広島県では初めて開催されます。

ここで突然ですが、私がサンプルで作ったバナーを見て頂きたいと思います。1つ目は病院を探すページへのリンクに使用するバナーです。
背景と文字のコントラストが低いバナーのサンプル

いかがでしょうか? 文字が見やすいでしょうか? 実はコントラスト比を計測すると2.905となっており、私は正直文字が読みにくいです。

福山市ではピンク色の背景に白文字がよく見られますが、こちらはいかがでしょうか。
背景と文字のコントラストが低いバナーのサンプル2。背景色が福山市でよく使われるピンク色、文字が白色になっています。

実はこの色の組み合わせもコントラスト比が4.357とわずかに不足しています。

これらのバナーを見やすくなるように改善するにはどのようにしたら良いでしょうか? それは「Webアクセシビリティの学校」の講義で解説される「色の使い方」に答えがあります。

より多くの人がWebサイトを快適に利用できるように

最近ではCMSが広く普及するなどし、多くの方がWebサイトを制作・編集するようになりました。しかし、誰もが問題なくWebサイトを利用できる状況にあるか?という観点から見ると、私はまだまだではないかと感じます。先に例を出した色のコントラスト比の問題、視覚に障害のある方が利用されるスクリーンリーダーや検索エンジンのロボットが画像を含むコンテンツにアクセスしても内容を理解できない問題、またリンクの文字が全て「こちら」となっておりどのようなコンテンツにリンクしているのか分からない問題...、さまざまな問題がWebサイトには潜んでいるのです。

Webアクセシビリティの学校では"「Webアクセシビリティ」の基本の「キ」"として、このような問題をひとつひとつ丁寧に解説してくださいます。もちろんなぜWebアクセシビリティに取り組む必要があるのか、という前提の知識についてもしっかり解説があります。基本の「キ」は10項目ほどあるのですが、最初から全て完璧に理解し実践するのは難しいかもしれません。しかしWebアクセシビリティは全然ダメとか完璧のどちらかのみではありません。日々の業務でできることから取り組みを進め、今より少しずつでもWebサイトがアクセシブルになっていけば良いと思います。

Webサイトのアクセシビリティが向上すれば、ある人にとって使いにくかったサイトが改善される可能性があります。今まで利用できていた人がさらに利用しやすいサイトになることもあります。また、最近音声で操作するデバイスが流行していますが、そのようなデバイスからのアクセスにも対応できる可能性を秘めています。

Web制作者のみなさま、また企業のWeb担当者のみなさま、「Webアクセシビリティの学校 in 広島」で「Webアクセシビリティ」について楽しく学び、よりよいWebを一緒に作っていきませんか?

お問い合わせ Contact

制作のご依頼、ご相談などは下記のフォームからご連絡ください。