メインコンテンツまで移動する

Twitter と Instagram の遅延読み込みで WordPress を高速化

  • 公開日

Akira Web クリエイター

はじめに

WordPress に Twitter のツイートやタイムラインを埋め込んでいるサイトは多いと思います。また、Instagram の投稿を埋め込んでいるサイトも多く見かけます。

ただ、Twitter や Instagram の埋め込みがある場合は、PageSpeed Insights のスコアが低下します。実際のサイトの表示速度も遅くなると思います。

これを手間をかけずに改善するカスタマイズの紹介です。

検証

WordPress 公式テーマ Twenty Twenty-Two を使いカスタマイズの効果を検証します。計測は Lighthouse で行います。計測対象のデバイスはモバイルです。

まず、文字だけしかないページの計測結果です。おおよそ 85 点が出ます。

次に、文字に加えて、Twitter のツイートを 3 つ、Instagram の投稿を 3 つ追加した計測結果です。おおよそ 75 点とスコアが 10 点減りました。

Twitter のツイートが 3 つ、Instagram の投稿が 3 つがある状態のまま今回のカスタマイズを行った計測結果です。スコアが 85 点に回復しました。文字だけしかない時とほぼ同じスコアが出ると思います。

尚、検証結果は、あくまで目安です。どのサイトでも効果は出ると思いますが、サイトやページによってカスタマイズの効果は異なります。

対象

今回のカスタマイズの対象としている埋め込みは、以下のものです。

  • ブロックで埋め込んだ Twitter の投稿とタイムライン
  • Twitter Publish で生成した埋め込みコードをブロックかウィジェットの「カスタム HTML」に追加した Twitter の投稿とタイムライン
  • 埋め込みコード をブロックかウィジェットの「カスタム HTML」に追加した Instagram の投稿

また、以下のテーマで動作を検証しました。

  • 公式テーマ Twenty Twenty-Two
  • 公式テーマ Twenty Twenty-One
  • 公式テーマ Twenty Twenty
  • 人気テーマ Cocoon

コード

カスタマイズはコピペするだけです。使用中のテーマの functions.php に以下のコードを追加します。

// get_headerではTwenty Twenty-Twoで遅かったためwpを使う
add_action( 'wp', function() {
	ob_start( function( $html ) {
		// カスタムHTMLでasyncがasync=""になるため空の値を削除し、ブロックのasyncと統一する
		$html = str_replace(
			'<script async="" src',
			'<script async src',
			$html
		);
		$twitter_script = '<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>';
		$instagram_script = '<script async src="//www.instagram.com/embed.js"></script>';
		$twitter_pos = strpos( $html, $twitter_script ) !== false ? true : false;
		$instagram_pos = strpos( $html, $instagram_script ) !== false ? true : false;
		$js = '';

		if ( $twitter_pos || $instagram_pos ) {
			$js .= "
				const loadEmbed = (scriptId, scriptSrc, targets) => {
					const observer = new IntersectionObserver(entries => {
						for (const entry of entries) {
							const embedJs = document.getElementById(scriptId);
							if (entry.isIntersecting && !embedJs) {
								const script = document.createElement('script');
								script.id = scriptId;
								script.src = scriptSrc;
								document.body.appendChild(script);
								observer.disconnect();
							}
						}
					}, {
						rootMargin: '1250px 0px',
					});

					for (const target of targets) {
						observer.observe(target);
					}
				};
			";

			if ( $twitter_pos ) {
				$html = str_replace( $twitter_script, '', $html );
				$js .= "
					const twitterSrc = 'https://platform.twitter.com/widgets.js';
					const twitterTargets = document.querySelectorAll('.twitter-tweet, .twitter-timeline');
					loadEmbed('twitter-load-embed-js', twitterSrc, twitterTargets);
				";
			}

			if ( $instagram_pos ) {
				$html = str_replace( $instagram_script, '', $html );
				$js .= "
					const instagramSrc = '//www.instagram.com/embed.js';
					const instagramTargets = document.getElementsByClassName('instagram-media');
					loadEmbed('instagram-load-embed-js', instagramSrc, instagramTargets);
				";
			}

			$html = str_replace(
				'</body>',
				'<script type="module">' . $js . '</script></body>',
				$html
			);
		}

		return $html;
	});
});

add_action( 'shutdown', function() {
	if ( ob_get_length() > 0 ) {
		ob_end_flush();
	}
});

説明

今回のカスタマイズで行っているのは、Intersection Observer API を使った Twitter と Instagram の <script> の遅延読み込みです。これは画像の遅延読み込みと同じです。

このようなことを行っています。

  1. ページの全ての HTML を取得する。
  2. その HTML の中に Twitter とInstagram の <script> があるかを調べる。
  3. Twitter とInstagram の <script> がある場合は、その <script> を全て削除する。
  4. 代わりに、</body> の直前に JavaScript を追加する。

</body> の直前に追加する JavaScript では、このようなことを行っています。

  1. Twitter と Instagram の埋め込みが ビューポート に入ってきた時に動き始める。
  2. ビューポートに入ってきたのが Twitter のツイートかタイムラインであれば、Twitter の <script><body> の最後に追加する。
  3. ビューポートに入ってきたのが Instagram の投稿であれば、Instagram の <script><body> の最後に追加する。

Twitter か Instagram の <script><body> の最後に追加された後は、カスタマイズ前と同じです。Twitter と Instagram の JavaScript が、埋め込み要素を <iframe> に変換します。

調整

コードの中に以下の部分があります。これはビューポートを上下に 1250px 拡大する指定です。

rootMargin: '1250px 0px',

この指定により、埋め込みが画面内に入ってくる 1250px 手前で Twitter や Instagram の <script> を追加します。

手前で <script> を追加する理由は、Twitter や Instagram が表示されるまで少し時間がかかるためです。もし、rootMargin を指定していない、もしくは値が小さい場合は、Twitter や Instagram が表示されるまでユーザーを待たせてしまいます。

rootMargin0px の場合です。埋め込みが画面内に入ってきてから、Twitter の <script> を追加します。そのため、Twitter が表示されるまでユーザーを待たせます。

一方、1250px 手前で <script> を追加した場合は、埋め込みが画面内に入ってきた時には、すでに Twitter や Instagram は表示されていると思います。

rootMargin1250px の場合です。埋め込みが画面内に入ってきた時には Twitter が表示されており、ユーザーを待たせません。

ユーザーに不快な思いをさせないために、ある程度手前での <script> の追加をおすすめします。もし、Twitter や Instagram の表示が遅いと感じる場合は、rootMargin の値を大きくします。

rootMargin の指定方法は、CSS の margin とほぼ同じです。ただ、0 であっても単位が必要です。

ただし、ビューポートの拡大は、ページの上部に埋め込みがある場合に影響が出るかもしれません。もし、ページを表示した時に最初からビューポート内に埋め込みがある場合は、すぐに Twitter や Instagram の <script> を追加します。追加する <script> は非同期で動作しますが、ページの表示速度に影響が出るかもしれません。

rootMargin の値の参考として、loading="lazy" 属性がある場合の Chrome の動作を書いておきます。<img>loading="lazy" 属性がある場合、Chrome における画像の遅延読み込みの動作は以下のとおりです。

  • 4G 回線などの高速回線の場合は、画面内に入ってくる 1250px 手前で画像を読み込む。
  • 3G 回線などの低速回線の場合は、画面内に入ってくる 2500px 手前で画像を読み込む。

画像より読み込みに時間がかかる <iframe> の場合は、さらに手前から読み込みます。

  • 4G 回線などの高速回線の場合は、画面内に入ってくる 2500px 手前でインラインフレームを読み込む。
  • 3G 回線などの低速回線の場合は、画面内に入ってくる 3500px 手前でインラインフレームを読み込む。

参考情報

テスト環境で試し限り、最低でも 800px は必要のように感じました。

フォローする