Enter access token to continue
moodco Snack Media
Private Report · July 2026

Snack Media — Technical Audit & Path Forward

A technical review of the Snack publisher network — using WrestleTalk as the worked example.

Prepared by Mood Digital for Snack Media · July 2026
Scroll
Executive Summary

Executive Summary

We audited WrestleTalk.com as a representative Snack publisher site. Goal: find what's holding traffic back, and propose a path that scales across publishers.

The clearest example: two conflicting schemas on one article

A live WrestleTalk article carries two separate, competing article schemas at once — a skeletal standalone NewsArticle block and Yoast's fuller graph typed as a generic Article, with two different types and two different date formats. Google has to guess which to trust, and neither is complete: the rich one has the weaker type, the correctly-typed one is bare. It's verifiable live in ten seconds (view-source, search NewsArticle), it's directly relevant to news/Discover eligibility, and the benchmark site emits one clean authoritative graph on an equivalent article.

1. Today

Not badly built — but tooling is installed without landing, plugins fight each other, and the site fights its own architecture.

2. Short-term

Most fixes ship in place as one mu-plugin and test results.

3. Long-term

Structural problems only go away with a move to headless — 30 live sites, one codebase (Phase 2).

Headline Points
Architecture

Why This Keeps Happening

Most of the findings below stem from one structural difference. Understanding it makes the rest of the audit click.

WrestleTalk Today (Typical Publisher)

User → BunnyCDN (10-min cache) → WordPress (PHP 8.4) renders full page
                                      └── theme, 37 plugins, jQuery, ads — all in one app

WordPress does everything: CMS, frontend rendering, API, media, ad injection. Every plugin and theme choice directly affects what visitors download. Plugins overlap and conflict (two schema generators, two caching/optimisation layers). The CMS is publicly reachable. Caching is a bolted-on layer.

wp-mood Platform (What We Run — 30 Sites)

User → Cloudflare CDN (HTTP/2 + HTTP/3) → Next.js (pre-rendered pages, ISR)
                                                   ↕
                                           WordPress (private CMS — never public-facing)
                                                   ↕
                                           Dedicated media CDN (R2, WebP)

WordPress is purely an editorial backend — editors use it exactly as they always have. But visitors never touch it. Pages are pre-rendered, cached with stale-while-revalidate, and served static. The public site ships one first-party stylesheet and no render-blocking first-party JavaScript — the only other external requests are the async/deferred ad + analytics tags. Security headers, structured data, image optimisation, sitemaps — all owned by the platform, so plugins can't fight each other for control of the output.

30 publisher sites run on this stack today. Same codebase, different brands.

Findings — SEO

SEO

The priority. Foundations are decent — the execution gaps (duplicate schema, no news sitemap, no breadcrumbs, ~16k thin tag pages) are most likely holding the site back.

What's Working

Solid Baseline

  • Clean URL structure (/news/slug/), consistent canonicals
  • Solid Yoast setup with structured sitemap index (118 sitemaps, lastmod maintained)
  • Article pages have good base meta (og:image, author, published + modified time, reading time)
  • max-image-preview:large set (important for Google Discover)
Article vs Benchmark (same day, similar length)
MetricWrestleTalk ArticleBenchmark Article
Article schemaTwo competing schemasOne clean NewsArticle @graph
BreadcrumbList schema❌ Missing✅ Present
Images lazy-loaded1 of 1514 of 18
Images in WebP0 of 1512 of 18
og:imageJPG, tag duplicated twiceWebP, clean
articleSectionLeaks internal taxonomy: "App Notifications - WWE""News"
og:localeen_US (UK publisher)en_GB
Title lengthInconsistent — this one ~110 chars (truncates); others fitConsistent ~70 chars
H2 structure5 H2s, 4 boilerplate3 H2s, all content
Head hygieneExposes /wp-json/ API endpoints as link tagsRSS feed declared
The Duplicate Schema Problem (Biggest Single SEO Finding)

The WrestleTalk article carries two separate, conflicting article schemas:

1. A standalone minimal NewsArticle block — only 7 properties, no publisher, no mainEntityOfPage, dates in +01:00 timezone. Looks hand-added or from a secondary plugin.

2. Yoast's full @graph — rich (author entity, WebPage, ImageObject, Organisation) but typed as generic Article, dates in +00:00, and missing dateModified entirely.

Two schemas, two types, two date formats — Google has to guess which to trust, and neither is complete: the rich one has the weaker type and no dateModified, the correctly-typed one is skeletal. Looks like a past schema patch that created a duplicate instead. On the benchmark there is a single authoritative graph — the platform guarantees one schema source and suppresses any competing block, so this conflict can't occur.

Verified live 29 Jul 2026 on /news/cm-punk-responds-grayson-waller-shoot-promo-wwe-nxt/: two application/ld+json blocks — a 7-property NewsArticle and a Yoast @graph typed Article with dateModified absent.

Remaining SEO Gaps
IssueWrestleTalkwp-moodImpact
News sitemap❌ None✅ DedicatedMajor for a news publisher — slower discovery of fresh content
Breadcrumbs❌ None visible, no schema✅ BothLost SERP breadcrumb display + internal linking signals
H1 tags3 on homepage1Minor — Google tolerates multiple H1s; tidy for clarity, not a likely ranking factor
Homepage og:image❌ Missing✅ PresentHomepage shares render without an image
Tag pages~16,000 thin pages in sitemapCuratedSite-quality dilution at 89k-article scale (crawl budget secondary) — see below
RSS link❌ Not declared✅ PresentReduced aggregator discoverability
PWA manifest❌ None✅ FullLow — installability/UX, not a ranking factor
robots.txtEverything open (Disallow: empty; search + wp-admin crawlable)Selective blockingLow-value URLs left crawlable
Author E-E-A-TThin author entitiesAuthor pages + Person/sameAs schemaTrust signal for News/Discover

Several of these (breadcrumbs, news sitemap) are already-installed or one-add-on-away Yoast features. Installed ≠ configured ≠ working.

What the "~16k Tag Pages" Actually Means

In WordPress, every tag an editor attaches to a post auto-generates its own archive page and URL (e.g. /tag/roman-reigns/). WrestleTalk has accumulated ~16,000 — a figure you can read straight off the sitemap index: 16 post_tag-sitemap*.xml files at ~1,000 URLs each. Most are thin: an auto-generated list of links with no original writing, many with one or two posts, overlapping category pages and search.

Two distinct harms, in priority order:

  1. Site-quality dilution (the bigger one). Google increasingly judges quality at the whole-site level. ~16k low-value pages can drag down how the algorithm perceives the site overall — exactly what a core / Helpful Content update penalises. Deindexing them concentrates quality signals on the ~89k real articles.
  2. Crawl budget (secondary). Googlebot crawls a finite number of URLs per site per day. Because these tag pages sit in the Yoast sitemap, Google is actively told to crawl them — spending budget it could use discovering and refreshing fresh articles, which for a news site is where the traffic is.

And it isn't only tags. The sitemap index also exposes star-rating, results (×4) + results_archive, champions_category, team, tribe_events and podcast sitemaps — more auto-generated thin archives on top of the 16k tags. The fix ("Curated" on the platform): noindex the thin archives, drop them from the sitemap, keep only the genuinely useful hubs.

Crawl Budget at Scale

~89k articles (verified: 89 post-sitemap files × 1,000 URLs) + ~16k tag pages + events/quizzes = fresh articles competing with 100k+ URLs for a finite crawl budget, on top of the quality issue above. Thin archives and stale events work against discovery. The fast-indexing-api and snack-missed-schedule plugins are a tell — symptomatic fixes, installed when someone's already fighting indexing.

Beyond SEO — Security, Performance & Accessibility (live-verified 29 Jul 2026)
  • REST user enumeration is open. GET /wp-json/wp/v2/users returns HTTP 200 and leaks author names + slugs. The head also exposes /wp-json/ and the Tribe Events API. (For accuracy: xmlrpc.php is already blocked — returns 403 — so the exposure is wp-json, not xmlrpc.)
  • No security headers. No HSTS, CSP, X-Frame-Options, X-Content-Type-Options or Permissions-Policy; Referrer-Policy is the weak legacy no-referrer-when-downgrade.
  • Heavy legacy JS → INP risk. A single article loads 19 external scripts, including jQuery + jQuery UI and 6 jQuery plugins (fancybox, marquee, nice-select, sticky…). INP is the Core Web Vital most at risk on an ad- and jQuery-heavy stack.
  • Image delivery. On the sampled article, 0 of 21 images were lazy-loaded and 0 were WebP (all JPG/GIF).
  • Accessibility: pinch-zoom disabled. Viewport is user-scalable=no, maximum-scale=1.0 — a WCAG 2.1 (1.4.4) failure, trivially fixed at the output layer.

None require a rebuild — all are output-layer fixes the Phase 1 mu-plugin can own.

The Plugin Question

37 Active Plugins

A platform migration doesn't mean supporting all of them — most become redundant or stay admin-side. Triage:

Made Redundant by the Platform (~60%)

Caching/optimisation: w3-total-cache, perfmatters, wp-rest-cache, use-bunny-dns.
Old-frontend API auth: json-api-*, jwt-authentication.
Ad injection: ad-inserter → replaced by platform slot config.
Symptomatic fixes: fast-indexing-api, snack-missed-schedule — the platform publishes reliably and has a news sitemap.
Admin-only (zero frontend work): akismet, disable-comments, disable-gutenberg, user-role-editor, post-duplicator, post-types-order, taxonomy-terms-order, edit-author-slug, mainwp-child, wp-crontrol, wp-mail-logging, safe-svg, bdvs-password-reset.

Needs a Frontend Component (~6–8)

Bounded, real work — but one-off. Each component built for WrestleTalk becomes a reusable platform capability for every subsequent publisher.

Should Be Removed Regardless

wp-file-manager — RCE vulnerability history; replace with SFTP access.

PluginFrontend NeedNotes
ninja-tables (+pro)Table rendering componentData via REST
quiz-makerQuiz componentBounded scope
the-events-calendarEvents listing + detail pagesAlready identified
league_wpLeague/results tablesCustom plugin — needs API review
pageviews-counterTrending/most-read widgetsSimple
onesignal / push-notificationsPush opt-inClient-side SDK, standard pattern
advanced-custom-fields-proField data via APIAlready supported on wp-mood
wordpress-seo (Yoast)Meta/schema sourcePlatform generates its own — Yoast becomes editorial input only

The honest position: this is real work, but it's bounded and it's a one-off — each component built for WrestleTalk becomes a reusable platform capability for every subsequent publisher. It is not an open-ended "backward compatibility" commitment to 37 plugins.

Path Forward

A Two-Phase Approach

We deliberately do not recommend jumping straight to a migration. The sequencing matters — both for risk and for proving value quickly.

1

Fix in Place, Packaged to Scale

Weeks, not months Low risk · Reversible

Most findings don't require touching the theme or the ad stack — they're output-layer fixes. Packaged as a single deployable mu-plugin ("must-use" plugin — drops into mu-plugins/, always on, can't be deactivated or fought by other plugins)

  • Security headers — HSTS, nosniff, X-Frame-Options, Referrer-Policy, Permissions-Policy
  • Leak plugging — strip X-Powered-By and generator meta, disable XML-RPC, restrict /wp-json/ user/plugin enumeration
  • Schema correction — suppress duplicates, emit one authoritative NewsArticle graph with BreadcrumbList, dateModified, publisher entity
  • Head hygiene — homepage og:image fallback, og:locale correction, RSS declaration, viewport zoom unblocking
  • Image output filtering — enforce loading="lazy" on below-fold images via WordPress output filters
  • Crawl budget & quality — noindex thin tag pages and the other auto-generated thin archives (star-rating, results, team, champions_category…), prune them + stale events from the sitemaps, tighten robots.txt
  • Google News sitemap generation
Portfolio-scale · One codebase, every site

Outside the mu-plugin (still Phase 1, different levers)

  • WebP conversion — best done at CDN level (Bunny Optimizer), zero WordPress changes
  • Script deferral for theme scripts + jQuery upgrade — needs testing against the ad stack, per-site
  • Font Awesome slimming — theme-level change
  • Removing wp-file-manager — admin/process decision

Each change measurable in Search Console and CrUX within weeks.

Honest limits: an mu-plugin can polish the output, but it's still working against the current — it can't fix render-blocking theme scripts, can't stop plugins fighting each other at the source, can't protect the origin from traffic spikes, and can't hide the CMS. That ceiling is exactly why Phase 2 exists.

2

The Platform (Strategic, Per-Publisher)

Per-publisher decision Strategic · Post Phase 1

For publishers where the economics justify it, migrate onto the headless stack:

  • What every publisher gets by default: A-grade security, hidden CMS, WebP + lazy loading, zero render-blocking resources, NewsArticle schema with breadcrumbs, news sitemap, ISR + stale-while-revalidate caching, spike-proof origin, HTTP/3, PWA manifest, RSS — and the Snack ad integration, already built
  • What stays unique per site: design, branding, layout, navigation, content types
  • Editorial workflow unchanged: editors keep WordPress exactly as they know it

How the code is structured: one core, forked per publisher

This is the key to keeping the whole network aligned with Google without maintaining dozens of separate sites. Rather than a branch per site (which drift apart and become impossible to keep in sync), we run a core platform repo plus a fork per major publisher.

Core Platform Repo — the SEO engine
Schema · sitemaps · security · caching · Discover / core-update alignment
↓  core updates pulled downstream (versioned)  ↓
WrestleTalkfork · brand
Publisher Bfork · brand
Publisher Cfork · brand
Forks hold design, layout, navigation & content types — nothing Google-facing
  • Core repo = the SEO engine. Everything Google cares about — schema, sitemaps, security, caching, Discover fundamentals — lives here, once. No brand code touches it.
  • Each big publisher gets a fork. The fork holds only that site's design, layout, navigation and content types — not a branch of a shared codebase, a proper repo of its own that the publisher's site is built from.
  • Core updates flow downstream. When Google ships a core update, the fix lands once in the core repo; every fork pulls it in. One change, whole network aligned — no per-site rework.
  • Distributed as a versioned dependency, not a raw merge. Forks consume the core as a pinned version (like any package) and bump it deliberately — so a core update never risks breaking a publisher's custom design, and each fork upgrades on its own schedule with a clear changelog.
One core · One fix · Every publisher stays current

Scale economics: publisher #1 carries the component-building work (events, quizzes, tables) into the core; publishers #2–3 are mostly design/fork config; #4+ is primarily configuration and QA. The core gets stronger with each site.

Phase 1 de-risks Phase 2: by the time a migration decision is made, the content is clean, the schema is right, the portfolio is already benefiting — and we've proven we can deliver.

The #1 migration risk we own up-front: URL preservation. The biggest SEO danger in any platform move for an 89k-article site is breaking URLs or losing redirects. Our migration keeps the existing URL structure 1:1, carries over every legacy redirect, and diffs the live URL inventory (from the existing sitemaps) against the new build before cutover — so there is no ranking loss from the move itself. A hard commitment, not an afterthought.

Traffic Forensics (Parallel Workstream)

With GSC access, we overlay the traffic drop against known Google update dates and segment by page type (articles / tags / Discover / News) to identify what the cliff actually was. Without it, the Phase 1 gap-closing still stands on its own — the fixes align the site with what core updates reward regardless. GSC just makes the recovery story evidence-backed rather than inferred.

Full Comparison

Snack Site (WrestleTalk) vs wp-mood Platform

The structural differences that matter for traffic.

Metricwrestletalk.comwp-mood Platform
ArchitectureMonolithic WordPress + BunnyCDNHeadless WP + Next.js ISR + Cloudflare
HTTP protocolHTTP/2HTTP/2 + HTTP/3
CompressionBrotli ✅Brotli ✅
TTFB (cached)~75 ms ✅~75–200 ms ✅
CMS exposed⚠️ wp-json open (user enum); xmlrpc blocked (403)❌ Private
Article schema2 conflicting blocks1 authoritative NewsArticle @graph
Breadcrumbs❌✅
News sitemap❌✅
Thin tag pages~16k in sitemapCurated
Cache strategy10-min CDN TTLISR + stale-while-revalidate
Origin protection❌ Render storm risk✅ Structural
What We Need From You

Next Steps

The brief for this call is simple: get traffic working again across the Snack network — starting with WrestleTalk as the pilot — without breaking anything operationally, while we scope the long-term headless move.

Reversible, low-risk, measurable

Phase 1 ships without touching the theme, ad stack, or editorial workflow — and rolls back instantly. The mu-plugin is additive; CDN changes are toggles; everything's measured in Search Console and CrUX. Nothing short-term puts current traffic or ad revenue at risk.

1

Google Search Console Access

WrestleTalk + any other affected sites — so we can overlay the traffic drop against Google update dates and fix what the data points at, not what we assume.

2

Green-light Phase 1 on WrestleTalk as the Pilot

Security headers, schema fix, crawl-budget cleanup, image delivery, zoom fix. Prove the gains on one site, then roll the same mu-plugin across the network.

3

Confirmation of the Traffic-drop Timeline

Roughly when the cliff happened — so we can line it up against known Google core/Discover updates from day one.

Give us #1 and #2 and we can show measurable movement before the next check-in.

Phase 1: days-to-weeks of work, not a rebuild. The mu-plugin is a single build we deploy across the portfolio; CDN changes are configuration. First measurable wins within weeks.

Measurement: Baseline Before We Touch Anything

So the gains are provable rather than asserted, we capture a baseline the moment we get GSC access and before Phase 1 ships:

  • Search: Discover clicks, Google News impressions, clicks/impressions by page type (articles / tags / other), and average indexation latency for new articles.
  • Core Web Vitals (field / CrUX): INP p75 first (the metric most at risk here), then LCP and CLS.
  • Indexation: indexed vs. submitted URLs, and the size of the "crawled – currently not indexed" bucket (where thin tag pages tend to land).

Every Phase 1 change is then reported against that baseline in Search Console and CrUX.