Rettyグルメニュース入稿システムの脱 WordPress リニューアル

こんにちは。エンジニアの山本です。
(アプリチームにもエンジニアの山本がいますが、Web チームの山本です。)

本日は、Rettyグルメニュースの入稿システムの紹介をさせていただきます。

Rettyグルメニュースとは

Rettyグルメニュース(retty.news)は、Retty が運営するグルメに関する Web メディアです。 「ニュース」と冠してはいるものの、新店情報だけでなく、「福島県で自然酒を作る酒蔵に取材に行った記事」や 「美容室の中にプリン工場を作った人のこだわりをインタビューした記事」など、さまざまな観点から実際に現地に行った人がグルメ情報を紹介するメディアです。

2017年9月にリニューアルを行い、Retty から別サービスとして切り出されました。 その際に入稿システムも作り直し、そこから1年以上経ち様々な改善を行ってきました。

Rettyグルメニュース入稿システム

通称は Gohan です。 当時余っていた gohan を含むドメインを使おうか、という話があったためこのような名前になりましたが、実際にそのドメインがこの入稿システムに使われることはありませんでした。

f:id:rettydev:20190128203627p:plain
記事編集画面

機能紹介

プロフィール埋め込み機能

グルメニュースでは、システムにログインできるメールやパスワードを持った情報を User とし、記事内に登場する人間の情報を Profile としています。 User は必ず一つ Profile を持ち、記事内に自分が登場するときは即座にその情報を埋め込むことができます。 また、外部ライターさんからテキストで納品していただき、内部の編集者が入稿するときのために、記事そのものも入稿者としての User とライターとしての Profile を持ちます。 記事内では登録された Profile を検索して、食レポに行った人やインタビューに答えてくれた人、店主などの情報を埋め込むことができます。 Profile は人物紹介文の他に各種 SNS やブログへのリンクを持っており、Profile を編集することで埋め込まれたすべての記事の内容を書き換えることができます。

f:id:rettydev:20190128221110p:plain
プロフィール設定画面

店鋪リンク、口コミ埋め込み機能

紹介したお店やお店に対する口コミもポップアップ画面で URL を入力することで埋め込むことができ、店名の変更や住所の変更時にグルメニュース側で記事を編集する必要がない作りになっています。

店鋪リンク設定画面
店鋪リンク設定画面

口コミ設定画面
口コミ設定画面
(Retty エンジニアであり、焼きそばブロガーの塩崎さん)

画像など

店鋪リンクやプロフィールはマークダウンを拡張した記法でコンテンツとして保存されます。 画像やリンク、引用などもマークダウンで記述しますが、それぞれ GUI をもたせており、ポップアップに入力することで、マークダウンが現在のキャレット位置に挿入されます。 こうすることで、マークダウンで書きたい人はマークダウンで、マークダウンを知らない人は GUI で、モードを切り替えることなく記述できるようになっています。

プレビュー

プレビュー画面では、記事を保存せずともその場でプレビューを見ることができ、 UserAgent を切り替えなくてもボタン一つでスマートフォンでの見え方まで確認することができます。

プレビュー画面
プレビュー画面

(当時最新のiPhoneで作ったのですが、すでに古さを感じる…)

編集以外の機能

編集以外にも、入稿システムから

  • 内部リンクの設定
  • 申請された記事の差し戻し・公開・公開予約
  • カテゴリや連載の管理
  • Profile の管理
  • 読者・ライターさんへのお知らせ設定
  • 申請などがあったときの Slack 編集者チャンネルへの通知

などができるようになっています。

リニューアル振り返り

さて、ここからはリニューアルの振り返りをしていきます。 リニューアル前のグルメニュースは Retty の Web サービス上に WordPress を乗っけたような構成になっており、リニューアルで解決すべき主な課題は以下のようなものでした。

  1. WordPress によって DB に HTML が保存してあり、スタイルの変更などが困難
  2. カスタムした WordPressPHP の管理画面上に置かれていて入稿機能だけを担っており、その場でプレビューが見れない
  3. 記事の申請やその差戻しなど、外部ライターさんと一緒に使う機能が不十分

これを3ヶ月ほどのリニューアル期間で、配信側と入稿側合わせて作り直す必要がありました。

リニューアル手順

  • 入稿システムの要件をヒアリングし、必要そうな機能の UI を View だけ作って編集部に見せる。
  • 確認がとれたら実装
  • 実装が終わったら触ってもらって確認

の繰り返しで、エンジニアサイドから要件を掘り起こす形で行いました。 ここでのポイントが、既存の入稿画面を見慣れてる編集者に 画面の詳細までヒアリングを行わない、ということです。 「必要な"機能"をユースケースと一緒にヒアリングし、それを満たす画面構成や画面遷移を整理・提案・実装・確認」というサイクルを繰り返しました。 また、画像をドラッグ&ドロップでアップロードできる機能の UI は WordPress に似せるなど、システム移行後の編集者の学習コストを抑えるような工夫をしました。

フロントエンド

デザインは AdminLTE に頼ったものの、jQuery は排除し Vue.js を採用しました。 サーバーサイドは Laravel を利用していましたが、Laravel Mix はフロントエンドのビルドがサーバーサイドフレームワークに依存するというのが個人的に好きではなく、使っていません。webpack-dev-server でフロントエンド開発用のサーバーを起動し、フロントエンドのビルド対象物以外のリクエストを Docker で起動したサーバーサイドアプリケーションに流すことでサーバーサイドとフロントエンドの開発を同時に行ってましたが、これはプロトコルを決めて別々に開発してもよかったかなと思ってます。

DBリニューアル

サービスを切り離すついでにデータベースごとリニューアルしました。 新システムでは記事本文コンテンツをマークダウンで管理するようにしたため、HTML で保存されていた記事を変換する必要がありました。

そこで、リニューアルの開発が落ち着いた頃に移植作業を行いました。 PHPDOMDocument を用いて HTML をパースし、マークダウンに変更していきました。 ワードで作ってコピペしたような、HTML とは呼べない XML や、ツリー構造が壊れた HTML なども混入しており骨が折れましたがコンテンツの90%程はこのスクリプトで移植しました。

記事内に登場する人物のプロフィール情報や店鋪情報などは直接マークダウンで書き込まず、カスタムしたマークダウン記法に変換する必要がありましたが、コンテンツ移植時点ではプロフィール情報の登録が終わっていなかったため、プロフィールが入ることを示すマークに置換していき、登録が終わった後に編集部と確認しながら埋め込みました。

配信側の作成

入稿システムが終わったら配信側のアプリケーションを作ってリニューアル終了です。 入稿システムのプレビュー機能と配信側アプリケーションの二箇所で拡張マークダウンを HTML に変換する処理が必要でしたが、処理を一箇所にまとめ完全なプレビューができるようにしました。 また、通常時と AMP で別々に管理せずに済むよう、マークダウンパーサーにオプションを追加し AMP 用の HTML を作り、スタイルに関しても postcss-loader の小さなプラグインを作って自動で AMP が作成されるようにしました。

リニューアルまとめ

入稿システムに1ヶ月半、配信側に1ヶ月半、リニューアル前の URL からのリダイレクト処理、古いコード・データベース の削除、QA などに1週間ほどかけ、リニューアルが終了しました。 小さなチームで、編集者とエンジニアが協力しあってリニューアルしながら改善サイクルを回すことができたのが良い点でした。 一方で、リニューアルという多くのタスクが存在するプロジェクトのタスク管理が不足しており、リリース前にバタついてしまい、大きな反省となりました。

リリース後

PWA

配信側を PWA にしてキャッシュによる高速化を試みたりしましたが、配信側は SPA ではなくサーバーサイドでHTMLを生成するアプリケーションなため、キャッシュ効率が悪く、現在業務の合間にインターン生と一緒に入稿システムの GraphQL API 化と配信側の Nuxt.js による SPA 化を進めています。

textlint

グルメニュースリニューアル以前から Slack に #rss_gourmet_news というチャンネルがあり、そこに公開された記事が流れてくるのですが、誤字・脱字・表記ゆれを社員から指摘される、ということが多々ありました。 入稿システムの開発者としてなんとかできないかと、textlint などの導入を考えたところ、2018年新卒エンジニアの諏訪くんが入社し、一緒にグルメニュースの保守を担当してくれることになり、textlint の導入をかって出てくれました。

それにより以下のキャプチャのように、ルールに反した記述を機械的に判定できるようになりました。

textlink による文チェック
textlink による文チェック

ランキング機能

グルメニュースに表示されているランキングは、入稿システムのワーカーによって毎日更新されています。 この機能はリニューアル当時、とりあえず Google AnalyticsAPI を叩いて実現していましたが、読者さんが増えたため Analytics のサンプリングのしきい値を超えてしまい、 API から返ってくる値が正確ではなくなってしまいました。 弊社の DWH に PV 数を記録し、BigQuery を叩いてランキングを生成するようにする変更も諏訪くんがやってくれました。

おわりに

グルメニュースリニューアルからかなり時間が経っていますが、管理画面は社員でも限られた人しかログインできないため、振り返り記事で見てくれたらいいなという思いもあって記事になりました。 世の中にはすでに様々な Web エディターがありますし、最近では Headless CMS も盛り上がっていて、場合によっては入稿画面を自力で作らなくても良いこともあるでしょう。 そのチーム、プロダクトにあった入稿画面でライターさんが楽しく入稿でき、編集チームが楽に管理できる管理画面があることが重要だと思います。