2026年9月30日

2026年9月30日

WordPressでフリーランサーマーケットサイトを構築する方法:3つの作り方と実装の要点

WordPressでフリーランサーと発注者をつなぐマーケットサイトを作るには、「案件掲載だけを行う求人ボード型」「WooCommerceとマルチベンダー拡張でサービスを販売する型」「カスタム投稿タイプで案件と提案を自作する型」の3つの作り方があります。最初は代金の受け渡しをサイトで扱わない形で始め、利用が増えてから決済を組み込むのが現実的です。この記事では、各方式の向き不向き、自作する場合の案件・提案機能の実装例、運営前に整理すべき決済と法律の論点を説明します。

最初に決めること:代金をサイトで扱うか

フリーランサーマーケットの設計で最も影響が大きいのは、発注者からフリーランサーへの支払いをサイト上で仲介するかどうかです。

  • 仲介しない:サイトは案件の掲載と応募・提案の受付までを担い、契約と支払いは当事者同士で行います。作るのも運営するのも軽く、小さく始めるのに向きます
  • 仲介する:運営者が代金を受け取り、手数料を差し引いてフリーランサーに支払います。収益化しやすい反面、決済サービスの選定、返金・紛争対応、本人確認、法律面の整理が必要になります

代金を一時的に預かって後から渡す仕組みは、国内では資金決済に関する法律などの規制にかかわる可能性があります。自前で預かり金の仕組みを作らず、Stripe Connectのようにプラットフォーム向けに設計された決済サービスを使い、事業の形が固まった段階で弁護士など専門家に確認してください。

作り方1:求人ボード型(WP Job Manager)

WP Job Managerは、案件(求人)の投稿・一覧・検索・応募をまとめて提供するプラグインです。発注者がフロントエンドから案件を投稿し、運営者が承認してから公開する、といった流れを標準機能で組めます。有料アドオンで応募管理や掲載期限の延長などを追加できます。

代金の仲介をせず、案件と人を結びつける場として始めるならこの方式が最短です。ただし「フリーランサーのプロフィール一覧」や「提案の比較」は標準の守備範囲外なので、必要なら会員系プラグインや自作で補います。

作り方2:WooCommerce+マルチベンダー拡張

フリーランサーを「出品者」、スキルや作業を「商品(サービス)」として扱う方式です。WooCommerceにDokan、WCFM Marketplace、MultiVendorX、WC Vendorsなどのマルチベンダー拡張を組み合わせると、出品者ごとのストアページ、売上管理、手数料設定を持つマーケットプレイスになります。

この方式は「ロゴ制作 1件」「記事執筆 3,000字」のように、内容と単価を先に決められるパッケージ型のサービス販売に向きます。一方、発注者が案件を出して複数の提案から選ぶ「コンペ・見積もり型」の流れには合わないことが多いです。出品者への自動送金(支払いの分配)は、拡張の有料版や決済サービス側の対応状況によって可否が変わるため、導入前に各拡張の公式ドキュメントで確認します。

作り方3:案件と提案を自作する

見積もり型の流れを自由に設計したい場合は、カスタム投稿タイプで「案件」と「提案」を作り、ユーザーの役割(ロール)で権限を分けます。テーマを替えても機能が残るよう、子テーマではなく専用プラグインかmu-plugin(wp-content/mu-plugins/ に置くファイル)に書くのがおすすめです。作業前にバックアップを取り、ステージング環境で試してください。

投稿タイプとロールを登録する

<?php
/**
 * Plugin Name: Freelance Market Core
 */

add_action( 'init', function () {
	register_post_type( 'fl_project', array(
		'labels'       => array( 'name' => '案件', 'singular_name' => '案件' ),
		'public'       => true,
		'has_archive'  => true,
		'rewrite'      => array( 'slug' => 'projects' ),
		'supports'     => array( 'title', 'editor', 'author' ),
		'show_in_rest' => true,
	) );

	register_post_type( 'fl_proposal', array(
		'labels'   => array( 'name' => '提案', 'singular_name' => '提案' ),
		'public'   => false,
		'show_ui'  => true,
		'supports' => array( 'title', 'editor', 'author' ),
	) );

	// add_role() はデータベースに保存されるので、未登録のときだけ実行する
	if ( ! get_role( 'fl_freelancer' ) ) {
		add_role( 'fl_freelancer', 'フリーランサー', array(
			'read'               => true,
			'fl_submit_proposal' => true,
		) );
	}
	if ( ! get_role( 'fl_client' ) ) {
		add_role( 'fl_client', '発注者', array( 'read' => true ) );
	}
} );

提案(fl_proposal)は一般公開しないため public を false にし、管理画面でだけ確認できるようにしています。投稿タイプを追加したあとは、管理画面の「設定」→「パーマリンク」を開いて保存し直すと、/projects/ のURLが有効になります。

提案フォームと受付処理

案件の詳細ページに、フリーランサーだけが見える提案フォームを置きます。送信先はWordPress標準の admin-post.php で、nonce(使い捨ての確認用トークン)を埋め込みます。

<?php if ( current_user_can( 'fl_submit_proposal' ) ) : ?>
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
	<?php wp_nonce_field( 'fl_proposal_' . get_the_ID() ); ?>
	<input type="hidden" name="action" value="fl_submit_proposal">
	<input type="hidden" name="project_id" value="<?php echo esc_attr( get_the_ID() ); ?>">
	<label for="fl-message">提案内容</label>
	<textarea id="fl-message" name="message" rows="8" required></textarea>
	<button type="submit">提案を送る</button>
</form>
<?php endif; ?>

受付処理は、nonceの検証、権限チェック、案件の実在確認、入力のサニタイズの順に行います。

add_action( 'admin_post_fl_submit_proposal', function () {
	$project_id = isset( $_POST['project_id'] ) ? absint( $_POST['project_id'] ) : 0;
	check_admin_referer( 'fl_proposal_' . $project_id );

	if ( ! current_user_can( 'fl_submit_proposal' ) ) {
		wp_die( '提案する権限がありません。', 403 );
	}

	$project = get_post( $project_id );
	if ( ! $project || 'fl_project' !== $project->post_type || 'publish' !== $project->post_status ) {
		wp_die( '案件が見つかりません。', 404 );
	}

	$message = isset( $_POST['message'] ) ? sanitize_textarea_field( wp_unslash( $_POST['message'] ) ) : '';
	if ( '' === $message ) {
		wp_die( '提案内容を入力してください。', 400 );
	}

	wp_insert_post( array(
		'post_type'    => 'fl_proposal',
		'post_status'  => 'private',
		'post_title'   => sprintf( '提案: %s', $project->post_title ),
		'post_content' => $message,
		'post_author'  => get_current_user_id(),
		'post_parent'  => $project_id,
	) );

	wp_safe_redirect( add_query_arg( 'proposal', 'sent', get_permalink( $project_id ) ) );
	exit;
} );

admin_post_{action} はログイン中のユーザーにだけ実行されるフックなので、未ログインの送信はここに届きません。提案は post_parent に案件IDを入れて紐づけているため、発注者向けの画面では get_posts() に post_parent を指定して一覧にできます。実運用では、同じ案件への二重提案の防止、短時間の連続送信の制限、発注者への通知メールを足していきます。

つまずきやすい点

  • 発注者に管理画面を触らせない:案件の投稿もフロントエンドのフォームで受け、post_status を pending(承認待ち)にして運営者が確認してから公開すると、スパム案件を防げます
  • 個人情報の見せ方:氏名・連絡先・実績はプロフィールに集まります。公開範囲を項目ごとに決め、連絡先は契約が成立するまで非表示にするなど、直接取引への誘導や情報の悪用を防ぐ設計にします
  • メッセージ機能:当事者間のやり取りが必要なら、BuddyPressのような実績あるコミュニティ系プラグインの利用を検討します。自作するとスパム対策や通報機能まで作る必要があり、負担が大きくなります

運営前に整理しておくこと

技術より先に、利用規約とルールを整えておくことが運営の安定につながります。

  • 利用規約とプライバシーポリシー:禁止行為、手数料、トラブル時の対応範囲、個人情報の利用目的と第三者提供を明記する
  • 特定商取引法に基づく表記:手数料を取るなど有償のサービスを提供するなら、表示義務の対象になるかを確認する
  • フリーランス保護の法律:2024年11月に施行されたフリーランス・事業者間取引適正化等法は、主に発注者側の義務(取引条件の明示など)を定めています。マーケットの画面で取引条件を明示しやすくする設計は、利用者の助けになります
  • 本人確認と審査:フリーランサーの登録を承認制にするか、どこまで本人確認するかを決める

法律の適用範囲は事業の形によって変わります。ここでの説明は論点の整理にとどまるため、具体的な判断は専門家に相談してください。制度や決済サービスの条件は(2026年10月現在)の状況をもとにしており、今後変わる可能性があります。

まとめ

  • 最初に「代金をサイトで仲介するか」を決める。小さく始めるなら仲介しない形が軽い
  • 掲載だけならWP Job Manager、パッケージ型のサービス販売ならWooCommerce+マルチベンダー拡張、見積もり型ならカスタム投稿タイプで自作する
  • 自作する場合は専用プラグインかmu-pluginに書き、nonce・権限チェック・サニタイズ・エスケープを省かない
  • 代金の預かりは自作せず、プラットフォーム向けの決済サービスを使い、法律面は専門家に確認する
  • 個人情報の公開範囲、承認制、利用規約を運営開始前に整える

お気軽にご相談ください

お見積りへ お問い合わせへ
▲