article

Wednesday, November 13, 2024

Nextjs + WordPress Load Posts with Featured Image and View Single Page

Nextjs + WordPress Load Posts with Featured Image and View Single Page

app\posts\page.tsx
//app\posts\page.tsx
import { Suspense } from "react";
import { Spinner } from "@/components/spinner";
import PostTable from "@/components/tableposts";

const Posts = async () => {

  return (
    <div className="max-w-screen-lg mx-auto py-14">
      <h1 className="text-4xl font-bold">Nextjs + WordPress Load Posts with Featured Image and View Single Page</h1>
      <div className="flex items-end justify-between m-12">
        <h1 className="text-4xl font-bold">Latest Post</h1>
      </div>

      <Suspense fallback={<Spinner />}>
        <PostTable/>
      </Suspense>

    </div>
  );
};

export default Posts;
app\components\tableposts.tsx
//app\components\tableposts.tsx
import Image from "next/image";
import Link from "next/link";
import { formatDate } from "@/lib/utils";

const PostTable = async () => {
  const res = await fetch("http://localhost:8888/cairocoders/wp-json/wp/v2/posts?_embed");
  const data = await res.json();

  return (
      <div className="grid md:grid-cols-3 gap-5 mt-10">
        {data.map((post: any) => (
          <div key={post.id} className="max-w-sm border border-gray-200 rounded-md shadow">
            <div className="relative aspect-video">
              <Image
                src={post._embedded["wp:featuredmedia"][0].media_details.sizes.full.source_url}
                alt={post.title.rendered}
                fill
                priority
                sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
                className="rounded-t-md object-cover"
              />
            </div>
            <div className="p-5">
              <h1>
                <Link href={`/posts/${post.slug}`}>{post.title.rendered}</Link>
              </h1>
            </div>
            <div className="flex items-center justify-between">
              <div className="py-3 text-sm text-black rounded-bl-md w-full text-center">{formatDate(post.date.toString())}</div>
            </div>
          </div>
        ))}
      </div>
  );
};

export default PostTable;
app\components\Spinner.tsx
//app\components\Spinner.tsx
export const Spinner = () => {
  return (
    <span className="loading loading-spinner loading-lg">Loading</span>
  );
};
app\posts\[slug]\page.tsx
//app\posts\[slug]\page.tsx
import { notFound } from "next/navigation";
 
const PostPage = async ({ params }: { params: { slug: string } }) => {
  const slug = params.slug;
  //console.log(data);

  const res = await fetch(`http://localhost:8888/cairocoders/wp-json/wp/v2/posts?_embed&slug=${slug}`);
  const data = await res.json();

  if (!data) return notFound();
 
  return (
    <div className="min-h-screen flex items-center justify-center bg-slate-100">
      <div className="bg-white rounded-sm shadow p-8">
        {data.map((post) => (
          <div key={post.id}>
            <h1 className="text-2xl font-bold mb-5">{post.title.rendered}</h1>
            <div className="mb-4">            
              <div 
                dangerouslySetInnerHTML={{ __html: post['content']['rendered'] }}
              />   
            </div>
          </div>
        ))}

      </div>
    </div>
  );
};
 
export default PostPage;
next.config.mjs
//next.config.mjs
/** @type {import('next').NextConfig} */
//const nextConfig = {};
const nextConfig = {
  reactStrictMode: true,
  images : {
    domains : ['localhost'] // Domain name
  }
}

export default nextConfig;
themes\cairocoders\functions.php
//themes\cairocoders\functions.php
<?php
/**
 * Theme functions and definitions
 *
 * @package cairocoders
 */

add_action('rest_api_init', 'register_rest_images' );

function register_rest_images(){
    register_rest_field( array('post'),
        'fimg_url',
        array(
            'get_callback'    => 'get_rest_featured_image',
            'update_callback' => null,
            'schema'          => null,
        )
    );
}

function get_rest_featured_image( $object, $field_name, $request ) {
    if( $object['featured_media'] ){
        $img = wp_get_attachment_image_src( $object['featured_media'], 'app-thumb' );
        return $img[0];
    }
    return false;
}
run C:\nextjs>npm run dev

Related Post