Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ assets/packaged
.vscode/settings.json
.idea

.phpunit.result.cache
tests/cypress/screenshots
docs/.vitepress/dist
/vendor-prefixed
Expand Down
1 change: 1 addition & 0 deletions docs/en/documentation/advanced-functionality/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
* [Configure cache](cache)
* [Change default values for timeframe creation](change-timeframe-creation-defaults)
* [Hooks and filters](hooks-and-filters)
* [Sitemaps and SEO](sitemaps-and-seo)
90 changes: 90 additions & 0 deletions docs/en/documentation/advanced-functionality/sitemaps-and-seo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Sitemaps and SEO

So that **Items** and **Locations** can be discovered by search engines and listed in your site's
sitemap, a small amount of configuration is recommended. CommonsBooking handles the technical
groundwork automatically — you just need to choose how to expose it.

---

## What CommonsBooking does automatically

CommonsBooking registers its custom post types with the correct WordPress flags so that the right
content is discoverable and the right content stays private:

| Post type | Public | In sitemap by default |
|---|---|---|
| Item (`cb_item`) | Yes | **Yes** |
| Location (`cb_location`) | Yes | **Yes** |
| Timeframe (`cb_timeframe`) | No | No |
| Booking (`cb_booking`) | No | No |
| Restriction (`cb_restriction`) | — | **Excluded by plugin** |
| Map (`cb_map`) | — | **Excluded by plugin** |

`cb_restriction` and `cb_map` are excluded from the sitemap via the `wp_sitemaps_post_types`
filter even though they are technically public post types (required for front-end rendering). They
contain administrative configuration, not content that should be indexed.

---

## Recommended setup: install an SEO plugin

WordPress 5.5 includes a built-in sitemap at `/wp-sitemap.xml`. For most sites, installing a
dedicated SEO plugin gives you better control over titles, descriptions, canonical URLs, and
structured data. We recommend one of the following:

### Yoast SEO

[Yoast SEO](https://yoast.com/wordpress/plugins/seo/) is the most widely used SEO plugin for
WordPress. After installation:

1. Go to **Yoast SEO → Search Appearance → Content Types**.
2. Find **Items** (`cb_item`) and **Locations** (`cb_location`).
3. Set **Show in search results** to **Yes** for both.
4. Optionally customise the SEO title and meta description templates using Yoast's variables
(e.g. `%%title%% – %%sitename%%`).
5. Yoast will automatically generate a sitemap entry for each published Item and Location.

### RankMath

[RankMath](https://rankmath.com/) is a lightweight alternative with a guided setup wizard. After
installation:

1. Go to **RankMath → Titles & Meta → Items** (and repeat for **Locations**).
2. Enable **Add to sitemap**.
3. Set a sensible title pattern, e.g. `%title% - %sitename%`.
4. RankMath will include Items and Locations in its sitemap automatically.

---

## Using the WordPress core sitemap (no SEO plugin)

If you prefer not to install an SEO plugin, the core sitemap at `/wp-sitemap.xml` already
includes Items and Locations out of the box. Individual post type sitemaps are available at:

```
/wp-sitemap-posts-cb_item-1.xml
/wp-sitemap-posts-cb_location-1.xml
```

You can submit these URLs directly to Google Search Console or Bing Webmaster Tools.

---

## Excluding specific posts from the sitemap

To exclude individual Items or Locations from the sitemap (e.g. items in draft or under
maintenance), set the post status to **Draft** rather than **Published**. Both the core sitemap
and SEO plugins only index `publish`-status posts.

With Yoast SEO you can also exclude a single post by opening its editor and setting
**Yoast SEO → Advanced → Allow search engines to show this post in search results** to **No**.

---

## Structured data (JSON-LD)

For richer search results (e.g. showing the item name and availability directly in Google),
structured data markup is needed. This is beyond CommonsBooking's scope — a developer can add
`wp_head` hooks with custom JSON-LD using the post meta fields CommonsBooking stores (location
address, item description, etc.). See the
[hooks and filters reference](hooks-and-filters) for available data access points.
12 changes: 12 additions & 0 deletions includes/OptionsArray.php
Original file line number Diff line number Diff line change
Expand Up @@ -1587,6 +1587,18 @@
),
],
),
'rssfeed' => array(
'title' => esc_html__( 'RSS Feed', 'commonsbooking' ),
'desc' => commonsbooking_sanitizeHTML( __( 'Enables public RSS feeds for Items, Locations and Timeframes so users can subscribe to updates in any feed reader.', 'commonsbooking' ) ),
'id' => 'rss_feed_group',
'fields' => [
array(
'name' => esc_html__( 'Enable RSS feed', 'commonsbooking' ),
'id' => 'rss_feed_enabled',
'type' => 'checkbox',
),
],
),
'experimental' => array(
'title' => commonsbooking_sanitizeHTML( __( 'Advanced caching settings', 'commonsbooking' ) ),
'id' => 'caching_group',
Expand Down
14 changes: 14 additions & 0 deletions src/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use CommonsBooking\Service\Cache;
use CommonsBooking\Service\Scheduler;
use CommonsBooking\Service\iCalendar;
use CommonsBooking\Service\RssFeed;
use CommonsBooking\Service\Upgrade;
use CommonsBooking\Settings\Settings;
use CommonsBooking\Repository\BookingCodes;
Expand Down Expand Up @@ -831,6 +832,19 @@ function () {

// iCal rewrite
iCalendar::initRewrite();

// RSS feed rewrite
RssFeed::initRewrite();

// Exclude admin-only CPTs from WP core sitemaps (WP 5.5+).
// Yoast SEO and RankMath respect this same filter.
// cb_item and cb_location are intentionally left in (public content).
add_filter( 'wp_sitemaps_post_types', static function ( array $types ): array {
unset( $types['cb_restriction'] );
unset( $types['cb_map'] );
return $types;
} );

}

/**
Expand Down
Loading
Loading