npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@szymonpiatek/nextwordpress

v0.0.25

Published

Szymon Piątek - Next.js WordPress client (types, queries, fetcher)

Downloads

3,539

Readme

@szymonpiatek/nextwordpress

A strictly typed, high-performance WordPress client for Next.js. This library provides a unified interface for interacting with WordPress via REST API and WPGraphQL, with first-class support for WooCommerce, Yoast SEO, ACF, and more.

npm version License: UNLICENSED

Features

  • 🚀 Built for Next.js: Optimized for Server Components and SSR.
  • 🛡️ Strictly Typed: Full TypeScript support for all API responses.
  • 🔗 Dual Integration: Support for both standard REST API and WPGraphQL.
  • 🛒 WooCommerce Ready: Deep integration with WooCommerce REST & GQL, including EU Omnibus directive support.
  • Next.js Optimized: Built-in support for Next.js fetch cache, revalidation, and tags.
  • 🔍 Preview Mode: Built-in FaustJS-compatible draft/preview handlers for Next.js.
  • 📝 Contact Form 7: Ready-to-use CF7 REST API integration.
  • 👍 WP ULike: Like/unlike posts, comments, and custom item types via REST API.
  • 🍪 Cookie Consent: GDPR-compliant cookie consent handler compatible with Cookie Notice & Compliance plugin.
  • 📦 Tree-shakeable: Only bundle what you use.

Installation

npm install @szymonpiatek/nextwordpress

Quick Start

1. WordPress REST API

The REST client is ideal for standard WordPress data fetching.

import { createWordPressClient } from '@szymonpiatek/nextwordpress';

const wp = createWordPressClient({
  serverURL: 'https://api.yourstore.com', // Internal URL (e.g., Docker)
  clientURL: 'https://yourstore.com',      // Public URL
});

// Fetch posts
const posts = await wp.getPosts({ _embed: true });

// Fetch a single page by slug
const page = await wp.getPageBySlug('about-us');

2. WPGraphQL

Use the GraphQL client for complex queries and better performance.

import { createWPGraphQLClient } from '@szymonpiatek/nextwordpress';

const gq = createWPGraphQLClient({
  serverURL: 'https://yourstore.com/graphql',
});

// Fetch posts via GraphQL
const { nodes: posts } = await gq.getPosts({ first: 10 });

Integrations

WooCommerce

Full support for products, orders, customers, and more. Includes a dedicated helper for the EU Omnibus Directive.

import { createWooCommerceClient, withOmnibus } from '@szymonpiatek/nextwordpress';

const woo = createWooCommerceClient({
  serverURL: 'https://yourstore.com',
  consumerKey: process.env.WC_CONSUMER_KEY!,
  consumerSecret: process.env.WC_CONSUMER_SECRET!,
});

const product = await woo.getProductById(123);

// Apply Omnibus directive helpers (lowest price in 30 days)
const productWithHistory = withOmnibus(product);
console.log(productWithHistory.omnibus.lowestPrice);

FaustJS / Preview Mode

Enable WordPress draft preview in Next.js using FaustJS-compatible route handlers. Requires the FaustJS WordPress plugin and a FAUST_SECRET_KEY environment variable.

// app/api/faust/[...route]/route.ts
import { createFaustAuthHandler } from '@szymonpiatek/nextwordpress';
import { NextRequest } from 'next/server';

const handler = createFaustAuthHandler({
  wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL!,
  secretKey: process.env.FAUST_SECRET_KEY!,
});

export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ route: string[] }> }
) {
  const { route } = await params;
  return handler(request, route.join('/'));
}
// app/api/preview/route.ts
import { createPreviewHandler } from '@szymonpiatek/nextwordpress';
import { draftMode } from 'next/headers';
import { redirect } from 'next/navigation';

export const GET = createPreviewHandler(
  {
    wpUrl: process.env.WORDPRESS_URL!,
    secretKey: process.env.FAUST_SECRET_KEY!,
    previewPath: 'posts', // default
  },
  {
    enableDraftMode: async () => { (await draftMode()).enable(); },
    redirect,
  },
);

WP ULike

Add like/unlike functionality to posts, comments, and any custom item type. Requires the WP ULike WordPress plugin.

import { createWPULikeClient } from '@szymonpiatek/nextwordpress';

const ulike = createWPULikeClient({
  serverURL: process.env.WORDPRESS_URL!,
  clientURL: process.env.NEXT_PUBLIC_WORDPRESS_URL!,
});

// Get like stats for a post
const stats = await ulike.getLikeStats({ id: 42, type: 'post' });
console.log(stats.count); // 17

// Check if the current user already liked (requires auth)
const check = await ulike.checkLikeStatus({ id: 42 });
console.log(check.liked); // false

// Like a post (requires auth token or nonce)
const result = await ulike.vote({ id: 42, status: 'like' }, authToken);
console.log(result.count); // 18

React hook for client-side use:

'use client';
import { useWPULike } from '@szymonpiatek/nextwordpress/hooks';

function LikeButton({ postId }: { postId: number }) {
  const { data, vote } = useWPULike(config, { id: postId });

  return (
    <button onClick={() => vote('like')}>
      👍 {data?.count ?? 0}
    </button>
  );
}

Cookie Consent

GDPR-compliant cookie consent management compatible with the Cookie Notice & Compliance WordPress plugin. Uses the same cookie_notice_accepted cookie so consent set by the plugin is respected in Next.js, and vice versa.

1. Create the API route:

// app/api/cookie-consent/route.ts
import { createCookieConsentHandler } from '@szymonpiatek/nextwordpress';

const handler = createCookieConsentHandler();

export const GET = handler;
export const POST = handler;
export const DELETE = handler;

2. Read consent in Server Components (e.g. to conditionally load analytics scripts):

import { parseCookieConsent } from '@szymonpiatek/nextwordpress';
import { cookies } from 'next/headers';

export default async function RootLayout({ children }) {
  const cookieStore = await cookies();
  const req = new Request('http://localhost', {
    headers: { cookie: cookieStore.toString() },
  });
  const consent = parseCookieConsent(req);

  return (
    <html>
      <body>
        {consent?.analytics && <GoogleAnalyticsScript />}
        {children}
      </body>
    </html>
  );
}

3. React hook for your CookiesConsent component:

'use client';
import { useCookieConsent } from '@szymonpiatek/nextwordpress/hooks';

function CookiesConsent() {
  const { consent, isLoaded, setConsent, clearConsent } = useCookieConsent();

  if (!isLoaded || consent !== null) return null;

  return (
    <div>
      <button onClick={() => setConsent({ analytics: true, marketing: true })}>
        Akceptuj wszystkie
      </button>
      <button onClick={() => setConsent({ analytics: false, marketing: false })}>
        Odrzuć opcjonalne
      </button>
    </div>
  );
}

| Option | Default | Description | |--------|---------|-------------| | cookieName | cookie_notice_accepted | Cookie name (matches Cookie Notice plugin) | | maxAge | 31536000 (1 year) | Cookie lifetime in seconds |

Password Reset

Two-step password reset flow for WordPress and WooCommerce customers (WooCommerce customers are standard WordPress users). Uses WPGraphQL mutations — requires the WPGraphQL plugin.

Flow:

  1. User submits email → WordPress sends a reset link via email
  2. User clicks the link → your Next.js page receives key and login as query params
  3. User submits a new password → password is changed

Headless setup: By default WordPress emails a link to wp-login.php. To redirect it to your Next.js page, add a filter in your theme or plugin:

add_filter('retrieve_password_message', function ($message, $key, $login) {
    $reset_url = "https://your-nextjs-app.com/reset-password?key={$key}&login={$login}";
    return str_replace(network_site_url("wp-login.php?action=rp&key={$key}&login={$login}"), $reset_url, $message);
}, 10, 3);

Step 1 — request a reset email:

// Server-side
import { createWPGraphQLMutationsClient } from '@szymonpiatek/nextwordpress';

const gql = createWPGraphQLMutationsClient({
  serverURL: process.env.WORDPRESS_URL!,
  clientURL: process.env.NEXT_PUBLIC_WORDPRESS_URL!,
});

await gql.sendPasswordResetEmail({ username: '[email protected]' });
// Client-side hook
'use client';
import { useSendPasswordResetEmail } from '@szymonpiatek/nextwordpress/hooks';

function ForgotPasswordForm() {
  const { trigger, isMutating, data, error } = useSendPasswordResetEmail({
    serverURL: process.env.NEXT_PUBLIC_WORDPRESS_URL!,
    clientURL: process.env.NEXT_PUBLIC_WORDPRESS_URL!,
  });

  return (
    <form onSubmit={async (e) => {
      e.preventDefault();
      const email = new FormData(e.currentTarget).get('email') as string;
      await trigger({ username: email });
    }}>
      <input name="email" type="email" required />
      <button type="submit" disabled={isMutating}>Send reset link</button>
      {data && <p>Check your inbox!</p>}
      {error && <p>Something went wrong. Try again.</p>}
    </form>
  );
}

Step 2 — set a new password (on the page that receives the key and login URL params):

// Server-side
await gql.resetUserPassword({
  key: searchParams.key,
  login: searchParams.login,
  password: 'NewSecurePassword123!',
});
// Client-side hook
'use client';
import { useResetUserPassword } from '@szymonpiatek/nextwordpress/hooks';

function ResetPasswordForm({ resetKey, login }: { resetKey: string; login: string }) {
  const { trigger, isMutating, data, error } = useResetUserPassword({
    serverURL: process.env.NEXT_PUBLIC_WORDPRESS_URL!,
    clientURL: process.env.NEXT_PUBLIC_WORDPRESS_URL!,
  });

  return (
    <form onSubmit={async (e) => {
      e.preventDefault();
      const password = new FormData(e.currentTarget).get('password') as string;
      await trigger({ key: resetKey, login, password });
    }}>
      <input name="password" type="password" minLength={8} required />
      <button type="submit" disabled={isMutating}>Set new password</button>
      {data?.user && <p>Password changed! You can now log in.</p>}
      {error && <p>Link is invalid or expired. Request a new one.</p>}
    </form>
  );
}

Wishlist (YITH & TI)

Support for popular WooCommerce wishlist plugins. Both integrations require a JWT Bearer token for user-scoped operations.

import { 
  createYithWishlistFetcher, 
  createWishlistQueries,
  createTIWishlistFetcher,
  createTIWishlistQueries
} from '@szymonpiatek/nextwordpress';

// YITH Wishlist
const yithFetcher = createYithWishlistFetcher({ serverURL, token });
const yith = createWishlistQueries(yithFetcher);
const myWishlist = await yith.getWishlists();

// TI Wishlist
const tiFetcher = createTIWishlistFetcher({ serverURL, token });
const ti = createTIWishlistQueries(tiFetcher);
const tiWishlist = await ti.getWishlistsByUser(userId);

Contact Form 7

Submit Contact Form 7 forms directly from Next.js via the CF7 REST API. Requires the Contact Form 7 WordPress plugin.

import { createCF7Queries } from '@szymonpiatek/nextwordpress';

const cf7 = createCF7Queries({
  serverURL: process.env.WORDPRESS_URL!,
  clientURL: process.env.NEXT_PUBLIC_WORDPRESS_URL!,
});

const result = await cf7.submitForm(123, {
  your_name: 'Jan Kowalski',
  your_email: '[email protected]',
  your_message: 'Hello!',
});

if (result.status === 'mail_sent') {
  console.log('Message sent successfully');
} else if (result.status === 'validation_failed') {
  console.log('Validation errors:', result.invalid_fields);
}

For client components use the useCF7Submit hook:

'use client'
import { useCF7Submit } from '@szymonpiatek/nextwordpress/client';

function ContactForm() {
  const { trigger, isMutating, data } = useCF7Submit({
    serverURL: process.env.NEXT_PUBLIC_WORDPRESS_URL!,
    clientURL: process.env.NEXT_PUBLIC_WORDPRESS_URL!,
  });

  return (
    <form onSubmit={async (e) => {
      e.preventDefault();
      await trigger({ formId: 123, fields: { 'your-name': 'Jan', 'your-email': '[email protected]' } });
    }}>
      <button type="submit" disabled={isMutating}>Send</button>
      {data?.status === 'mail_sent' && <p>Sent!</p>}
    </form>
  );
}

Yoast SEO & ACF

Easily fetch SEO metadata and ACF fields via WPGraphQL.

import { 
  createWPGraphQLClient, 
  buildPostWithACFQuery 
} from '@szymonpiatek/nextwordpress';

const gq = createWPGraphQLClient({ serverURL: '...' });

// Fetch post with Yoast SEO data
const post = await gq.getPostBySlug('hello-world');
// post.seo.title, post.seo.metaDesc etc.

// ACF support
const acfQuery = buildPostWithACFQuery('my_field_group');

Caching & Revalidation

The library leverages the Next.js Extended fetch API for server-side ISR caching and SWR for client-side polling.

Server-side (ISR)

Pass cacheTTL in the config to control how long Next.js caches responses before revalidating. Defaults to 300 seconds (5 minutes).

const wp = createWordPressClient({
  serverURL: 'http://wordpress:8080',
  clientURL: 'https://example.com',
  cacheTTL: 60, // revalidate every 60 seconds
});

const gq = createWPGraphQLClient({
  serverURL: 'https://example.com',
  cacheTTL: 60,
});

Mutations (wpMutate, gqlMutate) always bypass the cache with cache: 'no-store' regardless of cacheTTL.

All queries accept optional FetchOptions for fine-grained control over caching and headers:

const posts = await wp.getPosts({}, {
  next: { 
    tags: ['my-posts-tag'], 
    revalidate: 3600 
  },
  headers: { 'Authorization': 'Bearer ...' }
});

// Invalidate from a webhook route:
// revalidateTag('my-posts-tag');

Client-side (SWR)

React hooks accept swrOptions as the last argument. Pass refreshInterval (in ms) to poll for updates in the browser:

import { usePosts, useGQLPosts } from '@szymonpiatek/nextwordpress';

// Poll every 30 seconds
usePosts(config, filter, { refreshInterval: 30_000 });

// GraphQL equivalent
useGQLPosts(config, 10, undefined, filter, { refreshInterval: 30_000 });

Advanced Configuration

Next.js 13/14+ Internal/External URLs

The library handles the common pattern where your Next.js server communicates with WordPress over a different URL (e.g., inside a Docker network) than the client's browser.

const wp = createWordPressClient({
  serverURL: 'http://wordpress-container:80', // Used for SSR
  clientURL: 'https://public-domain.com',     // Used for client-side links/assets
});

API Modules

| Module | Description | | --- | --- | | core | Posts, Pages, Categories, Tags, Media, Menus, Comments, Authors, Site Settings, Search, Revisions, Post Types, Taxonomies, Templates, Template Parts, Navigation, Block Patterns, WP Settings, Themes, Plugins. | | woocommerce | Full WooCommerce REST API v3: Products, Categories, Tags, Attributes, Reviews, Shipping Classes, Orders, Order Notes, Order Refunds, Coupons, Customers, Payment Gateways, Taxes, Shipping Zones/Methods, Webhooks, Settings, Reports, Data, System Status, Wishlists (YITH & TI). | | graphQl | Core GQL queries, WooCommerce GQL, ACF, Yoast SEO, CPT, Password Reset. | | contactForm7 | Contact Form 7 REST API submission. | | wpulike | WP ULike REST API: like stats, like/unlike voting, status check. | | nextjs/faust | FaustJS-compatible auth and preview/draft mode handlers. | | nextjs/cookieConsent | GDPR cookie consent handler compatible with Cookie Notice & Compliance plugin. | | shared | Common types, URL helpers, and schemas. |

Coverage

✅ supported  ·  🔐 requires auth token  ·  N/A not supported by the API  ·  — not implemented

WordPress Core

| Module | REST read | REST create | REST update | REST delete | GQL read | GQL create | GQL update | GQL delete | |--------|:---------:|:-----------:|:-----------:|:-----------:|:--------:|:----------:|:----------:|:----------:| | posts | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | | pages | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | | categories | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | | tags | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | | comments | ✅ | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ | ✅ | ✅ 🔐 | ✅ 🔐 | | authors | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ | ✅ | ✅ 🔐 | ✅ 🔐 | | menus | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ | N/A | N/A | N/A | | media | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | | site settings | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | | search | ✅ | N/A | N/A | N/A | ✅ | N/A | N/A | N/A | | revisions | ✅ 🔐 | N/A | N/A | ✅ 🔐 | ✅ 🔐 | N/A | N/A | N/A | | post types | ✅ | N/A | N/A | N/A | ✅ | N/A | N/A | N/A | | taxonomies | ✅ | N/A | N/A | N/A | ✅ | N/A | N/A | N/A | | templates | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ | N/A | N/A | N/A | | template parts | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ | N/A | N/A | N/A | | navigation | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ | N/A | N/A | N/A | | block patterns | ✅ | N/A | N/A | N/A | ✅ | N/A | N/A | N/A | | wp settings | ✅ 🔐 | N/A | ✅ 🔐 | N/A | ✅ | N/A | N/A | N/A | | themes | ✅ 🔐 | N/A | N/A | N/A | ✅ | N/A | N/A | N/A | | plugins | ✅ 🔐 | N/A | ✅ 🔐 | ✅ 🔐 | ✅ | N/A | N/A | N/A |

Notes:

  • Comments create does not require auth when WordPress allows anonymous posting.
  • Authors GQL create uses registerUser (open registration) — no auth needed by default.
  • Menus GQL mutations are N/A: WPGraphQL does not natively support menu/menu-item mutations.
  • Media REST create uploads files as binary (Content-Disposition attachment); metadata can be set in the same call.
  • Media GQL create requires a publicly accessible filePath URL (WPGraphQL fetches the file server-side).

WPGraphQL Extensions

| Module | REST | GQL read | Notes | |--------|:----:|:--------:|-------| | Yoast SEO | — | ✅ | embedded in post/page queries | | ACF | — | ✅ | custom fragment builder | | Custom Post Types | — | ✅ | generic CPT query helper |

WooCommerce

| Module | REST read | REST create | REST update | REST delete | GQL read | |--------|:---------:|:-----------:|:-----------:|:-----------:|:--------:| | products | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ | | categories | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ | | tags | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ | | orders | ✅ | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ | | coupons | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ | | customers | ✅ | ✅ | ✅ 🔐 | ✅ 🔐 | ✅ | | omnibus (EU) | ✅ | — | — | — | N/A | | payment gateways | ✅ 🔐 | — | — | — | N/A | | order notes | ✅ 🔐 | ✅ 🔐 | — | ✅ 🔐 | N/A | | order refunds | ✅ 🔐 | ✅ 🔐 | — | ✅ 🔐 | N/A | | product attributes | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | N/A | | attribute terms | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | N/A | | product reviews | ✅ | ✅ | ✅ 🔐 | ✅ 🔐 | N/A | | shipping classes | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | N/A | | tax rates | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | N/A | | tax classes | ✅ 🔐 | ✅ 🔐 | — | ✅ 🔐 | N/A | | shipping zones | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | N/A | | shipping zone locations | ✅ 🔐 | — | ✅ 🔐 | — | N/A | | shipping zone methods | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | N/A | | shipping methods | ✅ 🔐 | — | — | — | N/A | | webhooks | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | N/A | | settings | ✅ 🔐 | — | ✅ 🔐 | — | N/A | | reports | ✅ 🔐 | — | — | — | N/A | | data (currencies/countries) | ✅ | — | — | — | N/A | | system status | ✅ 🔐 | — | — | — | N/A | | TI Wishlist | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | — | | YITH Wishlist | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | ✅ 🔐 | — |

Notes:

  • WooCommerce REST mutations use consumer key/secret authentication (not Bearer token).
  • Orders create is public (no auth required for guest checkout); update/delete require admin credentials.
  • Customers create is public (self-registration); update/delete require admin credentials.
  • Product reviews create is public; update/delete require admin credentials.
  • Data endpoints (currencies, countries, continents, time zones) are public read-only.
  • Omnibus is a REST utility helper — no equivalent in WPGraphQL WooCommerce.
  • GQL mutations for WooCommerce are not supported by WPGraphQL WooCommerce core.

Next.js Utilities

| Utility | Support | Notes | |--------------------------|:-------:|-------------------------------------------------------------------| | ISR revalidation handler | ✅ | createRevalidationHandler — webhook-triggered cache tag revalidation | | FaustJS auth handler | ✅ | createFaustAuthHandler — token exchange + httpOnly cookie management | | Preview / draft mode | ✅ | createPreviewHandler — Next.js draftMode() integration | | Contact Form 7 | ✅ | createCF7Queries — CF7 REST API form submission | | WP ULike | ✅ | createWPULikeClient — like stats, vote, status check; hooks: useWPULike, useWPULikeStats, useWPULikeCheck | | Cookie Consent | ✅ | createCookieConsentHandler — GDPR consent cookie (get/set/clear); parseCookieConsent — server-side read; hook: useCookieConsent |

Development

# Install dependencies
npm install

# Run tests
npm test

# Run integration tests (requires Docker)
npm run test:integration

# Build package
npm run build

License

This project is currently UNLICENSED. (C) Szymon Piątek.