Skip to content

Commit

Permalink
feat: add multilang support for sitemap
Browse files Browse the repository at this point in the history
  • Loading branch information
BernhardBaumrock committed Apr 24, 2024
1 parent ac2dc3e commit 71c6e41
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 9 deletions.
80 changes: 71 additions & 9 deletions RockFrontend.module.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ class RockFrontend extends WireData implements Module, ConfigurableModule
/** @var array */
protected $js = [];

public $langMaps;

/** @var Engine */
private $latte;

Expand Down Expand Up @@ -137,6 +139,7 @@ class RockFrontend extends WireData implements Module, ConfigurableModule
public $seo;

private $sitemapCallback;
private $sitemapOptions;

private $styles;

Expand Down Expand Up @@ -2399,11 +2402,32 @@ public function sitemap($callback = null, $options = []): void
return $page;
};
$this->sitemapCallback = $callback;
$this->sitemapOptions = $options;
wire()->addHookAfter("/sitemap.xml", $this, "sitemapRender");
wire()->addHookAfter("Modules::refresh", $this, "sitemapReset");
wire()->addHookAfter("Pages::saved", $this, "sitemapReset");
}

public function sitemapLang(Language $lang): string
{
$langs = $this->sitemapLangData();
return $langs->get($lang->name) ?: "";
}

private function sitemapLangData(): WireData
{
if ($this->sitemapLangData) return $this->sitemapLangData;
$data = new WireData();
$arr = array_filter(explode("\n", $this->langMaps));
foreach ($arr as $item) {
$item = trim($item);
$parts = explode("=", $item, 2);
$data->set($parts[0], $parts[1]);
}
$this->sitemapLangData = $data;
return $data;
}

public function sitemapMarkup(): string
{
// start timer
Expand Down Expand Up @@ -2432,13 +2456,7 @@ public function sitemapMarkup(): string
// don't traverse further down the tree
return;
} elseif ($result instanceof Page) {
// if a page is returned we create a basic default markup
$modified = date("Y-m-d", $result->modified);
$out .= "<url>\n"
. "<loc>{$result->httpUrl()}</loc>\n"
. "<lastmod>$modified</lastmod>\n"
. "</url>\n"
. $result->sitemapAppendMarkup;
$out .= $this->sitemapMarkupPage($result);
} elseif ($result) {
// custom markup returned - add it to output
$out .= "$result\n";
Expand All @@ -2459,6 +2477,41 @@ public function sitemapMarkup(): string
return $out;
}

private function sitemapMarkupPage(Page $page)
{
if ($page->noSitemap) return;

$modified = date("Y-m-d", $page->modified);
$multilang = "";

// check for multilang system
if ($this->wire->languages) {
foreach ($this->wire->languages as $lang) {
if ($lang->isDefault()) continue;

// if page is not active in this language we dont add the alternate
if ($page->get("status$lang") !== 1) continue;

$this->wire->user->language = $lang;
$multilang .= "<xhtml:link "
. "rel='alternate' "
. "hreflang='{$this->sitemapLang($lang)}' "
. "href='{$page->httpUrl()}' />\n";
}

// reset language to default for final markup (default page)
$this->wire->user->language = $this->wire->languages->getDefault();
}

// return final markup
return "<url>\n"
. "<loc>{$page->httpUrl()}</loc>\n"
. $multilang
. "<lastmod>$modified</lastmod>\n"
. "</url>\n"
. $page->sitemapAppendMarkup;
}

protected function sitemapRender()
{
// create sitemap.xml file
Expand Down Expand Up @@ -2863,7 +2916,7 @@ private function configSEO($inputfields)
$warn = '<svg style="color:#F9A825" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0-18 0m9-3v4m0 3v.01"/></svg>';
$check = '<svg style="color:#388E3C" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0-18 0"/><path d="m9 12l2 2l4-4"/></g></svg>';

if ($this->wire->config->ajax) {
if ($this->wire->config->ajax || $this->wire->input->post->langMaps) {
$http = new WireHttp();

$fs->add([
Expand All @@ -2884,7 +2937,7 @@ private function configSEO($inputfields)
? "$check sitemap.xml was found"
: "$warn no sitemap.xml in site root",
'notes' => is_file($root . "sitemap.xml")
? ''
? 'Open [sitemap.xml](/sitemap.xml)'
: 'See [docs](https://www.baumrock.com/en/processwire/modules/rockfrontend/docs/seo/).',
'columnWidth' => 50,
]);
Expand Down Expand Up @@ -2919,6 +2972,15 @@ private function configSEO($inputfields)
: 'Use [realfavicongenerator](https://realfavicongenerator.net/) to add a favicon to your site.',
'columnWidth' => 50,
]);

$fs->add([
'type' => 'textarea',
'label' => 'Sitemap Language Mappings',
'name' => 'langMaps',
'description' => 'Here you can define the language shortcode that ends up in the sitemaps "hreflang" attribute. Don\'t add the default language here.',
'notes' => 'A setting of "german=de" will lead to output hreflang=de in your sitemap, where "german" is the name of the language.',
'value' => $this->langMaps,
]);
}
}

Expand Down
11 changes: 11 additions & 0 deletions docs/seo/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,17 @@ rockfrontend()->sitemap(function (Page $page) {
});
```

If you are a module developer and want to make sure that your data pages do not appear in RockFrontend's sitemap you can set the `noSitemap` property of your page and RockFrontend will automatically exclude it.

Example of RockCommerce RootPage:

```php
class RootPage extends Page
{
public $noSitemap = true;
}
```

### Adding pages to the sitemap

Sometimes you have endpoints that are not represented by pages in the pagetree (these docs are an example as they are rendered from markdown files rather than from ProcessWire pages).
Expand Down

0 comments on commit 71c6e41

Please sign in to comment.