feat: Initial SEO integration

This commit is contained in:
2026-01-26 11:57:35 -05:00
parent 9cd99c36db
commit c5ce607fae
8 changed files with 2464 additions and 26 deletions

View File

@@ -32,12 +32,14 @@
"lintfix": "vendor/bin/phpcbf" "lintfix": "vendor/bin/phpcbf"
}, },
"require": { "require": {
"axepress/wp-graphql-rank-math": "*",
"lewebsimple/advanced-custom-fields-pro": "*", "lewebsimple/advanced-custom-fields-pro": "*",
"lewebsimple/kaliroots": "*", "lewebsimple/kaliroots": "*",
"lewebsimple/wp-graphql-headless-login": "*", "lewebsimple/wp-graphql-headless-login": "*",
"wpackagist-plugin/acf-extended": "*", "wpackagist-plugin/acf-extended": "*",
"wpackagist-plugin/clean-image-filenames": "*", "wpackagist-plugin/clean-image-filenames": "*",
"wpackagist-plugin/disable-comments": "*", "wpackagist-plugin/disable-comments": "*",
"wpackagist-plugin/seo-by-rank-math": "*",
"wpackagist-plugin/wp-graphql": "*", "wpackagist-plugin/wp-graphql": "*",
"wpackagist-plugin/wpgraphql-acf": "*" "wpackagist-plugin/wpgraphql-acf": "*"
}, },

181
composer.lock generated
View File

@@ -4,8 +4,169 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "aec2b0e396a71ea02fe95432358ca91e", "content-hash": "9673ea7f3e3f21866ae50f70e1d6a16b",
"packages": [ "packages": [
{
"name": "axepress/wp-graphql-plugin-boilerplate",
"version": "0.1.1",
"source": {
"type": "git",
"url": "https://github.com/AxeWP/wp-graphql-plugin-boilerplate.git",
"reference": "09495b61346453baabdf4c71a38ada3cfc91c3a7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/AxeWP/wp-graphql-plugin-boilerplate/zipball/09495b61346453baabdf4c71a38ada3cfc91c3a7",
"reference": "09495b61346453baabdf4c71a38ada3cfc91c3a7",
"shasum": ""
},
"require": {
"php": ">=7.4"
},
"require-dev": {
"axepress/wp-graphql-cs": "^2.0.0",
"axepress/wp-graphql-stubs": "^2.3.0",
"phpcompatibility/php-compatibility": "dev-develop as 9.9.9",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^2.0",
"phpstan/phpstan-deprecation-rules": "^2.0.1",
"szepeviktor/phpstan-wordpress": "^2.0",
"wp-cli/wp-cli-bundle": "^2.8.1"
},
"type": "library",
"autoload": {
"psr-4": {
"AxeWP\\GraphQL\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-3.0-or-later"
],
"authors": [
{
"name": "AxePress Development",
"homepage": "https://axepress.dev"
},
{
"name": "David Levine",
"role": "Developer"
}
],
"description": "Boilerplate for creating WPGraphQL extensions",
"support": {
"issues": "https://github.com/AxeWP/wp-graphql-plugin-boilerplate/issues",
"source": "https://github.com/AxeWP/wp-graphql-plugin-boilerplate/tree/0.1.1"
},
"funding": [
{
"url": "https://github.com/AxeWp",
"type": "github"
}
],
"time": "2025-06-07T02:03:50+00:00"
},
{
"name": "axepress/wp-graphql-rank-math",
"version": "0.3.4",
"source": {
"type": "git",
"url": "https://github.com/AxeWP/wp-graphql-rank-math.git",
"reference": "167bdd4a5350717ed34069c304e0ffc3fe02bc7d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/AxeWP/wp-graphql-rank-math/zipball/167bdd4a5350717ed34069c304e0ffc3fe02bc7d",
"reference": "167bdd4a5350717ed34069c304e0ffc3fe02bc7d",
"shasum": ""
},
"require": {
"axepress/wp-graphql-plugin-boilerplate": "^0.1.1",
"php": ">=7.4"
},
"require-dev": {
"axepress/wp-graphql-cs": "^2.0.0",
"axepress/wp-graphql-stubs": "^2.0.0",
"codeception/lib-innerbrowser": "^1.0",
"codeception/module-asserts": "^1.0",
"codeception/module-cli": "^1.0",
"codeception/module-db": "^1.0",
"codeception/module-filesystem": "^1.0",
"codeception/module-phpbrowser": "^1.0",
"codeception/module-rest": "^2.0",
"codeception/module-webdriver": "^1.0",
"codeception/phpunit-wrapper": "^9.0",
"codeception/util-universalframework": "^1.0",
"lucatume/wp-browser": "<3.5",
"php-coveralls/php-coveralls": "^2.5",
"phpcompatibility/php-compatibility": "dev-develop as 9.9.9",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^2.1.5",
"phpunit/phpunit": "^9.5",
"szepeviktor/phpstan-wordpress": "^2.0.1",
"wp-cli/wp-cli-bundle": "^2.8.1",
"wp-graphql/wp-graphql-testcase": "~3.4.0"
},
"type": "wordpress-plugin",
"extra": {
"strauss": {
"packages": [
"axepress/wp-graphql-plugin-boilerplate"
],
"classmap_prefix": "WPGraphQL_RankMath_",
"constant_prefix": "WPGRAPHQL_SEO_",
"namespace_prefix": "WPGraphQL\\RankMath\\Vendor\\",
"target_directory": "vendor-prefixed",
"update_call_sites": false,
"exclude_from_prefix": {
"namespaces": [],
"file_patterns": []
},
"include_modified_date": false,
"delete_vendor_packages": true
}
},
"autoload": {
"files": [
"access-functions.php"
],
"psr-4": {
"WPGraphQL\\RankMath\\": "src/"
},
"classmap": [
"vendor-prefixed/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-3.0-or-later"
],
"authors": [
{
"name": "AxePress Development",
"email": "support@axepress.dev",
"homepage": "https://axepress.dev"
},
{
"name": "David Levine",
"role": "Developer"
}
],
"description": "Adds WPGraphQL support for RankMath SEO",
"support": {
"email": "support@axepress.dev",
"forum": "https://github.com/AxeWP/wp-graphql-rank-math/discussions",
"issues": "https://github.com/AxeWP/wp-graphql-rank-math/issues",
"source": "https://github.com/AxeWP/wp-graphql-rank-math/tree/0.3.4"
},
"funding": [
{
"url": "https://github.com/sponsors/AxeWP",
"type": "github"
}
],
"time": "2025-06-07T12:05:15+00:00"
},
{ {
"name": "composer/installers", "name": "composer/installers",
"version": "v2.3.0", "version": "v2.3.0",
@@ -257,6 +418,24 @@
"type": "wordpress-plugin", "type": "wordpress-plugin",
"homepage": "https://wordpress.org/plugins/disable-comments/" "homepage": "https://wordpress.org/plugins/disable-comments/"
}, },
{
"name": "wpackagist-plugin/seo-by-rank-math",
"version": "1.0.262",
"source": {
"type": "svn",
"url": "https://plugins.svn.wordpress.org/seo-by-rank-math/",
"reference": "tags/1.0.262"
},
"dist": {
"type": "zip",
"url": "https://downloads.wordpress.org/plugin/seo-by-rank-math.1.0.262.zip"
},
"require": {
"composer/installers": "^1.0 || ^2.0"
},
"type": "wordpress-plugin",
"homepage": "https://wordpress.org/plugins/seo-by-rank-math/"
},
{ {
"name": "wpackagist-plugin/wp-graphql", "name": "wpackagist-plugin/wp-graphql",
"version": "2.6.0", "version": "2.6.0",

View File

@@ -0,0 +1,20 @@
import type { NodeByUriQueryResult, NodeSeoFragment } from "#graphql/operations";
export function useNodeSeo(node: NodeByUriQueryResult["nodeByUri"]) {
// Check if node has SEO data
if (!node || !("seo" in node) || !node.seo) {
return;
}
const { seo } = node as NodeSeoFragment;
useSeoMeta({
title: seo?.title || undefined,
description: seo?.description || undefined,
robots: (seo?.robots || []).join(", "),
ogTitle: seo?.openGraph?.title || undefined,
ogDescription: seo?.openGraph?.description || undefined,
ogImage: seo?.openGraph?.image?.url || undefined,
ogUrl: seo?.canonicalUrl || undefined,
twitterCard: "summary_large_image",
});
}

View File

@@ -1,8 +1,27 @@
fragment NodeSeo on NodeWithRankMathSeo {
seo {
title
description
robots
canonicalUrl
openGraph {
title
description
image {
url
}
}
}
}
query NodeByUri($uri: String!) { query NodeByUri($uri: String!) {
nodeByUri(uri: $uri) { nodeByUri(uri: $uri) {
__typename __typename
... on Page { ... on Page {
... NodePage ... NodePage
} }
... on NodeWithRankMathSeo {
... NodeSeo
}
} }
} }

View File

@@ -1,8 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
// Resolve Node component from URI
const { path: uri } = useRoute(); const { path: uri } = useRoute();
const { data } = await useAsyncGraphQLQuery("NodeByUri", { uri }); const { data } = await useAsyncGraphQLQuery("NodeByUri", { uri });
// Resolve and validate Node component
if (!data.value.nodeByUri) { if (!data.value.nodeByUri) {
throw createError({ statusCode: 404, message: `La page demandée est introuvable: ${uri}`, fatal: true }); throw createError({ statusCode: 404, message: `La page demandée est introuvable: ${uri}`, fatal: true });
} }
@@ -10,10 +9,13 @@ const componentName = `Node${data.value.nodeByUri.__typename}`;
if (!useNuxtApp().vueApp.component(componentName)) { if (!useNuxtApp().vueApp.component(componentName)) {
throw createError({ statusCode: 404, message: `La page demandée ne peut pas être affichée correctement: ${componentName}`, fatal: true }); throw createError({ statusCode: 404, message: `La page demandée ne peut pas être affichée correctement: ${componentName}`, fatal: true });
} }
useNodeSeo(data.value.nodeByUri);
</script> </script>
<template> <template>
<div v-if="data.nodeByUri" id="page-node-from-uri"> <div v-if="data.nodeByUri" id="page-node-from-uri">
<Component :is="componentName" v-bind="data.nodeByUri" /> <Component :is="componentName" v-bind="data.nodeByUri" />
<pre>{{ data.nodeByUri }}</pre>
</div> </div>
</template> </template>

View File

@@ -20,13 +20,14 @@ function moonshine_after_setup_theme() {
// Bypass headless home URL for specific cases // Bypass headless home URL for specific cases
add_filter( 'home_url', 'moonshine_bypass_home_url', 10, 4 ); add_filter( 'home_url', 'moonshine_bypass_home_url', 10, 4 );
function moonshine_bypass_home_url( $url, $path, $orig_scheme, $blog_id ) { function moonshine_bypass_home_url( $url, $path, $orig_scheme, $blog_id ) {
$excluded_patterns = array( $excluded_patterns = array(
'#/wp-json(/|$)#i', '#/wp-json(/|$)#i', // WP REST API
); '#\.(xsl|xml)$#i', // Sitemap and XSLT files
foreach ( $excluded_patterns as $pattern ) { );
if ( preg_match( $pattern, $url ) ) { foreach ( $excluded_patterns as $pattern ) {
return get_site_url( $blog_id, $path, $orig_scheme ); if ( preg_match( $pattern, $url ) ) {
} return get_site_url( $blog_id, $path, $orig_scheme );
} }
return $url; }
return $url;
} }

View File

@@ -56,8 +56,6 @@ export default defineNuxtConfig({
}, },
}, },
sitemap: { sitemap: false,
zeroRuntime: true,
},
}); });

File diff suppressed because it is too large Load Diff