[{"data":1,"prerenderedAt":371},["ShallowReactive",2],{"content-/wordpress-site-final-polish":3,"all-pages-for-dir":351,"related-/wordpress-site-final-polish":352,"og-image-/wordpress-site-final-polish":370},{"id":4,"title":5,"body":6,"category":332,"concepts":333,"description":334,"extension":335,"meta":336,"navigation":237,"ogImage":333,"path":337,"project_name":338,"published":339,"publishedAt":340,"seo":341,"stem":342,"tags":343,"todo":333,"unpublished":339,"updatedAt":333,"__hash__":350},"pages/2026-07/2026-07-26/wordpress-site-final-polish.md","本番切替の前に移行先サイトを仕上げた日 — 画像の謎、フォームの文字化け、トップページの作り直し",{"type":7,"value":8,"toc":316},"minimark",[9,13,16,21,24,27,30,33,36,44,47,52,55,58,61,64,67,71,74,77,80,129,132,135,139,142,145,148,151,154,158,161,164,167,171,174,177,180,183,186,189,192,195,198,201,208,215,218,221,224,276,279,312],[10,11,12],"p",{},"DNS を切り替えてしまえば、あとから直すのは全部「本番の修正」になる。だから切替の前に、移行先サイトを自分で全ページ見ておきたかった。dev サーバーを 3500 番で立ち上げてもらって、上から順にクリックしていく。",[10,14,15],{},"3ページ目で手が止まった。コンセプトページの画像が、1枚も出ていない。",[17,18,20],"h2",{"id":19},"画像が消えていたのはデータではなく-dev-サーバーだった","画像が消えていたのはデータではなく dev サーバーだった",[10,22,23],{},"真っ先に疑ったのは移行データのほうだった。WordPress のバックアップから記事を引っ張ってきたとき、画像の復元だけ取りこぼしたのではないか。それなら移行手順のやり直しで、この日の予定は全部飛ぶ。",[10,25,26],{},"原因を調べてもらったら、答えは逆だった。まだ稼働している現行サイトの同じページを開くと、画像は全部出ている。ファイルは移行先にもちゃんと存在していた。出ていないのは dev サーバーだけで、画像のパスにアクセスすると 404 が返る。ビルド後の成果物では 200 が返る。",[10,28,29],{},"つまり配信設定の穴で、移行そのものは無傷だった。dev 限定の配信設定を足して、参照側 8 か所を置き換えてもらったら、ローカルでも画像が並んだ。",[10,31,32],{},"移行案件でいちばん怖いのは「データが欠けている」ことなので、そうではないと分かった時点でこの日の残りが全部やりやすくなった。逆に、ここで dev の 404 を「まあ本番では出るだろう」と流していたら、全ページレビューの信頼度そのものが落ちていたと思う。",[17,34,35],{"id":35},"お問い合わせフォームを本番で1周させる",[10,37,38,39,43],{},"移行先には問い合わせ導線がまだなかった。",[40,41,42],"code",{},"/info"," にフォーム本体を実装してもらったところ、最初はページが出ずに catch-all ルートに吸われた。dev サーバーを再起動してルートテーブルを作り直させたら、意図どおりの画面が SSR された。",[10,45,46],{},"ここからは本番相当の環境でないと試せない。ローカルでフォームを叩いてもメールは飛ばないからだ。デモとして Cloudflare Pages にデプロイしてもらうことにした。",[48,49,51],"h3",{"id":50},"apiキーは自分の手で貼った","APIキーは自分の手で貼った",[10,53,54],{},"メール送信にはメール配信サービスの API キーが要る。値そのものを AI に渡す気はなかったので、Chrome で設定画面まで進めてもらい、変数名の入力までを任せた。値の欄だけ自分で貼り付けて保存する。",[10,56,57],{},"この分担はやってみると気持ちがよかった。画面の階層を探すのは面倒なわりに判断がいらない作業で、そこだけ肩代わりしてもらい、渡してはいけないものは自分の指で入れる。",[48,59,60],{"id":60},"送信テストは通った",[10,62,63],{},"全 238 ページのビルドが終わったところでデプロイしてもらい、実際のフォームから送信した。画面には「送信が完了しました」。Gmail を確認させると、2 通着信していた。フォームの入力からメール受信までが一本につながった。",[10,65,66],{},"受信先も増やした。通知が届くのは 1 つのアドレスだけの実装だったので、もう 1 つの受信箱にも同時に届くよう、Functions 側の通知先に追加して再デプロイしてもらう。2 宛先とも届くところまで実測した。",[17,68,70],{"id":69},"_2通目から日本語が壊れていた","2通目から日本語が壊れていた",[10,72,73],{},"着信メールを開いたら、2 通目の日本語が全部化けていた。お名前も題名も本文も読めない。",[10,75,76],{},"フォーム側のエンコード指定を疑うのが筋に見える。ところが化けているのは差し込まれた値だけで、テンプレート側の見出しや「様」の文字は正常に出ていた。同じメールの中で、片方は読めて片方は読めない。",[10,78,79],{},"原因は送信経路の違いだった。1 通目はブラウザのフォームから送ったもので、日本語は正しく届いている。2 通目は Windows のターミナルから curl で直接 POST したテストで、日本語が cp932 のままサーバーに渡り、UTF-8 として解釈されて壊れていた。",[81,82,87],"pre",{"className":83,"code":84,"language":85,"meta":86,"style":86},"language-bash shiki shiki-themes vitesse-light vitesse-light","# 化けたのはこの経路だけ（ターミナルの既定エンコーディングのまま送っていた）\ncurl -X POST .../api/contact -d '{\"name\":\"テスト\", ...}'\n","bash","",[40,88,89,98],{"__ignoreMap":86},[90,91,94],"span",{"class":92,"line":93},"line",1,[90,95,97],{"class":96},"sxvE3","# 化けたのはこの経路だけ（ターミナルの既定エンコーディングのまま送っていた）\n",[90,99,101,105,109,113,116,119,123,126],{"class":92,"line":100},2,[90,102,104],{"class":103},"senZ8","curl",[90,106,108],{"class":107},"snbK4"," -X",[90,110,112],{"class":111},"sdGka"," POST",[90,114,115],{"class":111}," .../api/contact",[90,117,118],{"class":107}," -d",[90,120,122],{"class":121},"sMJiu"," '",[90,124,125],{"class":111},"{\"name\":\"テスト\", ...}",[90,127,128],{"class":121},"'\n",[10,130,131],{},"つまりフォームは最初から正常で、壊れていたのはテストのやり方だった。UTF-8 を明示して再送すると、化けは消えた。",[10,133,134],{},"自分でテストを書いていたら、「文字化け＝アプリのバグ」と決めつけて実装をいじり回していたと思う。テンプレート文言だけ無事という一点を証拠にして切り分けてもらえたので、正常なコードを壊さずに済んだ。",[17,136,138],{"id":137},"トップページをもっと見たくなる入口に作り替える","トップページを「もっと見たくなる」入口に作り替える",[10,140,141],{},"レビューを続けていて気になったのは、トップページと記事一覧の中身がほぼ同じだったことだ。新着記事が並ぶだけで、初めて来た人がこのサイトで何が読めるのか分からない。",[10,143,144],{},"構成案をいくつか出してもらい、推した案をそのまま実装してもらった。画面で見たら悪くなかったので、勢いでヘッダーと同じ紺色のフッターも足した。サイト内リンクと外部サービスへの導線をまとめて置く。",[10,146,147],{},"ただ、まだ物足りなかった。このサイトには記事の中に自分で作ったアニメーションがあるし、絵本形式のコンテンツも別ページに置いてある。それが入口からは一切見えない。",[10,149,150],{},"そこで注文を足した。記事の中で動いているアニメーションをトップでも再生させて、その場で「詳細はこの記事へ」に流す。あわせて、絵本コンテンツの中身をスライドビューで数枚めくれるようにする。",[10,152,153],{},"素材のファイルサイズまで実測させたうえで計画書を書いてもらい、承認して実装に入った。コンポーネントを 2 つ作ってトップに組み込み、dev で描画とコンソールエラーを確認してからビルド、デプロイ。動く図解と試し読みビューアが入口に並んだ。",[48,155,157],{"id":156},"小さすぎたのでモーダルで拡大してページ送りできるようにした","小さすぎたので、モーダルで拡大してページ送りできるようにした",[10,159,160],{},"本番で見て、絵本ビューアの画像が小さすぎることに気づいた。並べたページの中身が読めない。これでは「試し読み」にならない。",[10,162,163],{},"クリックで全画面のモーダルに拡大し、そのまま矢印でページを送れるようにしてもらった。Esc・背景クリック・× のどれでも閉じる。dev で開閉とページ送りと暗幕を確認してから、ビルドしてデプロイ。",[10,165,166],{},"拡大できるようになった瞬間、同じコンポーネントの印象が変わった。縮小した状態では「何かの画像が並んでいる」でしかなかったものが、中身を読ませる導線になった。",[17,168,170],{"id":169},"計画書は-markdown-か-html-か","計画書は Markdown か HTML か",[10,172,173],{},"途中で、計画書の作り方そのものを相談することになった。",[10,175,176],{},"きっかけは単純で、計画書のパスだけ渡されても自分にはレビューする手段がなかったからだ。Markdown をエディタで開いて読むのは、図が入ると特につらい。Chrome で読める形にして表示してほしい、と伝えた。",[10,178,179],{},"その場で pandoc で HTML に変換して Chrome のタブに出してもらい、「計画書を作ったら Chrome に表示するところまでやる」をユーザーレベルのルールに足した。",[10,181,182],{},"そこで疑問が出た。図を入れるなら最初から HTML で書いたほうが早いのではないか。ずっと Markdown で書いてきたが、計画書だけ HTML 原本に切り替える手はある。",[10,184,185],{},"引っかかったのは、同じ内容のファイルが md と html の 2 つ残ることだった。どちらが原本か分からないファイルが並ぶのは、後から読むときに邪魔になる。表示用 HTML を一時ディレクトリに逃がす案も出してもらったが、それはそれで表示のたびに生成し直す手間が増える。",[10,187,188],{},"結局、原本は Markdown、表示用 HTML も同じディレクトリに置いたままでいくことにした。リポジトリに 2 つ残ること自体は許容する。diff が読めて編集も軽い Markdown を原本にしておいたほうが、あとで直すときに困らない。",[10,190,191],{},"判断を変えたのは、「無駄をなくす」より「どっちを直せばいいか迷わない」を優先したからだった。",[17,193,194],{"id":194},"コンセプトページを1カラムにする",[10,196,197],{},"最後に、コンセプトページのレイアウトを直した。",[10,199,200],{},"移行元の WordPress では 2 カラムで、右に目次が付いていた。移行先で同じ構成にすると、本文の幅が狭すぎる。このページは通読させたい文章で、見出しを飛ばして読む種類のページではない。目次を外して 1 カラムにし、本文の幅を広げてもらうことにした。",[10,202,203,204,207],{},"全記事から目次が消えると困るので、",[40,205,206],{},"[...slug].vue"," 側に条件分岐を入れて、このページだけ 1 カラムにする形にしてもらった。frontmatter のスキーマを変えたので dev サーバーの再起動が要る。似た構成の別ページでは目次が残っていることも実画面で確認した。モバイル幅も見て、コンソールには既知の画像 404 以外のエラーが出ていない。",[10,209,210,211,214],{},"コミットは学習ゲートに掛かったので、そのまま ",[40,212,213],{},"/learn"," を回した。4 問全問正解で受領証が出て、3 ファイルのコミットが通った。",[17,216,217],{"id":217},"この日の締め",[10,219,220],{},"この日の変更一式は 34 ファイル・+2,289 行でコミットした。移行先サイトは、画像が出て、フォームからメールが届き、入口で中身が動くところまで来た。",[10,222,223],{},"残っているのは DNS の切替だけで、これは押したら戻すのに時間がかかる操作なので次のセッションに回した。",[225,226,229,240,246,252,258,264,270],"ul",{"className":227},[228],"contains-task-list",[230,231,234,239],"li",{"className":232},[233],"task-list-item",[235,236],"input",{"checked":237,"disabled":237,"type":238},true,"checkbox"," コンセプトページの画像表示を dev でも直す",[230,241,243,245],{"className":242},[233],[235,244],{"checked":237,"disabled":237,"type":238}," お問い合わせフォームを本番で送信からメール着信まで通す",[230,247,249,251],{"className":248},[233],[235,250],{"checked":237,"disabled":237,"type":238}," 通知先アドレスを2つに増やす",[230,253,255,257],{"className":254},[233],[235,256],{"checked":237,"disabled":237,"type":238}," トップページに動く図解と試し読みビューアを入れる",[230,259,261,263],{"className":260},[233],[235,262],{"checked":237,"disabled":237,"type":238}," 試し読みビューアをモーダルで拡大・ページ送りできるようにする",[230,265,267,269],{"className":266},[233],[235,268],{"checked":237,"disabled":237,"type":238}," コンセプトページを1カラムにして本文幅を広げる",[230,271,273,275],{"className":272},[233],[235,274],{"disabled":237,"type":238}," DNS切替（本番切替）",[17,277,278],{"id":278},"学び",[225,280,281,288,294,300,306],{},[230,282,283,287],{},[284,285,286],"strong",{},"「表示されない」の原因が移行データ側とは限らない。"," 現行サイトと移行先の同じページを並べて見るだけで、データの欠損か配信の穴かが切り分けられた。先に環境差を潰すほうが早い",[230,289,290,293],{},[284,291,292],{},"テストが壊れているのか、実装が壊れているのかを先に決める。"," メールの一部だけが化けていたという事実が、フォーム本体を触らずに済む決め手になった",[230,295,296,299],{},[284,297,298],{},"シークレットは値の入力だけ自分の手でやる。"," 画面遷移を任せてキーの値だけ自分で貼る分担なら、面倒さと安全性の両方が立つ",[230,301,302,305],{},[284,303,304],{},"小さく置いた画像は、拡大できないと存在しないのと同じ。"," 試し読みビューアは、モーダルを足してようやく導線になった",[230,307,308,311],{},[284,309,310],{},"原本を1つに決めておくと、あとで直すときに迷わない。"," ファイルが2つ残る無駄より、どちらを編集すべきか分かることを優先した",[313,314,315],"style",{},"html pre.shiki code .sxvE3, html code.shiki .sxvE3{--shiki-default:#A0ADA0;--shiki-dark:#A0ADA0}html pre.shiki code .senZ8, html code.shiki .senZ8{--shiki-default:#59873A;--shiki-dark:#59873A}html pre.shiki code .snbK4, html code.shiki .snbK4{--shiki-default:#A65E2B;--shiki-dark:#A65E2B}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html pre.shiki code .sMJiu, html code.shiki .sMJiu{--shiki-default:#B5695977;--shiki-dark:#B5695977}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":86,"searchDepth":100,"depth":100,"links":317},[318,319,324,325,328,329,330,331],{"id":19,"depth":100,"text":20},{"id":35,"depth":100,"text":35,"children":320},[321,323],{"id":50,"depth":322,"text":51},3,{"id":60,"depth":322,"text":60},{"id":69,"depth":100,"text":70},{"id":137,"depth":100,"text":138,"children":326},[327],{"id":156,"depth":322,"text":157},{"id":169,"depth":100,"text":170},{"id":194,"depth":100,"text":194},{"id":217,"depth":100,"text":217},{"id":278,"depth":100,"text":278},"dev",null,"DNS切替の前に移行先サイトを全ページレビュー。コンセプトページの画像が出ない原因、お問い合わせメールが2通目から文字化けした理由、トップページを深掘りしたくなる作りに変えるまでの記録。","md",{},"/wordpress-site-final-polish","eurekapu",false,"2026-07-26T00:00:00.000Z",{"title":5,"description":334},"2026-07/2026-07-26/wordpress-site-final-polish",[344,345,346,347,348,349],"WordPress移行","Nuxt","Cloudflare Pages","お問い合わせフォーム","文字化け","UI改善","MjC_eZDmh_GVwsKEJgo6Q0sZErokPQZb2LkroiTgIZw",[],[353,357,360,363,366],{"title":354,"path":355,"publishedAt":356},"移行サイトのSEO・AI-SEO改善を1日で回した — 画像altを480件、記事の要点を203本、OG画像を署名付きに","/wordpress-nuxt-ai-seo-phase-c","2026-07-27T00:00:00.000Z",{"title":358,"path":359,"publishedAt":356},"Herokuを止められるか、nuxt generate を4回回して確かめた — 旧Nuxt 2アプリ静的化の実測","/app-static-build-heroku-retirement",{"title":361,"path":362,"publishedAt":340},"語源英単語コースの手触りを直した一日 - 音の鳴り方から、設定のユーザー別DB保存まで","/etymology-learning-ux-and-settings-sync",{"title":364,"path":365,"publishedAt":340},"インタラクティブ教材を1枚に集約し、本文の線を減らした日","/interactive-content-consolidation",{"title":367,"path":368,"publishedAt":369},"簿記学習サイトのクイズ入口をハブ化 — 問題文UIから矢印キー移動まで一気に整理した","/bookkeeping-quiz-hub-redesign","2026-07-25T00:00:00.000Z","https://log.eurekapu.com/og/blog/wordpress-site-final-polish.png?v=2026-07-26T00%3A00%3A00.000Z&title=%E6%9C%AC%E7%95%AA%E5%88%87%E6%9B%BF%E3%81%AE%E5%89%8D%E3%81%AB%E7%A7%BB%E8%A1%8C%E5%85%88%E3%82%B5%E3%82%A4%E3%83%88%E3%82%92%E4%BB%95%E4%B8%8A%E3%81%92%E3%81%9F%E6%97%A5%20%E2%80%94%20%E7%94%BB%E5%83%8F%E3%81%AE%E8%AC%8E%E3%80%81%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%AE%E6%96%87%E5%AD%97%E5%8C%96%E3%81%91%E3%80%81%E3%83%88%E3%83%83%E3%83%97%E3%83%9A%E3%83%BC%E3%82%B8%E3%81%AE%E4%BD%9C%E3%82%8A%E7%9B%B4%E3%81%97&author=Kei%20Komatsu&sig=490f9b58c6346a87",1785379974605]