投稿画面にカスタムフィールドを設置し、フォーム完了ページにダウンロードボタンを実装したい

カスタムフィールドを設置し、フォーム完了ページにダウンロードボタンを実装したい
目次

こんな時におすすめ

以下のように、実装したい時に検討してみてください!

  • WordPress管理画面で、ダウンロードファイルを設定したい。
  • 投稿ページのフォームの完了ページに、ダウンロードボタンを表示させたい。(そのボタンは投稿ごとに変えたい)

「固定ページにカスタムフィールドを設置して、フォーム完了ページにダウンロードボタンを実装したい」方は、こちらの記事を参考にしてください。

あわせて読みたい
固定ページにカスタムフィールドを設置し、フォーム完了ページにダウンロードボタンを実装したい こんな時におすすめ 以下のように、実装したい時に検討してみてください! WordPress管理画面で、ダウンロードファイルを設定したい。 固定ページにカスタムフィールド...

完成イメージ

ボタンを押すと、ボタンの下にダウンロードのローダー(くるくるするアニメーション)も出てきます。
カスタムフィールドに何も設定されていないと、ボタンは表示されない仕組みです。

実装方法

以下の想定でご紹介します。ご自分で使用する際はアレンジしてお使いください!

  1. カスタム投稿タイプ(dounload)の記事に、「Contact Form 7のフォーム」を設置。
  2. 「送信ボタン」をクリックすると、「完了ページ(ディレクトリ名:document-complete)にリダイレクト」。
    その時に「パラメーターに記事IDをつける」。
    ※記事IDをパラメータにつけることで、その記事の「カスタムフィールドの値を引っ張ってくる」ことができます。
  3. 完了ページに「ボタン」を設置。クリックすると、ポップアップは起動せずにファイルをダウンロードする。
  • 1. 完了ページはあらかじめ、固定ページ(ディレクトリ名はdocument-complete)で作成しておきます。
  • 2. 完了ページにパラメータをつけた時、URLはこのようになります。
    例:https://hogehoge.com/document-complete?post_id=447

この記事では、「Google Driveのファイル(共有URLを使用)」「WordPressにアップロードしたファイル」の2つの方法もご紹介しております。
ご自分が使用する方を参考にしてくださいね。

1. カスタムフィールド Advanced Custom Fields(ACF)を作成

「Google Driveのファイル」と「WordPressにアップロードしたファイル」でACFの設定が変わります。

Google Driveのファイル(共有URL)を使いたい場合

Google Driveの共有URLをクリックすると、普通はGoogle Driveのページが表示されるのですが、
ご紹介する方法では、そのページの表示なしで直接PDFをダウンロードできるようになります。

管理画面での実装イメージ
Advanced Custom Fields(ACF)の設定画面
  • フィールドタイプ:URL
  • フィールドラベル(任意):
    例:資料請求完了ページに載せる、Google Driveの共有URLを入れてください。
  • フィールド名(任意):document_download_url

WordPressにアップロードしたファイルを使いたい場合

PDFを想定しています。(WordやExcelも使えるかもしれませんので、テストしてみてください。)

管理画面での実装イメージ
Advanced Custom Fields(ACF)の設定画面
  • フィールドタイプ:ファイル
  • フィールドラベル(任意):
    例:資料請求完了ページに載せる、PDFをアップロードしてください。
  • フィールド名(任意):document_file
  • 返り値:ファイル配列

2. Contact Form 7独自のショートコードを作成

Contact Form 7に「現在の投稿IDをhiddenフィールドの値(value)にセット」するために、独自のショートコードを作成します。

functions.phpに以下のコードを作成

/**
 * Contact Form 7で独自のショートコードを設定
 * そのショートコードを使って、現在の投稿IDをhiddenフィールドの値に出力(documentのみ)
 * Contact Form 7内に、[post_id your-post-id] を設置。
 * 参考サイト:https://rishuntrading.co.jp/blog/wordpress/call_shortcode_in_contactform7/
 *  wpcf7_add_shortcode の使用は Contact Form 7 バージョン 4.6 から非推奨になったので、wpcf7_add_form_tagに変更。
 *  【ショートコード作成の注意点】
 *  以下のようにすると、文字列として出力されてしまう。
 *  ※1 ショートコードは小文字にする。大文字は×。
 *  ※2 カッコを入れ子に使用できない。例:[hidden your-post-id "[post_id]"]
 */
function cf7_post_id_form_tag_handler($tag) {
    if (!is_singular('document')) { // カスタム投稿(document)のみ.
        return ''; // 投稿ページまたは固定ページ以外では空を返す.
    }

    global $post;
    $post_id = $post->ID;
    $html = sprintf('<input type="hidden" name="%s" value="%s">', esc_attr($tag->name), esc_attr($post_id));
    return $html;
}

wpcf7_add_form_tag('post_id', 'cf7_post_id_form_tag_handler', ['name-attr' => true]); // Contact Form 7用のショートコードを追加

3. Contact Form 7の管理画面でショートコードを入れる

<div>[post_id your-post-id]</div>

独自で作ったショートコードに何もタグを囲っていないと、勝手にpタグで囲んでしまうので、
ショートコードをdivタグで囲んでください。
(pタグにCSSが設定されていることが多く、この部分が思わぬ余白として出てしまうのを防ぐためです)

フォームが出力されると、このショートコードはinputタグのtype=”hidden”になります。
なので表示はされないですが、pタグは勝手についちゃいます。
このせいでフォームが崩れる場合は、divタグにclassをつけるなどして、対応してください。

<div>
	<p><input type="hidden" name="your-post-id" value="447"></p>
</div>

4. Contact Form 7 送信完了ページに投稿IDを渡しつつ、JavaScriptでリダイレクトする

先ほどのショートコードで設定した、hiddenフィールドの値(value)に投稿IDが入っています。
それを送信完了ページにリダイレクトする時に、投稿IDをパラメータとして付与します。

完了ページのURL例:https://hogehoge.com/document-complete?post_id=447
※447が記事IDになります。

方法は2通りあります。

方法1:JavaScriptファイルに書き込む

「特定のフォームのみに、特定のJavaScriptファイルを読み込むようにしている」場合、こちらを使ってください。
例えば、Contact Form 7のフォームを2種類以上使っている(もう一方はこの記事の仕組みを使わない)」の時に便利です。

// Contact Form 7 送信完了ページにpost_idを渡しつつ、JavaScriptでリダイレクトする(お役立ち資料のみ)-----------
// functions.php内に、独自のショートコード[post_id your-post-id]を設置しています。
document.addEventListener(
  "wpcf7mailsent",
  function (event) {
    var inputs = event.detail.inputs;
    var postId;
    //inputsはフォーム内全ての入力フィールド(input, select, textareaなど)が入っている
    inputs.forEach(function (input) {
      if (input.name === "your-post-id") {
        postId = input.value; // フォーム内にhiddenに設定した、name="your-post-id"のvalue(現在の投稿ID)を取得.
      }
    });
    // サンクスページにリダイレクト。その時に、クエリパラメータとして現在の投稿IDを渡す.
    // locationオブジェクトはグローバルオブジェクトなので、変数の宣言はいらない。
    location = "/document-complete/?post_id=" + postId;
  },
  false
);

方法2:functions.phpに書き込む

方法1が使えない場合は、functions.phpにて条件分岐で該当するページだけ設置する方法もあります。
(フォームを1種類しか使っていない場合も、今後フォームを増やす可能性があるので、条件分岐を設定するをおすすめします。)

/**
 * Contact Form 7 送信完了ページにpost_idを渡しつつ、JavaScriptでリダイレクトする(documentのみ)
 * functions.php内に、独自のショートコード[post_id your-post-id]を設置しています。
 * ここに書くと全ページに適用されるので、特定のページのみに適用する
 */
add_action('wp_footer', 'custom_redirect_for_specific_form');
function custom_redirect_for_specific_form() {
		if (is_singular('document')) { // カスタム投稿(document)のみ.
    ?>
    <script type="text/javascript">
        document.addEventListener(
          "wpcf7mailsent",
          function (event) {
            var inputs = event.detail.inputs;
            var postId;
            //inputsはフォーム内全ての入力フィールド(input, select, textareaなど)が入っている
            inputs.forEach(function (input) {
              if (input.name === "your-post-id") {
                postId = input.value; // フォーム内にhiddenに設定した、name="your-post-id"のvalue(現在の投稿ID)を取得.
              }
            });
            // サンクスページにリダイレクト。その時に、クエリパラメータとして現在の投稿IDを渡す.
            // locationオブジェクトはグローバルオブジェクトなので、変数の宣言はいらない。
            location = "/document-complete/?post_id=" + postId;
          },
          false
        );
    </script>
    <?php
		}
}

5. 完了ページ(page-document-complete.php)の設定

PHP, HTML, Javascriptの部分

「Google Driveのファイル」と「WordPressにアップロードしたファイル」でPHPが変わります。

カスタムフィールドに何も設定されていないと、ボタンは表示されない仕組みです。

どちらも固定ページのPHP(今回は、page-document-complete.php)に記入します。

Google Driveのファイルの場合
<?php // 投稿IDを取得
	if(isset($_GET['post_id'])) :
			// クエリパラメータから投稿IDを整数として安全に取得
			$post_id = intval($_GET['post_id']);
			// ACFの値に入った、Google Driveの共有URLを取得
			$shared_url = get_field('document_download_url', $post_id);

			// Google Driveの共有URLからFILE_IDを抽出
			//(/d/ から次の / までにある番号がFILE_ID。
			// 例:https://drive.google.com/file/d/1A2B3C4D5E6F7G8H9I/view?usp=sharing")
			preg_match('/\/d\/(.+?)\//', $shared_url, $matches);
			$file_id = $matches[1] ?? '';

			// ダウンロードリンクを作成
			$download_link = "https://drive.google.com/uc?export=download&id=" . $file_id;
	?>

<!-- ダウンロードボタンのHTML -->	
<p class="c-btn-ellipse c-btn-ellipse--download p-complete__download-btn">
	<button class="js-download-btn">資料ダウンロード</button>
	<span class="loader js-loader"></span>
</p>

<!-- ダウンロード機能を実装するJavaScript -->
<script>
document.addEventListener('DOMContentLoaded', function() {
	const btn = document.querySelector('.js-download-btn');
	const loader = document.querySelector('.js-loader');
	btn.addEventListener('click', () => {
		// ローダーを表示
		loader.style.display = 'block';

		// 一時的なダウンロードリンクを作成
		const element = document.createElement('a');
		// esc_urlなどの無害化をすると、Googleのエラーが出るのでしない。
		element.href = '<?php echo $download_link; ?>';
		// PDF名は仮で設定。(ダウンロード時にGoogle Driveのファイル名に置き換わります。)
		element.download = 'downloaded_document.pdf';

		// ダウンロードリンクをクリック。ダウンロードを実行する
		element.click();

		// 一定時間後にローダーを非表示
		setTimeout(function() {
			loader.style.display = 'none';
		}, 6000); // 6秒後にローダーを非表示にする(適宜調整)
	}, false);
});
</script>
<?php endif; ?>
WordPressにアップロードしたファイルの場合
<?php
// ACFを使用したファイルダウンロード機能

// URLパラメータから投稿IDを取得
if(isset($_GET['post_id'])) :
    // GETパラメータから投稿IDを整数として安全に取得
    $post_id = intval($_GET['post_id']);

    // ACFフィールド 'document_file' から文書ファイルの情報を取得
    $document_file = get_field('document_file', $post_id);

    // ファイル情報が存在し、配列形式であることを確認
    if($document_file && is_array($document_file)) :
        // ファイルのURLと元のファイル名を取得
        $document_download_url = $document_file['url'];
        $document_filename = $document_file['filename'];

        // ファイルの内容を取得する関数
        function get_file_contents($url) {
            if (function_exists('curl_init')) {
                // cURLが利用可能な場合、cURLを使用してファイルを取得
				// cURLとは様々なプロトコルをサポートしているライブラリ。Local by Flywheelでも使用でき、file_get_contents()よりも高速。
                $ch = curl_init();
                curl_setopt($ch, CURLOPT_URL, $url);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                $file_contents = curl_exec($ch);
                curl_close($ch);
                return $file_contents;
            } else {
                // cURLが利用できない場合、file_get_contents()を使用
                return file_get_contents($url);
            }
        }

        // ファイルの内容を取得
        $file_contents = get_file_contents($document_download_url);

        if ($file_contents !== false) {
            // ファイルの内容をBase64エンコード
            $document_download_url_base64_url = base64_encode($file_contents);
?>
	<!-- ダウンロードボタンのHTML -->
	<p class="c-btn-ellipse">
		<button class="js-download-btn">資料ダウンロード</button>
		<span class="c-btn-ellipse__loader js-loader"></span>
	</p>

	<!-- ダウンロード機能を実装するJavaScript -->
	<script>
	document.addEventListener('DOMContentLoaded', function() {
		// ダウンロードボタンの要素を取得
		const btn = document.querySelector('.js-download-btn');

		// ボタンクリックイベントのリスナーを追加
		btn.addEventListener('click', () => {
			// 一時的なa要素を作成
			let element = document.createElement('a');
			// Base64エンコードされたファイルデータをhref属性に設定
			// 'data:application/pdf;base64,' は、ブラウザにこれがBase64エンコードされたPDFであることを伝える
			element.href = 'data:application/pdf;base64,<?php echo $document_download_url_base64_url; ?>';
			// ダウンロードするファイル名を設定
			element.download = '<?php echo $document_filename; ?>';
			// a要素のクリックイベントをプログラムから発火
			element.click();
		}, false);
	});
	</script>
	<?php
        } else {
            // ファイルの取得に失敗した場合、エラーをログに記録
            error_log("Failed to retrieve file contents: " . $document_download_url);
        }
    endif;
endif;
?>

CSSの部分

HTMLの構造とclass名はこのようにしています。

<p class="c-btn-ellipse">
	<!-- ↓ボタン部分 -->
	<button class="c-btn-ellipse__link js-download-btn">資料ダウンロード</button>
	<!-- ↓ローダー部分 -->
	<span class="c-btn-ellipse__loader js-loader"></span>
</p>

CSSはこれを叩き台にカスタマイズしてください。

.c-btn-ellipse{
	position: relative; //ローダーを固定する

	// ボタン部分--------------
	&__link {
		background-color: #007eff;
		color: #fff;
		position: relative;
		padding: 0.8em 0.8em 0.8em 0.6em;
	    font-size: 1.5rem;
	    font-weight: 600;
	    line-height: 0.0666666667;

		// ボタンのアイコン部分
		&:before {
			content: "";
			display: inline-block;
			margin-right: 0.5em;
			width: 1em;
			height: 1em;
			background: url("アイコンのURL") no-repeat center center / contain;
			transition: all 0.3s;
		}
	}

	//ローダー部分---------------
	&__loader {
		// ローダーの位置
		position: absolute; //ボタンの下に表示するようにする
		bottom: -25px; //ボタンの下に表示するようにする
		left: 0;
		right: 0;
		margin: 0 auto;
		display: none; //最初は非表示

		// ローダーのデザイン・アニメーション
		width: 10px;
		padding: 8px;
		aspect-ratio: 1;
		border-radius: 50%;
		background: #007eff;
		--_m: conic-gradient(#0000 10%, #000),
			linear-gradient(#000 0 0) content-box;
		-webkit-mask: var(--_m);
		mask: var(--_m);
		-webkit-mask-composite: source-out;
		mask-composite: subtract;
		animation: l3 1s infinite linear;
	}
}

注意点

  • ファイル名は、「半角英数字」にするようにしてください。
    Google Driveファイル名が日本語の時、Safariでダウンロードした時にファイル名が文字化けしました。
    他のブラウザでも文字化けしかねないので、ファイル名は半角英数字にするようにしましょう。
    (WordPressにアップロードするファイルには、対策として「WP Multibyte Patch」というプラグインを入れておくと、日本語の全角文字(マルチバイト文字)を自動的に半角英数字(1バイト文字)に変換してくれます。)
  • ダウンロードするファイルの重さですが、あまり重いサイズは設定しないようにしましょう。
    (軽ければ軽いに越したことはありません。目安として20MG未満にした方が良さそうです。)
カスタムフィールドを設置し、フォーム完了ページにダウンロードボタンを実装したい

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!

コメント

コメント一覧 (1件)

目次