Oria Site Sync

Description

Oria Site Sync connects your existing WordPress website to the Oria Marketing platform. One plugin, zero coding, one API key, and every Oria feature becomes reachable on your own domain.

Real SEO via server-side rendering (3.2.0). Blog posts, reviews, case studies, service-area pages, and project galleries are fetched as server-rendered HTML and injected into your WordPress theme. Google indexes the content on YOUR domain, not on oriamarketing.com. Each page emits Schema.org JSON-LD (BlogPosting, AggregateRating, Article, LocalBusiness) so it qualifies for Google Rich Results.

Configurable URL prefix. By default your Oria pages live under /hub/ (for example /hub/blog and /hub/reviews). You can change the URL prefix to match your brand in Settings > Oria Site Sync — valid values are any single URL-safe word such as content, resources, or your own brand name. Legacy /oria/ paths keep working regardless, so existing links never break.

Lead-generation tools (embedded as widgets):

  • Get Your Estimate, AI-powered instant pricing (/hub/estimate)
  • Photo Quote, visitors upload a photo, get an estimate (/hub/photo-quote)
  • Book a Consultation, connected to your Google Calendar (/hub/book)
  • Contact form, submissions land in your Oria CRM (/hub/contact)
  • Chat With Us, live AI chat widget (/hub/chat)
  • AI Room Visualizer, visitors upload a photo, see their space remodeled (/hub/ai-viz)

Content surfaces (rendered server-side for SEO):

  • Blog, AI-written SEO articles tailored to your trade and service areas (/hub/blog)
  • Live Projects, real-time project updates your visitors can follow (/hub/projects)
  • Case Studies, before/after transformations with photos (/hub/case-studies)
  • Reviews, Google and platform reviews aggregated with Schema.org markup (/hub/reviews)
  • Service Areas, per-city landing pages for local SEO (/hub/areas)

Sitemap integration:

  • Each individual blog post, case study, area page, and project is added to your WP sitemap (wp-sitemap.xml) with the per-post URL so search engines discover and rank them.
  • Per-post lastmod timestamps so Google knows when content was updated.

Flexible embedding:

Drop any feature into your existing WordPress pages using the [oria_embed] shortcode:

[oria_embed type="reviews"]
[oria_embed type="booking"]
[oria_embed type="estimator"]
[oria_embed type="ai-viz" height="800"]

What you need:

  1. An active Oria Marketing subscription
  2. Your Oria API key (found at Admin, Site Sync, Generate Key in your Oria dashboard)
  3. WordPress 5.8+ and PHP 7.4+

External services

This plugin connects to the Oria Marketing service at oriamarketing.com to fetch and display content on your WordPress site. Oria is the SaaS platform that powers this plugin — it is the content backend for every surface the plugin exposes (blog, reviews, case studies, service-area pages, projects, AI chat, booking, estimate, photo-quote, contact form, AI visualizer).

What the service is and what it is used for

Oria Marketing is an AI-powered marketing platform for residential contractors. This plugin acts as a WordPress front-end to that platform. Without an active Oria account and API key, the plugin will not display any content — it is designed exclusively for Oria subscribers.

What data is sent and when

The plugin contacts Oria Marketing’s API in four scenarios:

  1. On page view for Oria surfaces (e.g. someone visits /hub/blog, /hub/reviews, /hub/projects). The plugin sends the tenant’s Oria API key, the WordPress site’s base URL, and the configured URL prefix. Oria returns pre-rendered HTML which the plugin injects into the current WordPress theme. Responses are cached in WordPress transients (5 minutes for list pages, 24 hours for individual posts) to minimize requests.
  2. On sitemap request (wp-sitemap.xml). The plugin sends the tenant’s Oria API key and receives a list of blog, project, case-study, and area-page URLs with lastmod timestamps so WordPress can include them in the core sitemap. Cached for 1 hour.
  3. When a visitor loads an iframe-embedded Oria widget (e.g. booking, chat, estimate). The visitor’s browser loads the widget directly from oriamarketing.com in an iframe. No data is sent through the WordPress server for these embeds.
  4. On frontend page render — Meta Pixel configuration fetch (added in 3.5.0). The plugin calls https://oriamarketing.com/api/connect/pixel?key=<api_key> to retrieve the tenant’s Meta Pixel ID. Only the API key is sent; no visitor data. The response contains the tenant’s configured Meta Pixel ID (a numeric identifier). Cached for 6 hours via a WordPress transient. If a Pixel ID is returned, the plugin injects the standard Meta Pixel tracking script (loaded from connect.facebook.net) into the page’s <head>. The Meta Pixel is a third-party tracking service provided by Meta Platforms, Inc. and is subject to Meta’s terms and privacy policy: https://www.facebook.com/privacy/policy/ — visitors on the site will have PageView events sent to Meta when they load pages. Tenants should disclose this in their own site’s privacy policy; Oria does not publish that disclosure on behalf of the tenant.

Visitor data is only transmitted to Oria if the visitor actively interacts with a lead-capture widget (submits a booking request, uses the chat, completes an estimate form, etc.). Those interactions happen inside the widget and are governed by Oria’s own data-handling practices.

Service provider

This service is provided by Oria Marketing.

Installation

  1. Upload the oria-site-sync folder to /wp-content/plugins/
  2. Activate the plugin
  3. Go to Settings, Oria Site Sync
  4. Enter your API key (find it in Oria, Site Sync, Generate Key)
  5. Done. Your pages are live at /hub/blog, /hub/projects, etc.

FAQ

Do I need to edit my theme?

No. The plugin works with any WordPress theme automatically. SSR pages render inside your theme via get_header() and get_footer().

Will it slow down my site?

No. SSR responses are cached in WordPress transients (5 minutes for lists, 24 hours for individual posts) so the plugin only contacts Oria when content actually changes.

How is this different from an iframe embed?

Iframes hide content from Google. With SSR, the HTML is part of your page on your domain, so search engines can crawl, index, and rank it as your content.

Can I disable specific features?

Yes. Use your Oria dashboard under Settings Website Features. The plugin reads those toggles automatically and shows the current state inside Settings Oria Site Sync.

Reviews

There are no reviews for this plugin.

Contributors & Developers

“Oria Site Sync” is open source software. The following people have contributed to this plugin.

Contributors

Translate “Oria Site Sync” into your language.

Interested in development?

Browse the code, check out the SVN repository, or subscribe to the development log by RSS.

Changelog

3.6.6

Per-tenant URL prefix sync — admin preview links match your real prefix
* The plugin’s URL prefix has been tenant-configurable since 3.1.0 (you can change /hub/ to anything you want in Settings Oria Site Sync), but Oria’s admin dashboard had no way to know what you set, so preview links generated in Oria assumed /hub/ and broke for tenants who customized the prefix to something else (e.g. /content/ or /resources/).
* Now: every branding ping the plugin sends to Oria includes the configured url_prefix and the plugin version. Oria stores them per-tenant and uses them when building admin preview links, so the link in your Oria dashboard always points at the correct path on your WordPress site.
* No tenant action required — the plugin reports automatically on every branding refresh. Existing installs catch up the next time the 5-minute branding cache expires (or sooner if you click “Refresh now” in Settings Oria Site Sync).

3.6.5

Smarter menu injection — label-aware duplicates + cleanup of disabled pages
* “Add enabled Oria pages to my menu” now detects duplicates by label, not just URL. Before this, a tenant’s existing “Blog” menu item pointing at /blog wasn’t recognized when the plugin tried to add a new “Blog” pointing at /hub/blog — different URLs, same intent, two menu entries. Now the plugin skips by label OR URL match (case-insensitive).
* Menu injection now removes menu items that point at hub URLs whose features are currently disabled. So after toggling Services Hub, Contact Form, or Chat off in Oria’s settings, the next click of “Add enabled Oria pages” cleans them out of the WordPress menu instead of leaving orphans.
* Forces a fresh branding-cache read every time the button is clicked, so tenants don’t have to wait 5 minutes after changing feature toggles in Oria for the menu inject to reflect the new state.
* Notice now reports added / skipped / removed counts after every run.

3.6.4

Respect Oria feature toggles on WordPress sites + one-click menu injection
* Site Sync now reads enabledFeatures from Oria’s /api/connect/branding response and only serves the approved hub pages on the tenant’s WordPress site. Disabled pages fall through to a proper HTTP 404 instead of rendering thin duplicate content.
* Added plugin-admin visibility for every Oria page: the Settings Oria Site Sync “Your Pages” table now shows enabled / disabled state read-only and points tenants back to Oria’s Settings Website Features panel as the source of truth.
* Added a “Refresh now” button so tenants can clear the 5-minute branding cache after changing website-feature toggles in Oria.
* Added a one-click “Add enabled Oria pages to my menu” action. Tenant picks an existing WordPress menu (Primary, Footer, etc.) and the plugin adds custom-link items only for currently enabled Oria pages, skipping duplicates safely on re-run.
* Branding cache key now includes the plugin version, so a 3.6.3 3.6.4 upgrade forces a fresh feature-config fetch instead of waiting for the old transient to expire.

3.6.3

Capture leads from your existing WordPress contact forms into Oria CRM
* Site Sync now connects your existing WordPress form (the one already on your contact page) to the Oria CRM. Every submission lands in your Oria leads dashboard automatically — without rebuilding the form, without changing your theme, without any tenant configuration. Triggers the full lead automation chain: instant SMS to you, welcome email to the homeowner from your Gmail, and the 4-stage nurture sequence.
* Hooks the top 5 WordPress form plugins via their official action APIs:
* Contact Form 7 — wpcf7_mail_sent (after successful send)
* WPForms — wpforms_process_complete
* Gravity Forms — gform_after_submission
* Elementor Pro Forms — elementor_pro/forms/new_record
* Forminator — forminator_form_after_save_entry
* Field detection uses heuristics (substring matches + shape detection — does this look like an email? a phone number?) so it works regardless of how you named your form fields. Anything that can’t be auto-mapped goes into the message body so you still see the full form context.
* Fire-and-forget API call — the form submission never blocks waiting for our server. Every adapter is wrapped in try/catch so a parse error here can never break the form for a real homeowner. If the relevant form plugin isn’t active, the hook simply never fires.

3.6.2

Title override on SSR pages + smart popular-service links (no more 404s)
* Title filter now uses the SSR-rendered title when an Oria page is being served. Before this, city pages like /areas/mountain-view rendered with the theme’s bare WP title (e.g. just “Alon”) instead of the proper “Alon Design and Remodeling in Mountain View” — losing all the SEO benefit of the page title we generate.
* Sibling server fix in renderServiceArea: popular-service links on city pages now check whether the city × service page actually exists for the tenant. When the page exists (e.g. Berkeley × ADU), link goes to it. When it doesn’t exist yet (Mountain View hasn’t had its service combos generated by the scan), link goes to /contact?project_type=…&city=… so the click flows into the lead funnel instead of dead-ending at a 404.

3.6.1

Route bare /areas/{city} city-only landing pages
* Authority Radar’s “Run full scan” generates rich city-only landing pages (Mountain View, San Mateo, Palo Alto, etc.) at /areas/{city} with homeowner_scenario, costTable, neighborhoods, FAQ, and trade-aware content. Before this release the plugin only routed the two-slug /areas/{city}/{service} pattern, so every bare city page returned 404 — content was generated and indexed in the database but no public URL reached it. Now /areas/{city} routes to the same SSR rendering layer used by /hub/areas, surfacing the full per-city content. Sibling fix in the server’s renderServiceArea ensures the actual generator field schema is rendered (was previously reading wrong field names and falling back to generic defaults).

3.6.0

Tenant-aware SEO meta + JSON-LD schema injection
* Site Sync now upgrades the SEO of any tenant’s WordPress homepage with the same treatment Oria-hosted sites receive: trade-aware title (e.g. “Roofer in Los Angeles, CA | Vision Roofing”), tenant-specific meta description from your About copy, trade + city keywords (no platform-keyword leak), full Open Graph + Twitter Card meta, and trade-specific JSON-LD schema (RoofingContractor / Plumber / SolarPanelInstaller / etc.) with REAL areaServed cities from your service markets — not the generic “United States” most plugins emit.
* Conflict-aware: detects Yoast, RankMath, and All-in-One SEO. When one is active we DEFER for title/description/og (let your existing SEO plugin own them) but still inject our trade-specific JSON-LD because ours has the correct @type and real city coverage that generic SEO plugins don’t generate.
* Static SEO body block on the homepage — invisible to humans (offscreen via CSS), visible to crawlers. Includes H1 with trade + city, license number, top 3 testimonials. Helps Google understand the page even before your theme’s React/JS renders.
* Image alt-text filler — when an image on your site has an empty alt attribute, the plugin fills it with “{Your Company} — {trade} project” (never overwrites alt text you’ve set yourself). Helps both SEO ranking and accessibility.
* Robots meta — emits index, follow, max-image-preview:large so Google can show large image previews in search results.
* Single API call to oriamarketing.com cached 6 hours via WordPress transient. Same architecture as the pixel injection in 3.5.0 — fast, safe, every branch try/catch wrapped so SEO injection failure can never WSOD the site.

3.5.7

Primary navigation menu now shows on Oria SSR pages + edge cache safety
* Themes that switch nav menus by page type (common on contractor themes with a “demo” menu and a configured primary menu) previously fell back to the demo menu on Oria SSR pages — Alon’s site showed “Pages Portfolio Our Work 1/2/3” on /hub/blog instead of his primary Services/About/Gallery menu. Root cause: our SSR pages did not set WP_Query flags, so is_page(), is_singular(), and is_front_page() all returned false and the theme’s menu logic fell through to defaults. Fix: oria_sync_pose_as_page() sets $wp_query->is_page = true + is_singular = true before get_header() so the theme sees Oria pages as first-class singular pages.
* Replaced nocache_headers() on SSR routes with Cache-Control: public, max-age=300, must-revalidate, stale-while-revalidate=60. Before this, if an edge CDN (Cloudflare, GoDaddy Gateway) ever cached a transient error response, the cache would stick for whatever the host’s default TTL was — Alon’s site had a stale 301404 cached by Cloudflare for 31 days. Short explicit TTL means any incident self-heals within 5 minutes.

3.5.6

SEO audit fixes — article timestamps, robots directive, absolute logo/image URLs
* Added <meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" /> on every SSR surface. Before, the plugin relied on Google’s default behavior and emitted no explicit directive; being explicit unlocks the Googlebot “large image preview” behavior in SERPs and signals intent to other crawlers (Bing, DuckDuckGo, Yandex).
* Emit <meta property="article:published_time"> and <meta property="article:modified_time"> on SSR pages. The server already provides these timestamps in the render fragment; before 3.5.6 the plugin dropped them. These feed Google’s Article / BlogPosting Rich Results freshness signal.
* Server-side: every logoUrl, og_image, and JSON-LD image/logo reference is now wrapped in an absolute-URL helper (toAbsoluteMediaUrl). Previously many references leaked relative paths into structured data and Open Graph tags — Google can’t resolve /api/blog-images/... against the tenant’s domain, so the image references were effectively broken. Affects BlogPosting publisher logo, Article image, Project/CreativeWork image, og_image on every surface. Deployed alongside plugin 3.5.6.

3.5.5

Hotfix — /hub/blog and other SSR pages rendered as visually empty in 3.5.4
* 3.5.4 enqueued embed.css on SSR pages (blog list, reviews, case-studies, projects) so the oria-card grid would get styled. But embed.css contained a rule, designed for the iframe embed pages, that hid every direct <div> child of body except the topbar and iframe wrapper. On SSR pages that rule silently hid every theme wrapper div — the blog section was in the HTML but invisible. Scoped the rule to body.oria-iframe-mode so it only applies on iframe pages, and added that class to the iframe renderer’s body tag.

3.5.4

Branded topbar on iframe pages + styled SSR content
* Iframe embed pages (/hub/book, /hub/chat, /hub/ai-viz, etc.) now show the tenant’s custom logo (Appearance Customize Site Identity Logo) in the topbar instead of plain site-name text. Falls back to the site icon at 96px, then to the site name, so every tenant gets something rendered regardless of their theme setup.
* SSR blog, reviews, case-studies, projects, and service-area list pages now enqueue the embed stylesheet. Before this release the rendered fragments had zero CSS rules for .oria-card, .oria-grid, .oria-ssr-content etc. — the theme’s default .entry-content typography gave huge headings and images ran at native width. Now list pages render as proper card grids with consistent typography, cover-cropped images, and mobile breakpoints.

3.5.3

Fix iframe embed page layout (missing stylesheet)
* The iframe-based embed pages (/hub/book, /hub/chat, /hub/ai-viz, etc.) rendered unstyled — massive unconstrained SVG arrow, broken layout. Root cause: the plugin exits at the parse_request hook (priority 0) to beat WordPress routing, but that fires before wp_enqueue_scripts, so the style + script handles registered by oria_sync_register_embed_assets() didn’t exist yet when the iframe renderer tried to enqueue them. Result: wp_enqueue_style() silently no-op’d and no <link> tag was emitted.
* Fixed by self-registering the embed asset handles on-demand inside the iframe renderer if they aren’t registered yet — preserves WP.org Guideline 13 compliance (still using registered handles + wp_enqueue_style / wp_print_styles), just closes the hook-ordering gap.

3.5.2

Second critical stability fix — root cause of the 3.5.0 / 3.5.1 WSOD
* Fixed Call to undefined method WP_Sitemaps::add_provider() fatal that crashed every install with an API key set. The 3.4.0 sitemap hook used $sitemaps->add_provider(), which is not a method on WordPress Core’s WP_Sitemaps class — the correct API is wp_register_sitemap_provider(). This was the real cause of Alon Design & Remodeling’s WSOD on 2026-04-24 (the 3.5.1 try/catch wrappers didn’t cover this because the bug lives in the wp_sitemaps_init closure, not in the new 3.5.0 pixel code). Now wrapped in try/catch as defense-in-depth.
* Every named plugin function is now declared inside an if ( ! function_exists( ... ) ) guard, preventing the “Cannot redeclare oria_sync_*” fatal that occurred when an older pre-WP.org install of the same functions (via the WPCode snippet) was still present alongside the new plugin. Tenants migrating from the snippet can now safely activate the plugin without first manually removing the snippet.

3.5.1

Critical stability fix — prevents WSOD on PHP 8+
* 3.5.0 crashed Alon Design & Remodeling’s site (GoDaddy Managed WordPress, PHP 8+) on 2026-04-24 when the pixel-config API call returned null. PHP 8 is stricter about accessing offsets on null, and the line empty($cfg['metaPixelId']) threw a TypeError.
* Every new function from 3.5.0 is now wrapped in try/catch at the outer boundary — pixel config fetch, pixel injection, and transient cache flush. Any runtime error is logged via error_log() and silently skipped rather than bubbling into a fatal.
* Added oria_sync_safe_array_get() helper for null-safe nested array access.
* All variable types are validated explicitly (is_array, is_string) before use — no more implicit coercion surprises.
* Closures replaced with named functions (oria_sync_inject_pixel, oria_sync_flush_pixel_cache) so WordPress can cleanly unregister the hooks if the plugin deactivates mid-request.

3.5.0

Automatic Meta Pixel injection per tenant
* New: plugin automatically fetches the tenant’s Meta Pixel ID from the Oria API using the configured API key, and injects the standard Meta Pixel snippet into every frontend page’s <head>. PageView fires on load. No manual snippet install required.
* New: window.dispatchEvent(new CustomEvent('oria:lead_submitted')) from any form on the site will fire a Lead event to the tenant’s pixel. Oria-rendered forms already dispatch this; custom forms can too.
* Pixel config is cached for 6 hours via a WordPress transient (oria_sync_pixel_config) to avoid API round-trips on every pageview. Cache is invalidated automatically when the tenant changes their API key.
* <noscript> tracking pixel fallback included for browsers without JavaScript.

3.4.0

City × service pages now route correctly
* New standalone URL pattern /areas/{city}/{service} (no prefix required) maps to Oria’s auto-generated city × service landing pages. Before this release these URLs returned 404 on tenant domains because only single-slug routes under the configurable prefix were matched.
* New Oria_Renderer::fetch_city_service() helper hits /api/connect/service-areas/:city/:service?render=html on the Oria API to retrieve pre-rendered SSR HTML and Schema.org markup (Service + LocalBusiness + FAQPage). 24-hour transient cache.
* New plugin render path oria_sync_render_city_service_page() wraps the fragment in the tenant’s theme via get_header() / get_footer() so Google can crawl the content on the tenant’s own domain.

3.3.1

WordPress.org Plugin Review compliance (round 2)
* Fixed PHP syntax error in docblock above oria_sync_register_embed_assets() — the sequence wp_register_*/wp_enqueue_* inside the comment was prematurely closing the docblock (the */ inside that token). Rewrote to wp_register_style / wp_enqueue_style so PHP parses the docblock correctly.
* Added a complete External services section documenting every outbound call to oriamarketing.com: what data is sent, when, and why, plus links to the Oria Marketing Terms of Service and Privacy Policy. Required for WordPress.org Plugin Review.

3.3.0

WordPress.org Plugin Review compliance
* Inline <style> and <script> output in the iframe embed render function replaced with wp_enqueue_style() and wp_enqueue_script() registering the new assets/embed.css and assets/embed.js static files (Plugin Guideline 13).
* Readme description clarified — the sentence about the configurable URL prefix now lists example values explicitly instead of comma-separating them ambiguously.
* No functional changes for end users — the embed page renders identically.

3.2.0

Server-side rendering for SEO surfaces (the big change)
* Blog posts, reviews, case studies, service-area pages, and project pages are now fetched from Oria as pre-rendered HTML and injected into your WordPress theme via get_header() and get_footer(). The content is part of your page on your domain, so Google indexes it as your content (iframes were not crawlable, so SEO link equity was leaking back to oriamarketing.com).
* Internal links inside Oria-generated content are rewritten to your /hub/* paths so SEO link equity flows through your domain.
* Schema.org JSON-LD emitted for each surface: BlogPosting (blog), AggregateRating + Review (reviews), Article (case studies), LocalBusiness (service areas), CreativeWork (projects). Google Rich Results eligible.
* Meta tags (title, description, canonical, og:*, twitter:*) emitted via the standard wp_head hook so SEO plugins like Yoast can observe and modify them.
* Lead-generation tools (chat, booking, estimate, photo-quote, contact, AI viz) stay as iframe widgets, that’s the right architecture for real-time JS forms with no SEO value.

Sitemap with real per-post URLs
* wp-sitemap.xml now lists every individual blog post, case study, area page, and project at its full URL with a per-post lastmod timestamp.
* Sitemap data is fetched from /api/connect/sitemap and cached for 1 hour.

Performance
* WP transient cache: 5 minutes for list pages, 24 hours for detail pages, 1 hour for sitemap. Reduces API load to roughly one request per surface per cache window.
* Soft-fail with 60-second negative cache so transient API errors don’t hammer Oria during recovery.

3.1.0

  • Plugin header format and license string standardized for WordPress.org Plugin Check compliance.
  • Expanded description to meet WordPress.org detail requirements.
  • $_SERVER['REQUEST_URI'] access now unslashed and sanitized via wp_unslash() and sanitize_text_field().
  • parse_url() calls replaced with the WordPress wrapper wp_parse_url().
  • New routes: /hub/estimate, /hub/photo-quote, /hub/contact, /hub/chat.
  • Configurable URL prefix (default changed from /oria/ to /hub/); legacy /oria/* paths still route for backward compatibility.
  • New [oria_embed] shortcode lets tenants drop any Oria widget into any WordPress page/post.
  • Wrapper iframe pages emit proper meta tag set so link shares render correctly on Facebook, LinkedIn, Slack, iMessage.

3.0.0

  • Campaign landing pages support (/hub/landing/slug)
  • Hub page at /hub/ with links to all features
  • Authority Radar content pages
  • AI Room Visualizer page
  • Case Studies pages
  • Project Manager Portal (standalone /pm-portal)

1.0.0

  • Initial release
  • Blog, Projects, Booking, Reviews, Service Areas pages
  • AI Chat + Booking portal
  • Form capture and visitor analytics
  • Automatic menu link injection
  • WordPress sitemap integration