---
title: "Custom Queries"
description: "Extend WPNuxt with your own GraphQL queries"
canonical_url: "https://wpnuxt.com/guide/custom-queries"
---
# Custom Queries

> Extend WPNuxt with your own GraphQL queries

WPNuxt ships with default composables for common WordPress content — posts, pages, menus, and settings. Custom queries let you go beyond the defaults: fetch ACF fields, custom post types, SEO metadata, WooCommerce products, or lighter data shapes that only include the fields you need.

## When to Create Custom Queries

<table>
<thead>
  <tr>
    <th>
      Scenario
    </th>
    
    <th>
      What to Use
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Fetch recent posts or pages
    </td>
    
    <td>
      Default composables (<code>
        usePosts()
      </code>
      
      , <code>
        usePages()
      </code>
      
      )
    </td>
  </tr>
  
  <tr>
    <td>
      Fetch posts with extra fields (ACF, SEO, custom taxonomies)
    </td>
    
    <td>
      Custom query or override default query
    </td>
  </tr>
  
  <tr>
    <td>
      Fetch a custom post type (e.g. <code>
        products
      </code>
      
      , <code>
        events
      </code>
      
      )
    </td>
    
    <td>
      Custom query
    </td>
  </tr>
  
  <tr>
    <td>
      Fetch a lighter data shape (e.g. only titles and URIs for a listing)
    </td>
    
    <td>
      Custom query
    </td>
  </tr>
  
  <tr>
    <td>
      Change the default number of posts returned
    </td>
    
    <td>
      Override default query
    </td>
  </tr>
</tbody>
</table>

## Complete Workflow

### 1. Check Your Schema

Before writing a query, verify that the fields you need exist in your WordPress GraphQL schema. Visit `{your-wordpress-url}/graphql` to open the GraphQL IDE and explore available types and fields.

### 2. Create the Query File

Add a `.gql` file to `extend/queries/`:

```graphql [extend/queries/FeaturedPosts.gql]
query FeaturedPosts($limit: Int = 5) {
  posts(first: $limit, where: { tag: "featured" }) {
    nodes {
      ...Post
    }
  }
}
```

<callout type="info">

The query name becomes the composable name. `query FeaturedPosts` generates `useFeaturedPosts()`.

</callout>

### 3. Regenerate Types

Run prepare to trigger the composable generation pipeline:

```bash
pnpm nuxt prepare
```

### 4. Use the Composable

The composable is auto-imported and fully typed:

```vue
<script setup lang="ts">
const { data: featured } = await useFeaturedPosts({ limit: 3 })
</script>

<template>
  <article v-for="post in featured" :key="post.id">
    <h2>{{ post.title }}</h2>
  </article>
</template>
```

### 5. Verify Types

Hover over `featured` in your editor — you should see the correct TypeScript types based on the fields in your query and fragment.

## Using Fragments

Fragments let you define reusable sets of fields. This is useful when multiple queries need the same fields, or when you want to extend WPNuxt's built-in fragments with additional data.

Place fragment files in `extend/queries/fragments/` with a `.fragment.gql` extension:

```graphql [extend/queries/fragments/PostWithAuthor.fragment.gql]
fragment PostWithAuthor on Post {
  ...Post
  author {
    node {
      name
      avatar {
        url
      }
    }
  }
}
```

Then use the fragment in a query:

```graphql [extend/queries/AuthorPosts.gql]
query AuthorPosts($authorId: Int!) {
  posts(where: { author: $authorId }) {
    nodes {
      ...PostWithAuthor
    }
  }
}
```

<callout type="tip">

**Naming convention:** Name fragment files `{FragmentName}.fragment.gql` and place them in the `fragments/` subfolder. This keeps queries and fragments organized.

</callout>

## Reactive Filtering with Where Args

Custom queries with `where` args combine with reactive params for server-side filtering:

```graphql [extend/queries/Events.gql]
query Events($first: Int = 20, $where: RootQueryToEventConnectionWhereArgs) {
  events(first: $first, where: $where) {
    nodes {
      ...Event
    }
  }
}
```

```vue
<script setup lang="ts">
const filters = reactive({
  category: undefined as string | undefined,
  status: undefined as string | undefined,
})

const params = computed(() => ({
  first: 20,
  where: {
    categoryName: filters.category,
    status: filters.status,
  }
}))

const { data: events, pending } = useEvents(params)
// Auto-refetches when any filter changes
</script>
```

The `where` args are fully typed via your GraphQL schema — your editor will autocomplete available filter fields.

## Overriding Default Queries

To modify what a default composable returns, create a file with **the same name** as the default query:

```graphql [extend/queries/Posts.gql]
query Posts($first: Int = 10) {
  posts(first: $first) {
    nodes {
      ...Post
      customField
      seo {
        title
        metaDesc
      }
    }
  }
}
```

Your version replaces the default. The composable name stays the same — `usePosts()` will now return your custom fields.

<callout type="warning">

Keep the query name and structure (`nodes { ... }`) identical to the original. Changing the query name would generate a different composable instead of overriding the existing one.

</callout>

## How Query Merging Works

At build time, WPNuxt merges queries from two sources:

1. **Default queries** from `@wpnuxt/core` (`src/runtime/queries/`)
2. **Your queries** from `extend/queries/` (configurable via `wpNuxt.queries.extendFolder`)

Both are copied to a `.queries/` folder. If a file exists in both locations, your version wins. The merged folder is then parsed to generate composables. This is why you can override any default query by matching its filename.

## Folder Structure

```text
extend/
└── queries/
    ├── FeaturedPosts.gql           ← new custom query
    ├── Posts.gql                   ← overrides default Posts query
    ├── AuthorPosts.gql             ← new custom query
    └── fragments/
        └── PostWithAuthor.fragment.gql
```

## Troubleshooting

<table>
<thead>
  <tr>
    <th>
      Problem
    </th>
    
    <th>
      Cause
    </th>
    
    <th>
      Fix
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Composable not generated
    </td>
    
    <td>
      Types not regenerated after adding <code>
        .gql
      </code>
      
       file
    </td>
    
    <td>
      Run <code>
        pnpm nuxt prepare
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Composable not auto-imported
    </td>
    
    <td>
      Query file not in <code>
        extend/queries/
      </code>
    </td>
    
    <td>
      Check path matches <code>
        wpNuxt.queries.extendFolder
      </code>
      
       (default: <code>
        extend/queries/
      </code>
      
      )
    </td>
  </tr>
  
  <tr>
    <td>
      Field returns <code>
        null
      </code>
    </td>
    
    <td>
      Field not exposed in WPGraphQL schema
    </td>
    
    <td>
      Check schema in GraphQL IDE; some fields require plugins (e.g. ACF → WPGraphQL for ACF)
    </td>
  </tr>
  
  <tr>
    <td>
      Types are stale
    </td>
    
    <td>
      Old types cached
    </td>
    
    <td>
      Delete <code>
        .nuxt/
      </code>
      
       folder and run <code>
        pnpm nuxt prepare
      </code>
      
       again
    </td>
  </tr>
  
  <tr>
    <td>
      Fragment not found
    </td>
    
    <td>
      Fragment file not in <code>
        fragments/
      </code>
      
       subfolder or missing <code>
        .fragment.gql
      </code>
      
       extension
    </td>
    
    <td>
      Check filename and location
    </td>
  </tr>
  
  <tr>
    <td>
      Override not working
    </td>
    
    <td>
      Query file name doesn't match the default
    </td>
    
    <td>
      Check the exact filename in <code>
        node_modules/@wpnuxt/core/src/runtime/queries/
      </code>
    </td>
  </tr>
</tbody>
</table>

## Related Pages

- **How WPNuxt Works** — Understand the composable generation pipeline
- **Fetching Data** — Composable options (lazy loading, watching, refreshing)
- **Pagination** — Add `pageInfo` to your query for cursor-based pagination
- **Configuration** — Configure the queries folder path


## Sitemap

See the full [sitemap](https://wpnuxt.com/sitemap.md) for all pages.
