{"id":12314,"date":"2026-10-15T16:47:36","date_gmt":"2026-10-15T07:47:36","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=12314"},"modified":"2026-10-15T19:08:40","modified_gmt":"2026-10-15T10:08:40","slug":"nextjs-sns-server-51-5","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/10\/15\/nextjs-sns-server-51-5\/","title":{"rendered":"[nextjs]SNS Server-51(myapp61+)[like]\u00a0"},"content":{"rendered":"\n<p>\ud83d\udc49\ud83c\udffb \uc774\ubc88\uc5d0\ub294 \uc88b\uc544\uc694\ubd80\ubd84\uc758 \uad6c\uc870 \ubd80\ubd84\uc744 \uc0b4\ud3b4 \ubd05\ub2c8\ub2e4.<br>Next, we will examine the structure of the &#8220;like&#8221; section.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \uc88b\uc544\uc694 \ubd80\ubd84\uc758 \ub300\ub7b5\uc801\uc778 \ub370\uc774\ud130 \ud750\ub984\uc740 \uc774\uc804\uc758 \ud398\uc774\uc9c0\ub124\uc774\uc158\uc774\ub098 \uc561\ud2f0\ube0c \ud14c\ub9c8 \ubd80\ubd84\uacfc \uac70\uc758 \uac19\uc2b5\ub2c8\ub2e4.<br>The general data flow for the &#8220;likes&#8221; section is nearly identical to that of the pagination or active theme sections mentioned earlier.<\/p>\n\n\n\n<p>\ud83d\udcc1 &#8220;\uc88b\uc544\uc694&#8221;\ubd80\ubd84\uc758 \ub370\uc774\ud130 \ud750\ub984<br>Data flow for the &#8220;Like&#8221; section<\/p>\n\n\n\n<p>1) ClientPage.tsx<\/p>\n\n\n\n<p>A.ClientPage.tsx\uc5d0\uc11c handleLike\ud568\uc218\ub97c \ud14c\ub9c8\ub514\ub809\ud1a0\ub9ac\uc758 MainTheme.tsx\uc758 MainTheme\ud568\uc218\uc5d0 \ud30c\ub77c\uba54\ud130\ub85c \uc804\ub2ec \ub429\ub2c8\ub2e4.<br>In ClientPage.tsx, the <code>handleLike<\/code> function is passed as a parameter to the <code>MainTheme<\/code> function, which is located in <code>MainTheme.tsx<\/code> within the <code>theme<\/code> directory.<\/p>\n\n\n\n<p>B.\uc561\ud2f0\ube0c\ud14c\ub9c8\uc758 \uc791\ub3d9\uc5d0 \uad00\ub828\ub41c\ubd80\ubd84\uc740 [nextjs]SNS Server-51(myapp61+)[Active theme]&nbsp; \ud3ec\uc2a4\ud2b8\ub97c \ucc38\uc870\ud558\uc138\uc694<br>For details regarding the operation of the active theme, please refer to the post: [nextjs]SNS Server-51(myapp61+)[Active theme].<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code> ... ... \n  const timelineRef = useRef&lt;any&#91;]&gt;(&#91;]);\n  useEffect(() =&gt; { timelineRef.current = timeline; }, &#91;timeline]);\n... ...\n const<em> <\/em><strong>handleLike<\/strong> = async (post: any) =&gt; {\n\n    \/\/ \u2705 \ud56d\uc0c1 \ucd5c\uc2e0 timeline\uc5d0\uc11c \ucc3e\uae30 \/ Always find from the latest timeline\n    const latest = timelineRef.current.find((p: any) =&gt; p.id === post.id) || post;\n    let target = latest.original_id || latest.id;\n\n    if (!target.startsWith('http')) {\n      if (latest.actor &amp;&amp; latest.actor.startsWith('http')) {\n        try {\n          const actorUrl = new URL(latest.actor);\n          const parts = actorUrl.pathname.split('\/');\n          const usersIdx = parts.indexOf('users');\n          const actorUsername = usersIdx!== -1? parts&#91;usersIdx + 1] : latest.username;\n          target = `${actorUrl.origin}\/users\/${actorUsername}\/statuses\/${target}`;\n        } catch {\n          target = `https:\/\/${process.env.NEXT_PUBLIC_DOMAIN || 'aloy-horizon.duckdns.org'}\/users\/${latest.username}\/statuses\/${target}`;\n        }\n      } else {\n        target = `https:\/\/${process.env.NEXT_PUBLIC_DOMAIN || 'aloy-horizon.duckdns.org'}\/users\/${latest.username}\/statuses\/${target}`;\n      }\n    }\n\n    const currentlyLiked = latest.isMyLike;\n    console.log('\u2b50 like click', { target, isMyLike: currentlyLiked, shortId: target.split('\/').pop() });\n\n    \/\/ Optimistic + \uc11c\ubc84\uac12\uc73c\ub85c \ub36e\uc5b4\uc4f0\uae30\n    \/\/ Overwrite with Optimistic + Server values\n    setTimeline(prev =&gt; prev.map((p: any) =&gt;\n      p.id === latest.id\n       ? {...p, isMyLike:!currentlyLiked, likeCount: (p.likeCount || 0) + (currentlyLiked? -1 : 1) }\n        : p\n    ));\n\n    try {\n      const res = await fetch(`\/api\/like`, {\n        method: currentlyLiked? 'DELETE' : 'POST',\n        headers: { 'Content-Type': 'application\/json' },\n        body: JSON.stringify({ username, target }),\n        cache: 'no-store'\n      });\n      const data = await res.json();\n      console.log('\u2b50 like \uc751\ub2f5 \/ Like response', data);\n\n      \/\/ \uc11c\ubc84\uac00 \uc900 \uac12 \ud65c\uc6a9\ud558\uae30\n      \/\/ Using the value provided by the server\n      setTimeline(prev =&gt; prev.map((p: any) =&gt;\n        p.id === latest.id\n         ? {...p, isMyLike: data.isMyLike, likeCount: data.likeCount }\n          : p\n      ));\n\n      \/\/ \ud639\uc2dc \ubaa8\ub974\ub2c8 \ud55c\ubc88 \ub354 \ub3d9\uae30\ud654\n      \/\/ Synchronize one more time just in case\n      if (data.alreadyLiked || data.alreadyUnliked) {\n        await refreshTimeline();\n      }\n\n    } catch (e) {\n      console.error('\u274c like \uc2e4\ud328', e);\n      await refreshTimeline();\n    }\n  };\n\n... ...\n const <strong>props<\/strong> = { timeline, username, initialView, onBoost: handleBoost, <strong>onLike: handleLike,<\/strong> onShare: handleShare };\n... ...\n  return <strong>&lt;ActiveTheme {...props}<\/strong> \/&gt;;<\/code><\/pre>\n\n\n\n<p> 2)MainTheme.tsx<\/p>\n\n\n\n<p>A.\ud14c\ub9c8\ub514\ub809\ud1a0\ub9ac\uc758 MainThem.tsx\ud30c\uc77c\uc758 MainTheme\ud568\uc218\uc5d0 \ud30c\ub77c\uba54\ud130\ub85c \uc88b\uc544\uc694(onLike: handleLike)\uac00 \uc804\ub2ec \ub429\ub2c8\ub2e4.<br>The <code>onLike<\/code> prop (with the value <code>handleLike<\/code>) is passed as a parameter to the <code>MainTheme<\/code> function within the <code>MainTheme.tsx<\/code> file located in the <code>theme<\/code> directory.<\/p>\n\n\n\n<p>B.onLike\ud568\uc218\ub294 \ub2e4\uc2dc handleLikeClick\ud568\uc218 \ub0b4\uc5d0\uc11c \ud638\ucd9c \ub429\ub2c8\ub2e4.<br>The onLike function is called within the handleLikeClick function.<\/p>\n\n\n\n<p>C. \uc774\ub54c \uc774 handleLikeClick\ud568\uc218\ub294 \ub85c\uadf8\uc778\ud558\uc9c0 \uc54a\uc740\uacbd\uc6b0 \ub85c\uadf8\uc778 \ud398\uc774\uc9c0\ub85c \uc774\ub3d9\ud558\ub294 \uae30\ub2a5\uc744 \uc218\ud589\ud569\ub2c8\ub2e4.<br>In this case, the <code>handleLikeClick<\/code> function performs the action of redirecting the user to the login page if they are not logged in.<\/p>\n\n\n\n<p>D.handleLikeClick\ud568\uc218\ub97c TimelineList \ucef4\ud3ec\ub10c\ud2b8\uc758 \ud30c\ub77c\uba54\ud130(onLIke)\ub85c \uc804\ub2ec\ud569\ub2c8\ub2e4.<br>Pass the <code>handleLikeClick<\/code> function as a parameter (<code>onLike<\/code>) to the <code>TimelineList<\/code> component.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\nexport function MainTheme({ timeline : initialTimeline, username, initialView, onBoost, <strong>onLike<\/strong>, onShare }: any) {\n... ...\n  const <strong>handleLikeClick<\/strong> = (p: any) =&gt; {\n    if (!currentUser) return window.location.href = `\/auth\/login?next=\/@${username}`;\n    <strong>onLike(p);<\/strong>\n  };\n... ...\n\n  return (\n    &lt;&gt; ... ...\n               {view === 'timeline' &amp;&amp; (\n            &lt;&gt;\n            {\/* \u2705 myapp56 - ADD Dropdown(Home\/Local\/Federated Tabs ) *\/}\n\n              &lt;TimelineList\n                timeline={timeline}\n                tab={tab}\n                onTabChange={setTab}\n                currentUser={currentUser}\n                onDelete={handleDelete}\n                onBoost={handleBoostClick}\n              <strong>  onLike={handleLikeClick}<\/strong>\n                onShare={onShare}\n              \/&gt;\n            &lt;\/&gt;\n          )} {\/* end view === 'timeline' *\/}\n ... ...\n    &lt;\/&gt;\n  )\n}<\/code><\/pre>\n\n\n\n<p>3)TimelineList.tsx<\/p>\n\n\n\n<p>A.\ud30c\ub77c\uba54\ud130\ub85c \ubc1b\uc740 onLike\ub294 return()\uad6c\ubb38 \uc548\uc758  \ubc84\ud2bc \uc774\ubca4\ud2b8\uc778 onClick\uc5d0 \uc801\uc6a9\ub429\ub2c8\ub2e4.<br>The <code>onLike<\/code> parameter is applied to the <code>onClick<\/code> event of the button within the <code>return()<\/code> statement.<\/p>\n\n\n\n<p>B.\uc88b\uc544\uc694 \ubc84\ud2bc\uc744 \ud074\ub9ad\ud558\uba74 \uacb0\uad6d ClientPage.tsx\uc758 handleClick\ud568\uc218 \uc2e4\ud589\ub429\ub2c8\ub2e4.<br>Clicking the &#8220;like&#8221; button ultimately triggers the <code>handleClick<\/code> function in <code>ClientPage.tsx<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\nexport default function TimelineList({ \n  timeline: initialTimeline, currentUser, tab, onTabChange, onDelete, onBoost, <strong>onLike<\/strong>, onShare }: Props) { \n... ...\n  const flat = (flatData || &#91;]).flat().filter(Boolean) as any&#91;];\n  const data = flat.length &gt; 0 ? flat : initialTimeline.filter((p:any) =&gt; p &amp;&amp; p.id);\n... ...\n  return(\n      &lt;&gt;\n... ...\n{data.filter((p:any) =&gt; p &amp;&amp; p.id).map((p: any, idx: number) =&gt; {\n... ...\n              {\/** boost,like,share *\/}\n              &lt;div className=\"flex gap-4 mt-2\"&gt;\n                &lt;button onClick={() =&gt; onBoost(p)} className={`bg-none border-none cursor-pointer text-&#91;#999] px-2 py-1 rounded-xl text-sm hover:bg-&#91;#f3f4f6] hover:text-&#91;#333] ${p.isMyBoost? '!text-&#91;#1b9c59] font-bold bg-&#91;#dcfce7]' : ''}`}&gt;\ud83d\udd01 {p.boostCount || ''}&lt;\/button&gt;\n                &lt;button <strong>onClick={() =&gt; onLike(p)} <\/strong>className={`bg-none border-none cursor-pointer text-&#91;#999] px-2 py-1 rounded-xl text-sm hover:bg-&#91;#f3f4f6] hover:text-&#91;#333] ${p.isMyLike? '!text-&#91;#e0245e] bg-&#91;#ffe4e6]' : ''}`}&gt;\u2b50 {p.likeCount || ''}&lt;\/button&gt;\n\n                &lt;button onClick={() =&gt; onShare(p)} className=\"bg-none border-none cursor-pointer text-&#91;#999] px-2 py-1 rounded-xl text-sm hover:bg-&#91;#f3f4f6] hover:text-&#91;#333]\"&gt;\u2708&lt;\/button&gt;\n                &lt;button className=\"bg-none border-none cursor-pointer text-&#91;#999] px-2 py-1 rounded-xl text-sm hover:bg-&#91;#f3f4f6] hover:text-&#91;#333]\"&gt;\ud83d\udcac&lt;\/button&gt;\n              &lt;\/div&gt;\n... ...\n      })}\n... ...\n     &lt;\/&gt;\n  )\n... ...\n}<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 API<\/p>\n\n\n\n<p>\u2714\ufe0f API\uc758 \uacbd\ub85c\ub294 \ub2e4\uc74c\uacfc \uac19\uc2b5\ub2c8\ub2e4.<br>The API path is as follows:<\/p>\n\n\n\n<p>A.app\/api\/like\/route.ts<\/p>\n\n\n\n<p>\u2714\ufe0f \uc88b\uc544\uc694 \uc800\uc7a5 \/ Like Save<\/p>\n\n\n\n<p>A. \ub0b4\uac00 \uc791\uc131\ud55c \uae00\uc778 \uacbd\uc6b0<br>In the case of content I have written<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\nexport async function POST(req: NextRequest) {\n... ...\n  const { target } = await req.json();\n  const username = authUser;\n... ...\n\n  const existing = db.prepare(`SELECT id FROM likes WHERE actor =? AND object LIKE '%' ||? || '%'`).get(myActor, shortId) as any;\n  if (existing) {\n    const likeCount = (db.prepare(`SELECT COUNT(*) as c FROM likes WHERE object LIKE '%' ||? || '%'`).get(shortId) as any).c;\n    return NextResponse.json({ ok: true, alreadyLiked: true, isMyLike: true, likeCount });\n  }\n... ...\n  db.prepare('INSERT OR IGNORE INTO likes (id, actor, object, username) VALUES (?,?,?,?)')\n   .run(likeDoc.id, myActor, likeDoc.object.replace('\/posts\/', '\/statuses\/'), username);\n\n  const likeCount = (db.prepare(`SELECT COUNT(*) as c FROM likes WHERE object LIKE '%' ||? || '%'`).get(shortId) as any).c;\n  return NextResponse.json({ ok: true, isMyLike: true, likeCount });\n}\n... ...<\/code><\/pre>\n\n\n\n<p>a) \uc88b\uc544\uc694\ub97c \uc2e4\ud589\ud588\ub294\uc9c0 \ud655\uc778(existing)\ud558\uace0 \uc874\uc7ac\ud558\uba74 \ub9ac\ud134<br>Check if a &#8216;like&#8217; has already been cast (existing), and return if it already exists.<\/p>\n\n\n\n<p>b)existing\uc774 \uc5c6\uc73c\uba74 db\uc5d0 \uc88b\uc544\uc694\ub97c \uc800\uc7a5\ud558\uace0 { ok: true, isMyLike: true, likeCount } \ub9ac\ud134<br>If <code>existing<\/code> does not exist, save the &#8220;like&#8221; to the DB and return <code>{ ok: true, isMyLike: true, likeCount }<\/code>.<\/p>\n\n\n\n<p>B. \ub2e4\ub978 \uc11c\ubc84\uc758 \uae00\uc778\uacbd\uc6b0<br>In the case of a post from another server<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\nexport async function POST(req: NextRequest) {\n... ...\n  const { target } = await req.json();\n  const username = authUser;\n... ...\n  if (!isOwnPost) {\n    try {\n      const pr = await <strong>signedFetch<\/strong>(target, username);\n      if (pr.ok) {\n        const d = await pr.json();\n        apObjectId = (d.id || target).replace('\/posts\/', '\/statuses\/');\n        const info = await <strong>getActorData<\/strong>((d.attributedTo || d.actor) as any, username);\n        inbox = info.inbox;\n      }\n    } catch {}\n  }\n... ...\nconst likeDoc = isOwnPost\n   ? { id: `${myActor}\/likes\/${crypto.randomUUID()}`, actor: myActor, object: apObjectId }\n    : (await <strong>sendLike<\/strong>(inbox!, apObjectId, username)).likeDoc;\n\n  db.prepare('INSERT OR IGNORE INTO likes (id, actor, object, username) VALUES (?,?,?,?)')\n   .run(likeDoc.id, myActor, likeDoc.object.replace('\/posts\/', '\/statuses\/'), username);\n\n  const likeCount = (db.prepare(`SELECT COUNT(*) as c FROM likes WHERE object LIKE '%' ||? || '%'`).get(shortId) as any).c;\n\n  return NextResponse.json({ ok: true, isMyLike: true, likeCount });\n}<\/code><\/pre>\n\n\n\n<p>a)\ub0b4\uac00 \uc791\uc131\ud55c \uae00\uc774 \uc544\ub2c8\uba74(!isOwnPost) \uc6d0\ubcf8 \uae00\uc758 \uc11c\ubc84\uc5d0\uc11c \uae00\uc744 \ucc3e\uae30<br>If I did not write the post (!isOwnPost), I will find the post on the original post&#8217;s server.<\/p>\n\n\n\n<p>b)target\uc740 \uc0c1\ub300\ubc29\uc11c\ubc84\uc5d0 \uc6d0\ubcf8\uae00\uc774 \uc874\uc7ac\ud558\ub294\uc9c0 \ud655\uc778\ud558\ub294 \uc6a9\ub3c4\ub85c \uc0ac\uc6a9\ud568<br>Target is used to check if the original post exists on the counterpart server.<\/p>\n\n\n\n<p>c)signedFetch\ud568\uc218\uc640 getActorData\ud568\uc218\ub97c \ud1b5\ud574\uc11c \uc2e4\uc81c\ub85c \uc6d0\ubcf8\uc758 \uae00\uc758 \uc815\ubcf4\ub97c \uac00\uc838\uc634<br>The <code>signedFetch<\/code> and <code>getActorData<\/code> functions are used to actually retrieve information about the original post.<\/p>\n\n\n\n<p>d)\ub0b4 \uc11c\ubc84\uc758 \uae00\uc774 \uc544\ub2c8\uba74 sendLike\ud568\uc218\ub85c \uc6d0\ubcf8\uae00\uc774 \uc704\uce58\ud55c \uc11c\ubc84\uc5d0 \uc88b\uc544\uc694\ub97c \uc800\uc7a5<br>If the post is not on my server, use the sendLike function to save the like to the server where the original post is located.<\/p>\n\n\n\n<p>e)\ub0b4 \uc11c\ubc84\uc5d0 \uc88b\uc544\uc694\ub97c \uc800\uc7a5\ud558\uace0 { ok: true, isMyLike: true, likeCount }\ub97c \ub9ac\ud134<br>Save the &#8216;like&#8217; to my server and return { ok: true, isMyLike: true, likeCount }<\/p>\n\n\n\n<p>\u2714\ufe0f \uc88b\uc544\uc694 \uc0ad\uc81c \/ Delete Like<\/p>\n\n\n\n<p>A. app\/api\/like\/route.ts<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code> const myActor = `https:\/\/${DOMAIN}\/users\/${username}`;\n  const shortId = target.replace('\/posts\/', '\/statuses\/').split('\/').pop()!.split('?')&#91;0];\n\n  const likeRow = db.prepare(`SELECT id, object FROM likes WHERE actor =? AND object LIKE '%' ||? || '%'`).get(myActor, shortId) as any;\n\n  if (!likeRow) {\n    const likeCount = (db.prepare(`SELECT COUNT(*) as c FROM likes WHERE object LIKE '%' ||? || '%'`).get(shortId) as any).c;\n    return NextResponse.json({ ok: true, alreadyUnliked: true, isMyLike: false, likeCount });\n  }<\/code><\/pre>\n\n\n\n<p>a)\ub0b4\uac00 \ub0b4 \uc11c\ubc84\uc758 \uae00\uc5d0 \uc88b\uc544\uc694\ub97c \ub204\ub978\uc801\uc774 \uc788\ub294\uc9c0 \ud655\uc778 \ud558\uae30(likeRow)<br>Check whether I have already &#8216;liked&#8217; a post on my server (likeRow)<\/p>\n\n\n\n<p>b)\uc88b\uc544\uc694\ub97c \ub204\ub978\uc801\uc774 \uc5c6\uc73c\uba74{ ok: true, alreadyUnliked: true, isMyLike: false, likeCount } \uc774 \uac12\uc744 \ub9ac\ud134<br>If you haven&#8217;t liked it before, return this value { ok: true, alreadyUnliked: true, isMyLike: false, likeCount }.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>  if (!isOwnPost) {\n    try {\n      const u = new URL(objectForCheck);\n      const parts = u.pathname.split('\/').filter(Boolean);\n      const idx = parts.indexOf('users');\n      const inbox = idx!== -1? `${u.origin}\/users\/${parts&#91;idx+1]}\/inbox` : null;\n      if (inbox) {\n        await sendUndoLike(inbox, likeRow.id, objectForCheck, username);\n      }\n    } catch (e) {\n      console.error('Undo Like \ubc30\ub2ec \uc2e4\ud328', e);\n    }\n  }<\/code><\/pre>\n\n\n\n<p>a)\ub0b4 \uc11c\ubc84\uc758 \uae00\uc774 \uc544\ub2c8\uba74 \uc6d0\ubcf8 \uae00\uc758 \uc8fc\uc18c\uc5d0 \uc88b\uc544\uc694 \ucde8\uc18c \ubc30\ub2ec<br>If the post is not from my server, forward the &#8220;cancel like&#8221; action to the original post&#8217;s URL.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>\n  db.prepare('DELETE FROM likes WHERE id =?').run(likeRow.id);\n  const likeCount = (db.prepare(`SELECT COUNT(*) as c FROM likes WHERE object LIKE '%' ||? || '%'`).get(shortId) as any).c;\n  return NextResponse.json({ ok: true, isMyLike: false, likeCount });<\/code><\/pre>\n\n\n\n<p>a) \ub0b4\uc11c\ubc84\uc5d0\uc11c\ub3c4 \uc88b\uc544\uc694\ub97c \uc0ad\uc81c\ud558\uace0 { ok: true, isMyLike: false, likeCount } \uc774 \uac12\uc744 \ub9ac\ud134<br>Delete the &#8220;like&#8221; on my server as well, and return the following value: { ok: true, isMyLike: false, likeCount }.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\ub9c8\ud0dc\ubcf5\uc74c 21\uc7a5 22\uc808 \/ Matthew 21: 22<\/p>\n\n\n\n<p>&#8220;\ub108\ud76c\uac00 \uae30\ub3c4\ud560 \ub54c\uc5d0 \ubb34\uc5c7\uc774\ub4e0\uc9c0 \ubbff\uace0 \uad6c\ud558\ub294 \uac83\uc740 \ub2e4 \ubc1b\uc73c\ub9ac\ub77c \ud558\uc2dc\ub2c8\ub77c&#8221;<\/p>\n\n\n\n<p>&#8220;And everything you ask in prayer, believing, you will receive.&#8221;<\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>\ud83d\udc49\ud83c\udffb \uc774\ubc88\uc5d0\ub294 \uc88b\uc544\uc694\ubd80\ubd84\uc758 \uad6c\uc870 \ubd80\ubd84\uc744 \uc0b4\ud3b4 \ubd05\ub2c8\ub2e4.Next, we will examine the structure of the &#8220;like&#8221; section. \ud83d\udc49\ud83c\udffb \uc88b\uc544\uc694 \ubd80\ubd84\uc758 \ub300\ub7b5\uc801\uc778 \ub370\uc774\ud130 \ud750\ub984\uc740 \uc774\uc804\uc758 \ud398\uc774\uc9c0\ub124\uc774\uc158\uc774\ub098 \uc561\ud2f0\ube0c \ud14c\ub9c8 \ubd80\ubd84\uacfc \uac70\uc758 \uac19\uc2b5\ub2c8\ub2e4.The general data flow for the &#8220;likes&#8221; section is nearly identical to that of the pagination or active theme sections mentioned earlier. \ud83d\udcc1 &#8220;\uc88b\uc544\uc694&#8221;\ubd80\ubd84\uc758 \ub370\uc774\ud130 \ud750\ub984Data flow [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[28,27,1,7],"tags":[],"class_list":["post-12314","post","type-post","status-publish","format-standard","hentry","category-news","category-nextjs","category-uncategorized","category-website","missing-thumbnail"],"_links":{"self":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/12314","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/comments?post=12314"}],"version-history":[{"count":32,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/12314\/revisions"}],"predecessor-version":[{"id":12348,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/12314\/revisions\/12348"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=12314"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=12314"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=12314"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}