WordPressで外部サイトや内部ページへのリンクを紹介する際、単純なテキストリンクよりも視覚的に魅力的なリンクボックス(リンクカード)を表示したいことがありますよね。
この記事では、URLを指定するだけで自動的にタイトル・サムネイル・抜粋文を取得し、美しいリンクボックスを生成するWordPressショートコードの作成方法を解説します。
完成イメージ
ショートコード [linkbox href="https://example.com/"]
を記述するだけで、上記のようなリンクボックスが自動生成されます。
特徴
- 自動メタデータ取得: URLからタイトル・説明文・OGP画像を自動取得
- パフォーマンス最適化: 投稿保存時に一度だけ変換、表示時は高速
- target属性対応: 内部リンク・外部リンクの使い分けが可能
- レスポンシブ対応: モバイルでも美しく表示
- WordPressライク: デフォルトテーマに馴染むデザイン
実装方法
1. PHPコードの実装
以下のコードを functions.php
に追加します。
<?php
//投稿保存時にショートコードをHTMLに変換する機能
//投稿保存時のフック
add_action('save_post', 'convert_linkbox_shortcodes_to_html', 10, 3);
function convert_linkbox_shortcodes_to_html($post_id, $post, $update) {
//自動保存やリビジョンを除外
if (wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
return;
}
//投稿タイプを限定(必要に応じて調整)
if (!in_array($post->post_type, array('post', 'page'))) {
return;
}
//無限ループを防ぐためのフラグ
if (get_transient('linkbox_processing_' . $post_id)) {
return;
}
$content = $post->post_content;
//linkboxショートコードが含まれているかチェック
if (strpos($content, '[linkbox') === false) {
return;
}
//処理中フラグを設定(30秒)
set_transient('linkbox_processing_' . $post_id, true, 30);
//ショートコードを検索して変換(target属性も考慮)
$updated_content = preg_replace_callback(
'/[linkboxs+href=["']([^"']+)["'](?:s+target=["']([^"']+)["'"])?s*]/',
'convert_single_linkbox_to_html',
$content
);
//内容が変更された場合のみ更新
if ($updated_content !== $content) {
//無限ループを防ぐため、フックを一時的に削除
remove_action('save_post', 'convert_linkbox_shortcodes_to_html', 10);
wp_update_post(array(
'ID' => $post_id,
'post_content' => $updated_content
));
//フックを再追加
add_action('save_post', 'convert_linkbox_shortcodes_to_html', 10, 3);
}
//処理中フラグを削除
delete_transient('linkbox_processing_' . $post_id);
}
//個別のlinkboxショートコードをHTMLに変換
function convert_single_linkbox_to_html($matches) {
$url = trim($matches[1]);
$target = isset($matches[2]) ? trim($matches[2]) : ''; //target属性を取得
//URLを検証
if (!filter_var($url, FILTER_VALIDATE_URL)) {
return '<p>無効なURLです: ' . esc_html($url) . '</p>';
}
//メタデータを取得
$metadata = get_url_metadata_for_conversion($url);
if (!$metadata) {
return '<p>URLの情報を取得できませんでした: ' . esc_html($url) . '</p>';
}
//target属性の処理
$target_attr = '';
if ($target === '_blank') {
$target_attr = ' target="_blank"';
}
//HTMLを生成
$html = sprintf(
'<a href="%s" class="linkbox my-1.5r"%s>
<strong class="linkbox-title">%s</strong>
%s
<span class="linkbox-excerpt">%s
<u class="linkbox-more">続きを読む</u>
</span>
</a>',
esc_url($url),
$target_attr, //target属性を条件付きで追加
esc_html($metadata['title']),
$metadata['image'] ? sprintf(
'<picture class="linkbox-thumbnail">
<img width="300" height="200" src="%s?ver=20250901110912" alt="%s" loading="lazy" />
</picture>',
esc_url($metadata['image']),
esc_attr($metadata['title'])
) : '',
esc_html($metadata['description'])
);
return $html;
}
//変換用のメタデータ取得関数(保存時専用)
function get_url_metadata_for_conversion($url) {
//タイムアウトを長めに設定(保存時なので多少時間をかけても良い)
$response = wp_remote_get($url, array(
'timeout' => 30,
'user-agent' => 'Mozilla/5.0 (compatible; WordPressBot/1.0)',
'headers' => array(
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
),
'redirection' => 5,
'sslverify' => false
));
if (is_wp_error($response)) {
return false;
}
$status_code = wp_remote_retrieve_response_code($response);
if ($status_code !== 200) {
return false;
}
$html = wp_remote_retrieve_body($response);
if (empty($html)) {
return false;
}
//HTMLをパース
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');
if (!$dom->loadHTML($html)) {
libxml_clear_errors();
return false;
}
libxml_clear_errors();
$xpath = new DOMXPath($dom);
$metadata = array(
'title' => '',
'description' => '',
'image' => ''
);
//タイトルを取得
$og_title = $xpath->query('//meta[@property="og:title"]/@content');
if ($og_title->length > 0) {
$metadata['title'] = trim($og_title->item(0)->nodeValue);
} else {
$title_tag = $xpath->query('//title');
if ($title_tag->length > 0) {
$metadata['title'] = trim($title_tag->item(0)->nodeValue);
}
}
//説明文を取得
$og_description = $xpath->query('//meta[@property="og:description"]/@content');
if ($og_description->length > 0) {
$metadata['description'] = trim($og_description->item(0)->nodeValue);
} else {
$meta_description = $xpath->query('//meta[@name="description"]/@content');
if ($meta_description->length > 0) {
$metadata['description'] = trim($meta_description->item(0)->nodeValue);
}
}
//画像を取得
$og_image = $xpath->query('//meta[@property="og:image"]/@content');
if ($og_image->length > 0) {
$image_url = trim($og_image->item(0)->nodeValue);
if (strpos($image_url, 'http') !== 0) {
$parsed_url = parse_url($url);
if ($parsed_url && isset($parsed_url['scheme']) && isset($parsed_url['host'])) {
$base_url = $parsed_url['scheme'] . '://' . $parsed_url['host'];
if (strpos($image_url, '/') === 0) {
$image_url = $base_url . $image_url;
} else {
$image_url = $base_url . '/' . $image_url;
}
}
}
$metadata['image'] = $image_url;
}
//説明文の長さを制限
if (mb_strlen($metadata['description']) > 130) {
$metadata['description'] = mb_substr($metadata['description'], 0, 130) . '...';
}
return $metadata;
}
//下書き時のプレビュー機能
function shortcode_linkbox_preview($atts, $content = '') {
$atts = shortcode_atts(array(
'href' => '',
'target' => '',
), $atts);
$url = trim($atts['href']);
$target = trim($atts['target']);
if (empty($url)) {
return '';
}
if (!filter_var($url, FILTER_VALIDATE_URL)) {
return '<p>無効なURLです: ' . esc_html($url) . '</p>';
}
$target_display = $target === '_blank' ? ' (新しいタブで開く)' : ' (同じタブで開く)';
return '<div style="border: 2px dashed #ccc; padding: 10px; margin: 10px 0;">
<strong>Linkboxプレビュー:</strong> ' . esc_html($url) . $target_display . '<br>
<small>※保存時に実際のリンクボックスに変換されます</small>
</div>';
}
add_shortcode('linkbox', 'shortcode_linkbox_preview');
?>
2. CSSスタイルの追加
WordPressテーマのCSSファイルまたは管理画面の「外観」→「カスタマイズ」→「追加CSS」に以下を追加します。
/* .linkbox */
.linkbox {
display: flow-root;
padding: 1.5rem;
line-height: 1.55;
font-size: clamp(0.8125rem, calc(0.8125rem + ((1vw - 0.225rem) * 0.1563)), 0.875rem);
font-weight: 400;
border: 1px solid hsl(223, 6%, 84%);
box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
background: hsl(223, 6%, 100%);
color: hsl(223, 6%, 53%);
text-decoration: none;
transition: all 0.3s ease;
}
.linkbox:hover {
border-color: #007cba;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
text-decoration: none;
}
.linkbox .linkbox-thumbnail {
float: left;
max-width: calc(160px + 1.25rem);
/* padding: 上 右 下 左 */
padding: calc(0.5lh - 0.5em) 1.25rem 0.08lh 0pc;
}
.linkbox .linkbox-thumbnail img {
width: 100%;
height: 100%;
/* アスペクト比(横 / 縦) */
aspect-ratio: 3 / 2;
border-radius: 4px;
}
.linkbox .linkbox-title {
line-height: 1.33;
font-size: clamp(1rem, calc(1rem + ((1vw - 0.225rem) * 0.4688)), 1.1875rem);
font-weight: 600;
color: #1F2023;
margin-bottom: 1rem;
}
.linkbox .linkbox-excerpt {
margin: 0;
}
.linkbox .linkbox-more {
color: hsl(223, 6%, 74%);
text-decoration: underline;
}
/* レスポンシブ対応 */
@media (max-width: 600px) {
.linkbox .linkbox-thumbnail {
float: none;
max-width: 100%;
padding: 0 0 1rem 0;
}
}
使用方法
基本的な使い方
URLの情報を取得できませんでした: https://example.com/page/
新しいタブで開く場合
external-site.com - Situs web ini dijual! - external site Sumber daya dan Informasi.
Situs web ini dijual! external-site.com adalah sumber pertama dan terbaik Anda untuk semua informasi yang Anda cari. Mulai dari to...
続きを読む
動作の仕組み
1. 投稿保存時の自動変換
ショートコードは投稿保存時に自動的にHTMLに変換されます。これにより:
- 高速表示: 表示時はHTTPリクエスト不要
- 安定性: 外部サイトの状況に依存しない
- SEO効果: 静的HTMLなので検索エンジンも認識
2. メタデータ取得の優先順位
- タイトル:
og:title
→<title>
タグ - 説明文:
og:description
→meta description
- 画像:
og:image
3. エラーハンドリング
- 無効なURL
- HTTPエラー
- メタデータ取得失敗
- HTMLパースエラー
すべて適切に処理され、エラー時は代替表示されます。
カスタマイズ
説明文の文字数制限を変更
//130文字から200文字に変更
if (mb_strlen($metadata['description']) > 200) {
$metadata['description'] = mb_substr($metadata['description'], 0, 200) . '...';
}
対象投稿タイプを追加
//カスタム投稿タイプも対象に含める
if (!in_array($post->post_type, array('post', 'page', 'custom_post_type'))) {
return;
}
タイムアウト時間の調整
//15秒に短縮
'timeout' => 15,
まとめ
このショートコードを使用することで:
✅ 簡単導入: ショートコード1行でリンクボックス作成
✅ 高パフォーマンス: 保存時変換で高速表示
✅ 美しいデザイン: WordPressデフォルトに馴染むスタイル
✅ 柔軟性: 内部・外部リンクの使い分け対応
✅ 保守性: エラーハンドリングも万全
WordPressサイトでのリンク紹介がより魅力的になること間違いなしです!
参考
この記事が役に立ったら、いいねやストックをお願いします! 🙏