WP REST APIは、WordPressの4.7から使えるようになった「外部からWordPressにアクセスすることができる」便利な機能です。
このWP REST APIとタブを、ネイティブなJavaScriptで、カテゴリ別の記事をタブに格納して表示させる方法について解説していきます。
コード量は多いですが、是非最後までご覧ください。
WP REST API
WP REST APIは、WordPressの外部からそのWordPressにアクセスすることができるAPIです。
この記事ではそんなWP REST APIで記事情報を取得するときに、カテゴリーの分類のパラメータを加えて記事を取得しています。
この辺りは、この記事の後半で詳細を解説しますがはじめに概要だけ抑えておきたい方は、以下の記事もチェックしてみてください。
WP REST APIで記事一覧を表示記事をカテゴリー別にタブで表示したサンプル
早速サンプルです。カテゴリー別の記事をそれぞれのタブに格納して表示させています。
タブの見出しにカテゴリー名を表示させています。
サンプルのコード
サンプルのコードは、HTML・JavaScript・CSSの3種類です。順に解説していきます。
HTML
HTMLのほとんどは「タブ」に関する記述がほとんどで、タブの見出しは「tab」のclass名の箇所。そして、タブの中身は「content-tab」のclass名の箇所に記述します。
<div class="javaTab">
<div class="javaTabInner">
<div class="javaContainer">
<ul>
<li class="tab is-active" onclick="openTab(event,'Section1')"><a>TLD</a></li>
<li class="tab" onclick="openTab(event,'Section2')"><a>ドメインの価格</a></li>
<li class="tab" onclick="openTab(event,'Section3')"><a>ドメイン用語</a></li>
</ul>
</div>
</div>
</div>
<!-- タブの中身 -->
<div class="container section">
<div id="Section1" class="content-tab" >
<ul id="viewPostsTab1"></ul>
</div>
<div id="Section2" class="content-tab" style="display:none">
<ul id="viewPostsTab2"></ul>
</div>
<div id="Section3" class="content-tab" style="display:none">
<ul id="viewPostsTab3"></ul>
</div>
</div>
<!-- タブの中身 -->
タブの表示・非表示のトリガーは、「tab」のclass名のつくタグに onclick="openTab()"
のイベントハンドラで記述しています。
JavaScript
JavaScriptで書くコードは、APIの記述も3回分あるので多めです。また、読み込ませていく順番も重要なので、それぞれ適切な場所に書き込んでいきましょう。
まずはじめに、以下の WP REST APIのコードは、HTMLのヘッダーで読み込ませるように記述しましょう。
// categoy11
const getPosts1 = "https://dubdesign.net/domain/wp-json/wp/v2/posts?_embed&categories=11&per_page=10"
fetch(getPosts1).then(
response => {
return response.json(); // get JSON data$
}).then(data => {
for (let i = 0; i < data.length; i++) {
var date2 = new Date(data[i].date);
var year = date2.getFullYear();
var month = date2.getMonth() + 1;
var day = date2.getDate();
viewPostsTab1.innerHTML += '<li class="posts">' // contentwrapper
+ '<a href="' + data[i].link + '" class="linkID_' + data[i].id +'">'
+ '<img src="' + data[i]._embedded["wp:featuredmedia"][0].source_url + '" alt="' + data[i].title.rendered +'">'
+ '<time class="postTime dfont" itemprop="datePublished" datetime="' + data[i].date + '">' + year + '年' + month + '月' + day + '日' + '</time>'
+ '<p class="postTitle">' + data[i].title.rendered + '</p>'
+ '</a>' // href end
+ '</li>' // end content
}
}).catch(err => {
// Do something with error here
console.log('Error: ' + err)
})
// categoy16
const getPosts2 = "https://dubdesign.net/domain/wp-json/wp/v2/posts?_embed&categories=16&per_page=10"
fetch(getPosts2).then(
response => {
return response.json(); // get JSON data$
}).then(data => {
for (let i = 0; i < data.length; i++) {
var date2 = new Date(data[i].date);
var year = date2.getFullYear();
var month = date2.getMonth() + 1;
var day = date2.getDate();
viewPostsTab2.innerHTML += '<li class="posts">' // contentwrapper
+ '<a href="' + data[i].link + '" class="linkID_' + data[i].id +'">'
+ '<img src="' + data[i]._embedded["wp:featuredmedia"][0].source_url + '" alt="' + data[i].title.rendered +'">'
+ '<time class="postTime dfont" itemprop="datePublished" datetime="' + data[i].date + '">' + year + '年' + month + '月' + day + '日' + '</time>'
+ '<p class="postTitle">' + data[i].title.rendered + '</p>'
+ '</a>' // href end
+ '</li>' // end content
}
}).catch(err => {
// Do something with error here
console.log('Error: ' + err)
})
// categoy3
const getPosts3 = "https://dubdesign.net/domain/wp-json/wp/v2/posts?_embed&categories=2&per_page=10"
fetch(getPosts3).then(
response => {
return response.json(); // get JSON data$
}).then(data => {
for (let i = 0; i < data.length; i++) {
var date2 = new Date(data[i].date);
var year = date2.getFullYear();
var month = date2.getMonth() + 1;
var day = date2.getDate();
viewPostsTab3.innerHTML += '<li class="posts">' // contentwrapper
+ '<a href="' + data[i].link + '" class="linkID_' + data[i].id +'">'
+ '<img src="' + data[i]._embedded["wp:featuredmedia"][0].source_url + '" alt="' + data[i].title.rendered +'">'
+ '<time class="postTime dfont" itemprop="datePublished" datetime="' + data[i].date + '">' + year + '年' + month + '月' + day + '日' + '</time>'
+ '<p class="postTitle">' + data[i].title.rendered + '</p>'
+ '</a>' // href end
+ '</li>' // end content
}
}).catch(err => {
// Do something with error here
console.log('Error: ' + err)
})
そして、各タブに仕込みたいカテゴリーは、URLの指定で「?」から始まるパラメータで指定します。例えば、表示させたいカテゴリーIDが「9」の場合、categories=9
と書きます。
const getPosts1 = "https://sample.com/wp-json/wp/v2/posts?_embed&categories=9&per_page=10"
上記のようにパラメータでカテゴリーの指定をします。カテゴリーIDは、管理画面から確認するか、記事一覧のJSONのデータで確認できます。
サンプルのコードでは、タブの数に応じて取得するURLも3つあるのでご注意ください。
次に読み込むのは「タブ」のコードで、以下のコードを <body>〜</body>
のクロージングタグ直前に記述して読み込ませます。
function openTab(evt, tabName) {
var i, x, tablinks;
x = document.getElementsByClassName("content-tab");
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
tablinks = document.getElementsByClassName("tab");
for (i = 0; i < x.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" is-active", "");
}
document.getElementById(tabName).style.display = "block";
evt.currentTarget.className += " is-active";
}
全体的には for
文のループで、class名の入れ替えと display
プロパティを操作して、タブの表示・非表示を切り替える仕様です。
CSS
CSSで、「タブ」の全体的なコンテナに関するものは /* javaTabs */
の箇所。そして、APIで取得したリンクカードは /* tab inner */
以降のコメントアウトの箇所です。
/* javaTabs */
.javaContainer ul {
list-style: none;
padding: 0;
margin: 0 0 1rem;
border: none;
display: flex;
justify-content: space-between;
box-shadow: 0 7px 34px rgba(50,50,93,.1), 0 3px 6px rgba(0,0,0,.08);
}
.javaContainer ul li {
width: calc(100%/3);
text-align: center;
transition: all 0.2s ease;
padding: 0;
}
.javaContainer ul li:first-child a {
border-radius: 3px 0 0 3px;
border-right: solid 1px #eee;
}
.javaContainer ul li:last-child a{
border-radius: 0 3px 3px 0;
border-left: solid 1px #eee;
}
.javaContainer ul li a {
width: 100%;
display: block;
line-height: 50px;
text-decoration: none;
background: #FFF;
}
li.tab.is-active a {
background: linear-gradient(45deg, #bdb9ff, #67b8ff);
color: #FFF;
}
@keyframes fadeIn {
0% {
opacity: 0;
transform: translateY(30px);
}
100% {
opacity: 1;
}
}
.content-tab {
animation: fadeIn 0.7s ease 0s 1 normal;
}
.content-tab p {
margin:0;
}
/* tab inner */
ul#viewPostsTab1, ul#viewPostsTab2, ul#viewPostsTab3 {
display: flex;
flex-wrap: wrap;
list-style: none;
padding: 0;
border: none;
justify-content: space-between;
gap: 30px;
margin: 30px 0 0;
}
li.posts {
width: 47.5%;
margin: 0;
padding: 0;
}
li.posts a {
display: flex;
flex-direction: column;
height: 100%;
text-decoration: none;
background: #FFF;
box-shadow: 0 0 3px 0 rgb(0 0 0 / 12%), 0 2px 3px 0 rgb(0 0 0 / 22%);
cursor: pointer;
transition: 0.2s ease-in-out;
border-radius: 3px;
}
li.posts a:hover {
box-shadow: 0 15px 30px -5px rgb(0 0 0 / 15%), 0 0 5px rgb(0 0 0 / 10%);
transform: translateY(-4px);
}
li.posts a img {
margin-bottom: 15px;
object-fit: cover;
height: 200px;
border-radius: 3px 3px 0 0;
}
time.postTime {
display: block;
margin: 0 0 3px;
color: #b5b5b5;
font-size: 0.9rem;
font-weight: bold;
padding: 0 20px;
position: relative;
}
time.postTime:before {
content: "\f017";
font-family: "Font Awesome 5 Free";
font-weight: 900;
padding-right: 5px;
font-size: 0.85rem;
opacity: 0.6;
vertical-align: bottom;
}
p.postTitle {
padding: 0px 20px 0;
font-size: 18px;
line-height: 1.56;
color: #555;
font-weight: 600;
margin-bottom: 1.2rem;
}
@media screen and (max-width: 767px) {
/* (ここにモバイル用スタイルを記述) */
.javaContainer ul {
flex-direction: column;
}
.javaContainer ul li {
width: 100%;
display: block;
}
.javaContainer ul li:first-child a {
border-radius: 3px 3px 0 0;
border-right: none;
border-bottom: solid 1px #eee;
}
.javaContainer ul li:last-child a {
border-radius: 0 0 3px 3px;
border-left: none;
border-top: solid 1px #eee;
}
li.posts {
width: 100%;
}
}
特にリンクカードのデザインは当サイトに合わせたデザインなので、設置するサイトに合わせてカスタマイズして使うようにしましょう。