Compare commits
8 Commits
v0.1.4
...
4492d760bb
| Author | SHA1 | Date | |
|---|---|---|---|
| 4492d760bb | |||
| 489ac82faa | |||
| d7cf08db00 | |||
| 4ae9b67b9c | |||
| 3b706c0092 | |||
| baa3061685 | |||
| fd61895bbd | |||
| cdcb09e24b |
@@ -1,5 +1,15 @@
|
||||
# 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
|
||||
|
||||
[compare changes](https://gitea.websimple.com/templates/wp-headless/compare/v0.1.2...v0.1.4)
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
# 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">
|
||||
import type { BuilderSectionsFragment } from "#graphql/fragments";
|
||||
import type { BuilderSectionsFragment } from "#graphql/operations";
|
||||
|
||||
const props = defineProps<BuilderSectionsFragment>();
|
||||
const sections = computed(() => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { LayoutContainedFragment } from "#graphql/fragments";
|
||||
import type { LayoutContainedFragment } from "#graphql/operations";
|
||||
import { tv, type VariantProps } from "tailwind-variants";
|
||||
|
||||
const props = defineProps<LayoutContainedFragment>();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { NodePageFragment } from "#graphql/fragments";
|
||||
import type { NodePageFragment } from "#graphql/operations";
|
||||
|
||||
defineProps<NodePageFragment>();
|
||||
</script>
|
||||
@@ -9,6 +9,6 @@ defineProps<NodePageFragment>();
|
||||
<h1 v-if="!isFrontPage" class="font-bold text-4xl">
|
||||
{{ title }}
|
||||
</h1>
|
||||
<BuilderSections v-bind="groupPostPage" />
|
||||
<BuilderSections :sections="groupPostPage?.sections || []" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { SectionTextBlockFragment } from "#graphql/fragments";
|
||||
import type { SectionTextBlockFragment } from "#graphql/operations";
|
||||
|
||||
defineProps<SectionTextBlockFragment>();
|
||||
</script>
|
||||
|
||||
@@ -13,7 +13,7 @@ login( input: { provider: PASSWORD, credentials: { username: $username, password
|
||||
authToken
|
||||
refreshToken
|
||||
user {
|
||||
...AuthUser
|
||||
... AuthUser
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
query GeneralSettings {
|
||||
generalSettings {
|
||||
fragment GeneralSettings on GeneralSettings {
|
||||
title
|
||||
description
|
||||
}
|
||||
|
||||
query GeneralSettings {
|
||||
generalSettings {
|
||||
... GeneralSettings
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
// Vendors
|
||||
require_once __DIR__ . '/includes/vendors/acf.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",
|
||||
"description": "Headless WordPress theme based on Nuxt.",
|
||||
"version": "0.1.4",
|
||||
"version": "0.1.5",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -17,7 +17,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify-json/lucide": "^1.2.86",
|
||||
"@lewebsimple/nuxt-graphql": "^0.5.2",
|
||||
"@lewebsimple/nuxt-graphql": "^0.5.11",
|
||||
"@nuxt/ui": "4.3.0",
|
||||
"@nuxtjs/seo": "^3.3.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")
|
||||
}
|
||||
|
||||
"""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."""
|
||||
type AuthenticationData {
|
||||
"""A new authentication token to use in future requests."""
|
||||
@@ -3480,6 +3495,32 @@ interface GroupPostPage_Fields implements AcfFieldGroup & AcfFieldGroupFields &
|
||||
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.
|
||||
"""
|
||||
@@ -5926,6 +5967,23 @@ interface OneToOneConnection implements Edge {
|
||||
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.
|
||||
"""
|
||||
@@ -8436,7 +8494,7 @@ interface Previewable {
|
||||
}
|
||||
|
||||
"""The root entry point into the Graph"""
|
||||
type Query {
|
||||
type Query implements WithAcfOptionsPageOptionsSite {
|
||||
"""Entry point to get all settings for the site"""
|
||||
allSettings: Settings
|
||||
|
||||
@@ -8721,6 +8779,9 @@ type Query {
|
||||
uri: String!
|
||||
): UniformResourceIdentifiable
|
||||
|
||||
""""""
|
||||
optionsSite: OptionsSite
|
||||
|
||||
"""An object of the page Type. """
|
||||
page(
|
||||
"""
|
||||
@@ -14080,6 +14141,20 @@ interface WithAcfGroupPostPage {
|
||||
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"""
|
||||
type WritingSettings {
|
||||
"""Catégorie d’article par défaut."""
|
||||
|
||||
@@ -2,15 +2,15 @@ import type { H3Event } from "h3";
|
||||
import { GraphQLClient } from "graphql-request";
|
||||
import { jwtDecode } from "jwt-decode";
|
||||
import type { User } from "#auth-utils";
|
||||
import type { AuthUserFragment } from "#graphql/fragments";
|
||||
import { AuthRefreshTokenDocument, type AuthLoginResult } from "#graphql/operations";
|
||||
import type { AuthUserFragment, AuthLoginMutationResult } from "#graphql/operations";
|
||||
import { AuthRefreshTokenDocument } from "#graphql/operations";
|
||||
|
||||
// Handle login result and store user session
|
||||
export async function handleLogin(event: H3Event, loginData: AuthLoginResult) {
|
||||
if (!loginData?.login) {
|
||||
export async function handleLogin(event: H3Event, loginResult: AuthLoginMutationResult) {
|
||||
if (!loginResult?.login) {
|
||||
return false;
|
||||
}
|
||||
const { user, authToken, refreshToken } = loginData.login;
|
||||
const { user, authToken, refreshToken } = loginResult.login;
|
||||
if (!user || !authToken || !refreshToken) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// 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[] {
|
||||
return connection?.nodes || [] as T[];
|
||||
export function extractNodes<T>(connection: { nodes?: readonly T[] } | null | undefined): readonly T[] {
|
||||
return connection?.nodes ?? [];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user