[{"data":1,"prerenderedAt":2027},["ShallowReactive",2],{"blog-\u002Fblog\u002Fwpnuxt-v2":3,"blog-surround-\u002Fblog\u002Fwpnuxt-v2":2016},{"id":4,"title":5,"author":6,"body":11,"date":2004,"description":2005,"extension":2006,"image":2007,"meta":2010,"minRead":583,"navigation":161,"path":2011,"seo":2012,"social":2013,"stem":2014,"__hash__":2015},"blog\u002Fblog\u002F993.wpnuxt-v2.md","WPNuxt 2.0: Type-Safe Headless WordPress for Nuxt 4",{"name":7,"description":8,"avatar":9},"Wouter Vernaillen","Full Stack Developer",{"src":10,"alt":7},"\u002Fimages\u002Fwoutervernaillen.jpg",{"type":12,"value":13,"toc":1982},"minimark",[14,18,21,79,97,110,113,118,133,192,195,198,332,339,354,359,369,417,424,426,430,433,495,501,588,591,635,638,645,647,651,655,662,716,730,748,752,757,889,892,911,954,980,991,995,1005,1007,1010,1015,1070,1073,1162,1168,1201,1204,1206,1210,1214,1227,1319,1322,1328,1334,1344,1353,1365,1369,1372,1433,1439,1443,1446,1467,1470,1474,1481,1519,1529,1549,1551,1555,1558,1639,1645,1647,1651,1654,1670,1673,1687,1756,1759,1776,1842,1848,1850,1854,1857,1892,1900,1902,1906,1911,1933,1938,1965,1970,1978],[15,16,17],"p",{},"WPNuxt 2.0 brings type-safe composables, multi-layer caching, Gutenberg block rendering, and full authentication to headless WordPress with Nuxt. After 16 alpha releases, 7 betas, and over 700 commits, it's ready for production.",[15,19,20],{},"WPNuxt connects WordPress with Nuxt via GraphQL, generating typed composables from your queries so you can fetch and render WordPress content without writing boilerplate. Version 2 adds the features that were missing to make this a complete solution for production headless WordPress sites.",[22,23,24,32,38,44,50,56,62,68],"ul",{},[25,26,27,31],"li",{},[28,29,30],"strong",{},"Type-safe composables"," generated from GraphQL queries with full autocomplete",[25,33,34,37],{},[28,35,36],{},"Three-layer caching"," — server (Nitro SWR), client deduplication, and SSR payload",[25,39,40,43],{},[28,41,42],{},"Gutenberg block rendering"," with 10 built-in Vue components",[25,45,46,49],{},[28,47,48],{},"Authentication"," with password, OAuth, and external provider support",[25,51,52,55],{},[28,53,54],{},"AI-powered development"," via MCP server integration",[25,57,58,61],{},[28,59,60],{},"Serverless-ready"," — no jsdom, works on Vercel out of the box",[25,63,64,67],{},[28,65,66],{},"SSG support"," — full static site generation with prerender route fetching",[25,69,70,73,74,78],{},[28,71,72],{},"GraphQL mutations"," — generated ",[75,76,77],"code",{},"useMutation*()"," composables alongside queries",[15,80,81,82,85,86,89,90,89,93,96],{},"WPNuxt v1 worked as a single module wrapping ",[75,83,84],{},"nuxt-graphql-middleware",", but it had gaps: no built-in caching strategy, no authentication, and serverless deployments on Vercel broke due to jsdom in the server bundle. Version 2 fills those gaps. Three packages (",[75,87,88],{},"@wpnuxt\u002Fcore",", ",[75,91,92],{},"@wpnuxt\u002Fblocks",[75,94,95],{},"@wpnuxt\u002Fauth",") ship from a unified monorepo with synchronized versions, shared testing infrastructure, and a CI compatibility matrix covering multiple WordPress and Nuxt versions.",[15,98,99,100,103,104,109],{},"Upgrading from v1? The MCP server includes a ",[75,101,102],{},"wpnuxt_migrate"," tool that scans your project and guides you through the changes. See ",[105,106,108],"a",{"href":107},"#breaking-changes","breaking changes"," below.",[111,112],"hr",{},[114,115,117],"h2",{"id":116},"composable-api","Composable API",[15,119,120,121,124,125,128,129,132],{},"The composable API is cleaner in v2. The configurable prefix is gone — all composables use a consistent ",[75,122,123],{},"use"," naming convention. The separate ",[75,126,127],{},"useAsync*"," composables are replaced by a ",[75,130,131],{},"lazy"," option.",[134,135,140],"pre",{"className":136,"code":137,"language":138,"meta":139,"style":139},"language-diff shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","- const { data } = await useWPPosts()\n+ const { data } = await usePosts()\n\n- const { data } = await useWPPageByUri({ uri })\n+ const { data } = await usePageByUri({ uri })\n\n- const { data } = useAsyncWPPosts()\n+ const { data } = usePosts(undefined, { lazy: true })\n","diff","",[75,141,142,150,156,163,169,175,180,186],{"__ignoreMap":139},[143,144,147],"span",{"class":145,"line":146},"line",1,[143,148,149],{},"- const { data } = await useWPPosts()\n",[143,151,153],{"class":145,"line":152},2,[143,154,155],{},"+ const { data } = await usePosts()\n",[143,157,159],{"class":145,"line":158},3,[143,160,162],{"emptyLinePlaceholder":161},true,"\n",[143,164,166],{"class":145,"line":165},4,[143,167,168],{},"- const { data } = await useWPPageByUri({ uri })\n",[143,170,172],{"class":145,"line":171},5,[143,173,174],{},"+ const { data } = await usePageByUri({ uri })\n",[143,176,178],{"class":145,"line":177},6,[143,179,162],{"emptyLinePlaceholder":161},[143,181,183],{"class":145,"line":182},7,[143,184,185],{},"- const { data } = useAsyncWPPosts()\n",[143,187,189],{"class":145,"line":188},8,[143,190,191],{},"+ const { data } = usePosts(undefined, { lazy: true })\n",[15,193,194],{},"Every composable is auto-imported and fully typed. The module generates TypeScript declarations from your GraphQL queries and fragments at build time, so you get autocomplete and type checking all the way from WordPress through to your Vue templates.",[15,196,197],{},"Each composable now accepts options for retry, timeout, and caching:",[134,199,204],{"className":200,"code":201,"filename":202,"language":203,"meta":139,"style":139},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const { data: post } = await usePostByUri({\n  uri: route.params.slug\n}, {\n  retry: 3,\n  retryDelay: 1000,\n  timeout: 5000,\n  clientCache: false\n})\n","app\u002Fpages\u002Fblog\u002F[...slug].vue","ts",[75,205,206,247,268,276,290,302,314,325],{"__ignoreMap":139},[143,207,208,212,216,220,223,227,230,233,237,241,244],{"class":145,"line":146},[143,209,211],{"class":210},"spNyl","const",[143,213,215],{"class":214},"sMK4o"," {",[143,217,219],{"class":218},"swJcz"," data",[143,221,222],{"class":214},":",[143,224,226],{"class":225},"sTEyZ"," post ",[143,228,229],{"class":214},"}",[143,231,232],{"class":214}," =",[143,234,236],{"class":235},"s7zQu"," await",[143,238,240],{"class":239},"s2Zo4"," usePostByUri",[143,242,243],{"class":225},"(",[143,245,246],{"class":214},"{\n",[143,248,249,252,254,257,260,263,265],{"class":145,"line":152},[143,250,251],{"class":218},"  uri",[143,253,222],{"class":214},[143,255,256],{"class":225}," route",[143,258,259],{"class":214},".",[143,261,262],{"class":225},"params",[143,264,259],{"class":214},[143,266,267],{"class":225},"slug\n",[143,269,270,273],{"class":145,"line":158},[143,271,272],{"class":214},"},",[143,274,275],{"class":214}," {\n",[143,277,278,281,283,287],{"class":145,"line":165},[143,279,280],{"class":218},"  retry",[143,282,222],{"class":214},[143,284,286],{"class":285},"sbssI"," 3",[143,288,289],{"class":214},",\n",[143,291,292,295,297,300],{"class":145,"line":171},[143,293,294],{"class":218},"  retryDelay",[143,296,222],{"class":214},[143,298,299],{"class":285}," 1000",[143,301,289],{"class":214},[143,303,304,307,309,312],{"class":145,"line":177},[143,305,306],{"class":218},"  timeout",[143,308,222],{"class":214},[143,310,311],{"class":285}," 5000",[143,313,289],{"class":214},[143,315,316,319,321],{"class":145,"line":182},[143,317,318],{"class":218},"  clientCache",[143,320,222],{"class":214},[143,322,324],{"class":323},"sfNiH"," false\n",[143,326,327,329],{"class":145,"line":188},[143,328,229],{"class":214},[143,330,331],{"class":225},")\n",[15,333,334,335,338],{},"Retry uses exponential backoff by default. Timeouts create an ",[75,336,337],{},"AbortController"," under the hood and clean up properly when the request completes or the component unmounts.",[15,340,341,342,345,346,349,350,353],{},"WPNuxt 2 also generates composables for GraphQL mutations. Define a mutation in your ",[75,343,344],{},"extend\u002Fqueries\u002F"," folder and the module generates a ",[75,347,348],{},"useMutation{Name}()"," composable — fully typed, auto-imported, and ready to use for creating comments, submitting forms, or any custom WordPress mutation. The ",[75,351,352],{},"usePrevNextPost()"," composable provides previous\u002Fnext post navigation out of the box.",[355,356,358],"h3",{"id":357},"extending-queries","Extending Queries",[15,360,361,362,365,366,368],{},"WPNuxt provides default GraphQL queries for posts, pages, menus, and settings. You can override any of these or add your own by creating ",[75,363,364],{},".gql"," files in the ",[75,367,344],{}," folder:",[134,370,375],{"className":371,"code":372,"filename":373,"language":374,"meta":139,"style":139},"language-graphql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","query CustomPosts($limit: Int = 10) {\n  posts(first: $limit) {\n    nodes {\n      ...Post\n      customField\n    }\n  }\n}\n","extend\u002Fqueries\u002FCustomPosts.gql","graphql",[75,376,377,382,387,392,397,402,407,412],{"__ignoreMap":139},[143,378,379],{"class":145,"line":146},[143,380,381],{},"query CustomPosts($limit: Int = 10) {\n",[143,383,384],{"class":145,"line":152},[143,385,386],{},"  posts(first: $limit) {\n",[143,388,389],{"class":145,"line":158},[143,390,391],{},"    nodes {\n",[143,393,394],{"class":145,"line":165},[143,395,396],{},"      ...Post\n",[143,398,399],{"class":145,"line":171},[143,400,401],{},"      customField\n",[143,403,404],{"class":145,"line":177},[143,405,406],{},"    }\n",[143,408,409],{"class":145,"line":182},[143,410,411],{},"  }\n",[143,413,414],{"class":145,"line":188},[143,415,416],{},"}\n",[15,418,419,420,423],{},"This generates ",[75,421,422],{},"useCustomPosts()"," and a lazy variant automatically — fully typed, auto-imported, and cached.",[111,425],{},[114,427,429],{"id":428},"multi-layer-caching","Multi-Layer Caching",[15,431,432],{},"One of the biggest improvements in v2 is a structured three-layer caching system that works out of the box:",[434,435,436,452],"table",{},[437,438,439],"thead",{},[440,441,442,446,449],"tr",{},[443,444,445],"th",{},"Layer",[443,447,448],{},"Scope",[443,450,451],{},"What It Does",[453,454,455,469,482],"tbody",{},[440,456,457,463,466],{},[458,459,460],"td",{},[28,461,462],{},"Server (Nitro)",[458,464,465],{},"All users",[458,467,468],{},"SWR-based caching of GraphQL responses (~1-5ms vs ~200-500ms uncached)",[440,470,471,476,479],{},[458,472,473],{},[28,474,475],{},"Client (GraphQL)",[458,477,478],{},"Per browser",[458,480,481],{},"Deduplicates identical queries during navigation",[440,483,484,489,492],{},[458,485,486],{},[28,487,488],{},"Payload",[458,490,491],{},"Per request",[458,493,494],{},"Prevents refetch during SSR-to-client hydration",[15,496,497,498,222],{},"Configure it in ",[75,499,500],{},"nuxt.config.ts",[134,502,504],{"className":200,"code":503,"filename":500,"language":203,"meta":139,"style":139},"export default defineNuxtConfig({\n  wpNuxt: {\n    cache: {\n      enabled: true,\n      maxAge: 300,\n      swr: true\n    }\n  }\n})\n",[75,505,506,521,530,539,551,563,573,577,581],{"__ignoreMap":139},[143,507,508,511,514,517,519],{"class":145,"line":146},[143,509,510],{"class":235},"export",[143,512,513],{"class":235}," default",[143,515,516],{"class":239}," defineNuxtConfig",[143,518,243],{"class":225},[143,520,246],{"class":214},[143,522,523,526,528],{"class":145,"line":152},[143,524,525],{"class":218},"  wpNuxt",[143,527,222],{"class":214},[143,529,275],{"class":214},[143,531,532,535,537],{"class":145,"line":158},[143,533,534],{"class":218},"    cache",[143,536,222],{"class":214},[143,538,275],{"class":214},[143,540,541,544,546,549],{"class":145,"line":165},[143,542,543],{"class":218},"      enabled",[143,545,222],{"class":214},[143,547,548],{"class":323}," true",[143,550,289],{"class":214},[143,552,553,556,558,561],{"class":145,"line":171},[143,554,555],{"class":218},"      maxAge",[143,557,222],{"class":214},[143,559,560],{"class":285}," 300",[143,562,289],{"class":214},[143,564,565,568,570],{"class":145,"line":177},[143,566,567],{"class":218},"      swr",[143,569,222],{"class":214},[143,571,572],{"class":323}," true\n",[143,574,575],{"class":145,"line":182},[143,576,406],{"class":214},[143,578,579],{"class":145,"line":188},[143,580,411],{"class":214},[143,582,584,586],{"class":145,"line":583},9,[143,585,229],{"class":214},[143,587,331],{"class":225},[15,589,590],{},"You can also disable caching per-query for content that needs to be fresh, like authenticated or preview content:",[134,592,594],{"className":200,"code":593,"language":203,"meta":139,"style":139},"const { data } = await useViewer(undefined, {\n  clientCache: false\n})\n",[75,595,596,621,629],{"__ignoreMap":139},[143,597,598,600,602,605,607,609,611,614,616,619],{"class":145,"line":146},[143,599,211],{"class":210},[143,601,215],{"class":214},[143,603,604],{"class":225}," data ",[143,606,229],{"class":214},[143,608,232],{"class":214},[143,610,236],{"class":235},[143,612,613],{"class":239}," useViewer",[143,615,243],{"class":225},[143,617,618],{"class":214},"undefined,",[143,620,275],{"class":214},[143,622,623,625,627],{"class":145,"line":152},[143,624,318],{"class":218},[143,626,222],{"class":214},[143,628,324],{"class":323},[143,630,631,633],{"class":145,"line":158},[143,632,229],{"class":214},[143,634,331],{"class":225},[15,636,637],{},"Every deployment automatically generates a unique build hash that invalidates the cache, so stale content never survives a redeploy.",[15,639,640,641,644],{},"The SSG support deserves a special mention. WPNuxt normalizes WordPress URIs with trailing slashes to ensure consistent cache keys between prerendered payloads and client-side navigation. The ",[75,642,643],{},"getCachedData"," functions are defined at module level (not inside the composable) to maintain stable function references across SSR and hydration, preventing Nuxt's \"incompatible options\" warnings.",[111,646],{},[114,648,650],{"id":649},"content-rendering","Content Rendering",[355,652,654],{"id":653},"the-wpcontent-component","The WPContent Component",[15,656,657,658,661],{},"The ",[75,659,660],{},"\u003CWPContent>"," component handles WordPress content rendering:",[134,663,668],{"className":664,"code":665,"filename":666,"language":667,"meta":139,"style":139},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Ctemplate>\n  \u003CWPContent :node=\"page\" \u002F>\n\u003C\u002Ftemplate>\n","app\u002Fpages\u002F[...slug].vue","vue",[75,669,670,681,707],{"__ignoreMap":139},[143,671,672,675,678],{"class":145,"line":146},[143,673,674],{"class":214},"\u003C",[143,676,677],{"class":218},"template",[143,679,680],{"class":214},">\n",[143,682,683,686,689,692,695,698,702,704],{"class":145,"line":152},[143,684,685],{"class":214},"  \u003C",[143,687,688],{"class":218},"WPContent",[143,690,691],{"class":210}," :node",[143,693,694],{"class":214},"=",[143,696,697],{"class":214},"\"",[143,699,701],{"class":700},"sfazB","page",[143,703,697],{"class":214},[143,705,706],{"class":214}," \u002F>\n",[143,708,709,712,714],{"class":145,"line":158},[143,710,711],{"class":214},"\u003C\u002F",[143,713,677],{"class":218},[143,715,680],{"class":214},[15,717,718,719,721,722,725,726,729],{},"WPContent automatically detects whether ",[75,720,92],{}," is installed. If it is, content renders through the ",[75,723,724],{},"BlockRenderer"," for structured Gutenberg blocks. Otherwise, it falls back to sanitized HTML via the built-in ",[75,727,728],{},"v-sanitize-html"," directive.",[15,731,732,733,736,737,89,740,743,744,747],{},"The component also intercepts clicks on internal links and uses ",[75,734,735],{},"navigateTo()"," for client-side navigation. It respects modifier keys (Ctrl\u002FCmd+click for new tab), ",[75,738,739],{},"target=\"_blank\"",[75,741,742],{},"download"," attributes, and ",[75,745,746],{},"rel=\"external\""," — so link behavior stays predictable.",[355,749,751],{"id":750},"gutenberg-blocks","Gutenberg Blocks",[15,753,657,754,756],{},[75,755,92],{}," package renders WordPress Gutenberg blocks as Vue components. Each block type maps to a dedicated component:",[434,758,759,769],{},[437,760,761],{},[440,762,763,766],{},[443,764,765],{},"Component",[443,767,768],{},"Block Type",[453,770,771,783,795,807,819,831,843,855,867,879],{},[440,772,773,778],{},[458,774,775],{},[75,776,777],{},"CoreParagraph",[458,779,780],{},[75,781,782],{},"core\u002Fparagraph",[440,784,785,790],{},[458,786,787],{},[75,788,789],{},"CoreHeading",[458,791,792],{},[75,793,794],{},"core\u002Fheading",[440,796,797,802],{},[458,798,799],{},[75,800,801],{},"CoreImage",[458,803,804],{},[75,805,806],{},"core\u002Fimage",[440,808,809,814],{},[458,810,811],{},[75,812,813],{},"CoreButton",[458,815,816],{},[75,817,818],{},"core\u002Fbutton",[440,820,821,826],{},[458,822,823],{},[75,824,825],{},"CoreButtons",[458,827,828],{},[75,829,830],{},"core\u002Fbuttons",[440,832,833,838],{},[458,834,835],{},[75,836,837],{},"CoreQuote",[458,839,840],{},[75,841,842],{},"core\u002Fquote",[440,844,845,850],{},[458,846,847],{},[75,848,849],{},"CoreGallery",[458,851,852],{},[75,853,854],{},"core\u002Fgallery",[440,856,857,862],{},[458,858,859],{},[75,860,861],{},"CoreSpacer",[458,863,864],{},[75,865,866],{},"core\u002Fspacer",[440,868,869,874],{},[458,870,871],{},[75,872,873],{},"CoreDetails",[458,875,876],{},[75,877,878],{},"core\u002Fdetails",[440,880,881,886],{},[458,882,883],{},[75,884,885],{},"EditorBlock",[458,887,888],{},"Fallback for unsupported blocks",[15,890,891],{},"Install the blocks package alongside core:",[134,893,897],{"className":894,"code":895,"language":896,"meta":139,"style":139},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm add @wpnuxt\u002Fblocks\n","bash",[75,898,899],{"__ignoreMap":139},[143,900,901,905,908],{"class":145,"line":146},[143,902,904],{"class":903},"sBMFI","pnpm",[143,906,907],{"class":700}," add",[143,909,910],{"class":700}," @wpnuxt\u002Fblocks\n",[134,912,914],{"className":200,"code":913,"filename":500,"language":203,"meta":139,"style":139},"export default defineNuxtConfig({\n  modules: ['@wpnuxt\u002Fblocks']\n})\n",[75,915,916,928,948],{"__ignoreMap":139},[143,917,918,920,922,924,926],{"class":145,"line":146},[143,919,510],{"class":235},[143,921,513],{"class":235},[143,923,516],{"class":239},[143,925,243],{"class":225},[143,927,246],{"class":214},[143,929,930,933,935,938,941,943,945],{"class":145,"line":152},[143,931,932],{"class":218},"  modules",[143,934,222],{"class":214},[143,936,937],{"class":225}," [",[143,939,940],{"class":214},"'",[143,942,92],{"class":700},[143,944,940],{"class":214},[143,946,947],{"class":225},"]\n",[143,949,950,952],{"class":145,"line":158},[143,951,229],{"class":214},[143,953,331],{"class":225},[15,955,956,957,960,961,964,965,968,969,972,973,975,976,979],{},"The blocks module automatically extends the ",[75,958,959],{},"Post"," and ",[75,962,963],{},"Page"," GraphQL fragments to include ",[75,966,967],{},"editorBlocks"," data. It also detects ",[75,970,971],{},"@nuxt\u002Fui"," and uses its components where appropriate — for example, ",[75,974,813],{}," renders as a ",[75,977,978],{},"UButton"," when Nuxt UI is available.",[15,981,982,983,986,987,990],{},"Override any block by creating your own component in ",[75,984,985],{},"components\u002Fblocks\u002F",". A ",[75,988,989],{},"CoreParagraph.vue"," in your project takes precedence over the built-in version, giving you full control over rendering without ejecting from the system.",[355,992,994],{"id":993},"serverless-ready-sanitization","Serverless-Ready Sanitization",[15,996,997,998,1001,1002,1004],{},"Version 1 used ",[75,999,1000],{},"@radya\u002Fnuxt-dompurify",", which pulled jsdom (~5.7 MB) into the server bundle. This broke SSR on serverless platforms like Vercel where the bundle size matters. Version 2 replaces this with a built-in ",[75,1003,728],{}," directive. On the server, HTML passes through as-is (WordPress is a trusted source). On the client, DOMPurify loads lazily using the native browser DOM — no jsdom required.",[111,1006],{},[114,1008,48],{"id":1009},"authentication",[15,1011,657,1012,1014],{},[75,1013,95],{}," package adds WordPress authentication with three supported flows:",[434,1016,1017,1030],{},[437,1018,1019],{},[440,1020,1021,1024,1027],{},[443,1022,1023],{},"Method",[443,1025,1026],{},"Flow",[443,1028,1029],{},"WordPress Plugin",[453,1031,1032,1045,1057],{},[440,1033,1034,1039,1042],{},[458,1035,1036],{},[28,1037,1038],{},"Password",[458,1040,1041],{},"Username\u002Fpassword via GraphQL mutation",[458,1043,1044],{},"Headless Login for WPGraphQL",[440,1046,1047,1052,1055],{},[458,1048,1049],{},[28,1050,1051],{},"External OAuth",[458,1053,1054],{},"Google, GitHub, etc.",[458,1056,1044],{},[440,1058,1059,1064,1067],{},[458,1060,1061],{},[28,1062,1063],{},"WordPress OAuth",[458,1065,1066],{},"Redirect to WordPress login",[458,1068,1069],{},"miniOrange WP OAuth Server",[15,1071,1072],{},"All three methods store JWT tokens in secure httpOnly cookies with automatic refresh handling.",[134,1074,1077],{"className":200,"code":1075,"filename":1076,"language":203,"meta":139,"style":139},"const { user, isAuthenticated, login, logout } = useWPAuth()\n\nawait login({ username: 'demo', password: 'secret' })\n","app\u002Fpages\u002Flogin.vue",[75,1078,1079,1114,1118],{"__ignoreMap":139},[143,1080,1081,1083,1085,1088,1091,1094,1096,1099,1101,1104,1106,1108,1111],{"class":145,"line":146},[143,1082,211],{"class":210},[143,1084,215],{"class":214},[143,1086,1087],{"class":225}," user",[143,1089,1090],{"class":214},",",[143,1092,1093],{"class":225}," isAuthenticated",[143,1095,1090],{"class":214},[143,1097,1098],{"class":225}," login",[143,1100,1090],{"class":214},[143,1102,1103],{"class":225}," logout ",[143,1105,229],{"class":214},[143,1107,232],{"class":214},[143,1109,1110],{"class":239}," useWPAuth",[143,1112,1113],{"class":225},"()\n",[143,1115,1116],{"class":145,"line":152},[143,1117,162],{"emptyLinePlaceholder":161},[143,1119,1120,1123,1125,1127,1130,1133,1135,1138,1141,1143,1145,1148,1150,1152,1155,1157,1160],{"class":145,"line":158},[143,1121,1122],{"class":235},"await",[143,1124,1098],{"class":239},[143,1126,243],{"class":225},[143,1128,1129],{"class":214},"{",[143,1131,1132],{"class":218}," username",[143,1134,222],{"class":214},[143,1136,1137],{"class":214}," '",[143,1139,1140],{"class":700},"demo",[143,1142,940],{"class":214},[143,1144,1090],{"class":214},[143,1146,1147],{"class":218}," password",[143,1149,222],{"class":214},[143,1151,1137],{"class":214},[143,1153,1154],{"class":700},"secret",[143,1156,940],{"class":214},[143,1158,1159],{"class":214}," }",[143,1161,331],{"class":225},[15,1163,657,1164,1167],{},[75,1165,1166],{},"useWPUser()"," composable provides role checking:",[134,1169,1171],{"className":200,"code":1170,"language":203,"meta":139,"style":139},"const { hasRole, isAdmin, isEditor } = useWPUser()\n",[75,1172,1173],{"__ignoreMap":139},[143,1174,1175,1177,1179,1182,1184,1187,1189,1192,1194,1196,1199],{"class":145,"line":146},[143,1176,211],{"class":210},[143,1178,215],{"class":214},[143,1180,1181],{"class":225}," hasRole",[143,1183,1090],{"class":214},[143,1185,1186],{"class":225}," isAdmin",[143,1188,1090],{"class":214},[143,1190,1191],{"class":225}," isEditor ",[143,1193,229],{"class":214},[143,1195,232],{"class":214},[143,1197,1198],{"class":239}," useWPUser",[143,1200,1113],{"class":225},[15,1202,1203],{},"Authentication is SSR-compatible — cookies are included in server-side requests, so authenticated content renders correctly on first load.",[111,1205],{},[114,1207,1209],{"id":1208},"developer-tools","Developer Tools",[355,1211,1213],{"id":1212},"mcp-server","MCP Server",[15,1215,1216,1217,1223,1224,222],{},"WPNuxt 2 ships with a ",[105,1218,1222],{"href":1219,"rel":1220},"https:\u002F\u002Fmodelcontextprotocol.io\u002F",[1221],"nofollow","Model Context Protocol"," server that integrates with AI assistants like Claude Code. Add it to your project's ",[75,1225,1226],{},".mcp.json",[134,1228,1232],{"className":1229,"code":1230,"filename":1226,"language":1231,"meta":139,"style":139},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"mcpServers\": {\n    \"wpnuxt\": {\n      \"type\": \"sse\",\n      \"url\": \"https:\u002F\u002Fwpnuxt.com\u002Fmcp\"\n    }\n  }\n}\n","json",[75,1233,1234,1238,1252,1266,1288,1307,1311,1315],{"__ignoreMap":139},[143,1235,1236],{"class":145,"line":146},[143,1237,246],{"class":214},[143,1239,1240,1243,1246,1248,1250],{"class":145,"line":152},[143,1241,1242],{"class":214},"  \"",[143,1244,1245],{"class":210},"mcpServers",[143,1247,697],{"class":214},[143,1249,222],{"class":214},[143,1251,275],{"class":214},[143,1253,1254,1257,1260,1262,1264],{"class":145,"line":158},[143,1255,1256],{"class":214},"    \"",[143,1258,1259],{"class":903},"wpnuxt",[143,1261,697],{"class":214},[143,1263,222],{"class":214},[143,1265,275],{"class":214},[143,1267,1268,1271,1274,1276,1278,1281,1284,1286],{"class":145,"line":165},[143,1269,1270],{"class":214},"      \"",[143,1272,1273],{"class":285},"type",[143,1275,697],{"class":214},[143,1277,222],{"class":214},[143,1279,1280],{"class":214}," \"",[143,1282,1283],{"class":700},"sse",[143,1285,697],{"class":214},[143,1287,289],{"class":214},[143,1289,1290,1292,1295,1297,1299,1301,1304],{"class":145,"line":171},[143,1291,1270],{"class":214},[143,1293,1294],{"class":285},"url",[143,1296,697],{"class":214},[143,1298,222],{"class":214},[143,1300,1280],{"class":214},[143,1302,1303],{"class":700},"https:\u002F\u002Fwpnuxt.com\u002Fmcp",[143,1305,1306],{"class":214},"\"\n",[143,1308,1309],{"class":145,"line":177},[143,1310,406],{"class":214},[143,1312,1313],{"class":145,"line":182},[143,1314,411],{"class":214},[143,1316,1317],{"class":145,"line":188},[143,1318,416],{"class":214},[15,1320,1321],{},"The MCP server provides tools across several categories:",[15,1323,1324,1327],{},[28,1325,1326],{},"WordPress Discovery"," — Connect to your WordPress site and explore content types, menus, taxonomies, installed plugins, and available Gutenberg blocks.",[15,1329,1330,1333],{},[28,1331,1332],{},"Content Fetching"," — Fetch posts, pages, and sample content directly, or run custom GraphQL queries.",[15,1335,1336,1339,1340,1343],{},[28,1337,1338],{},"Code Generation"," — Scaffold pages, components, GraphQL queries, and block renderers for your WPNuxt project. The ",[75,1341,1342],{},"wpnuxt_init"," tool generates a complete project structure.",[15,1345,1346,1349,1350,1352],{},[28,1347,1348],{},"Migration"," — The ",[75,1351,102],{}," tool scans v1 projects, identifies breaking changes, detects anti-patterns, and generates compatibility helpers for upgrading.",[15,1354,1355,1349,1358,960,1361,1364],{},[28,1356,1357],{},"Documentation Proxy",[75,1359,1360],{},"nuxt_docs",[75,1362,1363],{},"nuxt_ui_docs"," tools proxy official Nuxt and Nuxt UI documentation, so you only need one MCP server for your WPNuxt project.",[355,1366,1368],{"id":1367},"the-wpnuxi-cli","The wpnuxi CLI",[15,1370,1371],{},"A standalone CLI tool handles project scaffolding and diagnostics:",[134,1373,1375],{"className":894,"code":1374,"language":896,"meta":139,"style":139},"# Create a new WPNuxt project\nnpx wpnuxi init my-site\n\n# Display environment info\nnpx wpnuxi info\n\n# Run health checks\nnpx wpnuxi doctor\n",[75,1376,1377,1383,1397,1401,1406,1415,1419,1424],{"__ignoreMap":139},[143,1378,1379],{"class":145,"line":146},[143,1380,1382],{"class":1381},"sHwdD","# Create a new WPNuxt project\n",[143,1384,1385,1388,1391,1394],{"class":145,"line":152},[143,1386,1387],{"class":903},"npx",[143,1389,1390],{"class":700}," wpnuxi",[143,1392,1393],{"class":700}," init",[143,1395,1396],{"class":700}," my-site\n",[143,1398,1399],{"class":145,"line":158},[143,1400,162],{"emptyLinePlaceholder":161},[143,1402,1403],{"class":145,"line":165},[143,1404,1405],{"class":1381},"# Display environment info\n",[143,1407,1408,1410,1412],{"class":145,"line":171},[143,1409,1387],{"class":903},[143,1411,1390],{"class":700},[143,1413,1414],{"class":700}," info\n",[143,1416,1417],{"class":145,"line":177},[143,1418,162],{"emptyLinePlaceholder":161},[143,1420,1421],{"class":145,"line":182},[143,1422,1423],{"class":1381},"# Run health checks\n",[143,1425,1426,1428,1430],{"class":145,"line":188},[143,1427,1387],{"class":903},[143,1429,1390],{"class":700},[143,1431,1432],{"class":700}," doctor\n",[15,1434,657,1435,1438],{},[75,1436,1437],{},"doctor"," command checks your environment variables, WordPress URL validity, GraphQL endpoint reachability, introspection support, and project dependencies. It gives you a clear diagnostic when something isn't connecting.",[355,1440,1442],{"id":1441},"vercel-auto-configuration","Vercel Auto-Configuration",[15,1444,1445],{},"WPNuxt v2 auto-detects Vercel deployments and applies the right settings:",[22,1447,1448,1451,1454,1461],{},[25,1449,1450],{},"Native SWR for proper ISR (Incremental Static Regeneration) handling",[25,1452,1453],{},"SSR forced for all routes (fixes catch-all route classification issues)",[25,1455,1456,1457,1460],{},"WordPress uploads proxy (",[75,1458,1459],{},"\u002Fwp-content\u002Fuploads\u002F**"," forwarded to your WordPress site) — images and media referenced in WordPress content just work without exposing your WordPress domain",[25,1462,1463,1466],{},[75,1464,1465],{},"@nuxt\u002Fimage"," IPX configuration with proper WordPress domain aliases",[15,1468,1469],{},"No manual Vercel configuration needed — it just works.",[355,1471,1473],{"id":1472},"additional-configuration","Additional Configuration",[15,1475,1476,1477,1480],{},"For WordPress sites with public introspection disabled, WPNuxt supports a ",[75,1478,1479],{},"schemaAuthToken"," that sends a Bearer token during schema download without ever exposing it in the client bundle:",[134,1482,1484],{"className":200,"code":1483,"filename":500,"language":203,"meta":139,"style":139},"wpNuxt: {\n  schemaAuthToken: process.env.WPNUXT_SCHEMA_AUTH_TOKEN\n}\n",[75,1485,1486,1495,1515],{"__ignoreMap":139},[143,1487,1488,1491,1493],{"class":145,"line":146},[143,1489,1490],{"class":903},"wpNuxt",[143,1492,222],{"class":214},[143,1494,275],{"class":214},[143,1496,1497,1500,1502,1505,1507,1510,1512],{"class":145,"line":152},[143,1498,1499],{"class":903},"  schemaAuthToken",[143,1501,222],{"class":214},[143,1503,1504],{"class":225}," process",[143,1506,259],{"class":214},[143,1508,1509],{"class":225},"env",[143,1511,259],{"class":214},[143,1513,1514],{"class":225},"WPNUXT_SCHEMA_AUTH_TOKEN\n",[143,1516,1517],{"class":145,"line":158},[143,1518,416],{"class":214},[15,1520,1521,1522,960,1525,1528],{},"WPNuxt automatically creates ",[75,1523,1524],{},"server\u002FgraphqlMiddleware.serverOptions.ts",[75,1526,1527],{},"app\u002FgraphqlMiddleware.clientOptions.ts"," with sensible defaults for cookie forwarding, Authorization header passthrough, and preview mode support. Existing files are never overwritten, so custom configurations are preserved.",[15,1530,1531,1532,1535,1536,960,1539,1542,1543,1545,1546,1548],{},"Running ",[75,1533,1534],{},"nuxt prepare"," for the first time triggers an interactive setup that prompts for your WordPress URL, creates ",[75,1537,1538],{},".env",[75,1540,1541],{},".env.example"," files, sets up ",[75,1544,1226],{}," for AI assistant integration, and creates the ",[75,1547,344],{}," folder for custom GraphQL queries.",[111,1550],{},[114,1552,1554],{"id":1553},"breaking-changes","Breaking Changes",[15,1556,1557],{},"If you're upgrading from v1, the key changes are:",[22,1559,1560,1583,1597,1613,1633],{},[25,1561,1562,1565,1566,1569,1570,1573,1574,89,1577,1573,1580],{},[28,1563,1564],{},"Composable names"," — ",[75,1567,1568],{},"useWP*"," prefix dropped: ",[75,1571,1572],{},"useWPPosts()"," → ",[75,1575,1576],{},"usePosts()",[75,1578,1579],{},"useWPPageByUri()",[75,1581,1582],{},"usePageByUri()",[25,1584,1585,1565,1588,1590,1591,1593,1594],{},[28,1586,1587],{},"Lazy loading",[75,1589,127],{}," replaced by a ",[75,1592,131],{}," option: ",[75,1595,1596],{},"usePosts(undefined, { lazy: true })",[25,1598,1599,1565,1602,1605,1606,1609,1610],{},[28,1600,1601],{},"Cache config",[75,1603,1604],{},"enableCache"," \u002F ",[75,1607,1608],{},"cacheMaxAge"," replaced by ",[75,1611,1612],{},"cache: { enabled, maxAge, swr }",[25,1614,1615,1565,1618,1621,1622,1625,1626,1621,1629,1632],{},[28,1616,1617],{},"Removed composables",[75,1619,1620],{},"useFeaturedImage()"," (use ",[75,1623,1624],{},"post.featuredImage.node"," directly), ",[75,1627,1628],{},"useWPUri()",[75,1630,1631],{},"useRoute().params",")",[25,1634,1635,1638],{},[28,1636,1637],{},"Minimum versions"," — Nuxt 4.0+, Node.js 20+, nuxt-graphql-middleware 5.x",[15,1640,1641,1642,1644],{},"The WPNuxt MCP server includes a ",[75,1643,102],{}," tool that can scan your v1 project and generate a detailed migration plan.",[111,1646],{},[114,1648,1650],{"id":1649},"getting-started","Getting Started",[15,1652,1653],{},"The fastest way to start a new WPNuxt project:",[134,1655,1657],{"className":894,"code":1656,"language":896,"meta":139,"style":139},"npx wpnuxi init my-wordpress-site\n",[75,1658,1659],{"__ignoreMap":139},[143,1660,1661,1663,1665,1667],{"class":145,"line":146},[143,1662,1387],{"class":903},[143,1664,1390],{"class":700},[143,1666,1393],{"class":700},[143,1668,1669],{"class":700}," my-wordpress-site\n",[15,1671,1672],{},"Or manually:",[134,1674,1676],{"className":894,"code":1675,"language":896,"meta":139,"style":139},"pnpm add @wpnuxt\u002Fcore\n",[75,1677,1678],{"__ignoreMap":139},[143,1679,1680,1682,1684],{"class":145,"line":146},[143,1681,904],{"class":903},[143,1683,907],{"class":700},[143,1685,1686],{"class":700}," @wpnuxt\u002Fcore\n",[134,1688,1690],{"className":200,"code":1689,"filename":500,"language":203,"meta":139,"style":139},"export default defineNuxtConfig({\n  modules: ['@wpnuxt\u002Fcore'],\n  wpNuxt: {\n    wordpressUrl: 'https:\u002F\u002Fyour-wordpress-site.com'\n  }\n})\n",[75,1691,1692,1704,1723,1731,1746,1750],{"__ignoreMap":139},[143,1693,1694,1696,1698,1700,1702],{"class":145,"line":146},[143,1695,510],{"class":235},[143,1697,513],{"class":235},[143,1699,516],{"class":239},[143,1701,243],{"class":225},[143,1703,246],{"class":214},[143,1705,1706,1708,1710,1712,1714,1716,1718,1721],{"class":145,"line":152},[143,1707,932],{"class":218},[143,1709,222],{"class":214},[143,1711,937],{"class":225},[143,1713,940],{"class":214},[143,1715,88],{"class":700},[143,1717,940],{"class":214},[143,1719,1720],{"class":225},"]",[143,1722,289],{"class":214},[143,1724,1725,1727,1729],{"class":145,"line":158},[143,1726,525],{"class":218},[143,1728,222],{"class":214},[143,1730,275],{"class":214},[143,1732,1733,1736,1738,1740,1743],{"class":145,"line":165},[143,1734,1735],{"class":218},"    wordpressUrl",[143,1737,222],{"class":214},[143,1739,1137],{"class":214},[143,1741,1742],{"class":700},"https:\u002F\u002Fyour-wordpress-site.com",[143,1744,1745],{"class":214},"'\n",[143,1747,1748],{"class":145,"line":171},[143,1749,411],{"class":214},[143,1751,1752,1754],{"class":145,"line":177},[143,1753,229],{"class":214},[143,1755,331],{"class":225},[15,1757,1758],{},"To add blocks and authentication:",[134,1760,1762],{"className":894,"code":1761,"language":896,"meta":139,"style":139},"pnpm add @wpnuxt\u002Fblocks @wpnuxt\u002Fauth\n",[75,1763,1764],{"__ignoreMap":139},[143,1765,1766,1768,1770,1773],{"class":145,"line":146},[143,1767,904],{"class":903},[143,1769,907],{"class":700},[143,1771,1772],{"class":700}," @wpnuxt\u002Fblocks",[143,1774,1775],{"class":700}," @wpnuxt\u002Fauth\n",[134,1777,1779],{"className":200,"code":1778,"filename":500,"language":203,"meta":139,"style":139},"export default defineNuxtConfig({\n  modules: [\n    '@wpnuxt\u002Fcore',\n    '@wpnuxt\u002Fblocks',\n    '@wpnuxt\u002Fauth'\n  ]\n})\n",[75,1780,1781,1793,1802,1813,1823,1831,1836],{"__ignoreMap":139},[143,1782,1783,1785,1787,1789,1791],{"class":145,"line":146},[143,1784,510],{"class":235},[143,1786,513],{"class":235},[143,1788,516],{"class":239},[143,1790,243],{"class":225},[143,1792,246],{"class":214},[143,1794,1795,1797,1799],{"class":145,"line":152},[143,1796,932],{"class":218},[143,1798,222],{"class":214},[143,1800,1801],{"class":225}," [\n",[143,1803,1804,1807,1809,1811],{"class":145,"line":158},[143,1805,1806],{"class":214},"    '",[143,1808,88],{"class":700},[143,1810,940],{"class":214},[143,1812,289],{"class":214},[143,1814,1815,1817,1819,1821],{"class":145,"line":165},[143,1816,1806],{"class":214},[143,1818,92],{"class":700},[143,1820,940],{"class":214},[143,1822,289],{"class":214},[143,1824,1825,1827,1829],{"class":145,"line":171},[143,1826,1806],{"class":214},[143,1828,95],{"class":700},[143,1830,1745],{"class":214},[143,1832,1833],{"class":145,"line":177},[143,1834,1835],{"class":225},"  ]\n",[143,1837,1838,1840],{"class":145,"line":182},[143,1839,229],{"class":214},[143,1841,331],{"class":225},[15,1843,1844,1845,1847],{},"Run ",[75,1846,1534],{}," and WPNuxt handles the rest — downloading the GraphQL schema, generating composables, and setting up type declarations.",[111,1849],{},[114,1851,1853],{"id":1852},"whats-next","What's Next",[15,1855,1856],{},"WPNuxt 2.0 is stable and ready for production. Here's what's on the roadmap:",[22,1858,1859,1865,1871,1877,1883],{},[25,1860,1861,1864],{},[28,1862,1863],{},"Cursor-based pagination"," for large content sets",[25,1866,1867,1870],{},[28,1868,1869],{},"Deeper inner block nesting"," for complex Gutenberg layouts",[25,1872,1873,1876],{},[28,1874,1875],{},"Additional default queries"," for taxonomies and search",[25,1878,1879,1882],{},[28,1880,1881],{},"End-to-end tutorials"," for common use cases (blog, SEO, menus)",[25,1884,1885,1888,1889,1891],{},[28,1886,1887],{},"Media handling deep dive"," with ",[75,1890,1465],{}," optimization patterns",[15,1893,1894,1895,259],{},"Feedback, feature requests, and bug reports are welcome on the ",[105,1896,1899],{"href":1897,"rel":1898},"https:\u002F\u002Fgithub.com\u002Fwpnuxt\u002Fwpnuxt",[1221],"GitHub repository",[111,1901],{},[114,1903,1905],{"id":1904},"resources","Resources",[15,1907,1908],{},[28,1909,1910],{},"Getting Started:",[22,1912,1913,1920,1926],{},[25,1914,1915],{},[105,1916,1919],{"href":1917,"rel":1918},"https:\u002F\u002Fwpnuxt.com",[1221],"WPNuxt Documentation",[25,1921,1922],{},[105,1923,1925],{"href":1897,"rel":1924},[1221],"GitHub Repository",[25,1927,1928],{},[105,1929,1932],{"href":1930,"rel":1931},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@wpnuxt\u002Fcore",[1221],"npm: @wpnuxt\u002Fcore",[15,1934,1935],{},[28,1936,1937],{},"WordPress Requirements:",[22,1939,1940,1947,1957],{},[25,1941,1942],{},[105,1943,1946],{"href":1944,"rel":1945},"https:\u002F\u002Fwww.wpgraphql.com\u002F",[1221],"WPGraphQL Plugin",[25,1948,1949,1954,1955,1632],{},[105,1950,1953],{"href":1951,"rel":1952},"https:\u002F\u002Fgithub.com\u002Fwpengine\u002Fwp-graphql-content-blocks",[1221],"WPGraphQL Content Blocks"," (for ",[75,1956,92],{},[25,1958,1959,1954,1963,1632],{},[105,1960,1044],{"href":1961,"rel":1962},"https:\u002F\u002Fgithub.com\u002FAxeWP\u002Fwp-graphql-headless-login",[1221],[75,1964,95],{},[15,1966,1967],{},[28,1968,1969],{},"Related Posts:",[22,1971,1972],{},[25,1973,1974],{},[105,1975,1977],{"href":1976},"\u002Fblog\u002Fdiscoveringnuxt","Discovering Nuxt",[1979,1980,1981],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":139,"searchDepth":152,"depth":152,"links":1983},[1984,1987,1988,1993,1994,2000,2001,2002,2003],{"id":116,"depth":152,"text":117,"children":1985},[1986],{"id":357,"depth":158,"text":358},{"id":428,"depth":152,"text":429},{"id":649,"depth":152,"text":650,"children":1989},[1990,1991,1992],{"id":653,"depth":158,"text":654},{"id":750,"depth":158,"text":751},{"id":993,"depth":158,"text":994},{"id":1009,"depth":152,"text":48},{"id":1208,"depth":152,"text":1209,"children":1995},[1996,1997,1998,1999],{"id":1212,"depth":158,"text":1213},{"id":1367,"depth":158,"text":1368},{"id":1441,"depth":158,"text":1442},{"id":1472,"depth":158,"text":1473},{"id":1553,"depth":152,"text":1554},{"id":1649,"depth":152,"text":1650},{"id":1852,"depth":152,"text":1853},{"id":1904,"depth":152,"text":1905},"2026-03-14","Announcing WPNuxt 2.0 — type-safe composables, multi-layer caching, Gutenberg block rendering, authentication, and an AI-powered MCP server for headless WordPress with Nuxt","md",{"src":2008,"height":2009},"\u002Fimages\u002Fblog\u002F993.wpnuxt-v2\u002Fwpnuxt.png",400,{},"\u002Fblog\u002Fwpnuxt-v2",{"title":5,"description":2005},null,"blog\u002F993.wpnuxt-v2","_JhDaCAoHSPZsKpmYnHLak1x9Kw4HUdMYidWvV3QKZM",[2017,2022],{"title":2018,"path":2019,"stem":2020,"description":2021,"children":-1},"My Audio Runs on a Raspberry Pi — So I Built a Spectrum Visualizer That Doesn't Listen","\u002Fblog\u002Ffft-visualizer","blog\u002F992.fft-visualizer","FFT Visualizer 1.0 is out: a WebGL audio spectrum analyzer that draws spectra computed anywhere — born from a Pi control panel, grown into a TypeScript core with Vue and React wrappers",{"title":2023,"path":2024,"stem":2025,"description":2026,"children":-1},"Kaspa: digital silver","\u002Fblog\u002Fkaspa","blog\u002F994.kaspa","A proof-of-work cryptocurrency staying true to Satoshi's vision while using blockDAG technology for faster transactions",1788334243144]