// ─── Blog section (LP埋め込み & REST API取得) ───────────────────── function BlogSection() { const [posts, setPosts] = React.useState([]); const [categories, setCategories] = React.useState([]); const [filter, setFilter] = React.useState(0); // 0 = all const [loading, setLoading] = React.useState(true); const [error, setError] = React.useState(false); React.useEffect(() => { const base = "/wp-json/wp/v2"; Promise.all([ fetch(`${base}/posts?per_page=8&orderby=date&order=desc&_embed=true`).then(r => r.json()), fetch(`${base}/categories?hide_empty=true&per_page=100&orderby=count&order=desc`).then(r => r.json()), ]) .then(([p, c]) => { setPosts(Array.isArray(p) ? p : []); setCategories(Array.isArray(c) ? c.filter(cat => cat.slug !== "uncategorized") : []); setLoading(false); }) .catch(() => { setError(true); setLoading(false); }); }, []); const filtered = filter === 0 ? posts : posts.filter(p => p.categories && p.categories.includes(filter) ); return (
{categories.length > 0 && (
{categories.map(cat => ( ))}
)}
{loading && (
LOADING...
)} {error && (
記事の取得に失敗しました。
)} {!loading && !error && filtered.length === 0 && (
該当する記事がありません。
)} {!loading && !error && filtered.length > 0 && (
{filtered.map((post, i) => ( ))}
)}
すべての記事を見る
); } function BlogCard({ post, index }) { const thumb = post._embedded?.["wp:featuredmedia"]?.[0]?.source_url; const cat = post._embedded?.["wp:term"]?.[0]?.[0]; const dateStr = new Date(post.date).toLocaleDateString("ja-JP", { year: "numeric", month: "long", day: "numeric" }); const rawExcerpt = post.excerpt?.rendered?.replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim(); const excerpt = rawExcerpt && rawExcerpt.length > 72 ? rawExcerpt.slice(0, 72) + "…" : rawExcerpt; const hue = (post.id * 47 + index * 19) % 360; return (
{ window.location.href = post.link; }}>
{thumb ? {post.title?.rendered?.replace(/<[^]+>/g, "") || ""} className="blog-card__thumb-img" loading="lazy" /> :
} {cat && {cat.name}}
{dateStr}

{excerpt &&

{excerpt}

}

); } // ── Blog archive page ─────────────────────────────────────────── const BLOG_PER_PAGE = 12; function BlogPage({ go }) { const [posts, setPosts] = React.useState([]); const [categories, setCategories] = React.useState([]); const [filter, setFilter] = React.useState(0); const [page, setPage] = React.useState(1); const [totalPages, setTotalPages] = React.useState(1); const [loading, setLoading] = React.useState(true); const [error, setError] = React.useState(false); React.useEffect(() => { fetch("/wp-json/wp/v2/categories?hide_empty=true&per_page=100&orderby=count&order=desc") .then(r => r.json()) .then(c => setCategories(Array.isArray(c) ? c.filter(cat => cat.slug !== "uncategorized") : [])) .catch(() => {}); }, []); React.useEffect(() => { setLoading(true); setError(false); const catParam = filter !== 0 ? `&categories=${filter}` : ""; fetch(`/wp-json/wp/v2/posts?per_page=${BLOG_PER_PAGE}&page=${page}&orderby=date&order=desc&_embed=true${catParam}`) .then(r => { setTotalPages(parseInt(r.headers.get("X-WP-TotalPages") || "1", 10)); return r.json(); }) .then(p => { setPosts(Array.isArray(p) ? p : []); setLoading(false); }) .catch(() => { setError(true); setLoading(false); }); }, [filter, page]); const changeFilter = (catId) => { setFilter(catId); setPage(1); }; const changePage = (p) => { setPage(p); window.scrollTo({ top: 0, behavior: "smooth" }); }; return (
Web制作・保守の知識。} lead="WordPress保守・セキュリティ・SEO対策・Web制作に関する知識・事例を発信しています。" />
{categories.length > 0 && (
{categories.map(cat => ( ))}
)} {loading &&
LOADING...
} {error &&
記事の取得に失敗しました。
} {!loading && !error && posts.length === 0 &&
該当する記事がありません。
} {!loading && !error && posts.length > 0 && (
{posts.map((post, i) => )}
)} {totalPages > 1 && (
{page > 1 && ( )} {Array.from({ length: totalPages }, (_, i) => i + 1).map(p => ( ))} {page < totalPages && ( )}
)}
); } Object.assign(window, { BlogSection, BlogCard, BlogPage });