From b8aac5a46117b2cddc8f741244148d563a73a526 Mon Sep 17 00:00:00 2001 From: vfanucci Date: Mon, 15 Jun 2026 18:24:34 +0200 Subject: [PATCH 1/2] seo: link plugin logos to group page + fix dead EE redirect rules The plugin logo carousels (PluginsBlock, EveryPlugin, PluginsBox) built links as `/plugins/${artifactId}/${name}`. For ~82 plugins the `/${name}` subgroup URL does not exist (404) and the middleware catch-all 301-redirects it to the group page `/plugins/${artifactId}`. Screaming Frog flagged ~1,200 internal links pointing to these redirects, concentrated on /use-cases/* and /features/*. Since these are decorative logo links, point them straight at the plugin group page (always 200) to remove the 404 -> 301 hop. Also reorder src/contents/redirects/plugins.yml: the middleware applies the FIRST matching rule (notFoundRedirect -> allEntries[0]), so the catch-all `/plugins/plugin-([^/]+).*` placed before the specific EE batch/cloudrun rules made those rules dead. Moved the catch-all to the end and fixed a leading-space typo in the plugin-azure rule that prevented it from ever matching. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/components/common/PluginsBlock.astro | 5 ++++- src/components/common/PluginsBox.astro | 8 +++----- src/components/features/core/EveryPlugin.astro | 4 +++- src/contents/redirects/plugins.yml | 11 ++++++++--- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/components/common/PluginsBlock.astro b/src/components/common/PluginsBlock.astro index fdf663cb0d6..f7e75b3a260 100644 --- a/src/components/common/PluginsBlock.astro +++ b/src/components/common/PluginsBlock.astro @@ -21,7 +21,10 @@ const plugins = metadata .map((p) => { return { ...p, - link: `/plugins/${p.artifactId}${p.artifactId === `plugin-${p.name}` ? "" : `/${p.name}`}`, + // Logo links to the plugin group page (always 200). The previous + // `/${p.name}` suffix produced subgroup URLs that 404 for ~82 plugins + // and 301-redirect to this same group page, so we skip the hop. + link: `/plugins/${p.artifactId}`, } }) diff --git a/src/components/common/PluginsBox.astro b/src/components/common/PluginsBox.astro index 2799f446b5c..9320baa4b03 100644 --- a/src/components/common/PluginsBox.astro +++ b/src/components/common/PluginsBox.astro @@ -31,11 +31,9 @@ const plugins = await Promise.all( title: plugin.title, name: plugin.name, artifactId: plugin.artifactId, - link: - `/plugins/${plugin.artifactId}` + - (`plugin-${plugin.name}` != plugin.artifactId - ? "/" + plugin.name - : ""), + // Link logos to the plugin group page (always 200) to avoid the + // 404 -> 301 hop the `/${plugin.name}` subgroup suffix caused for ~82 plugins. + link: `/plugins/${plugin.artifactId}`, group: plugin.group, } }), diff --git a/src/components/features/core/EveryPlugin.astro b/src/components/features/core/EveryPlugin.astro index 2b6dd46dc8c..b8e55e59a9f 100644 --- a/src/components/features/core/EveryPlugin.astro +++ b/src/components/features/core/EveryPlugin.astro @@ -26,7 +26,9 @@ try { .filter((p) => p.artifactId && !excluded.test(p.artifactId)) .map((p) => ({ ...p, - link: `/plugins/${p.artifactId}${p.artifactId === `plugin-${p.name}` ? "" : `/${p.name}`}`, + // Link logos to the plugin group page (always 200) to avoid the + // 404 -> 301 hop the `/${p.name}` subgroup suffix caused for ~82 plugins. + link: `/plugins/${p.artifactId}`, })) .sort(randomSortFunction) .slice(0, 20) diff --git a/src/contents/redirects/plugins.yml b/src/contents/redirects/plugins.yml index d9aa99cec15..4bd34e39b10 100644 --- a/src/contents/redirects/plugins.yml +++ b/src/contents/redirects/plugins.yml @@ -1,3 +1,6 @@ +# Specific redirects MUST come before the catch-all below: the middleware +# applies the FIRST matching rule (notFoundRedirect -> allEntries[0]), so any +# rule placed after the catch-all "/plugins/plugin-(...)" never fires. - regexp: "/plugins/core/tasks/scripts/io.kestra.core.tasks.scripts.bash" to: "/plugins/plugin-script-shell/io.kestra.plugin.scripts.shell.script" - regexp: "/plugins/core/tasks/scripts/io.kestra.core.tasks.scripts.node" @@ -6,11 +9,9 @@ to: "/plugins/plugin-script-python/io.kestra.plugin.scripts.python.script" - regexp: "/plugins/core/triggers/io.kestra.core.models.triggers.types.webhook" to: "/plugins/core/trigger/io.kestra.plugin.core.trigger.webhook" -- regexp: "/plugins/plugin-([^/]+).*" - to: "/plugins/plugin-$1" - regexp: "/plugins/plugin-aws/io.kestra.plugin.aws.runner.batch" to: "/plugins/plugin-ee-aws/io.kestra.plugin.ee.aws.runner.batch" -- regexp: " /plugins/plugin-azure/io.kestra.plugin.azure.runner.batch" +- regexp: "/plugins/plugin-azure/io.kestra.plugin.azure.runner.batch" to: "/plugins/plugin-ee-azure/io.kestra.plugin.ee.azure.runner.batch" - regexp: "/plugins/plugin-gcp/io.kestra.plugin.gcp.runner.batch" to: "/plugins/plugin-ee-gcp/io.kestra.plugin.ee.gcp.runner.batch" @@ -18,3 +19,7 @@ to: "/plugins/plugin-ee-gcp/io.kestra.plugin.ee.gcp.runner.cloudrun" - regexp: "/plugins/plugin-kubernetes/io.kestra.plugin.kubernetes.runner.kubernetes" to: "/plugins/plugin-ee-kubernetes/io.kestra.plugin.ee.kubernetes.runner.kubernetes" +# Catch-all: any unknown plugin subgroup/task URL falls back to its group page. +# Keep this LAST so the specific rules above take precedence. +- regexp: "/plugins/plugin-([^/]+).*" + to: "/plugins/plugin-$1" From 6dc022099ca598c55a9d781fcdb3fa5454aae3dc Mon Sep 17 00:00:00 2001 From: vfanucci Date: Tue, 16 Jun 2026 15:51:25 +0200 Subject: [PATCH 2/2] seo: point reactivated EE redirect rules at their final (200) URLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verified live: the EE rule targets (e.g. /plugins/plugin-ee-aws/io.kestra. plugin.ee.aws.runner.batch) themselves 301 to a subgroup URL. Now that the catch-all is reordered last, these rules fire again — so point them straight at the final 200 URL (adding the aws-batch-task-runner / azure-runner / google-cloud-task-runner subgroup) to keep it a single 301 instead of a chain. Kubernetes already resolves 200 directly and is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/contents/redirects/plugins.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/contents/redirects/plugins.yml b/src/contents/redirects/plugins.yml index 4bd34e39b10..bad4f0d3020 100644 --- a/src/contents/redirects/plugins.yml +++ b/src/contents/redirects/plugins.yml @@ -10,13 +10,13 @@ - regexp: "/plugins/core/triggers/io.kestra.core.models.triggers.types.webhook" to: "/plugins/core/trigger/io.kestra.plugin.core.trigger.webhook" - regexp: "/plugins/plugin-aws/io.kestra.plugin.aws.runner.batch" - to: "/plugins/plugin-ee-aws/io.kestra.plugin.ee.aws.runner.batch" + to: "/plugins/plugin-ee-aws/aws-batch-task-runner/io.kestra.plugin.ee.aws.runner.batch" - regexp: "/plugins/plugin-azure/io.kestra.plugin.azure.runner.batch" - to: "/plugins/plugin-ee-azure/io.kestra.plugin.ee.azure.runner.batch" + to: "/plugins/plugin-ee-azure/azure-runner/io.kestra.plugin.ee.azure.runner.batch" - regexp: "/plugins/plugin-gcp/io.kestra.plugin.gcp.runner.batch" - to: "/plugins/plugin-ee-gcp/io.kestra.plugin.ee.gcp.runner.batch" + to: "/plugins/plugin-ee-gcp/google-cloud-task-runner/io.kestra.plugin.ee.gcp.runner.batch" - regexp: "/plugins/plugin-gcp/io.kestra.plugin.gcp.runner.cloudrun" - to: "/plugins/plugin-ee-gcp/io.kestra.plugin.ee.gcp.runner.cloudrun" + to: "/plugins/plugin-ee-gcp/google-cloud-task-runner/io.kestra.plugin.ee.gcp.runner.cloudrun" - regexp: "/plugins/plugin-kubernetes/io.kestra.plugin.kubernetes.runner.kubernetes" to: "/plugins/plugin-ee-kubernetes/io.kestra.plugin.ee.kubernetes.runner.kubernetes" # Catch-all: any unknown plugin subgroup/task URL falls back to its group page.