Compare commits
8 Commits
v0.1.4
...
4492d760bb
| Author | SHA1 | Date | |
|---|---|---|---|
| 4492d760bb | |||
| 489ac82faa | |||
| d7cf08db00 | |||
| 4ae9b67b9c | |||
| 3b706c0092 | |||
| baa3061685 | |||
| fd61895bbd | |||
| cdcb09e24b |
@@ -1,5 +1,15 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v0.1.5
|
||||||
|
|
||||||
|
[compare changes](https://gitea.websimple.com/templates/wp-headless/compare/v0.1.4...v0.1.5)
|
||||||
|
|
||||||
|
### 🩹 Fixes
|
||||||
|
|
||||||
|
- Auth server utils upgrade to latest nuxt-graphql (fd61895)
|
||||||
|
- Immutable extractNodes (baa3061)
|
||||||
|
- Type issue with NodePage (3b706c0)
|
||||||
|
|
||||||
## v0.1.4
|
## v0.1.4
|
||||||
|
|
||||||
[compare changes](https://gitea.websimple.com/templates/wp-headless/compare/v0.1.2...v0.1.4)
|
[compare changes](https://gitea.websimple.com/templates/wp-headless/compare/v0.1.2...v0.1.4)
|
||||||
|
|||||||
@@ -1,3 +1,12 @@
|
|||||||
# Moonshine
|
# Moonshine
|
||||||
|
|
||||||
Headless WordPress theme based on Nuxt.
|
Thème WordPress en headless basé sur Nuxt.
|
||||||
|
|
||||||
|
## Varaibles d'environnement
|
||||||
|
|
||||||
|
| Nom | Description | Exemple | Requise |
|
||||||
|
|-----|-------------|---------|---------|
|
||||||
|
| `NUXT_SESSION_PASSWORD` | Clé secrète pour l'authentification | `date \| md5sum` | ✅ |
|
||||||
|
| `NUXT_WP_URL` | URL du backend WordPress | https://wp.exemple.com | ✅ |
|
||||||
|
| `NUXT_SITE_URL` | URL du frontend Nuxt | https://www.example.com | ➖ |
|
||||||
|
| `NUXT_SITE_ENV` | Environnement | staging \| production | ➖ |
|
||||||
|
|||||||
60
wp-content/themes/moonshine/acf-json/group_options_site.json
Normal file
60
wp-content/themes/moonshine/acf-json/group_options_site.json
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"key": "group_options_site",
|
||||||
|
"title": "Options - Site",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"key": "field_697220310aaaf",
|
||||||
|
"label": "Email",
|
||||||
|
"name": "email",
|
||||||
|
"aria-label": "",
|
||||||
|
"type": "email",
|
||||||
|
"instructions": "",
|
||||||
|
"required": 1,
|
||||||
|
"conditional_logic": 0,
|
||||||
|
"wrapper": {
|
||||||
|
"width": "",
|
||||||
|
"class": "",
|
||||||
|
"id": ""
|
||||||
|
},
|
||||||
|
"default_value": "",
|
||||||
|
"allow_in_bindings": 0,
|
||||||
|
"placeholder": "",
|
||||||
|
"prepend": "",
|
||||||
|
"append": "",
|
||||||
|
"show_in_graphql": 1,
|
||||||
|
"graphql_description": "",
|
||||||
|
"graphql_field_name": "email",
|
||||||
|
"graphql_non_null": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"location": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"param": "options_page",
|
||||||
|
"operator": "==",
|
||||||
|
"value": "site-options"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"menu_order": 0,
|
||||||
|
"position": "normal",
|
||||||
|
"style": "seamless",
|
||||||
|
"label_placement": "top",
|
||||||
|
"instruction_placement": "label",
|
||||||
|
"hide_on_screen": "",
|
||||||
|
"active": true,
|
||||||
|
"description": "",
|
||||||
|
"show_in_rest": 0,
|
||||||
|
"display_title": "",
|
||||||
|
"acfe_autosync": [
|
||||||
|
"json"
|
||||||
|
],
|
||||||
|
"acfe_form": 0,
|
||||||
|
"show_in_graphql": 1,
|
||||||
|
"graphql_field_name": "GroupSite",
|
||||||
|
"map_graphql_types_from_location_rules": 0,
|
||||||
|
"graphql_types": "",
|
||||||
|
"acfe_meta": "",
|
||||||
|
"acfe_note": "",
|
||||||
|
"modified": 1769087407
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"key": "ui_options_page_site",
|
||||||
|
"title": "Options du site",
|
||||||
|
"active": true,
|
||||||
|
"menu_order": 0,
|
||||||
|
"page_title": "Options du site",
|
||||||
|
"menu_slug": "site-options",
|
||||||
|
"parent_slug": "options-general.php",
|
||||||
|
"advanced_configuration": 1,
|
||||||
|
"icon_url": "",
|
||||||
|
"menu_title": "",
|
||||||
|
"position": "",
|
||||||
|
"redirect": false,
|
||||||
|
"description": "",
|
||||||
|
"menu_icon": [],
|
||||||
|
"update_button": "Mise à jour",
|
||||||
|
"updated_message": "Options mises à jours",
|
||||||
|
"capability": "edit_posts",
|
||||||
|
"data_storage": "options",
|
||||||
|
"post_id": "",
|
||||||
|
"autoload": 0,
|
||||||
|
"show_in_graphql": 1,
|
||||||
|
"graphql_type_name": "OptionsSite",
|
||||||
|
"modified": 1769086997
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { BuilderSectionsFragment } from "#graphql/fragments";
|
import type { BuilderSectionsFragment } from "#graphql/operations";
|
||||||
|
|
||||||
const props = defineProps<BuilderSectionsFragment>();
|
const props = defineProps<BuilderSectionsFragment>();
|
||||||
const sections = computed(() => {
|
const sections = computed(() => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { LayoutContainedFragment } from "#graphql/fragments";
|
import type { LayoutContainedFragment } from "#graphql/operations";
|
||||||
import { tv, type VariantProps } from "tailwind-variants";
|
import { tv, type VariantProps } from "tailwind-variants";
|
||||||
|
|
||||||
const props = defineProps<LayoutContainedFragment>();
|
const props = defineProps<LayoutContainedFragment>();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { NodePageFragment } from "#graphql/fragments";
|
import type { NodePageFragment } from "#graphql/operations";
|
||||||
|
|
||||||
defineProps<NodePageFragment>();
|
defineProps<NodePageFragment>();
|
||||||
</script>
|
</script>
|
||||||
@@ -9,6 +9,6 @@ defineProps<NodePageFragment>();
|
|||||||
<h1 v-if="!isFrontPage" class="font-bold text-4xl">
|
<h1 v-if="!isFrontPage" class="font-bold text-4xl">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</h1>
|
</h1>
|
||||||
<BuilderSections v-bind="groupPostPage" />
|
<BuilderSections :sections="groupPostPage?.sections || []" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SectionTextBlockFragment } from "#graphql/fragments";
|
import type { SectionTextBlockFragment } from "#graphql/operations";
|
||||||
|
|
||||||
defineProps<SectionTextBlockFragment>();
|
defineProps<SectionTextBlockFragment>();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ login( input: { provider: PASSWORD, credentials: { username: $username, password
|
|||||||
authToken
|
authToken
|
||||||
refreshToken
|
refreshToken
|
||||||
user {
|
user {
|
||||||
...AuthUser
|
... AuthUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
|
fragment GeneralSettings on GeneralSettings {
|
||||||
|
title
|
||||||
|
description
|
||||||
|
}
|
||||||
|
|
||||||
query GeneralSettings {
|
query GeneralSettings {
|
||||||
generalSettings {
|
generalSettings {
|
||||||
title
|
... GeneralSettings
|
||||||
description
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fragment SiteOptions on GroupSite_Fields {
|
||||||
|
email
|
||||||
|
}
|
||||||
|
|
||||||
|
query OptionsSite {
|
||||||
|
optionsSite {
|
||||||
|
groupSite {
|
||||||
|
... SiteOptions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,4 +4,5 @@
|
|||||||
require_once __DIR__ . '/includes/core/theme-setup.php';
|
require_once __DIR__ . '/includes/core/theme-setup.php';
|
||||||
|
|
||||||
// Vendors
|
// Vendors
|
||||||
|
require_once __DIR__ . '/includes/vendors/acf.php';
|
||||||
require_once __DIR__ . '/includes/vendors/tinymce.php';
|
require_once __DIR__ . '/includes/vendors/tinymce.php';
|
||||||
|
|||||||
15
wp-content/themes/moonshine/includes/vendors/acf.php
vendored
Normal file
15
wp-content/themes/moonshine/includes/vendors/acf.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// Disable ACF / ACFE modules
|
||||||
|
add_filter( 'acf/settings/enable_post_types', '__return_false' );
|
||||||
|
add_action( 'acf/init', 'moonshine_acf_init' );
|
||||||
|
function moonshine_acf_init() {
|
||||||
|
acf_update_setting( 'acfe/modules/block_types', false );
|
||||||
|
acf_update_setting( 'acfe/modules/categories', false );
|
||||||
|
acf_update_setting( 'acfe/modules/forms', false );
|
||||||
|
acf_update_setting( 'acfe/modules/options', false );
|
||||||
|
acf_update_setting( 'acfe/modules/options_pages', false );
|
||||||
|
acf_update_setting( 'acfe/modules/post_types', false );
|
||||||
|
acf_update_setting( 'acfe/modules/taxonomies', false );
|
||||||
|
acf_update_setting( 'acfe/modules/templates', false );
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@lewebsimple/moonshine",
|
"name": "@lewebsimple/moonshine",
|
||||||
"description": "Headless WordPress theme based on Nuxt.",
|
"description": "Headless WordPress theme based on Nuxt.",
|
||||||
"version": "0.1.4",
|
"version": "0.1.5",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@iconify-json/lucide": "^1.2.86",
|
"@iconify-json/lucide": "^1.2.86",
|
||||||
"@lewebsimple/nuxt-graphql": "^0.5.2",
|
"@lewebsimple/nuxt-graphql": "^0.5.11",
|
||||||
"@nuxt/ui": "4.3.0",
|
"@nuxt/ui": "4.3.0",
|
||||||
"@nuxtjs/seo": "^3.3.0",
|
"@nuxtjs/seo": "^3.3.0",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
|
|||||||
713
wp-content/themes/moonshine/pnpm-lock.yaml
generated
713
wp-content/themes/moonshine/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -51,6 +51,21 @@ interface AcfFieldGroupFields {
|
|||||||
fieldGroupName: String @deprecated(reason: "Use __typename instead")
|
fieldGroupName: String @deprecated(reason: "Use __typename instead")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""Options Page registered by ACF"""
|
||||||
|
interface AcfOptionsPage implements Node {
|
||||||
|
"""The globally unique ID for the object"""
|
||||||
|
id: ID!
|
||||||
|
|
||||||
|
""""""
|
||||||
|
menuTitle: String
|
||||||
|
|
||||||
|
""""""
|
||||||
|
pageTitle: String
|
||||||
|
|
||||||
|
""""""
|
||||||
|
parentId: String
|
||||||
|
}
|
||||||
|
|
||||||
"""The Headless Login authentication data."""
|
"""The Headless Login authentication data."""
|
||||||
type AuthenticationData {
|
type AuthenticationData {
|
||||||
"""A new authentication token to use in future requests."""
|
"""A new authentication token to use in future requests."""
|
||||||
@@ -3480,6 +3495,32 @@ interface GroupPostPage_Fields implements AcfFieldGroup & AcfFieldGroupFields &
|
|||||||
sections: [GroupAbstractBuilderSections_Layout]
|
sections: [GroupAbstractBuilderSections_Layout]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
The "GroupSite" Field Group. Added to the Schema by "WPGraphQL for ACF".
|
||||||
|
"""
|
||||||
|
type GroupSite implements AcfFieldGroup & AcfFieldGroupFields & GroupSite_Fields {
|
||||||
|
"""
|
||||||
|
Field of the "email" Field Type added to the schema as part of the "GroupSite" Field Group
|
||||||
|
"""
|
||||||
|
email: String!
|
||||||
|
|
||||||
|
"""The name of the field group"""
|
||||||
|
fieldGroupName: String @deprecated(reason: "Use __typename instead")
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
Interface representing fields of the ACF "GroupSite" Field Group
|
||||||
|
"""
|
||||||
|
interface GroupSite_Fields implements AcfFieldGroup & AcfFieldGroupFields {
|
||||||
|
"""
|
||||||
|
Field of the "email" Field Type added to the schema as part of the "GroupSite" Field Group
|
||||||
|
"""
|
||||||
|
email: String!
|
||||||
|
|
||||||
|
"""The name of the field group"""
|
||||||
|
fieldGroupName: String @deprecated(reason: "Use __typename instead")
|
||||||
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Content that can be organized in a parent-child structure. Provides fields for navigating up and down the hierarchy and maintaining structured relationships.
|
Content that can be organized in a parent-child structure. Provides fields for navigating up and down the hierarchy and maintaining structured relationships.
|
||||||
"""
|
"""
|
||||||
@@ -5926,6 +5967,23 @@ interface OneToOneConnection implements Edge {
|
|||||||
node: Node!
|
node: Node!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OptionsSite implements AcfOptionsPage & Node & WithAcfGroupSite {
|
||||||
|
"""Fields of the GroupSite ACF Field Group"""
|
||||||
|
groupSite: GroupSite
|
||||||
|
|
||||||
|
"""The globally unique ID for the object"""
|
||||||
|
id: ID!
|
||||||
|
|
||||||
|
""""""
|
||||||
|
menuTitle: String
|
||||||
|
|
||||||
|
""""""
|
||||||
|
pageTitle: String
|
||||||
|
|
||||||
|
""""""
|
||||||
|
parentId: String
|
||||||
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Sort direction for ordered results. Determines whether items are returned in ascending or descending order.
|
Sort direction for ordered results. Determines whether items are returned in ascending or descending order.
|
||||||
"""
|
"""
|
||||||
@@ -8436,7 +8494,7 @@ interface Previewable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
"""The root entry point into the Graph"""
|
"""The root entry point into the Graph"""
|
||||||
type Query {
|
type Query implements WithAcfOptionsPageOptionsSite {
|
||||||
"""Entry point to get all settings for the site"""
|
"""Entry point to get all settings for the site"""
|
||||||
allSettings: Settings
|
allSettings: Settings
|
||||||
|
|
||||||
@@ -8721,6 +8779,9 @@ type Query {
|
|||||||
uri: String!
|
uri: String!
|
||||||
): UniformResourceIdentifiable
|
): UniformResourceIdentifiable
|
||||||
|
|
||||||
|
""""""
|
||||||
|
optionsSite: OptionsSite
|
||||||
|
|
||||||
"""An object of the page Type. """
|
"""An object of the page Type. """
|
||||||
page(
|
page(
|
||||||
"""
|
"""
|
||||||
@@ -14080,6 +14141,20 @@ interface WithAcfGroupPostPage {
|
|||||||
groupPostPage: GroupPostPage
|
groupPostPage: GroupPostPage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
Provides access to fields of the "GroupSite" ACF Field Group via the "groupSite" field
|
||||||
|
"""
|
||||||
|
interface WithAcfGroupSite {
|
||||||
|
"""Fields of the GroupSite ACF Field Group"""
|
||||||
|
groupSite: GroupSite
|
||||||
|
}
|
||||||
|
|
||||||
|
"""Access point for the "OptionsSite" ACF Options Page"""
|
||||||
|
interface WithAcfOptionsPageOptionsSite {
|
||||||
|
""""""
|
||||||
|
optionsSite: OptionsSite
|
||||||
|
}
|
||||||
|
|
||||||
"""The writing setting type"""
|
"""The writing setting type"""
|
||||||
type WritingSettings {
|
type WritingSettings {
|
||||||
"""Catégorie d’article par défaut."""
|
"""Catégorie d’article par défaut."""
|
||||||
|
|||||||
@@ -2,15 +2,15 @@ import type { H3Event } from "h3";
|
|||||||
import { GraphQLClient } from "graphql-request";
|
import { GraphQLClient } from "graphql-request";
|
||||||
import { jwtDecode } from "jwt-decode";
|
import { jwtDecode } from "jwt-decode";
|
||||||
import type { User } from "#auth-utils";
|
import type { User } from "#auth-utils";
|
||||||
import type { AuthUserFragment } from "#graphql/fragments";
|
import type { AuthUserFragment, AuthLoginMutationResult } from "#graphql/operations";
|
||||||
import { AuthRefreshTokenDocument, type AuthLoginResult } from "#graphql/operations";
|
import { AuthRefreshTokenDocument } from "#graphql/operations";
|
||||||
|
|
||||||
// Handle login result and store user session
|
// Handle login result and store user session
|
||||||
export async function handleLogin(event: H3Event, loginData: AuthLoginResult) {
|
export async function handleLogin(event: H3Event, loginResult: AuthLoginMutationResult) {
|
||||||
if (!loginData?.login) {
|
if (!loginResult?.login) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const { user, authToken, refreshToken } = loginData.login;
|
const { user, authToken, refreshToken } = loginResult.login;
|
||||||
if (!user || !authToken || !refreshToken) {
|
if (!user || !authToken || !refreshToken) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Helper: Extracts nodes from a GraphQL connection object, returning an empty array if nodes are absent.
|
// Helper: Extracts nodes from a GraphQL connection object, returning an empty array if nodes are absent.
|
||||||
export function extractNodes<T>(connection: { nodes?: T[] } | null | undefined): T[] {
|
export function extractNodes<T>(connection: { nodes?: readonly T[] } | null | undefined): readonly T[] {
|
||||||
return connection?.nodes || [] as T[];
|
return connection?.nodes ?? [];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user