<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>レンタルサーバー &#8211; まったりエンジニア</title>
	<atom:link href="https://javeo.jp/tag/%E3%83%AC%E3%83%B3%E3%82%BF%E3%83%AB%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC/feed/" rel="self" type="application/rss+xml" />
	<link>https://javeo.jp</link>
	<description>ほどほどレベルのプログラミング</description>
	<lastBuildDate>Sat, 03 Oct 2026 07:08:22 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>

<image>
	<url>https://javeo.jp/wp-content/uploads/2026/05/cropped-サイトアイコン2-32x32.png</url>
	<title>レンタルサーバー &#8211; まったりエンジニア</title>
	<link>https://javeo.jp</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Claude CodeでWordPress自動投稿【MCP活用】</title>
		<link>https://javeo.jp/claude-code-wordpress-mcp-xserver/</link>
					<comments>https://javeo.jp/claude-code-wordpress-mcp-xserver/#respond</comments>
		
		<dc:creator><![CDATA[ジャベ雄]]></dc:creator>
		<pubDate>Tue, 16 Jun 2026 05:01:10 +0000</pubDate>
				<category><![CDATA[AI・Claude]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Claude]]></category>
		<category><![CDATA[Claude Code]]></category>
		<category><![CDATA[MCP]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[レンタルサーバー]]></category>
		<category><![CDATA[自動化]]></category>
		<guid isPermaLink="false">https://javeo.jp/?p=4008</guid>

					<description><![CDATA[<p><img src="https://javeo.jp/wp-content/uploads/2026/06/claude-code-wordpress-mcp-xserver-ogp-1024x538.jpg" class="webfeedsFeaturedVisual" /></p>AIに書かせた記事を、そのままWordPressの下書きに届けたい人向けの記録です MCPサーバーはPythonで一から書かなくてもClaude Code本人に頼んで作れます 依頼文のコツ、アプリケーションパスワードの発行、動作テストの5ステップ、コード全文と補助プラグインまで載せました]]></description>
										<content:encoded><![CDATA[<p><img src="https://javeo.jp/wp-content/uploads/2026/06/claude-code-wordpress-mcp-xserver-ogp-1024x538.jpg" class="webfeedsFeaturedVisual" /></p><div class="codoc-evacuations" style="display:none;" data-shortcode=""></div>
<p class="wp-block-paragraph">「AIに記事を書かせて、そのままWordPressに下書き保存できたら楽なのに」と思ったことはないですか？</p>



<p class="wp-block-paragraph">今回は <strong>Claude Code で WordPress に自動投稿する仕組み</strong>を MCP（AIに外部サービスを操作させる仕組み）で作りました<br>投稿先はXserverで動かしている自分のブログで、届くのは下書きの状態<br>そのMCPサーバー自体、私がPythonを一行ずつ書いたというより<strong>Claude Code本人に「こういうサーバーを作って」と頼んで作ってもらった</strong>んです</p>



<p class="wp-block-paragraph">なので中心になるのは、<strong>Claudeにどう頼めばMCPサーバーができあがるのか、どうテストすれば任せられる状態になるのか</strong>、のあたり<br>すぐ動かしたい人向けに、いま動かしている全文も記事の末尾に折りたたんであります</p>



<h2 class="wp-block-heading">Claude CodeでWordPress自動投稿｜何ができるようになるか</h2>



<p class="wp-block-paragraph">セットアップが終わると、<strong>「VLOOKUPの解説記事を書いて、下書きで保存して」の一言</strong>でWordPress管理画面の「投稿一覧」に下書きができあがります</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">「VLOOKUP関数について、初心者向けに1000字くらいで解説記事を書いて、下書きで保存しておいて」</p>
</blockquote>



<p class="wp-block-paragraph">下書きを作るだけでなく、装飾やメタの設定まで会話で済みます</p>



<ul style="background-color:#FFFFDC80" class="wp-block-list -list-under-dashed has-background">
<li>テーマを伝えるだけで記事の下書きをWordPressに自動投稿</li>



<li><strong>アイキャッチ画像</strong>のアップロードと設定</li>



<li><strong>カテゴリ・タグ</strong>の設定（既存から選ぶ・足りなければ新規作成）</li>



<li><strong>メタディスクリプション</strong>（SEO用の説明文）の登録</li>



<li><strong>テーマ独自のブロック</strong>（SWELLのステップ・FAQ・注意ボックスなど）での装飾</li>



<li><strong>記事ごとのカスタムCSS</strong>（SWELLの投稿別CSS欄）の設定</li>



<li>既存記事の取得・編集も会話で完結（タイトル変更・本文追記など）</li>



<li>下書き一覧を出してもらって、書きかけ記事の整理も簡単</li>
</ul>



<p class="wp-block-paragraph">もちろん公開前のプレビュー確認は管理画面で行いますが、それ以外の編集作業をブラウザでぽちぽち進めなくて済むのは思ったより楽なんです</p>


<div class="swell-block-balloon"><div class="c-balloon -bln-left" data-col="blue"><div class="c-balloon__icon -circle"><img decoding="async" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="https://javeo.jp/wp-content/uploads/2026/05/cropped-サイトアイコン2.png" alt="" class="lazyload c-balloon__iconImg" width="80px" height="80px"><noscript><img decoding="async" src="https://javeo.jp/wp-content/uploads/2026/05/cropped-サイトアイコン2.png" alt="" class="c-balloon__iconImg" width="80px" height="80px"></noscript><span class="c-balloon__iconName">ジャベ雄</span></div><div class="c-balloon__body -speaking -border-on"><div class="c-balloon__text">
<p>私は下書き作成を、ぜんぶこれに寄せました</p>
<span class="c-balloon__shapes"><span class="c-balloon__before"></span><span class="c-balloon__after"></span></span></div></div></div></div>


<h3 class="wp-block-heading">テーマ独自のブロックは「見本ページ」を読ませて覚えさせる</h3>



<p class="wp-block-paragraph">1つだけコツがあって、「SWELLのステップブロックで書いて」と頼むだけではClaudeはあなたのテーマの正確なブロックの形までは分かりません<br>理由は単純で、ブロックの中身（HTML）がテーマごとに違うから</p>



<p class="wp-block-paragraph">そこで有効なのが、使いたいブロックを並べた<strong>見本用の固定ページを1枚だけ作っておく</strong>方法です</p>



<p class="wp-block-paragraph">その見本ページをClaudeに読み取らせると、実際のブロックのHTMLを覚えて、同じ形を記事の中で再現できるようになります</p>



<p class="wp-block-paragraph">私の場合は、ステップ・FAQ・吹き出し・各種ボックスなどを1ページにまとめた見本を作って、それをClaudeに読ませてから装飾してもらう、という流れにしています</p>



<h2 class="wp-block-heading">逆に苦手なこと｜任せきれない部分は人がやる</h2>



<p class="wp-block-paragraph">いちばんはっきりしているのが画像で、<strong><span class="swl-marker mark_yellow">AIは記事の見た目を見ているわけではないし、必要なスクショを自分で撮ることもできません</span></strong><br>「この記事に合うスクショを貼って」と頼んでも、返ってくるのは場所の提案まで</p>



<p class="wp-block-paragraph">ローカルの画像をアップロードするにしても、メディアライブラリから選ぶにしても、「どれが適切か」の判断はAIには難しいと思います<br>ここは人の出番</p>



<h3 class="wp-block-heading">代わりに「キャプチャのメモ」を入れてもらう</h3>



<p class="wp-block-paragraph">まるごと任せられないだけで、下ごしらえは頼めます</p>



<p class="wp-block-paragraph"><strong>「ここにスクショを入れる」という場所と、「何を写したスクショにするか」のメモ</strong>を、該当箇所に書いておいてもらう使い方です<br>そうすれば人は、メモ通りにスクショを撮って貼るだけ</p>



<p class="wp-block-paragraph">実際この記事の画像も、先にAIが「ここにアプリケーションパスワード発行画面のスクショ」とメモを置いておいて、その場所に私が撮ったものを入れています</p>



<h3 class="wp-block-heading">WordPress REST APIにないことはできない</h3>



<p class="wp-block-paragraph">このMCPはWordPressのREST API（記事・固定ページ・メディア・カテゴリなどを操作する窓口）を通して動いているので、そこに用意されていないこと——<strong>サイト全体に適用されるCSSやJavaScript、プラグインの設定、メニューやサイト構成の変更</strong>などは反映できません<br>記事1本ごとのCSSのほうは、後で触れる補助プラグインを入れれば設定できる範囲<br>JSも同じように開放はできますが、安全を考えるとおすすめしません</p>



<p class="wp-block-paragraph">「こう変えたい」と相談すれば書き方や手順の提案はしてくれますが、実際に反映するのはテーマ・カスタマイザー・プラグイン側の作業で、MCPの守備範囲の外になります</p>



<h3 class="wp-block-heading">あえて「触れる範囲」は絞っている</h3>



<p class="wp-block-paragraph">逆に、REST API経由で触れるメタ情報（SEOのディスクリプションなど）は、できる中でも<strong>あえて最小限に絞っています</strong><br>SEOのタイトルやog:imageなども、開放すればMCPから設定できる項目<br>ただ自動で書き換えられる範囲が広いほど、うっかり上書きや、認証情報が漏れたときの被害も大きくなります<br>なので「実際に自動化したいものだけ開けておく」のが安全だと思います</p>



<p class="wp-block-paragraph">具体的には、SEOプラグインのメタディスクリプションやSWELLの投稿別CSSは、標準のWordPressでは外部から書き込めません<br>そこを開けるための<strong>補助プラグイン</strong>をClaudeに作ってもらって、mu-pluginsという特別なフォルダに置いています（置き場所と中身は記事の末尾に）</p>



<p class="wp-block-paragraph">この「Claudeに作ってもらって自分で置く」流れは、MCPサーバー本体を作るときと同じ<br>補助プラグインは<strong>1ファイルの短いPHP</strong>なので、依頼すればすぐ作ってもらえます</p>



<p class="wp-block-paragraph">それから、これは「できない」というより<strong>最後は人が見ておきたい</strong>ところですが、仕上がりの見た目<br>AIはブロックのHTMLを組むところまでで、テーブルの幅やモバイルでの崩れといった<strong>実際の表示までは見えていません</strong><br>ファクトの裏取りと同じ感覚で、公開前にプレビューでさっと目を通しておくと取りこぼしが減ると思います</p>



<p class="wp-block-paragraph">もう1つ、これはMCPというよりAIに記事を書かせるとき全般のコツですが、「リストには下線を付ける」「画像は影付きスタイルにする」のような<strong>自分ルール</strong>を決めておくと、AIはそれに合わせて作ってくれます</p>



<h2 class="wp-block-heading">そもそもMCPって何｜AIと外部サービスを繋ぐ共通規格</h2>



<p class="wp-block-paragraph">「MCP」はModel Context Protocolの略で、Anthropic（Claudeを作っている会社）が提唱しているAIアシスタント業界の新しい標準仕様です</p>



<p class="wp-block-paragraph">ざっくり言うと、<strong>AIに外部のサービスを操作させるための共通言語</strong>のようなものになります</p>



<h3 class="wp-block-heading">MCPで何が変わるのか</h3>



<p class="wp-block-paragraph">これまでもAIに「○○をやって」と頼むことはできましたが、AI自身は実際にWordPressを操作したりファイルを読み書きしたりはできませんでした</p>



<p class="wp-block-paragraph">MCPサーバーを間に挟むことで、AIから外部システムを「ツール」として呼び出せるようになり、AIが実作業まで進められるようになります</p>



<h3 class="wp-block-heading">今回作る仕組みの全体像</h3>



<p class="wp-block-paragraph">図にするとこんな流れになります</p>



<pre class="wp-block-preformatted">[あなた] ⇄ [Claude Code] ⇄ [MCPサーバー] ⇄ [WordPress REST API] ⇄ [WordPress]</pre>



<ul style="background-color:#FFFFDC80" class="wp-block-list -list-under-dashed has-background">
<li>Claude Code が「下書きを保存して」というあなたの指示を理解する</li>



<li>MCPサーバー（自分のPCで動く小さなプログラム）がそれをWordPressが分かる形に翻訳する</li>



<li>WordPress REST API が実際に記事を作成する</li>
</ul>



<p class="wp-block-paragraph">2026年9月に確認した時点では、WordPress公式の<strong>MCP Adapter</strong>はあるものの、投稿を作る・直す能力までは入っていません（くわしくは後ろの節で）<br>なので今回はPythonで自作しました<br>といっても最初は<strong>だいたい200行の小さなもの</strong>をClaudeに作ってもらって、そこから少しずつツールを足していった形です</p>



<p class="wp-block-paragraph">Claude Code自体の基本的な使い方はまた別記事で書こうと思いますが、その前段として<a href="https://javeo.jp/claude-howto-beginner/" target="_blank" rel="noopener noreferrer">Claudeの使い方を初心者向けに解説した記事</a>もあるので、Claudeに触ったことがない人はそちらから読んでもらえると入りやすいです</p>



<h2 class="wp-block-heading">Claudeに「WordPress操作のMCPサーバーを作って」と頼む</h2>



<p class="wp-block-paragraph">MCPサーバーは自分でゼロからコードを書かなくても、<strong>Claude Code本人に作ってもらえます</strong></p>



<p class="wp-block-paragraph">コツは一度に全部を作らせないことで、<strong><span class="swl-marker mark_yellow">1つのツールを作る → 動かしてテスト → 次のツールを足す</span></strong>という小さいサイクルで育てていくと失敗しにくいです</p>


<div class="swell-block-balloon"><div class="c-balloon -bln-left" data-col="blue"><div class="c-balloon__icon -circle"><img decoding="async" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="https://javeo.jp/wp-content/uploads/2026/05/cropped-サイトアイコン2.png" alt="" class="lazyload c-balloon__iconImg" width="80px" height="80px"><noscript><img decoding="async" src="https://javeo.jp/wp-content/uploads/2026/05/cropped-サイトアイコン2.png" alt="" class="c-balloon__iconImg" width="80px" height="80px"></noscript><span class="c-balloon__iconName">ジャベ雄</span></div><div class="c-balloon__body -speaking -border-on"><div class="c-balloon__text">
<p>最初に全部まとめて作らせて、見事にやらかしたんです</p>
<span class="c-balloon__shapes"><span class="c-balloon__before"></span><span class="c-balloon__after"></span></span></div></div></div></div>


<h3 class="wp-block-heading">最初の依頼：土台と接続確認だけ</h3>



<p class="wp-block-paragraph">まずはこんなふうに、使う技術と認証の方針を伝えて土台を作ってもらいます</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">PythonでWordPressを操作するMCPサーバーを作りたいです<br>・FastMCP（mcp.server.fastmcp の FastMCP）を使う<br>・WordPress REST API（/wp-json/wp/v2/）を叩く<br>・認証はアプリケーションパスワードで、認証情報は .env から読む（python-dotenv）<br>・まずは接続確認のツール（サイト名とログインユーザーを返す）だけ作って</p>
</blockquote>



<p class="wp-block-paragraph">ここで<strong><span class="swl-marker mark_yellow">認証情報は .env から読む</span></strong>と最初に指定しておくと、あとの作業が楽になります<br>コードの中にパスワードが残らないので、そのまま公開しても問題ない形</p>



<h3 class="wp-block-heading">ツールを1つずつ足していく</h3>



<p class="wp-block-paragraph">接続確認が通ったら、記事を作るツールから順番に足していきます</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">接続確認が通ったので、記事を下書き保存するツール create_post を追加して<br>デフォルトのstatusはdraft、publishは明示したときだけにして</p>
</blockquote>



<p class="wp-block-paragraph">同じ調子で<strong>list_posts</strong>（一覧取得）、<strong>update_post</strong>（更新）、<strong>get_post</strong>（取得）と1つずつ頼んでいきます<br>カテゴリやタグの一覧取得・新規作成も、同じやり方</p>



<h3 class="wp-block-heading">うまく作ってもらうための小さなコツ</h3>



<ul style="background-color:#FFFFDC80" class="wp-block-list -list-under-dashed has-background">
<li>一度に全機能を作らせない、<strong>1ツールずつ作ってテストしてから</strong>次を足す</li>



<li>認証情報は最初に「.envから読む」と指定する（コードに直書きさせない）</li>



<li>接続確認のツールから作ると、最初の動作確認がすぐできる</li>



<li>エラーが出たら<strong>エラーメッセージをそのまま貼る</strong>と、原因を見つけて直してくれる</li>



<li>「デフォルトはdraft」のような安全側の仕様も、最初の依頼文に入れておく</li>
</ul>



<h2 class="wp-block-heading">Claude Code×WordPress自動投稿のセットアップ手順</h2>



<p class="wp-block-paragraph">Python・Claude Code（Pro以上）・アプリケーションパスワードの3つが揃えば、6ステップで接続確認まで終わります</p>



<h3 class="wp-block-heading">用意するもの</h3>



<figure class="wp-block-table is-style-stripes"><table><thead><tr><th>必要なもの</th><th>補足</th></tr></thead><tbody><tr><td>Claude Code（Desktop版）</td><td>ClaudeのPro / Maxプランで利用可能</td></tr><tr><td>WordPress（自己ホスト型）</td><td>Xserver、ロリポップ、ConoHaなど、バージョンは5.6以上</td></tr><tr><td>Python 3.10以上</td><td>Windows 11なら公式インストーラーで導入</td></tr><tr><td>PowerShell</td><td>Windows 11標準搭載、コマンドを数行打つだけ</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">Claude Codeは有料プラン専用なので、無料で試したい場合はClaudeのコネクタ機能を使う代替手段もあります</p>



<h3 class="wp-block-heading">Step1：プロジェクトフォルダを作る</h3>



<p class="wp-block-paragraph">任意の場所にフォルダを作ります<br>私の場合はデスクトップ</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain" data-lang="text"><code>C:\Users\ユーザー名\Desktop\blog\</code></pre></div>



<h3 class="wp-block-heading">Step2：必要なファイルをClaudeに作ってもらう</h3>



<p class="wp-block-paragraph">前の章で作ってもらった<strong>wp_mcp_server.py</strong>に加えて、動かすために次の3ファイルが必要です<br>いずれもClaudeに頼めば、そのまま作って配置までやってくれます</p>



<ul style="background-color:#FFFFDC80" class="wp-block-list -list-under-dashed has-background">
<li><strong>requirements.txt</strong>（必要なライブラリ一覧）</li>



<li><strong>.mcp.json</strong>（Claude CodeにMCPサーバーの場所を教える設定）</li>



<li><strong>.env</strong>（WordPressの認証情報を書く、<span class="swl-marker mark_yellow">中身は次のステップで自分で書く</span>）</li>
</ul>



<p class="wp-block-paragraph">こんな感じで頼めばまとめて作ってくれます</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">このサーバーを動かすのに必要な requirements.txt と .mcp.json も作って、同じフォルダに置いて<br>.env は中身が認証情報なので、空のテンプレート（WP_BLOG_BASE_URL / WP_BLOG_USERNAME / WP_BLOG_APP_PASSWORD の3つを書く枠）だけ作っておいて</p>
</blockquote>



<p class="wp-block-paragraph">.mcp.json や CLAUDE.md のような設定ファイルがどこに置かれて何をするのかは、最初はちょっと分かりにくいので、別記事で一覧にしてあります</p>


<div class="swell-block-postLink">			<div class="p-blogCard -internal" data-type="type1" data-onclick="clickLink">
				<div class="p-blogCard__inner">
					<span class="p-blogCard__caption">あわせて読みたい</span>
					<div class="p-blogCard__thumb c-postThumb"><figure class="c-postThumb__figure"><img decoding="async" src="https://javeo.jp/wp-content/uploads/2026/05/claude-thumbnail-300x158.png" alt="" class="c-postThumb__img u-obf-cover" width="320" height="180"></figure></div>					<div class="p-blogCard__body">
						<a class="p-blogCard__title" href="https://javeo.jp/claude-code-config-files-guide/" target="_blank" rel="noopener noreferrer">Claude Code 設定ファイル早見表 役割と場所</a>
						<span class="p-blogCard__excerpt">Claude Codeを触っていると次々に登場する設定ファイル(CLAUDE.md・settings.json・AGENT.md・SKILL.mdなど)を、保存場所と役割で一覧化した早見表記事です、微調整目線で抑えたい初心者〜中級者向けにまとめました</span>					</div>
				</div>
			</div>
		</div>


<p class="wp-block-paragraph"><strong><span class="swl-marker mark_yellow">.envの中身（=認証情報）だけは人が書きます</span></strong><br>ここはClaudeに渡さない情報なので、空のテンプレートだけ作ってもらって、値は次のステップで自分で埋めるのが安全です</p>



<h3 class="wp-block-heading">Step3：Pythonライブラリのインストールも頼める</h3>



<p class="wp-block-paragraph">requirements.txtができたら、ライブラリのインストールもClaudeに頼めます</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">requirements.txt のライブラリをインストールして</p>
</blockquote>



<p class="wp-block-paragraph">これで mcp・requests・markdown などのパッケージが入ります<br>自分で実行したい場合は、PowerShellで次のコマンドでもOK</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-powershell" data-lang="PowerShell"><code>cd C:\Users\ユーザー名\Desktop\blog\
python -m pip install -r requirements.txt</code></pre></div>



<h3 class="wp-block-heading">Step4：WordPressでアプリケーションパスワードを発行</h3>



<p class="wp-block-paragraph">ここが今回の肝<br>普段のログインパスワードではなく <strong>API専用の使い捨てパスワード</strong>を発行します</p>



<ol style="background-color:#f3fafe80" class="wp-block-list -list-under-dashed has-background">
<li>WordPress管理画面にログインして「ユーザー → プロフィール」を開く</li>



<li>ページ最下部にある「アプリケーションパスワード」欄まで移動</li>



<li>名前を入力（例：Claude MCP）して「新しいアプリケーションパスワードを追加」をクリック</li>



<li><strong>xxxx xxxx xxxx xxxx xxxx xxxx</strong> 形式の文字列が表示されるのでコピー</li>
</ol>



<figure class="wp-block-image size-large is-style-shadow"><a href="https://javeo.jp/wp-content/uploads/2026/05/2026-05-20_18h28_21.png"><img decoding="async" width="1024" height="538" src="https://javeo.jp/wp-content/uploads/2026/05/2026-05-20_18h28_21-1024x538.png" alt="WordPressのプロフィール画面にあるアプリケーションパスワードの欄" class="wp-image-4009" srcset="https://javeo.jp/wp-content/uploads/2026/05/2026-05-20_18h28_21-1024x538.png 1024w, https://javeo.jp/wp-content/uploads/2026/05/2026-05-20_18h28_21-300x158.png 300w, https://javeo.jp/wp-content/uploads/2026/05/2026-05-20_18h28_21-150x79.png 150w, https://javeo.jp/wp-content/uploads/2026/05/2026-05-20_18h28_21-768x403.png 768w, https://javeo.jp/wp-content/uploads/2026/05/2026-05-20_18h28_21.png 1198w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large is-style-shadow"><a href="https://javeo.jp/wp-content/uploads/2026/05/2026-05-20_18h28_30.png"><img decoding="async" width="1024" height="538" src="https://javeo.jp/wp-content/uploads/2026/05/2026-05-20_18h28_30-1024x538.png" alt="発行直後に一度だけ表示されるアプリケーションパスワード" class="wp-image-4010" srcset="https://javeo.jp/wp-content/uploads/2026/05/2026-05-20_18h28_30-1024x538.png 1024w, https://javeo.jp/wp-content/uploads/2026/05/2026-05-20_18h28_30-300x158.png 300w, https://javeo.jp/wp-content/uploads/2026/05/2026-05-20_18h28_30-150x79.png 150w, https://javeo.jp/wp-content/uploads/2026/05/2026-05-20_18h28_30-768x403.png 768w, https://javeo.jp/wp-content/uploads/2026/05/2026-05-20_18h28_30.png 1198w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<div class="wp-block-group is-style-big_icon_caution"><div class="wp-block-group__inner-container">
<p class="wp-block-paragraph"><strong><span class="swl-marker mark_yellow" style="color:#e8313b">この画面を閉じると二度と表示されません</span></strong><br>すぐ次のステップで貼り付けてください</p>
</div></div>



<h3 class="wp-block-heading">Step5：.envファイルに認証情報を書く</h3>



<p class="wp-block-paragraph">Step2でClaudeに枠だけ作ってもらった .env ファイルを開いて、次の3つの値を自分で埋めます</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain" data-lang=".env"><code>WP_BLOG_BASE_URL=https://あなたのドメイン
WP_BLOG_USERNAME=WordPressのログインユーザー名
WP_BLOG_APP_PASSWORD=xxxx xxxx xxxx xxxx xxxx xxxx</code></pre></div>



<p class="wp-block-paragraph">アプリケーションパスワードはスペース込みのままで大丈夫なので、わざわざ削る必要はありません</p>



<p class="wp-block-paragraph">末尾に載せた完全版は、旧い名前の WP_BASE_URL / WP_USERNAME / WP_APP_PASSWORD も同じ意味で読みます</p>



<h3 class="wp-block-heading">Step6：Claude Codeで動作確認</h3>



<p class="wp-block-paragraph">このフォルダでClaude Codeを起動すると、<strong>.mcp.json</strong> が自動で検出されてMCPサーバーの起動許可を求められます<br>「Allow」を押してください</p>



<p class="wp-block-paragraph">その後Claude Codeに次のように頼みます</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">「WordPressの接続確認をして」</p>
</blockquote>



<p class="wp-block-paragraph">サイト名とログインユーザー名が返ってくれば接続成功<br>ここでやっとひと息つけます</p>


<div class="p-blogParts post_content" data-partsID="5291">
<div class="jv-adshelf" data-shelf="ai">
<style>
.jv-adshelf{border:1px solid #d7ddea;border-radius:8px;background:#f8faff;padding:16px 18px;margin:2em 0}
.jv-adshelf__head{display:flex;align-items:center;gap:8px;margin-bottom:14px}
.jv-adshelf__title{font-weight:700;font-size:1.02em;line-height:1.4}
.jv-adshelf__pr{flex:none;font-size:.7em;font-weight:700;color:#fff;background:#8a94a6;border-radius:3px;padding:2px 6px;letter-spacing:.04em}
.jv-adshelf__card{display:flex;gap:16px;align-items:flex-start;flex-wrap:wrap;padding:14px 0}
.jv-adshelf__card+.jv-adshelf__card{border-top:1px dashed #d7ddea}
.jv-adshelf__banner{flex:0 0 200px;max-width:100%;display:flex;align-items:center;justify-content:center}
.jv-adshelf__banner img{max-width:100%;height:auto;display:block}
.jv-adshelf__body{flex:1 1 260px;min-width:0}
.jv-adshelf__name{font-weight:700;margin:0 0 6px;font-size:.95em;line-height:1.5}
.jv-adshelf__desc{margin:0 0 12px;font-size:.9em;line-height:1.8;color:#3d4451}
.jv-adshelf__btn{display:inline-block;background:#3B5BDB;color:#fff;font-weight:700;font-size:.9em;text-decoration:none;border-radius:5px;padding:9px 18px}
.jv-adshelf__btn:hover{opacity:.88}
@media(max-width:600px){.jv-adshelf__banner{flex:0 0 100%;max-width:240px;margin:0 auto}}
</style>
<div class="jv-adshelf__head"><span class="jv-adshelf__title">AIで仕事を減らしたい方へ</span><span class="jv-adshelf__pr">PR</span></div>
<div class="jv-adshelf__card">
<div class="jv-adshelf__banner"><a href="//af.moshimo.com/af/c/click?a_id=5654017&#038;p_id=7494&#038;pc_id=21647&#038;pl_id=93995" rel="nofollow" referrerpolicy="no-referrer-when-downgrade" attributionsrc><img decoding="async" src="//image.moshimo.com/af-img/7302/000000093995.png" width="500" height="500" style="border:none;"></a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=5654017&#038;p_id=7494&#038;pc_id=21647&#038;pl_id=93995" width="1" height="1" style="border:none;" loading="lazy"></div>
<div class="jv-adshelf__body">
<p class="jv-adshelf__name">AI鬼管理｜Claude Code活用の業務自動化トレーニング</p>
<p class="jv-adshelf__desc">Claude Code を業務の自動化に使うためのトレーニングです<br>いきなり申し込む形ではなく、まずは無料の業務効率化診断(オンライン面談)から始められます</p>
<a class="jv-adshelf__btn" href="//af.moshimo.com/af/c/click?a_id=5654017&#038;p_id=7494&#038;pc_id=21647&#038;pl_id=93995" target="_blank" rel="nofollow noopener" referrerpolicy="no-referrer-when-downgrade">無料の業務効率化診断を見てみる</a>
</div>
</div>
<div class="jv-adshelf__card">
<div class="jv-adshelf__banner"><a href="https://px.a8.net/svt/ejp?a8mat=4B41ZJ+57JLVM+5988+609HT" rel="nofollow"><img decoding="async" border="0" width="300" height="250" alt="" src="https://www23.a8.net/svt/bgt?aid=260529679315&#038;wid=003&#038;eno=01&#038;mid=s00000024524001009000&#038;mc=1"></a><img decoding="async" border="0" width="1" height="1" src="https://www14.a8.net/0.gif?a8mat=4B41ZJ+57JLVM+5988+609HT" alt=""></div>
<div class="jv-adshelf__body">
<p class="jv-adshelf__name">Notta｜AI自動文字起こし</p>
<p class="jv-adshelf__desc">会議や動画の音声を自動で文字にするサービスです<br>議事録や書き起こしの手作業を減らしたいときに</p>
<a class="jv-adshelf__btn" href="https://px.a8.net/svt/ejp?a8mat=4B41ZJ+57JLVM+5988+609HT" target="_blank" rel="nofollow noopener" referrerpolicy="no-referrer-when-downgrade">Nottaを見てみる</a>
</div>
</div>
</div>
</div>


<h2 class="wp-block-heading">作ってもらったサーバーの動作テスト手順</h2>



<p class="wp-block-paragraph">MCPサーバーのテストは<strong><span class="swl-marker mark_yellow">Claudeに実際に実行させて、会話で結果を確認するのが一番早い</span></strong>です</p>



<p class="wp-block-paragraph">ツールを1つ足すたびに次の流れを回しておくと、どこかが壊れた瞬間に気づけます<br>本格的なテストコード（pytestなど）を書くのは、仕様が固まってからで十分だと思います</p>



<div class="swell-block-step" data-num-style="circle">
<div class="swell-block-step__item"><div class="swell-block-step__number u-bg-main"><span class="__label">STEP</span></div><div class="swell-block-step__title u-fz-l">接続を確認する</div><div class="swell-block-step__body">
<p class="wp-block-paragraph">「WordPressの接続確認をして」と頼んで、サイト名とログインユーザー名が返ってくればまず合格です</p>
</div></div>



<div class="swell-block-step__item"><div class="swell-block-step__number u-bg-main"><span class="__label">STEP</span></div><div class="swell-block-step__title u-fz-l">テスト用の下書きを作る</div><div class="swell-block-step__body">
<p class="wp-block-paragraph">「テスト用の下書きを1件作って、投稿IDを教えて」と頼みます<br>WordPress管理画面の投稿一覧に下書きが増えていれば作成は成功</p>
</div></div>



<div class="swell-block-step__item"><div class="swell-block-step__number u-bg-main"><span class="__label">STEP</span></div><div class="swell-block-step__title u-fz-l">一覧と中身を取得する</div><div class="swell-block-step__body">
<p class="wp-block-paragraph">「下書き一覧を出して」「さっきの投稿の中身を見せて」と頼んで、取得系のツールがちゃんと動くかを見ます</p>
</div></div>



<div class="swell-block-step__item"><div class="swell-block-step__number u-bg-main"><span class="__label">STEP</span></div><div class="swell-block-step__title u-fz-l">テスト投稿を片付ける</div><div class="swell-block-step__body">
<p class="wp-block-paragraph">「さっきのテスト投稿を削除して」で後片付けまでできれば、作成から削除まで一通り通ったことになります</p>
</div></div>



<div class="swell-block-step__item"><div class="swell-block-step__number u-bg-main"><span class="__label">STEP</span></div><div class="swell-block-step__title u-fz-l">わざと失敗させてみる</div><div class="swell-block-step__body">
<p class="wp-block-paragraph">.envのパスワードを1文字だけ変えて、401（認証失敗）が分かりやすく返るかも見ておきます<br>エラーのときに何が起きたか分かる作りになっていれば、ひと安心<br>確認できたらパスワードは元に戻します</p>
</div></div>
</div>



<p class="wp-block-paragraph">この「会話で1ツールずつ叩く」テストの積み重ねが、結局いちばん速くて確実でした</p>



<h2 class="wp-block-heading">Claude Codeで実際に記事を投稿する流れ</h2>



<p class="wp-block-paragraph">セットアップが終わったら、基本はチャットで会話しながら書いてもらうだけです</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">「ExcelのVLOOKUPについて、初心者向けに1000字程度で解説記事を書いて、下書きで保存しておいて」</p>
</blockquote>



<p class="wp-block-paragraph">これだけで、Claudeが記事本文を生成して<strong>create_post</strong>ツール経由でWordPressに下書きとして投稿してくれます</p>



<p class="wp-block-paragraph">あとは管理画面でプレビューして、必要なら手直しして「公開」を押すだけです</p>



<h3 class="wp-block-heading">運用上の3つの注意点</h3>



<p class="wp-block-paragraph">便利な仕組みですが、AIに丸投げで運用する前にいくつか注意点があります</p>



<div class="wp-block-group is-style-big_icon_point"><div class="wp-block-group__inner-container">
<ul class="wp-block-list -list-under-dashed">
<li><strong>下書き保存を原則とする</strong>:AIが書いた記事は人間が目視チェックしてから公開する、私のセットアップではデフォルトを<strong>draft</strong>に固定しています</li>



<li><strong>認証情報はコミットしない</strong>:.env には認証情報が入るので、GitHubなどに公開しないよう .gitignore に原則追加</li>



<li><strong>ハルシネーション対策</strong>:固有名詞・日付・数字・出典は鵜呑みにせず裏取りを推奨</li>
</ul>
</div></div>



<p class="wp-block-paragraph">特にハルシネーション対策は、<a href="https://javeo.jp/claude-howto-beginner/" target="_blank" rel="noopener noreferrer">生成AIの裏取りのやり方</a>のところでも書いた通り、AI全般で気をつけたいポイントです</p>



<h2 class="wp-block-heading">自作しない選択肢｜公式のMCP Adapterと橋渡しプラグイン</h2>



<p class="wp-block-paragraph">2026年9月に確認した限りでは、<strong>プラグインを2つ入れるだけでも記事の下書き投稿までは届きます</strong><br>ただし私の環境で公式ルートを丸ごと動かしてみたわけではないので、ここからは公開されている説明を読んだ範囲での整理</p>



<p class="wp-block-paragraph">土台になるのがWordPress公式の<strong>MCP Adapter</strong>で、WordPress側にAIからの窓口を1つ開けるだけの部品みたいな感じです<br>でも、入れただけで見えるようになるのは discover / get-ability-info / execute の3つで、肝心の能力は既定で非公開のまま</p>



<p class="wp-block-paragraph">WordPress 6.9本体が持っている能力も、サイト情報・ユーザー情報・環境情報の3つだけ<br>投稿を作る・直す能力は<strong>7.2以降に先送り</strong>と公式の提案に書かれていて、読み取り専用のものすら7.1では見送られました</p>



<p class="wp-block-paragraph">だから、足りないところを外から足す橋渡しプラグインが出てきています（2つとも動かすには WordPress 6.9以上が前提）<br><strong>Enable Abilities for MCP</strong>は投稿の作成・更新・削除を含む112個の能力を足してくれて、Claude.aiから繋ぐためのOAuthコネクタまで入っているとのことでした</p>



<p class="wp-block-paragraph">MCPやコネクタといった言葉の意味は、<a href="https://javeo.jp/claude-glossary-beginner/" target="_blank" rel="noopener noreferrer">Claude用語集</a>のほうにまとめてあります</p>



<ul style="background-color:#FFFFDC80" class="wp-block-list -list-under-dashed has-background">
<li>SEOのメタは <strong>Yoast / Rank Math / SEOPress</strong> に対応、SEO SIMPLE PACK は書かれていない</li>



<li>MCP Adapterの既定の権限チェックは<strong>ログイン済みなら通る</strong>形なので、使うなら権限の設定をちゃんと足すことになる</li>



<li><strong>MCP Adapter</strong>はまだ1.0より前なので、バージョンが上がると書き方が変わることがある</li>



<li>旧 Automattic/wordpress-mcp は2026年1月にアーカイブ済み、READMEにも新規で使わないよう書かれている</li>
</ul>



<p class="wp-block-paragraph">私は公式ルートに寄せるかでちょっと迷いましたが、結局この記事の自作方式のままです<br>SEO SIMPLE PACK のメタだったり、3サイトの切り替えだったりが要るので、いまの公式ルートだと足りないままなんです</p>



<p class="wp-block-paragraph">逆に<strong>WordPressは1サイトだけ・SEOはYoastかRank Math・自作は避けたい</strong>という条件なら、やっぱり公式ルートのほうが近道だと思います</p>


<div class="swell-block-balloon"><div class="c-balloon -bln-left" data-col="blue"><div class="c-balloon__icon -circle"><img decoding="async" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="https://javeo.jp/wp-content/uploads/2026/05/cropped-サイトアイコン2.png" alt="" class="lazyload c-balloon__iconImg" width="80px" height="80px"><noscript><img decoding="async" src="https://javeo.jp/wp-content/uploads/2026/05/cropped-サイトアイコン2.png" alt="" class="c-balloon__iconImg" width="80px" height="80px"></noscript><span class="c-balloon__iconName">ジャベ雄</span></div><div class="c-balloon__body -speaking -border-on"><div class="c-balloon__text">
<p>公式が育ったら、自作のほうは引退させる予定です</p>
<span class="c-balloon__shapes"><span class="c-balloon__before"></span><span class="c-balloon__after"></span></span></div></div></div></div>


<h2 class="wp-block-heading">まとめ｜AIに任せる作業と人間がやるべき作業</h2>



<p class="wp-block-paragraph">AIに渡せたのは、下書き作成・装飾・メタ設定の3つでした</p>



<figure class="wp-block-table is-style-stripes"><table><thead><tr><th>やったこと</th><th>できるようになったこと</th></tr></thead><tbody><tr><td>MCPサーバー本体をClaudeに作ってもらう</td><td>Claude CodeからWordPressを直接操作（記事・カテゴリ・タグ・メタ・アイキャッチ）</td></tr><tr><td>アプリケーションパスワードで認証</td><td>普段のログインパスワードを使わずに済む</td></tr><tr><td>補助プラグインで触れる範囲を選ぶ</td><td>必要な項目（メタディスクリプション・投稿別CSS）だけ安全に開放</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">最初の接続確認さえ通れば「テーマを伝える → 下書きが管理画面にできてる」という流れがとても快適です</p>



<p class="wp-block-paragraph">個人的に思うのは、<strong><span class="swl-marker mark_yellow">「AIに全部任せる」じゃなくて、手間のかかる部分をAIに渡して、最後の判断は人間がする</span></strong>、この役割分担がちょうど良い距離感でした</p>



<p class="wp-block-paragraph">ここまで読むと細かい手順や注意点が多く見えるかもしれませんが、実際にはこの記事で書いたほど細かく指示しなくても、<strong><span class="swl-marker mark_yellow">Claudeが自分で判断してよしなに進めてくれる場面が多い</span></strong>です<br>必要なら途中で「ここはこうして」と相談すれば直してくれるので、まずは小さく頼んで動かしてみるところから始めてみてください</p>



<p class="wp-block-paragraph">同じくWordPress×AIの自動投稿を試したい方の参考になれば嬉しいです</p>


<div class="swell-block-balloon"><div class="c-balloon -bln-left" data-col="blue"><div class="c-balloon__icon -circle"><img decoding="async" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="https://javeo.jp/wp-content/uploads/2026/05/cropped-サイトアイコン2.png" alt="" class="lazyload c-balloon__iconImg" width="80px" height="80px"><noscript><img decoding="async" src="https://javeo.jp/wp-content/uploads/2026/05/cropped-サイトアイコン2.png" alt="" class="c-balloon__iconImg" width="80px" height="80px"></noscript><span class="c-balloon__iconName">ジャベ雄</span></div><div class="c-balloon__body -speaking -border-on"><div class="c-balloon__text">
<p>私も最初の1個は、接続確認だけでした</p>
<span class="c-balloon__shapes"><span class="c-balloon__before"></span><span class="c-balloon__after"></span></span></div></div></div></div>


<h2 class="wp-block-heading">コード全文と設定ファイル｜コピペで使う場合</h2>



<p class="wp-block-paragraph">完全版は<strong>18個のツールで、だいたい900行</strong><br>複数サイトの切り替え・Markdownファイルからの一発入稿・アイキャッチの設定・メディアのアップロードまで入っている形</p>



<h3 class="wp-block-heading">requirements.txt</h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain" data-lang="requirements.txt"><code>mcp&gt;=1.2.0
requests&gt;=2.32.0
python-dotenv&gt;=1.0.0
markdown&gt;=3.6
python-frontmatter&gt;=1.1.0</code></pre></div>



<h3 class="wp-block-heading">.mcp.json</h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-json" data-lang="JSON"><code>{
  &quot;mcpServers&quot;: {
    &quot;wordpress&quot;: {
      &quot;command&quot;: &quot;python&quot;,
      &quot;args&quot;: [&quot;C:\\path\\to\\wp_mcp_server.py&quot;],
      &quot;env&quot;: {}
    }
  }
}</code></pre></div>



<h3 class="wp-block-heading">wp_mcp_server.py（最小形の抜粋）</h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-file="wp_mcp_server.py" data-lang="Python"><code>from mcp.server.fastmcp import FastMCP
import os, requests
from dotenv import load_dotenv

load_dotenv()
WP_BASE_URL = os.getenv(&quot;WP_BASE_URL&quot;, &quot;&quot;).rstrip(&quot;/&quot;)
WP_USERNAME = os.getenv(&quot;WP_USERNAME&quot;, &quot;&quot;)
WP_APP_PASSWORD = os.getenv(&quot;WP_APP_PASSWORD&quot;, &quot;&quot;)
API_BASE = f&quot;{WP_BASE_URL}/wp-json/wp/v2&quot;

mcp = FastMCP(&quot;wordpress&quot;)

@mcp.tool()
def create_post(title: str, content: str, status: str = &quot;draft&quot;) -&gt; dict:
    &quot;&quot;&quot;新しい記事をWordPressに作成する（デフォルトは下書き）&quot;&quot;&quot;
    resp = requests.post(
        f&quot;{API_BASE}/posts&quot;,
        auth=(WP_USERNAME, WP_APP_PASSWORD),
        json={&quot;title&quot;: title, &quot;content&quot;: content, &quot;status&quot;: status},
        timeout=30,
    )
    resp.raise_for_status()
    return resp.json()

if __name__ == &quot;__main__&quot;:
    mcp.run()</code></pre></div>



<p class="wp-block-paragraph">この抜粋は旧い名前の WP_BASE_URL のほうを読む形なので、<strong>WP_BLOG_*</strong> で揃えるなら下のコード全文を使ってください</p>



<p class="wp-block-paragraph">短いコードですが、仕組みのポイントはこのあたりです</p>



<ul style="background-color:#FFFFDC80" class="wp-block-list -list-under-dashed has-background">
<li><strong>FastMCP(&#8220;wordpress&#8221;)</strong> でサーバーを1つ定義する</li>



<li><strong><span class="swl-marker mark_yellow">@mcp.tool() を付けた関数が、そのままClaudeから呼べるツールになる</span></strong></li>



<li>関数の説明文（docstring）が「このツールは何をするか」のClaude向けの説明になるので、日本語で丁寧に書いておく</li>



<li>認証・タイムアウト・エラー処理は共通の関数にまとめて、各ツールはそれを呼ぶだけにすると見通しが良い</li>



<li>接続先のサイトを引数で切り替えられるようにすると、複数サイトの運用にも対応できる</li>
</ul>



<p class="wp-block-paragraph">完成版もこの形で、create_post・update_post・upload_media などのツールを登録しています</p>



<p class="wp-block-paragraph">このサーバーをそっくり真似しなくても、<strong>「こういうツールが欲しい」とClaudeに伝えて1つずつ足していく</strong>やり方なら、自分の運用に合った形が作れます</p>



<h3 class="wp-block-heading">wp_mcp_server.py（コード全文）</h3>



<p class="wp-block-paragraph">.env に書くキーは <strong>WP_BLOG_BASE_URL / WP_BLOG_USERNAME / WP_BLOG_APP_PASSWORD</strong> の3つ<br>メタディスクリプションまで書き込みたいときは、次の補助プラグインもセットで要ります</p>



<div class="swell-block-accordion">
<details class="swell-block-accordion__item" data-swl-acc="wrapper"><summary class="swell-block-accordion__title" data-swl-acc="header"><span class="swell-block-accordion__label">コード全文（コピペ用）</span><span class="swell-block-accordion__icon c-switchIconBtn" data-swl-acc="icon" aria-hidden="true" data-opened="false"><i class="__icon--closed icon-caret-down"></i><i class="__icon--opened icon-caret-up"></i></span></summary><div class="swell-block-accordion__body" data-swl-acc="body">
<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-file="wp_mcp_server.py" data-lang="Python"><code>&quot;&quot;&quot;WordPress MCP Server (multi-site).

WordPress REST API(`/wp-json/wp/v2/`)とアプリケーションパスワード認証を使い、
Claude Code などの MCP クライアントから 投稿(posts)・固定ページ(pages)・メディア・
カテゴリ / タグ を操作するための MCP サーバー。

複数サイト対応:
  .env に `WP_&lt;NAME&gt;_BASE_URL` / `WP_&lt;NAME&gt;_USERNAME` / `WP_&lt;NAME&gt;_APP_PASSWORD` を置くと、
  `&lt;NAME&gt;` を小文字にしたものがサイト名になる(例: WP_BLOG_* → site=&quot;blog&quot;)。
  サイトはいくつでも登録でき、各ツールの `site` 引数で切り替える。

任意の環境変数:
  WP_DEFAULT_SITE                : site 省略時に使うサイト名(未設定なら &quot;blog&quot; があれば blog、無ければ最初に見つかったサイト)
  WP_&lt;NAME&gt;_AUTHOR_ID            : 新規作成する投稿・固定ページの著者 user_id(更新には影響しない)
  WP_META_DESCRIPTION_KEY        : frontmatter の meta_description を書き込む post meta キー
                                   (既定 &quot;ssp_meta_description&quot; = SEO SIMPLE PACK。空文字にすると書き込まない)
  WP_&lt;NAME&gt;_META_DESCRIPTION_KEY : 上をサイト別に上書きしたい場合
  ※ 書き込み先の meta キーは REST 公開(register_post_meta の show_in_rest)されている必要がある。
    SEO SIMPLE PACK 用の補助プラグインは mu-plugins/ssp-meta-rest.php を参照。

後方互換: 旧キー WP_BASE_URL / WP_USERNAME / WP_APP_PASSWORD は site=&quot;blog&quot; の別名として認識する。
&quot;&quot;&quot;

from __future__ import annotations

import os
import re
import sys
from pathlib import Path
from typing import Any

import frontmatter
import markdown as md
import requests
from dotenv import load_dotenv
from mcp.server.fastmcp import FastMCP

ROOT = Path(__file__).resolve().parent
load_dotenv(ROOT / &quot;.env&quot;)

TIMEOUT = 30

mcp = FastMCP(&quot;wordpress&quot;)


# =========================================================================
# サイト別認証情報の解決
# =========================================================================

# サイトは環境変数から自動発見する: WP_&lt;NAME&gt;_BASE_URL の &lt;NAME&gt; を小文字化したものがサイト名
_SITE_KEY_RE = re.compile(r&quot;^WP_([A-Z0-9]+)_BASE_URL$&quot;)
_LEGACY_BLOG_KEYS = {&quot;BASE_URL&quot;: &quot;WP_BASE_URL&quot;, &quot;USERNAME&quot;: &quot;WP_USERNAME&quot;, &quot;APP_PASSWORD&quot;: &quot;WP_APP_PASSWORD&quot;}


def _discover_sites() -&gt; list[str]:
    &quot;&quot;&quot;登録済みサイト名を列挙する(blog を先頭に、あとは名前順)。&quot;&quot;&quot;
    names: set[str] = set()
    for key, val in os.environ.items():
        m = _SITE_KEY_RE.match(key)
        if m and val.strip():
            names.add(m.group(1).lower())
    if os.getenv(&quot;WP_BASE_URL&quot;, &quot;&quot;).strip():
        names.add(&quot;blog&quot;)  # 旧キー(WP_BASE_URL / WP_USERNAME / WP_APP_PASSWORD)は blog の別名
    return sorted(names, key=lambda n: (n != &quot;blog&quot;, n))


def _env_for(site: str, suffix: str) -&gt; str:
    &quot;&quot;&quot;site 用の環境変数 WP_&lt;SITE&gt;_&lt;suffix&gt; を返す。site=&quot;blog&quot; は旧キーにもフォールバックする。&quot;&quot;&quot;
    val = os.getenv(f&quot;WP_{site.upper()}_{suffix}&quot;, &quot;&quot;).strip()
    if not val and site == &quot;blog&quot; and suffix in _LEGACY_BLOG_KEYS:
        val = os.getenv(_LEGACY_BLOG_KEYS[suffix], &quot;&quot;).strip()
    return val


def _default_site() -&gt; str:
    env = os.getenv(&quot;WP_DEFAULT_SITE&quot;, &quot;&quot;).strip().lower()
    if env:
        return env
    sites = _discover_sites()
    if not sites or &quot;blog&quot; in sites:
        return &quot;blog&quot;
    return sites[0]


DEFAULT_SITE = _default_site()


def _default_author(site: str) -&gt; int:
    &quot;&quot;&quot;新規作成時に立てる著者(user_id)。WP_&lt;SITE&gt;_AUTHOR_ID が数値なら送る。
    未設定なら author を送らない(= 認証ユーザーが著者)。更新系は author を送らないので影響しない。&quot;&quot;&quot;
    raw = _env_for((site or DEFAULT_SITE).strip().lower(), &quot;AUTHOR_ID&quot;)
    return int(raw) if raw.isdigit() else 0


def _meta_description_key(site: str) -&gt; str:
    &quot;&quot;&quot;frontmatter の meta_description を書き込む post meta キー。空文字なら書き込まない。
    優先順: WP_&lt;SITE&gt;_META_DESCRIPTION_KEY &gt; WP_META_DESCRIPTION_KEY &gt; &quot;ssp_meta_description&quot;(SEO SIMPLE PACK)。&quot;&quot;&quot;
    site = (site or DEFAULT_SITE).strip().lower()
    for key in (f&quot;WP_{site.upper()}_META_DESCRIPTION_KEY&quot;, &quot;WP_META_DESCRIPTION_KEY&quot;):
        if key in os.environ:
            return os.environ[key].strip()
    return &quot;ssp_meta_description&quot;


def _site_config(site: str) -&gt; dict[str, str]:
    site = (site or DEFAULT_SITE).strip().lower()
    known = _discover_sites()
    if site not in known:
        raise ValueError(
            f&quot;未知の site 名: {site!r}。.env に登録済みのサイト: {known}&quot;
            f&quot;(WP_{site.upper()}_BASE_URL / _USERNAME / _APP_PASSWORD を追加すると使えます)&quot;
        )
    return {
        &quot;site&quot;: site,
        &quot;base_url&quot;: _env_for(site, &quot;BASE_URL&quot;).rstrip(&quot;/&quot;),
        &quot;username&quot;: _env_for(site, &quot;USERNAME&quot;),
        &quot;password&quot;: _env_for(site, &quot;APP_PASSWORD&quot;),
    }


def _require_credentials(site: str) -&gt; dict[str, str]:
    cfg = _site_config(site)
    missing = [
        label
        for label, val in (
            (&quot;BASE_URL&quot;, cfg[&quot;base_url&quot;]),
            (&quot;USERNAME&quot;, cfg[&quot;username&quot;]),
            (&quot;APP_PASSWORD&quot;, cfg[&quot;password&quot;]),
        )
        if not val
    ]
    if missing:
        prefix = f&quot;WP_{cfg['site'].upper()}_&quot;
        env_hint = &quot; / &quot;.join(prefix + label for label in (&quot;BASE_URL&quot;, &quot;USERNAME&quot;, &quot;APP_PASSWORD&quot;))
        raise RuntimeError(
            f&quot;site={cfg['site']!r} の認証情報が不足: {', '.join(missing)}。&quot;
            f&quot;{ROOT / '.env'} に {env_hint} を設定してください&quot;
        )
    return cfg


def _request(method: str, path: str, *, site: str = DEFAULT_SITE, **kwargs: Any) -&gt; Any:
    cfg = _require_credentials(site)
    url = f&quot;{cfg['base_url']}/wp-json/wp/v2{path}&quot;
    resp = requests.request(
        method,
        url,
        auth=(cfg[&quot;username&quot;], cfg[&quot;password&quot;]),
        timeout=TIMEOUT,
        headers={&quot;Accept&quot;: &quot;application/json&quot;, **kwargs.pop(&quot;headers&quot;, {})},
        **kwargs,
    )
    if not resp.ok:
        raise RuntimeError(
            f&quot;WordPress API [{site}] {method} {path} failed: HTTP {resp.status_code} - {resp.text[:500]}&quot;
        )
    if resp.status_code == 204 or not resp.content:
        return None
    return resp.json()


# =========================================================================
# 汎用ヘルパー
# =========================================================================

def _resolve_terms(taxonomy: str, names_or_ids: list[str | int], *, site: str) -&gt; list[int]:
    &quot;&quot;&quot;カテゴリ・タグの名前を ID に変換。存在しない名前は新規作成する。&quot;&quot;&quot;
    if not names_or_ids:
        return []
    ids: list[int] = []
    for item in names_or_ids:
        if isinstance(item, int):
            ids.append(item)
            continue
        s = str(item).strip()
        if s.isdigit():
            ids.append(int(s))
            continue
        existing = _request(&quot;GET&quot;, f&quot;/{taxonomy}&quot;, site=site, params={&quot;search&quot;: s, &quot;per_page&quot;: 100})
        match = next((t for t in existing if t.get(&quot;name&quot;) == s), None)
        if match:
            ids.append(int(match[&quot;id&quot;]))
        else:
            created = _request(&quot;POST&quot;, f&quot;/{taxonomy}&quot;, site=site, json={&quot;name&quot;: s})
            ids.append(int(created[&quot;id&quot;]))
    return ids


def _markdown_to_html(text: str) -&gt; str:
    return md.markdown(
        text,
        extensions=[&quot;extra&quot;, &quot;sane_lists&quot;, &quot;toc&quot;],
        output_format=&quot;html5&quot;,
    )


def _entity_summary(entity: dict[str, Any]) -&gt; dict[str, Any]:
    &quot;&quot;&quot;投稿(post)または固定ページ(page)の共通サマリを返す。&quot;&quot;&quot;
    return {
        &quot;id&quot;: entity.get(&quot;id&quot;),
        &quot;status&quot;: entity.get(&quot;status&quot;),
        &quot;title&quot;: (entity.get(&quot;title&quot;) or {}).get(&quot;rendered&quot;) or (entity.get(&quot;title&quot;) or {}).get(&quot;raw&quot;),
        &quot;slug&quot;: entity.get(&quot;slug&quot;),
        &quot;link&quot;: entity.get(&quot;link&quot;),
        &quot;date&quot;: entity.get(&quot;date&quot;),
        &quot;modified&quot;: entity.get(&quot;modified&quot;),
        &quot;type&quot;: entity.get(&quot;type&quot;),
        &quot;parent&quot;: entity.get(&quot;parent&quot;),
        &quot;menu_order&quot;: entity.get(&quot;menu_order&quot;),
        &quot;categories&quot;: entity.get(&quot;categories&quot;, []),
        &quot;tags&quot;: entity.get(&quot;tags&quot;, []),
    }


# =========================================================================
# 接続確認
# =========================================================================

@mcp.tool()
def check_connection(site: str = DEFAULT_SITE) -&gt; dict[str, Any]:
    &quot;&quot;&quot;WordPress への接続と認証が正しいか確認する。

    Args:
        site: 接続先サイト名(.env の WP_&lt;NAME&gt;_* で登録した名前)。省略時は既定サイト。

    Returns:
        サイト情報とログインユーザー名。エラー時は例外を投げる。
    &quot;&quot;&quot;
    cfg = _require_credentials(site)
    site_resp = requests.get(
        f&quot;{cfg['base_url']}/wp-json&quot;,
        auth=(cfg[&quot;username&quot;], cfg[&quot;password&quot;]),
        timeout=TIMEOUT,
    )
    site_resp.raise_for_status()
    site_info = site_resp.json()
    me = _request(&quot;GET&quot;, &quot;/users/me&quot;, site=site)
    return {
        &quot;site&quot;: site,
        &quot;site_name&quot;: site_info.get(&quot;name&quot;),
        &quot;site_url&quot;: site_info.get(&quot;url&quot;) or site_info.get(&quot;home&quot;),
        &quot;logged_in_as&quot;: me.get(&quot;name&quot;),
        &quot;user_id&quot;: me.get(&quot;id&quot;),
        &quot;roles&quot;: me.get(&quot;roles&quot;),
        &quot;available_sites&quot;: _discover_sites(),
    }


# =========================================================================
# Posts (投稿)
# =========================================================================

@mcp.tool()
def create_post(
    title: str,
    content: str,
    status: str = &quot;draft&quot;,
    excerpt: str = &quot;&quot;,
    slug: str = &quot;&quot;,
    categories: list[str | int] | None = None,
    tags: list[str | int] | None = None,
    date: str = &quot;&quot;,
    content_is_markdown: bool = False,
    meta: dict[str, Any] | None = None,
    featured_media: int = 0,
    site: str = DEFAULT_SITE,
) -&gt; dict[str, Any]:
    &quot;&quot;&quot;新しい投稿を WordPress に作成する。

    Args:
        title: 投稿タイトル。
        content: 本文。HTML を想定。Markdown を渡す場合は content_is_markdown=True にする。
        status: &quot;draft&quot; (下書き / デフォルト), &quot;publish&quot; (公開), &quot;future&quot; (予約投稿), &quot;pending&quot;, &quot;private&quot; のいずれか。
        excerpt: 抜粋(任意)。
        slug: URL スラッグ(任意)。
        categories: カテゴリ名または ID の配列。名前が存在しなければ新規作成する。
        tags: タグ名または ID の配列。名前が存在しなければ新規作成する。
        date: 予約投稿用の日時 (ISO8601, 例 &quot;2026-06-01T10:00:00&quot;)。status=&quot;future&quot; 時に指定。
        content_is_markdown: True なら content を Markdown として HTML に変換してから投稿する。
        meta: post_meta に書き込むキー/値の辞書(例 {&quot;ssp_meta_description&quot;: &quot;...&quot;})。キーは REST 公開されている必要あり。
        featured_media: アイキャッチ画像のメディア ID(upload_media で取得した id)。0(デフォルト)なら設定しない。
        site: 対象サイト名(.env の WP_&lt;NAME&gt;_* で登録した名前)。省略時は既定サイト。

    Returns:
        作成された投稿の概要。
    &quot;&quot;&quot;
    if content_is_markdown:
        content = _markdown_to_html(content)
    payload: dict[str, Any] = {&quot;title&quot;: title, &quot;content&quot;: content, &quot;status&quot;: status}
    if excerpt:
        payload[&quot;excerpt&quot;] = excerpt
    if slug:
        payload[&quot;slug&quot;] = slug
    if categories:
        payload[&quot;categories&quot;] = _resolve_terms(&quot;categories&quot;, categories, site=site)
    if tags:
        payload[&quot;tags&quot;] = _resolve_terms(&quot;tags&quot;, tags, site=site)
    if date:
        payload[&quot;date&quot;] = date
    if meta:
        payload[&quot;meta&quot;] = meta
    if featured_media:
        payload[&quot;featured_media&quot;] = featured_media
    author_id = _default_author(site)
    if author_id:
        payload[&quot;author&quot;] = author_id
    post = _request(&quot;POST&quot;, &quot;/posts&quot;, site=site, json=payload)
    return _entity_summary(post)


@mcp.tool()
def update_post(
    post_id: int,
    title: str = &quot;&quot;,
    content: str = &quot;&quot;,
    status: str = &quot;&quot;,
    excerpt: str = &quot;&quot;,
    slug: str = &quot;&quot;,
    categories: list[str | int] | None = None,
    tags: list[str | int] | None = None,
    date: str = &quot;&quot;,
    content_is_markdown: bool = False,
    meta: dict[str, Any] | None = None,
    featured_media: int = 0,
    site: str = DEFAULT_SITE,
) -&gt; dict[str, Any]:
    &quot;&quot;&quot;既存投稿を更新する。空文字を渡したフィールドは変更されない。

    Args:
        post_id: 更新対象の投稿 ID。
        featured_media: アイキャッチ画像のメディア ID(upload_media で取得した id)。0(デフォルト)なら変更しない。
        site: 対象サイト名(.env の WP_&lt;NAME&gt;_* で登録した名前)。省略時は既定サイト。
        その他: create_post と同じ。

    Returns:
        更新後の投稿の概要。
    &quot;&quot;&quot;
    payload: dict[str, Any] = {}
    if title:
        payload[&quot;title&quot;] = title
    if content:
        payload[&quot;content&quot;] = _markdown_to_html(content) if content_is_markdown else content
    if status:
        payload[&quot;status&quot;] = status
    if excerpt:
        payload[&quot;excerpt&quot;] = excerpt
    if slug:
        payload[&quot;slug&quot;] = slug
    if categories is not None:
        payload[&quot;categories&quot;] = _resolve_terms(&quot;categories&quot;, categories, site=site)
    if tags is not None:
        payload[&quot;tags&quot;] = _resolve_terms(&quot;tags&quot;, tags, site=site)
    if date:
        payload[&quot;date&quot;] = date
    if meta is not None:
        payload[&quot;meta&quot;] = meta
    if featured_media:
        payload[&quot;featured_media&quot;] = featured_media
    if not payload:
        raise ValueError(&quot;更新項目が指定されていません&quot;)
    post = _request(&quot;POST&quot;, f&quot;/posts/{post_id}&quot;, site=site, json=payload)
    return _entity_summary(post)


@mcp.tool()
def get_post(post_id: int, context: str = &quot;edit&quot;, site: str = DEFAULT_SITE) -&gt; dict[str, Any]:
    &quot;&quot;&quot;投稿 1 件を取得する。

    Args:
        post_id: 取得する投稿 ID。
        context: &quot;view&quot; または &quot;edit&quot; (デフォルト)。
        site: 対象サイト名(.env の WP_&lt;NAME&gt;_* で登録した名前)。省略時は既定サイト。

    Returns:
        投稿の全フィールド。
    &quot;&quot;&quot;
    return _request(&quot;GET&quot;, f&quot;/posts/{post_id}&quot;, site=site, params={&quot;context&quot;: context})


@mcp.tool()
def list_posts(
    status: str = &quot;any&quot;,
    search: str = &quot;&quot;,
    per_page: int = 20,
    page: int = 1,
    category_ids: list[int] | None = None,
    tag_ids: list[int] | None = None,
    orderby: str = &quot;date&quot;,
    order: str = &quot;desc&quot;,
    site: str = DEFAULT_SITE,
) -&gt; list[dict[str, Any]]:
    &quot;&quot;&quot;投稿を一覧する。

    Args:
        site: 対象サイト名(.env の WP_&lt;NAME&gt;_* で登録した名前)。省略時は既定サイト。
        他引数: 従来通り。
    &quot;&quot;&quot;
    params: dict[str, Any] = {
        &quot;status&quot;: status,
        &quot;per_page&quot;: min(max(per_page, 1), 100),
        &quot;page&quot;: page,
        &quot;orderby&quot;: orderby,
        &quot;order&quot;: order,
        &quot;context&quot;: &quot;edit&quot;,
    }
    if search:
        params[&quot;search&quot;] = search
    if category_ids:
        params[&quot;categories&quot;] = &quot;,&quot;.join(str(i) for i in category_ids)
    if tag_ids:
        params[&quot;tags&quot;] = &quot;,&quot;.join(str(i) for i in tag_ids)
    posts = _request(&quot;GET&quot;, &quot;/posts&quot;, site=site, params=params)
    return [_entity_summary(p) for p in posts]


@mcp.tool()
def delete_post(post_id: int, force: bool = False, site: str = DEFAULT_SITE) -&gt; dict[str, Any]:
    &quot;&quot;&quot;投稿を削除する。デフォルトはゴミ箱へ移動。

    Args:
        post_id: 削除する投稿 ID。
        force: True なら完全削除、False (デフォルト) ならゴミ箱へ移動。
        site: 対象サイト名(.env の WP_&lt;NAME&gt;_* で登録した名前)。省略時は既定サイト。
    &quot;&quot;&quot;
    params = {&quot;force&quot;: &quot;true&quot;} if force else {}
    result = _request(&quot;DELETE&quot;, f&quot;/posts/{post_id}&quot;, site=site, params=params)
    return {&quot;deleted&quot;: True, &quot;force&quot;: force, &quot;result&quot;: result}


# =========================================================================
# Pages (固定ページ) - /app/ 中心に使用
# =========================================================================

@mcp.tool()
def create_page(
    title: str,
    content: str,
    status: str = &quot;draft&quot;,
    excerpt: str = &quot;&quot;,
    slug: str = &quot;&quot;,
    parent: int = 0,
    menu_order: int = 0,
    date: str = &quot;&quot;,
    content_is_markdown: bool = False,
    meta: dict[str, Any] | None = None,
    site: str = DEFAULT_SITE,
) -&gt; dict[str, Any]:
    &quot;&quot;&quot;新しい固定ページを WordPress に作成する。

    Args:
        title: ページタイトル。
        content: 本文。HTML を想定。content_is_markdown=True なら Markdown を HTML 変換。
        status: &quot;draft&quot; (下書き / デフォルト) / &quot;publish&quot; / &quot;private&quot; / &quot;pending&quot;。
        excerpt: 抜粋(任意)。
        slug: URL スラッグ(任意)。/app/{slug}/ になる。
        parent: 親ページ ID。階層構造を作る場合に指定 (0 ならトップレベル)。
        menu_order: 並び順(数字が小さいほど上)。
        date: 公開日時 (ISO8601)。
        content_is_markdown: True なら content を Markdown→HTML 変換。
        meta: post_meta に書き込む辞書。独自メタキーは事前に register_post_meta(show_in_rest=true) で REST 公開されている必要あり。
        site: 対象サイト名(.env の WP_&lt;NAME&gt;_* で登録した名前)。省略時は既定サイト。

    Returns:
        作成された固定ページの概要。
    &quot;&quot;&quot;
    if content_is_markdown:
        content = _markdown_to_html(content)
    payload: dict[str, Any] = {&quot;title&quot;: title, &quot;content&quot;: content, &quot;status&quot;: status}
    if excerpt:
        payload[&quot;excerpt&quot;] = excerpt
    if slug:
        payload[&quot;slug&quot;] = slug
    if parent:
        payload[&quot;parent&quot;] = int(parent)
    if menu_order:
        payload[&quot;menu_order&quot;] = int(menu_order)
    if date:
        payload[&quot;date&quot;] = date
    if meta:
        payload[&quot;meta&quot;] = meta
    author_id = _default_author(site)
    if author_id:
        payload[&quot;author&quot;] = author_id
    page = _request(&quot;POST&quot;, &quot;/pages&quot;, site=site, json=payload)
    return _entity_summary(page)


@mcp.tool()
def update_page(
    page_id: int,
    title: str = &quot;&quot;,
    content: str = &quot;&quot;,
    status: str = &quot;&quot;,
    excerpt: str = &quot;&quot;,
    slug: str = &quot;&quot;,
    parent: int | None = None,
    menu_order: int | None = None,
    date: str = &quot;&quot;,
    content_is_markdown: bool = False,
    meta: dict[str, Any] | None = None,
    site: str = DEFAULT_SITE,
) -&gt; dict[str, Any]:
    &quot;&quot;&quot;既存固定ページを更新する。空文字 / None を渡したフィールドは変更されない。

    Args:
        page_id: 更新対象の固定ページ ID。
        parent: 親ページ ID を変更する場合に指定(明示的に 0 にすればトップレベル化)。
        menu_order: 並び順を変更する場合に指定。
        site: 対象サイト名(.env の WP_&lt;NAME&gt;_* で登録した名前)。省略時は既定サイト。
        その他: create_page と同じ。

    Returns:
        更新後の固定ページの概要。
    &quot;&quot;&quot;
    payload: dict[str, Any] = {}
    if title:
        payload[&quot;title&quot;] = title
    if content:
        payload[&quot;content&quot;] = _markdown_to_html(content) if content_is_markdown else content
    if status:
        payload[&quot;status&quot;] = status
    if excerpt:
        payload[&quot;excerpt&quot;] = excerpt
    if slug:
        payload[&quot;slug&quot;] = slug
    if parent is not None:
        payload[&quot;parent&quot;] = int(parent)
    if menu_order is not None:
        payload[&quot;menu_order&quot;] = int(menu_order)
    if date:
        payload[&quot;date&quot;] = date
    if meta is not None:
        payload[&quot;meta&quot;] = meta
    if not payload:
        raise ValueError(&quot;更新項目が指定されていません&quot;)
    page = _request(&quot;POST&quot;, f&quot;/pages/{page_id}&quot;, site=site, json=payload)
    return _entity_summary(page)


@mcp.tool()
def get_page(page_id: int, context: str = &quot;edit&quot;, site: str = DEFAULT_SITE) -&gt; dict[str, Any]:
    &quot;&quot;&quot;固定ページ 1 件を取得する。

    Args:
        page_id: 取得する固定ページ ID。
        context: &quot;view&quot; (公開ビュー) または &quot;edit&quot; (デフォルト、編集用の raw 値を含む)。
        site: 取得先サイト。

    Returns:
        固定ページの全フィールド。
    &quot;&quot;&quot;
    return _request(&quot;GET&quot;, f&quot;/pages/{page_id}&quot;, site=site, params={&quot;context&quot;: context})


@mcp.tool()
def list_pages(
    status: str = &quot;any&quot;,
    search: str = &quot;&quot;,
    parent: int | None = None,
    per_page: int = 50,
    page: int = 1,
    orderby: str = &quot;menu_order&quot;,
    order: str = &quot;asc&quot;,
    site: str = DEFAULT_SITE,
) -&gt; list[dict[str, Any]]:
    &quot;&quot;&quot;固定ページを一覧する。

    Args:
        status: &quot;any&quot;, &quot;publish&quot;, &quot;draft&quot;, &quot;future&quot;, &quot;pending&quot;, &quot;private&quot;。
        search: タイトル/本文の部分検索キーワード。
        parent: 親ページ ID で絞り込み(0 を指定するとトップレベルのみ取得)。
        per_page: 1 ページあたりの件数 (最大 100)。
        page: ページ番号。
        orderby: &quot;menu_order&quot; (デフォルト・並び順)、&quot;date&quot;、&quot;modified&quot;、&quot;title&quot;、&quot;id&quot;。
        order: &quot;asc&quot; (デフォルト) または &quot;desc&quot;。
        site: 対象サイト名(.env の WP_&lt;NAME&gt;_* で登録した名前)。省略時は既定サイト。

    Returns:
        固定ページ概要の配列(id / slug / title / link / parent / menu_order など)。
    &quot;&quot;&quot;
    params: dict[str, Any] = {
        &quot;status&quot;: status,
        &quot;per_page&quot;: min(max(per_page, 1), 100),
        &quot;page&quot;: page,
        &quot;orderby&quot;: orderby,
        &quot;order&quot;: order,
        &quot;context&quot;: &quot;edit&quot;,
    }
    if search:
        params[&quot;search&quot;] = search
    if parent is not None:
        params[&quot;parent&quot;] = parent
    pages = _request(&quot;GET&quot;, &quot;/pages&quot;, site=site, params=params)
    return [_entity_summary(p) for p in pages]


@mcp.tool()
def delete_page(page_id: int, force: bool = False, site: str = DEFAULT_SITE) -&gt; dict[str, Any]:
    &quot;&quot;&quot;固定ページを削除する。デフォルトはゴミ箱へ移動。

    Args:
        page_id: 削除する固定ページ ID。
        force: True なら完全削除、False ならゴミ箱へ。
        site: 対象サイト。
    &quot;&quot;&quot;
    params = {&quot;force&quot;: &quot;true&quot;} if force else {}
    result = _request(&quot;DELETE&quot;, f&quot;/pages/{page_id}&quot;, site=site, params=params)
    return {&quot;deleted&quot;: True, &quot;force&quot;: force, &quot;result&quot;: result}


# =========================================================================
# Categories / Tags
# =========================================================================

@mcp.tool()
def list_categories(per_page: int = 100, search: str = &quot;&quot;, site: str = DEFAULT_SITE) -&gt; list[dict[str, Any]]:
    &quot;&quot;&quot;カテゴリを一覧する。&quot;&quot;&quot;
    params: dict[str, Any] = {&quot;per_page&quot;: min(max(per_page, 1), 100)}
    if search:
        params[&quot;search&quot;] = search
    cats = _request(&quot;GET&quot;, &quot;/categories&quot;, site=site, params=params)
    return [
        {&quot;id&quot;: c[&quot;id&quot;], &quot;name&quot;: c[&quot;name&quot;], &quot;slug&quot;: c[&quot;slug&quot;], &quot;count&quot;: c.get(&quot;count&quot;, 0), &quot;parent&quot;: c.get(&quot;parent&quot;, 0)}
        for c in cats
    ]


@mcp.tool()
def create_category(
    name: str, slug: str = &quot;&quot;, description: str = &quot;&quot;, parent: int = 0, site: str = DEFAULT_SITE
) -&gt; dict[str, Any]:
    &quot;&quot;&quot;カテゴリを新規作成する。&quot;&quot;&quot;
    payload: dict[str, Any] = {&quot;name&quot;: name}
    if slug:
        payload[&quot;slug&quot;] = slug
    if description:
        payload[&quot;description&quot;] = description
    if parent:
        payload[&quot;parent&quot;] = parent
    cat = _request(&quot;POST&quot;, &quot;/categories&quot;, site=site, json=payload)
    return {&quot;id&quot;: cat[&quot;id&quot;], &quot;name&quot;: cat[&quot;name&quot;], &quot;slug&quot;: cat[&quot;slug&quot;]}


@mcp.tool()
def list_tags(per_page: int = 100, search: str = &quot;&quot;, site: str = DEFAULT_SITE) -&gt; list[dict[str, Any]]:
    &quot;&quot;&quot;タグを一覧する。&quot;&quot;&quot;
    params: dict[str, Any] = {&quot;per_page&quot;: min(max(per_page, 1), 100)}
    if search:
        params[&quot;search&quot;] = search
    tags = _request(&quot;GET&quot;, &quot;/tags&quot;, site=site, params=params)
    return [
        {&quot;id&quot;: t[&quot;id&quot;], &quot;name&quot;: t[&quot;name&quot;], &quot;slug&quot;: t[&quot;slug&quot;], &quot;count&quot;: t.get(&quot;count&quot;, 0)}
        for t in tags
    ]


@mcp.tool()
def create_tag(name: str, slug: str = &quot;&quot;, description: str = &quot;&quot;, site: str = DEFAULT_SITE) -&gt; dict[str, Any]:
    &quot;&quot;&quot;タグを新規作成する。&quot;&quot;&quot;
    payload: dict[str, Any] = {&quot;name&quot;: name}
    if slug:
        payload[&quot;slug&quot;] = slug
    if description:
        payload[&quot;description&quot;] = description
    tag = _request(&quot;POST&quot;, &quot;/tags&quot;, site=site, json=payload)
    return {&quot;id&quot;: tag[&quot;id&quot;], &quot;name&quot;: tag[&quot;name&quot;], &quot;slug&quot;: tag[&quot;slug&quot;]}


# =========================================================================
# Markdown ファイル経由(投稿/固定ページ両対応)
# =========================================================================

@mcp.tool()
def post_from_markdown_file(
    file_path: str, override_status: str = &quot;&quot;, override_site: str = &quot;&quot;
) -&gt; dict[str, Any]:
    &quot;&quot;&quot;Markdown ファイル(frontmatter 付き)から投稿または固定ページを作成または更新する。

    frontmatter の `id` フィールドがあれば update、なければ create。
    create 後は元ファイルの frontmatter に `id` を書き戻して、次回以降が update になる。

    frontmatter 共通キー:
      title (str, 必須), status (&quot;draft&quot;/&quot;publish&quot;/...), excerpt, slug,
      date (ISO8601), id (int, 更新用), format (&quot;markdown&quot;/&quot;gutenberg&quot;/&quot;html&quot;),
      meta_description (str, post meta へ書き込む。キーは WP_META_DESCRIPTION_KEY で指定、既定 ssp_meta_description=SEO SIMPLE PACK),
      meta (dict, 任意の post_meta を直接指定。キーは REST 公開されている必要あり),
      site (str, 投稿先サイト名。.env の WP_&lt;NAME&gt;_* で登録した名前)

    投稿(post)用キー(post_type 未指定または &quot;post&quot;):
      categories (list), tags (list)
      featured_media (int): アイキャッチ画像のメディア ID(upload_media で取得した id)。
        指定すると create_post/update_post に渡り投稿に紐づく。未指定なら変更しない。
        ※ 固定ページ(page)側は create_page/update_page 未対応のため非対応。

    固定ページ(page)用キー(post_type / type に &quot;page&quot; を指定):
      parent (int): 親ページ ID
      menu_order (int): 並び順

    Args:
        file_path: 対象 Markdown ファイルの絶対または相対パス。
        override_status: 指定すると frontmatter の status を上書きする。
        override_site: 指定すると frontmatter の site を上書きする。

    Returns:
        作成/更新された投稿または固定ページの概要。
    &quot;&quot;&quot;
    path = Path(file_path)
    if not path.is_absolute():
        path = ROOT / path
    if not path.exists():
        raise FileNotFoundError(f&quot;ファイルが見つかりません: {path}&quot;)

    doc = frontmatter.load(path)
    fm = doc.metadata
    body = doc.content

    title = fm.get(&quot;title&quot;)
    if not title:
        raise ValueError(&quot;frontmatter に title が必要です&quot;)

    status = override_status or fm.get(&quot;status&quot;) or &quot;draft&quot;
    site = (override_site or fm.get(&quot;site&quot;) or DEFAULT_SITE).strip().lower()
    post_type = (fm.get(&quot;post_type&quot;) or fm.get(&quot;type&quot;) or &quot;post&quot;).strip().lower()

    fmt = (fm.get(&quot;format&quot;) or &quot;markdown&quot;).lower()
    html = body if fmt in (&quot;html&quot;, &quot;gutenberg&quot;, &quot;raw&quot;) else _markdown_to_html(body)

    post_meta: dict[str, Any] = {}
    # meta_description は _meta_description_key(site) のキーに書き込む
    # (既定は SEO SIMPLE PACK の ssp_meta_description、環境変数 WP_META_DESCRIPTION_KEY で変更可・空文字で無効化)
    # ※ 書き込み先キーは REST 公開されている必要がある(同梱の mu-plugins/ssp-meta-rest.php 参照)
    meta_key = _meta_description_key(site)
    if fm.get(&quot;meta_description&quot;) and meta_key:
        post_meta[meta_key] = fm[&quot;meta_description&quot;]
    # 任意の post_meta を直接指定したい場合は frontmatter の meta(dict)を使う
    if isinstance(fm.get(&quot;meta&quot;), dict):
        post_meta.update(fm[&quot;meta&quot;])

    import datetime as _dt
    date_val = fm.get(&quot;date&quot;) or &quot;&quot;
    if isinstance(date_val, (_dt.datetime, _dt.date)):
        date_val = date_val.isoformat()
    elif date_val and not isinstance(date_val, str):
        date_val = str(date_val)

    record_id = fm.get(&quot;id&quot;)
    excerpt_val = fm.get(&quot;excerpt&quot;, &quot;&quot;) or &quot;&quot;
    slug_val = fm.get(&quot;slug&quot;, &quot;&quot;) or &quot;&quot;
    featured_media_val = int(fm[&quot;featured_media&quot;]) if fm.get(&quot;featured_media&quot;) else 0

    if post_type == &quot;page&quot;:
        if record_id:
            result = update_page(
                page_id=int(record_id),
                title=title,
                content=html,
                status=status,
                excerpt=excerpt_val,
                slug=slug_val,
                parent=int(fm[&quot;parent&quot;]) if fm.get(&quot;parent&quot;) is not None else None,
                menu_order=int(fm[&quot;menu_order&quot;]) if fm.get(&quot;menu_order&quot;) is not None else None,
                date=date_val,
                meta=post_meta or None,
                site=site,
            )
        else:
            result = create_page(
                title=title,
                content=html,
                status=status,
                excerpt=excerpt_val,
                slug=slug_val,
                parent=int(fm.get(&quot;parent&quot;) or 0),
                menu_order=int(fm.get(&quot;menu_order&quot;) or 0),
                date=date_val,
                meta=post_meta or None,
                site=site,
            )
            doc.metadata[&quot;id&quot;] = result[&quot;id&quot;]
            path.write_text(frontmatter.dumps(doc), encoding=&quot;utf-8&quot;)
    else:
        if record_id:
            result = update_post(
                post_id=int(record_id),
                title=title,
                content=html,
                status=status,
                excerpt=excerpt_val,
                slug=slug_val,
                categories=fm.get(&quot;categories&quot;),
                tags=fm.get(&quot;tags&quot;),
                date=date_val,
                meta=post_meta or None,
                featured_media=featured_media_val,
                site=site,
            )
        else:
            result = create_post(
                title=title,
                content=html,
                status=status,
                excerpt=excerpt_val,
                slug=slug_val,
                categories=fm.get(&quot;categories&quot;),
                tags=fm.get(&quot;tags&quot;),
                date=date_val,
                meta=post_meta or None,
                featured_media=featured_media_val,
                site=site,
            )
            doc.metadata[&quot;id&quot;] = result[&quot;id&quot;]
            path.write_text(frontmatter.dumps(doc), encoding=&quot;utf-8&quot;)

    return result


@mcp.tool()
def markdown_to_html(text: str) -&gt; str:
    &quot;&quot;&quot;Markdown を WordPress 投稿向けの HTML に変換する(プレビュー用)。&quot;&quot;&quot;
    return _markdown_to_html(text)


# =========================================================================
# メディア(画像)アップロード
# =========================================================================

@mcp.tool()
def upload_media(
    file_path: str,
    filename: str = &quot;&quot;,
    title: str = &quot;&quot;,
    alt_text: str = &quot;&quot;,
    site: str = DEFAULT_SITE,
) -&gt; dict[str, Any]:
    &quot;&quot;&quot;ローカルの画像ファイルを WordPress のメディアライブラリにアップロードする。

    Args:
        file_path: アップロードする画像の絶対/相対パス。
        filename: メディアのファイル名(省略時は元ファイル名)。★Content-Disposition は ASCII 推奨なので、
                  日本語ファイル名のときは英数字+ハイフンの名前(例 &quot;screenshot-01.png&quot;)を明示指定する。
        title: メディアのタイトル(任意)。
        alt_text: 代替テキスト(任意、SEO/アクセシビリティ用)。
        site: 対象サイト名(.env の WP_&lt;NAME&gt;_* で登録した名前)。省略時は既定サイト。

    Returns:
        {id, source_url, mime_type, title}。source_url を wp:image ブロックの src に使う。
    &quot;&quot;&quot;
    import mimetypes

    cfg = _require_credentials(site)
    path = Path(file_path)
    if not path.is_absolute():
        path = ROOT / path
    if not path.exists():
        raise FileNotFoundError(f&quot;ファイルが見つかりません: {path}&quot;)

    name = filename or path.name
    ctype = mimetypes.guess_type(name)[0] or mimetypes.guess_type(str(path))[0] or &quot;application/octet-stream&quot;
    data = path.read_bytes()

    resp = requests.post(
        f&quot;{cfg['base_url']}/wp-json/wp/v2/media&quot;,
        auth=(cfg[&quot;username&quot;], cfg[&quot;password&quot;]),
        headers={
            &quot;Content-Disposition&quot;: f'attachment; filename=&quot;{name}&quot;',
            &quot;Content-Type&quot;: ctype,
        },
        data=data,
        timeout=TIMEOUT * 3,
    )
    if not resp.ok:
        raise RuntimeError(
            f&quot;media upload failed [{site}]: HTTP {resp.status_code} - {resp.text[:500]}&quot;
        )
    m = resp.json()

    if title or alt_text:
        patch: dict[str, Any] = {}
        if title:
            patch[&quot;title&quot;] = title
        if alt_text:
            patch[&quot;alt_text&quot;] = alt_text
        m = _request(&quot;POST&quot;, f&quot;/media/{m['id']}&quot;, site=site, json=patch)

    title_val = m.get(&quot;title&quot;)
    if isinstance(title_val, dict):
        title_val = title_val.get(&quot;rendered&quot;) or title_val.get(&quot;raw&quot;)
    return {
        &quot;id&quot;: m.get(&quot;id&quot;),
        &quot;source_url&quot;: m.get(&quot;source_url&quot;),
        &quot;mime_type&quot;: m.get(&quot;mime_type&quot;),
        &quot;title&quot;: title_val,
    }


if __name__ == &quot;__main__&quot;:
    try:
        mcp.run()
    except Exception as e:
        print(f&quot;MCP server error: {e}&quot;, file=sys.stderr)
        raise</code></pre></div>
</div></details>
</div>



<h3 class="wp-block-heading">補助プラグイン（mu-plugins 用）</h3>



<p class="wp-block-paragraph">置き場所は <strong>/wp-content/mu-plugins/ssp-meta-rest.php</strong>、mu-plugins（must-use plugins）フォルダが無ければ wp-content/ の下に自分で作ります<br>ここに置くと管理画面に項目も出ないまま自動で有効になるので、有効化のクリックは不要<br>テーマやプラグインを更新しても消えないので、自作の小さな仕組みを常駐させるのにちょうど良い場所</p>



<p class="wp-block-paragraph">JavaScriptを書き込む機能だけは、あえて公開していません<br>認証情報が漏れたときに、好きなスクリプトを埋め込まれかねないからです</p>



<div class="swell-block-accordion">
<details class="swell-block-accordion__item" data-swl-acc="wrapper"><summary class="swell-block-accordion__title" data-swl-acc="header"><span class="swell-block-accordion__label">補助プラグイン全文（コピペ用）</span><span class="swell-block-accordion__icon c-switchIconBtn" data-swl-acc="icon" aria-hidden="true" data-opened="false"><i class="__icon--closed icon-caret-down"></i><i class="__icon--opened icon-caret-up"></i></span></summary><div class="swell-block-accordion__body" data-swl-acc="body">
<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-file="ssp-meta-rest.php" data-lang="PHP"><code>&lt;?php
/**
 * Plugin Name: SEO SIMPLE PACK Meta REST API Support
 * Description: SEO SIMPLE PACK のメタフィールド + SWELL の投稿別カスタムCSS を WP REST API 経由で読み書きできるようにする補助プラグイン。投稿(post)・固定ページ(page)の両方に対応(/app/ のアプリ庫サイトは固定ページ運用のため page 必須)。
 * Author: Local helper
 * Version: 1.2.0
 *
 * 配置場所: /wp-content/mu-plugins/ssp-meta-rest.php
 *   (mu-pluginsフォルダが無ければ作成すること。配置するだけで自動有効化される)
 *
 * 変更履歴:
 *   1.0.0 - 初版(post のみ対応)
 *   1.1.0 - page 型にも対応(/app/ サイト用)
 *   1.2.0 - SWELL の投稿別カスタムCSS(swell_meta_css)を追加して MCP から記事ごとのCSSを書けるようにした。
 *           ※ JS(swell_meta_js)は「あえて公開しない」: 認証情報(アプリパスワード)が漏れた場合に
 *             サイト訪問者へ任意の JavaScript を注入できてしまう(実質 XSS)リスクがあるため。
 *           ※ そのまま出力フラグ(swell_meta_css_plane / swell_meta_js_plane)も、操作面・事故面を
 *             増やさないため公開しない(CSS は既定=&lt;style&gt; で囲む、で十分)。
 *
 * メタキーの根拠:
 *   - SEO SIMPLE PACK の post meta: ssp_meta_description / ssp_meta_robots(先頭アンダースコアなし)。
 *   - SWELL の投稿別CSS: swell_meta_css(投稿編集画面のメタボックス textarea name=&quot;swell_meta_css&quot; より確認)。
 *   いずれも標準では REST 非公開のため、本プラグインで show_in_rest 登録する。
 *   ※ 一括書き戻し前に1記事で読み書きを検証することを推奨。
 */

add_action('init', function () {
    // REST 公開するメタキー(値はすべて文字列)
    $rest_meta_keys = [
        'ssp_meta_description',   // SSP メタディスクリプション(書き戻しの本命)
        'ssp_meta_robots',        // SSP robots(noindex 等。必要な記事のみ)
        'swell_meta_css',         // SWELL 投稿別カスタムCSS(wp_head で出力)。JS はあえて非公開
    ];

    // 対象 post type:post(blog 用)+ page(/app/ 用、SWELL 固定ページ運用)
    $target_post_types = ['post', 'page'];

    foreach ($rest_meta_keys as $key) {
        foreach ($target_post_types as $post_type) {
            register_post_meta($post_type, $key, [
                'type'          =&gt; 'string',
                'single'        =&gt; true,
                'show_in_rest'  =&gt; true,
                'auth_callback' =&gt; function () use ($post_type) {
                    // post なら edit_posts、page なら edit_pages の権限チェック
                    return $post_type === 'page'
                        ? current_user_can('edit_pages')
                        : current_user_can('edit_posts');
                },
            ]);
        }
    }
});</code></pre></div>
</div></details>
</div>



<p class="wp-block-paragraph">更新版は <a href="https://github.com/javeo2022/wordpress-mcp-server" target="_blank" rel="noopener noreferrer">javeo2022/wordpress-mcp-server</a> にも置いています</p>


<div class="p-blogParts post_content" data-partsID="4603">
<div class="jv-books" data-shelf="ai"><div class="jv-books-head"><span class="jv-books-title"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Claude・生成AIを学べる本</span><span class="jv-books-pr">PR</span></div><div class="jv-books-grid"><div class="jv-book-card"><a class="jv-book-cover" href="https://www.amazon.co.jp/dp/4297153548?tag=javeo2022-22" target="_blank" rel="nofollow sponsored noopener noreferrer"><img decoding="async" src="https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/3540/9784297153540_1_2.jpg?_ex=240x240" alt="実践Claude Code入門" width="120" height="170" loading="lazy"></a><div class="jv-book-info"><p class="jv-book-title">実践Claude Code入門</p><p class="jv-book-author">西見公宏・吉田真吾・大嶋勇樹</p><div class="jv-book-btns"><a class="jv-btn jv-btn-az" href="https://www.amazon.co.jp/dp/4297153548?tag=javeo2022-22" target="_blank" rel="nofollow sponsored noopener noreferrer" data-shelf="ai" data-mall="amazon" data-book="4297153548">Amazonで見る</a><a class="jv-btn jv-btn-rk" href="https://hb.afl.rakuten.co.jp/hgc/24ecde15.e492bb61.24ecde16.6c9a125b/?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18439208%2F&#038;m=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18439208%2F" target="_blank" rel="nofollow sponsored noopener noreferrer" data-shelf="ai" data-mall="rakuten" data-book="4297153548">楽天で見る</a></div></div></div><div class="jv-book-card"><a class="jv-book-cover" href="https://www.amazon.co.jp/dp/4297152754?tag=javeo2022-22" target="_blank" rel="nofollow sponsored noopener noreferrer"><img decoding="async" src="https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/2758/9784297152758_1_2.jpg?_ex=240x240" alt="Claude CodeによるAI駆動開発入門" width="120" height="170" loading="lazy"></a><div class="jv-book-info"><p class="jv-book-title">Claude CodeによるAI駆動開発入門</p><p class="jv-book-author">平川知秀</p><div class="jv-book-btns"><a class="jv-btn jv-btn-az" href="https://www.amazon.co.jp/dp/4297152754?tag=javeo2022-22" target="_blank" rel="nofollow sponsored noopener noreferrer" data-shelf="ai" data-mall="amazon" data-book="4297152754">Amazonで見る</a><a class="jv-btn jv-btn-rk" href="https://hb.afl.rakuten.co.jp/hgc/24ecde15.e492bb61.24ecde16.6c9a125b/?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18401065%2F&#038;m=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18401065%2F" target="_blank" rel="nofollow sponsored noopener noreferrer" data-shelf="ai" data-mall="rakuten" data-book="4297152754">楽天で見る</a></div></div></div><div class="jv-book-card"><a class="jv-book-cover" href="https://www.amazon.co.jp/dp/4839990204?tag=javeo2022-22" target="_blank" rel="nofollow sponsored noopener noreferrer"><img decoding="async" src="https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/0206/9784839990206.jpg?_ex=240x240" alt="開発効率をアップする! Claude Code 実用入門" width="120" height="170" loading="lazy"></a><div class="jv-book-info"><p class="jv-book-title">開発効率をアップする! Claude Code 実用入門</p><p class="jv-book-author">大澤文孝</p><div class="jv-book-btns"><a class="jv-btn jv-btn-az" href="https://www.amazon.co.jp/dp/4839990204?tag=javeo2022-22" target="_blank" rel="nofollow sponsored noopener noreferrer" data-shelf="ai" data-mall="amazon" data-book="4839990204">Amazonで見る</a><a class="jv-btn jv-btn-rk" href="https://hb.afl.rakuten.co.jp/hgc/24ecde15.e492bb61.24ecde16.6c9a125b/?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18585359%2F&#038;m=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18585359%2F" target="_blank" rel="nofollow sponsored noopener noreferrer" data-shelf="ai" data-mall="rakuten" data-book="4839990204">楽天で見る</a></div></div></div></div><p class="jv-books-note">私のおすすめからランダムで3冊を表示しています</p></div>
<style>
.jv-books{border:1px solid #e0e0e0;border-radius:8px;padding:16px;margin:1.5em 0;background:#fff}
.jv-books-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}
.jv-books-title{font-weight:700;font-size:1.05em}
.jv-books-pr{font-size:.7em;color:#888;border:1px solid #ccc;border-radius:3px;padding:1px 6px;flex-shrink:0}
.jv-books-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;min-height:330px}
.jv-book-card{display:flex;flex-direction:column;align-items:center;text-align:center;border:1px solid #f0f0f0;border-radius:6px;padding:12px 8px;background:#fafafa}
.jv-book-cover img{width:auto;max-width:120px;height:170px;object-fit:contain}
.jv-book-info{width:100%;flex:1;display:flex;flex-direction:column}
.jv-book-title{font-size:.82em;font-weight:600;line-height:1.4;margin:8px 0 2px;min-height:2.8em;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.jv-book-author{font-size:.72em;color:#777;margin:0 0 8px}
.jv-book-btns{display:flex;flex-direction:column;gap:6px;width:100%;margin-top:auto}
.jv-btn{display:block;text-align:center;font-size:.78em;font-weight:600;color:#fff!important;text-decoration:none!important;border-radius:4px;padding:7px 4px;line-height:1.2}
.jv-btn-az{background:#e88b00}
.jv-btn-rk{background:#bf0000}
.jv-btn:hover{opacity:.85}
.jv-books-note{font-size:.7em;color:#999;text-align:right;margin:8px 0 0}
@media(max-width:599px){
.jv-books-grid{grid-template-columns:1fr;min-height:0}
.jv-book-card{flex-direction:row;text-align:left;gap:12px}
.jv-book-cover img{height:110px;max-width:80px}
.jv-book-info{min-width:0}
.jv-book-title{min-height:0}
.jv-book-btns{flex-direction:row}
.jv-btn{flex:1}
}
</style>
<script>
(function(){
var SHELF='ai';
var all=document.querySelectorAll('.jv-books[data-shelf="'+SHELF+'"]');
var root=null;
for(var k=0;k<all.length;k++){if(!all[k].dataset.jvinit){root=all[k];break;}}
if(!root)return;
root.dataset.jvinit='1';
var POOL=[{"t": "実践Claude Code入門", "a": "西見公宏・吉田真吾・大嶋勇樹", "img": "https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/3540/9784297153540_1_2.jpg?_ex=240x240", "az": "https://www.amazon.co.jp/dp/4297153548?tag=javeo2022-22", "rk": "https://hb.afl.rakuten.co.jp/hgc/24ecde15.e492bb61.24ecde16.6c9a125b/?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18439208%2F&#038;m=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18439208%2F", "id": "4297153548"}, {"t": "Claude CodeによるAI駆動開発入門", "a": "平川知秀", "img": "https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/2758/9784297152758_1_2.jpg?_ex=240x240", "az": "https://www.amazon.co.jp/dp/4297152754?tag=javeo2022-22", "rk": "https://hb.afl.rakuten.co.jp/hgc/24ecde15.e492bb61.24ecde16.6c9a125b/?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18401065%2F&#038;m=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18401065%2F", "id": "4297152754"}, {"t": "開発効率をアップする! Claude Code 実用入門", "a": "大澤文孝", "img": "https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/0206/9784839990206.jpg?_ex=240x240", "az": "https://www.amazon.co.jp/dp/4839990204?tag=javeo2022-22", "rk": "https://hb.afl.rakuten.co.jp/hgc/24ecde15.e492bb61.24ecde16.6c9a125b/?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18585359%2F&#038;m=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18585359%2F", "id": "4839990204"}, {"t": "Microsoft 365 Copilot踏み込み活用術", "a": "太田浩史", "img": "https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/3401/9784295023401_1_2.jpg?_ex=240x240", "az": "https://www.amazon.co.jp/dp/429502340X?tag=javeo2022-22", "rk": "https://hb.afl.rakuten.co.jp/hgc/24ecde15.e492bb61.24ecde16.6c9a125b/?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18401830%2F&#038;m=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18401830%2F", "id": "429502340X"}, {"t": "できるClaude &#038; Claude Cowork", "a": "清水理史・できるシリーズ編集部", "img": "https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/4842/9784295024842_1_2.jpg?_ex=240x240", "az": "https://www.amazon.co.jp/dp/4295024848?tag=javeo2022-22", "rk": "https://hb.afl.rakuten.co.jp/hgc/24ecde15.e492bb61.24ecde16.6c9a125b/?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18647512%2F&#038;m=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18647512%2F", "id": "4295024848"}, {"t": "Claude仕事術", "a": "佐藤傑", "img": "https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/5304/9784815645304.jpg?_ex=240x240", "az": "https://www.amazon.co.jp/dp/4815645302?tag=javeo2022-22", "rk": "https://hb.afl.rakuten.co.jp/hgc/24ecde15.e492bb61.24ecde16.6c9a125b/?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18632518%2F&#038;m=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18632518%2F", "id": "4815645302"}, {"t": "あらゆる仕事が爆速化する Claude Code徹底活用術", "a": "ひつじ", "img": "https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/2901/9784534062901_1_2.jpg?_ex=240x240", "az": "https://www.amazon.co.jp/dp/4534062907?tag=javeo2022-22", "rk": "https://hb.afl.rakuten.co.jp/hgc/24ecde15.e492bb61.24ecde16.6c9a125b/?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18631760%2F&#038;m=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18631760%2F", "id": "4534062907"}, {"t": "Microsoft 365 Copilot活用大全", "a": "アクセンチュア Copilot利活用推進チーム", "img": "https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/0519/9784296080519.jpg?_ex=240x240", "az": "https://www.amazon.co.jp/dp/4296080512?tag=javeo2022-22", "rk": "https://hb.afl.rakuten.co.jp/hgc/24ecde15.e492bb61.24ecde16.6c9a125b/?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18570834%2F&#038;m=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18570834%2F", "id": "4296080512"}, {"t": "［みのるん式］ビジネスパーソンのためのClaude Code仕事術", "a": "御田稔", "img": "https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/9399/9784297159399_1_2.jpg?_ex=240x240", "az": "https://www.amazon.co.jp/dp/4297159392?tag=javeo2022-22", "rk": "https://hb.afl.rakuten.co.jp/hgc/24ecde15.e492bb61.24ecde16.6c9a125b/?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18748006%2F&#038;m=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18748006%2F", "id": "4297159392"}, {"t": "この1冊でしっかりわかる Claudeの教科書", "a": "AI Evo Project", "img": "https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/5687/9784815645687.jpg?_ex=240x240", "az": "https://www.amazon.co.jp/dp/481564568X?tag=javeo2022-22", "rk": "https://hb.afl.rakuten.co.jp/hgc/24ecde15.e492bb61.24ecde16.6c9a125b/?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18628353%2F&#038;m=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18628353%2F", "id": "481564568X"}, {"t": "Google AI 仕事大全 Gemini・NotebookLM・AIエージェントをぜんぶ使う", "a": "澤田竹洋", "img": "https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/6909/9784297156909_1_2.jpg?_ex=240x240", "az": "https://www.amazon.co.jp/dp/4297156903?tag=javeo2022-22", "rk": "https://hb.afl.rakuten.co.jp/hgc/24ecde15.e492bb61.24ecde16.6c9a125b/?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18648290%2F&#038;m=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F18648290%2F", "id": "4297156903"}];
var REL='nofollow sponsored noopener noreferrer';
function el(tag,cls){var e=document.createElement(tag);if(cls)e.className=cls;return e;}
function btn(href,cls,label,mall,id){
var a=el('a','jv-btn '+cls);a.href=href;a.target='_blank';a.rel=REL;a.textContent=label;
a.setAttribute('data-shelf',SHELF);a.setAttribute('data-mall',mall);a.setAttribute('data-book',id);
return a;}
function card(b){
var d=el('div','jv-book-card');
var cover=el('a','jv-book-cover');cover.href=b.az;cover.target='_blank';cover.rel=REL;
var img=el('img');img.src=b.img;img.alt=b.t;img.width=120;img.height=170;img.loading='lazy';
cover.appendChild(img);
var info=el('div','jv-book-info');
var ttl=el('p','jv-book-title');ttl.textContent=b.t;
var au=el('p','jv-book-author');au.textContent=b.a;
var btns=el('div','jv-book-btns');
btns.appendChild(btn(b.az,'jv-btn-az','Amazonで見る','amazon',b.id));
if(b.rk){btns.appendChild(btn(b.rk,'jv-btn-rk','楽天で見る','rakuten',b.id));}
info.appendChild(ttl);info.appendChild(au);info.appendChild(btns);
d.appendChild(cover);d.appendChild(info);
return d;}
var pool=POOL.slice();
for(var i=pool.length-1;i>0;i--){var j=Math.floor(Math.random()*(i+1));var t=pool[i];pool[i]=pool[j];pool[j]=t;}
var grid=root.querySelector('.jv-books-grid');
grid.style.opacity='0';
while(grid.firstChild)grid.removeChild(grid.firstChild);
pool.slice(0,3).forEach(function(b){grid.appendChild(card(b));});
grid.style.transition='opacity .5s ease';
void grid.offsetWidth;
grid.style.opacity='1';
})();
</script>
</div>]]></content:encoded>
					
					<wfw:commentRss>https://javeo.jp/claude-code-wordpress-mcp-xserver/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>WordPressブログの始め方｜エックスサーバー＋SWELL</title>
		<link>https://javeo.jp/wordpress-blog-start/</link>
					<comments>https://javeo.jp/wordpress-blog-start/#respond</comments>
		
		<dc:creator><![CDATA[ジャベ雄]]></dc:creator>
		<pubDate>Sat, 06 Jun 2026 16:04:27 +0000</pubDate>
				<category><![CDATA[ブログ運営]]></category>
		<category><![CDATA[SWELL]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[レンタルサーバー]]></category>
		<category><![CDATA[初心者]]></category>
		<guid isPermaLink="false">https://javeo.jp/?p=4543</guid>

					<description><![CDATA[<p><img src="https://javeo.jp/wp-content/uploads/2022/07/2022-07-17_16h41_35-1024x538.jpg" class="webfeedsFeaturedVisual" /></p>初心者向けにWordPressブログの始め方をまとめました、エックスサーバーのクイックスタートで約10分で開設し、テーマSWELLで見た目を整えるまでの全手順を、実際にこのブログを運営する私が解説します]]></description>
										<content:encoded><![CDATA[<p><img src="https://javeo.jp/wp-content/uploads/2022/07/2022-07-17_16h41_35-1024x538.jpg" class="webfeedsFeaturedVisual" /></p><div class="codoc-evacuations" style="display:none;" data-shortcode=""></div>
<p class="wp-block-paragraph">「ブログを始めてみたいけど、何から手をつければいいのか分からない」——最初はみんなそこでつまずきますよね</p>



<p class="wp-block-paragraph">結論から言うと、WordPressブログに必要なものは<strong>サーバー・ドメイン・テーマの3つだけ</strong>で、今は申し込みから<strong><span class="swl-marker mark_yellow">約10分</span></strong>で開設できるところまで簡単になっています</p>



<p class="wp-block-paragraph">この記事では、実際にこのブログ（javeo.jp）をエックスサーバー＋SWELLで運営している私が、サーバー契約からWordPressの開設、テーマ導入、最初の記事を出すところまでの全手順を、初心者向けに順番にまとめてみました</p>



<h2 class="wp-block-heading">WordPressブログに必要なもの3つと費用の全体像</h2>



<p class="wp-block-paragraph">まず全体像をつかんでおきましょう、WordPressでブログを作るのに要るものは<strong><span class="swl-marker mark_yellow">たった3つ</span></strong>です</p>



<ul class="wp-block-list is-style-num_circle">
<li><strong>レンタルサーバー</strong>：サイトのデータを置く「土地」にあたるもの</li>



<li><strong>独自ドメイン</strong>：サイトの「住所」、このブログでいう javeo.jp の部分</li>



<li><strong>WordPressテーマ</strong>：サイトの「見た目」を決めるデザインの着せ替え</li>
</ul>



<p class="wp-block-paragraph">WordPress本体は無料で、上の3つにかかる費用の目安はこんな感じです（料金は記事執筆時点のもので、最新は各公式ページで確認してくださいね）</p>


<div class="c-scrollHint sp_"><span>スクロールできます <i class="icon-more_arrow"></i></span></div>
<figure data-table-scrollable="sp" class="wp-block-table is-style-stripes"><table style="--table-width:760px;"><thead><tr><th>必要なもの</th><th>役割</th><th>費用の目安（執筆時点）</th></tr></thead><tbody><tr><td>レンタルサーバー</td><td>サイトを置く土地</td><td>月600〜1,000円前後</td></tr><tr><td>独自ドメイン</td><td>サイトの住所（URL）</td><td>年1,000〜1,500円前後 ※サーバー特典で無料のことも</td></tr><tr><td>WordPressテーマ</td><td>サイトの見た目</td><td>無料〜2万円前後（SWELLは17,600円の買い切り）</td></tr><tr><td>WordPress本体</td><td>サイトを作るソフト</td><td>無料</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">合計しても<strong>月1,000円前後＋テーマ代</strong>くらいで始められます、無料ブログと違って独自ドメインのサイトは自分の資産になりますし、広告やデザインの自由度も高いので、本気で続けたいならWordPressで作っておくのが安心ですね</p>



<h2 class="wp-block-heading">【STEP1】レンタルサーバーを選ぶ</h2>



<p class="wp-block-paragraph">最初の関門がサーバー選びですが、ここで迷いすぎると前に進めません、初心者がチェックすべきポイントは<strong>表示速度・安定性・実績・管理画面の分かりやすさ</strong>くらいで十分です</p>



<p class="wp-block-paragraph">そのうえで私がおすすめするのは<strong>エックスサーバー</strong>です、理由はシンプルで、<strong><span class="swl-marker mark_yellow">このブログ自体もエックスサーバーで動かしている</span></strong>からで、長く使っていて速度も安定性も不満がなく、利用者が多いぶんネット上に情報が多くて困ったときに調べやすいんですね</p>



<p class="wp-block-paragraph">とはいえ比較なしに勧めるのもフェアじゃないので、もう一つの定番である<strong>ConoHa WING</strong>と並べてみます、どちらも質が高いので、最後は好みで選んで問題ないレベルです</p>


<div class="c-scrollHint sp_"><span>スクロールできます <i class="icon-more_arrow"></i></span></div>
<figure data-table-scrollable="sp" class="wp-block-table is-style-stripes"><table style="--table-width:700px;"><thead><tr><th>項目</th><th>エックスサーバー</th><th>ConoHa WING</th></tr></thead><tbody><tr><td>月額（執筆時点）</td><td>スタンダード 月693円〜（36ヶ月・30%OFF時）</td><td>ベーシック 月660円〜（36ヶ月）</td></tr><tr><td>初期費用</td><td>無料</td><td>無料</td></tr><tr><td>かんたん開設機能</td><td>WordPressクイックスタート</td><td>WordPressかんたんセットアップ</td></tr><tr><td>独自ドメイン無料</td><td>永久無料（12ヶ月以上で1つ等）</td><td>最大2つ無料</td></tr><tr><td>無料お試し</td><td>10日間</td><td>なし</td></tr><tr><td>私メモ</td><td>このブログも使用、情報が多くて安心</td><td>管理画面が新しめで見やすい</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">「とりあえず鉄板で間違いないものがいい」ならエックスサーバー、「管理画面の新しさや最安の月額を重視したい」ならConoHa WING、という選び方で大丈夫です、この記事ではこのあとエックスサーバーで開設する手順を例に進めていきますね</p>



<div class="swell-block-capbox cap_box is-style-onborder_ttl"><div class="cap_box_ttl"><span>まずはサーバーを確認してみる</span></div><div class="cap_box_content">
<p class="wp-block-paragraph">エックスサーバーは10日間の無料お試しがあるので、管理画面の雰囲気を先に見ておくのもありです、キャンペーン中なら月額がかなり下がっているので料金もあわせて確認しておきましょう</p>



<div class="swell-block-button is-style-btn_solid"><a href="https://px.a8.net/svt/ejp?a8mat=2ZTU22+94NAPE+CO4+61C2Q" rel="noopener noreferrer" class="swell-block-button__link"><span>エックスサーバーの料金を見てみる</span></a></div>
</div></div>



<p class="wp-block-paragraph">ConoHa WINGが気になる人はこちらもどうぞ、こちらも独自ドメインが最大2つ無料で付いてきます</p>



<div class="swell-block-button is-style-btn_line"><a href="https://px.a8.net/svt/ejp?a8mat=3T8KHY+4V1I6A+50+5SDXG2" rel="noopener noreferrer" class="swell-block-button__link"><span>ConoHa WINGも見てみる</span></a></div>



<h2 class="wp-block-heading">【STEP2】クイックスタートでWordPressを開設する</h2>



<p class="wp-block-paragraph">サーバーが決まったら、いよいよ開設です、昔はサーバー契約・ドメイン取得・WordPressインストール・SSL設定をバラバラにやる必要がありましたが、今は<strong><span class="swl-marker mark_yellow">クイックスタート</span></strong>を使えば、この4つを申し込みフォームの流れの中でまとめて終わらせられます</p>



<p class="wp-block-paragraph">実際の流れはこんな感じです、画面の案内に沿って入力していくだけなので、身構えなくて大丈夫ですよ</p>



<div class="swell-block-step" data-num-style="circle">
<div class="swell-block-step__item"><div class="swell-block-step__number u-bg-main"><span class="__label">STEP</span></div><div class="swell-block-step__title u-fz-l">申し込みフォームを開く</div><div class="swell-block-step__body">
<p class="wp-block-paragraph">エックスサーバー公式の「お申し込み」から「初めてご利用のお客様」を選びます、ここで「WordPressクイックスタート」を利用するにチェックを入れます</p>
</div></div>



<div class="swell-block-step__item"><div class="swell-block-step__number u-bg-main"><span class="__label">STEP</span></div><div class="swell-block-step__title u-fz-l">プランと契約期間を選ぶ</div><div class="swell-block-step__body">
<p class="wp-block-paragraph">個人ブログなら一番安いスタンダードで十分です、契約期間は長いほど月額が下がります、独自ドメイン永久無料の特典をねらうなら12ヶ月以上を選んでおくとよいですね</p>
</div></div>



<div class="swell-block-step__item"><div class="swell-block-step__number u-bg-main"><span class="__label">STEP</span></div><div class="swell-block-step__title u-fz-l">取得するドメインを決める</div><div class="swell-block-step__body">
<p class="wp-block-paragraph">そのまま使う独自ドメインを入力します、ここで決めた住所は後から変えられないので、落ち着いて決めましょう（決め方のコツはこの下に書いておきます）</p>
</div></div>



<div class="swell-block-step__item"><div class="swell-block-step__number u-bg-main"><span class="__label">STEP</span></div><div class="swell-block-step__title u-fz-l">WordPressの情報を入力する</div><div class="swell-block-step__body">
<p class="wp-block-paragraph">ブログ名・ユーザー名・パスワード・メールアドレスを入れます、ユーザー名とパスワードはログインで毎回使うので、忘れないように控えておいてくださいね、テーマを選ぶ欄があれば後で変えられるので無料のものでOKです</p>
</div></div>



<div class="swell-block-step__item"><div class="swell-block-step__number u-bg-main"><span class="__label">STEP</span></div><div class="swell-block-step__title u-fz-l">個人情報と支払いを入力する</div><div class="swell-block-step__body">
<p class="wp-block-paragraph">住所などの登録情報と、クレジットカードなどの支払い情報を入力します、最後にSMSか電話で本人確認をして申し込み完了です</p>
</div></div>



<div class="swell-block-step__item"><div class="swell-block-step__number u-bg-main"><span class="__label">STEP</span></div><div class="swell-block-step__title u-fz-l">開設完了のメールを待つ</div><div class="swell-block-step__body">
<p class="wp-block-paragraph">数分から十数分ほどでセットアップが終わり、WordPressのアドレスやログイン情報がメールで届きます、そのログインURLにアクセスできたら開設は成功です</p>
</div></div>
</div>



<div class="swell-block-capbox cap_box is-style-onborder_ttl"><div class="cap_box_ttl"><span>ドメイン名（URL）の決め方のコツ</span></div><div class="cap_box_content">
<ul class="wp-block-list is-style-check_list -list-under-dashed">
<li>短く・覚えやすく・打ちやすい文字列にする</li>



<li>サイトの内容や自分の名前と関連づけると愛着がわく</li>



<li>末尾は迷ったら .com が無難（一番なじみがある）</li>
</ul>
</div></div>



<div class="wp-block-group is-style-big_icon_caution"><div class="wp-block-group__inner-container">
<p class="wp-block-paragraph">クイックスタートを使うと、その場で料金の支払いが発生して<strong><span class="swl-marker mark_yellow" style="color:#e8313b">10日間の無料お試しは対象外</span></strong>になります、すぐに本格運用するなら問題ありませんが、「まず無料で触ってから決めたい」人は、クイックスタートを使わない通常の申し込みを選んでくださいね</p>
</div></div>



<p class="wp-block-paragraph">支払いまで終えてWordPressのログイン画面が開けば、もうあなたのブログは世界に公開されている状態です、ここまでで一番の山は越えました</p>



<div class="swell-block-button is-style-btn_solid"><a href="https://px.a8.net/svt/ejp?a8mat=2ZTU22+94NAPE+CO4+61C2Q" rel="noopener noreferrer" class="swell-block-button__link"><span>エックスサーバーで開設をはじめる</span></a></div>



<h2 class="wp-block-heading">【STEP3】WordPressの初期設定（最初にやる5つ）</h2>



<p class="wp-block-paragraph">開設できたら、記事を書き始める前に最低限の初期設定をすませておきます、ここを整えておくと後で困りません、特に<strong><span class="swl-marker mark_yellow">パーマリンク</span></strong>は最初に決めておくのが大事です</p>


<div class="c-scrollHint sp_"><span>スクロールできます <i class="icon-more_arrow"></i></span></div>
<figure data-table-scrollable="sp" class="wp-block-table is-style-stripes"><table style="--table-width:680px;"><thead><tr><th>設定</th><th>やること</th></tr></thead><tbody><tr><td>パーマリンク</td><td>「設定」→「パーマリンク」で<strong>投稿名</strong>を選ぶ、記事URLがきれいになる、後から変えると既存URLが変わってしまうので最初に決める</td></tr><tr><td>サイトタイトル</td><td>「設定」→「一般」でブログ名とキャッチフレーズを整える</td></tr><tr><td>SSL（https）</td><td>クイックスタートなら自動で設定済み、URLが https で表示されるか確認する</td></tr><tr><td>不要なものを削除</td><td>サンプル記事「Hello world」や使わないプラグインを消しておく</td></tr><tr><td>必須プラグイン</td><td>SEO SIMPLE PACK などを入れておくと後の設定が楽になる</td></tr></tbody></table></figure>



<div class="wp-block-group is-style-big_icon_point"><div class="wp-block-group__inner-container">
<p class="wp-block-paragraph">全部を完璧にやろうとしなくて大丈夫です、まずはパーマリンクとサイトタイトルだけ整えれば、記事を書き始められますよ</p>
</div></div>



<h2 class="wp-block-heading">【STEP4】テーマをSWELLにして見た目を整える</h2>



<p class="wp-block-paragraph">WordPressは「テーマ」を入れ替えるだけでサイト全体の見た目がガラッと変わります、無料テーマでも始められますが、デザインや使い勝手で時間を取られたくないなら、最初から完成度の高い有料テーマを入れてしまうのが結局は近道です</p>



<p class="wp-block-paragraph">私が使っているのが<strong>SWELL</strong>というテーマで、このブログもSWELLで作っています、おすすめする理由はこのあたりです</p>



<ul class="wp-block-list is-style-good_list">
<li>ブロックエディターに完全対応で、マウス操作だけで装飾できる（コード不要）</li>



<li>表示速度を上げるキャッシュや遅延読み込みの機能が最初から入っている</li>



<li>ボタンや吹き出し、ステップなどの装飾ブロックが標準でそろっている</li>
</ul>



<p class="wp-block-paragraph">価格は<strong><span class="swl-marker mark_yellow">17,600円（税込）の買い切り</span></strong>で、月額はかかりません（執筆時点・最新は公式で確認してくださいね）、バージョンアップも無料で、しかも<strong><span class="swl-marker mark_yellow">複数のサイトで使い回せる</span></strong>ので、ブログを増やしても買い直す必要がないのは大きいです</p>



<p class="wp-block-paragraph">それと、ここまでの手順どおりエックスサーバーを契約しているなら、<strong><span class="swl-marker mark_yellow">エックスサーバー経由でSWELLを買うと5%OFF（17,600円→16,720円）</span></strong>になります、サーバーをエックスサーバーにそろえておくと、こういう細かい得もあるんですね</p>



<p class="wp-block-paragraph">導入の手順もシンプルです</p>



<div class="swell-block-step" data-num-style="circle">
<div class="swell-block-step__item"><div class="swell-block-step__number u-bg-main"><span class="__label">STEP</span></div><div class="swell-block-step__title u-fz-l">SWELL公式で購入する</div><div class="swell-block-step__body">
<p class="wp-block-paragraph">公式サイトで会員登録して購入します、購入すると会員専用サイトにログインできるようになります</p>
</div></div>



<div class="swell-block-step__item"><div class="swell-block-step__number u-bg-main"><span class="__label">STEP</span></div><div class="swell-block-step__title u-fz-l">親テーマと子テーマをダウンロードする</div><div class="swell-block-step__body">
<p class="wp-block-paragraph">会員サイトから本体（親テーマ）と子テーマの2つのファイルをダウンロードします</p>
</div></div>



<div class="swell-block-step__item"><div class="swell-block-step__number u-bg-main"><span class="__label">STEP</span></div><div class="swell-block-step__title u-fz-l">WordPressにアップロードして有効化する</div><div class="swell-block-step__body">
<p class="wp-block-paragraph">「外観」→「テーマ」→「新規追加」から2つともアップロードし、<strong>子テーマのほうを有効化</strong>します、これで見た目がSWELLに切り替わります</p>
</div></div>
</div>



<div class="swell-block-capbox cap_box is-style-onborder_ttl"><div class="cap_box_ttl"><span>デザインで悩む時間を減らしたいなら</span></div><div class="cap_box_content">
<p class="wp-block-paragraph">SWELLは買い切りで複数サイトに使えるので、ブログを長く続けるつもりなら早めに入れてしまうほうがトータルでは得をしやすいです、公式で機能やデモを見てみてください</p>



<figure class="wp-block-image"><a href="//af.moshimo.com/af/c/click?a_id=4555738&amp;p_id=3885&amp;pc_id=9646&amp;pl_id=53838"><img decoding="async" src="//image.moshimo.com/af-img/3130/000000053838.jpg" alt=""/></a></figure>
</div></div>



<p class="wp-block-paragraph">ちなみに、すでにCocoonなど別のテーマでサイトを持っていて「SWELLに乗り換えたい」という人は、移行の手順を別記事にまとめています、<a href="https://javeo.jp/cocoon-to-swell-migration/" target="_blank" rel="noopener noreferrer">CocoonからSWELLへの移行手順</a>もあわせてどうぞ</p>



<h2 class="wp-block-heading">【STEP5】最初の記事を書いて公開する＋運営のコツ</h2>



<p class="wp-block-paragraph">ここまで来たら、あとは書くだけです、いきなり完璧な記事を目指さず、まずは1本公開してみるのがおすすめですよ</p>



<p class="wp-block-paragraph">記事を書き始める前に、最低限そろえておくとよいのがこのあたりです</p>



<ul class="wp-block-list is-style-check_list -list-under-dashed">
<li>固定ページ（プロフィール・お問い合わせ・プライバシーポリシー）を用意する</li>



<li>記事のカテゴリーをいくつか決めておく（書くテーマの軸になる）</li>



<li>アクセス解析（GA4）とサーチコンソールは、落ち着いてからつなげばOK</li>
</ul>



<p class="wp-block-paragraph">続けるコツは、最初から飛ばしすぎないことだと思います、テーマを絞って、自分が書きやすいジャンルから出していくと、無理なく記事がたまっていきます、完璧主義になりすぎず「直せばいい」くらいの気持ちで公開していきましょう</p>



<h2 class="wp-block-heading">追加でドメインが欲しくなったら（XServerドメイン vs お名前.com）</h2>



<p class="wp-block-paragraph">クイックスタートでは独自ドメインが1つ無料で付いてくるので、最初のブログはそれで十分です、ただ、2つ目のサイトを作りたくなったり、別ジャンルで新しい独自ドメインを取りたくなったときは、ドメイン取得サービスを使うことになります</p>



<p class="wp-block-paragraph">定番は<strong>XServerドメイン</strong>と<strong>お名前.com</strong>の2つです、軽く比較しておきますね（料金は執筆時点・税込）</p>


<div class="c-scrollHint sp_"><span>スクロールできます <i class="icon-more_arrow"></i></span></div>
<figure data-table-scrollable="sp" class="wp-block-table is-style-stripes"><table style="--table-width:700px;"><thead><tr><th>項目</th><th>XServerドメイン</th><th>お名前.com</th></tr></thead><tbody><tr><td>.com 取得</td><td>0円〜（キャンペーン時）</td><td>0円〜（1個目）</td></tr><tr><td>.com 更新（執筆時点）</td><td>年1,721円</td><td>年1,408円</td></tr><tr><td>向いている人</td><td>エックスサーバーと同じ管理画面でまとめたい</td><td>登録実績が多く、扱うドメインの種類も豊富</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">すでにエックスサーバーを使っているなら、管理画面をまとめられるXServerドメインが楽です、更新費を少しでも抑えたい・いろんな種類のドメインから選びたいならお名前.comも候補になります、ここも用途で選べば大丈夫ですよ</p>



<div class="swell-block-button is-style-btn_line"><a href="https://px.a8.net/svt/ejp?a8mat=3N8KKH+6NCBIA+CO4+15V79D" rel="noopener noreferrer" class="swell-block-button__link"><span>XServerドメインを見てみる</span></a></div>



<div class="swell-block-button is-style-btn_line"><a href="https://px.a8.net/svt/ejp?a8mat=2ZGTLV+14HJGI+50+2HHG82" rel="noopener noreferrer" class="swell-block-button__link"><span>お名前.comを見てみる</span></a></div>



<h2 class="wp-block-heading">まとめ｜まずはサーバー契約から動き出そう</h2>



<p class="wp-block-paragraph">WordPressブログの始め方を振り返っておきます、やることは大きく3ステップでした</p>



<ul class="wp-block-list is-style-num_circle -list-under-dashed">
<li>サーバーを選ぶ（迷ったらエックスサーバー、最安重視ならConoHa WING）</li>



<li>クイックスタートで開設する（サーバー・ドメイン・WordPress・SSLを一括で）</li>



<li>テーマをSWELLにして見た目を整える</li>
</ul>



<p class="wp-block-paragraph">頭で考えているうちは何も始まりませんが、サーバーさえ契約してしまえば、あとは流れで開設まで進めます、最初の一歩は<strong><span class="swl-marker mark_yellow">まずはサーバー契約から</span></strong>です、思い立った今日のうちに動いてしまいましょう</p>



<div class="swell-block-capbox cap_box is-style-onborder_ttl"><div class="cap_box_ttl"><span>今日から始めるなら</span></div><div class="cap_box_content">
<p class="wp-block-paragraph">エックスサーバーはキャンペーン中だと月額が下がっていることが多いので、まずは今の料金と空いているドメインを確認するところからどうぞ</p>



<div class="swell-block-button is-style-btn_solid"><a href="https://px.a8.net/svt/ejp?a8mat=2ZTU22+94NAPE+CO4+61C2Q" rel="noopener noreferrer" class="swell-block-button__link"><span>エックスサーバーでブログを始める</span></a></div>
</div></div>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://javeo.jp/wordpress-blog-start/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
