Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

generate sitemap.xml per site and per access public #188

Open
wants to merge 25 commits into
base: master-ibexa-4.5
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bb3f0d4
generate sitemap.xml per siteAccess && inject the multilingual and mu…
mohamed-larbi-jebari May 24, 2024
b00a797
Ibexa 4.6 seo (#190)
erdnaxelaweb Jun 4, 2024
7238354
generate sitemap.xml per siteAccess && inject the multilingual and mu…
mohamed-larbi-jebari Jun 4, 2024
93d8588
fix: issue when () are used in metas on Ibexa 4.6
Jun 24, 2024
a15adb6
fix: issue when () are used in metas on Ibexa 4.6
Jun 24, 2024
2b50789
generate sitemap.xml per siteAccess && inject the multilingual and mu…
mohamed-larbi-jebari Jun 25, 2024
370ac91
fix: CS
Jun 27, 2024
37e66d3
feat: switch ddev to node 18
Jun 27, 2024
1dbee60
Add ibexa_menu.*.yml translation file
RemyNovactive Jun 27, 2024
d194f99
Merge pull request #196 from Novactive/ezmenumanagerbundle/ibexa-4-6/…
erdnaxelaweb Jun 28, 2024
37fc577
feat: add support for siteaccess aware configuration
Jun 28, 2024
36969f0
Merge pull request #198 from Novactive/feat-SA-aware-saml-config
erdnaxelaweb Jun 28, 2024
39d78d2
Add ibexa_menu.*.yml translation file
RemyNovactive Jun 28, 2024
cff4695
novactive/ezsolrsearchextrabundle
RemyNovactive Jun 28, 2024
83f900f
Merge pull request #200 from Novactive/ezsolrsearchextrabundle/ibexa-…
erdnaxelaweb Jul 1, 2024
11472ff
Merge pull request #199 from Novactive/ibexatranslationuibundle/ibexa…
erdnaxelaweb Jul 1, 2024
7132731
Manage source url with site Access in UrlWildcardRouter
mohamed-larbi-jebari Jul 9, 2024
2671594
fix Ibexa 4.6 version in CI as later skeleton require PHP > 8.1
Jul 23, 2024
11299ac
Merge pull request #203 from Novactive/fix-ci
erdnaxelaweb Jul 23, 2024
5334fe7
fix: issue with filter tag removing `(` `)` from value
Jul 23, 2024
a84773e
Merge pull request #202 from Novactive/fix-solr-filter-tag
erdnaxelaweb Jul 23, 2024
b4e4f94
fix: issue with redirect where source is a siteaccess with en URI match
Jul 26, 2024
1afa9d1
Merge remote-tracking branch 'origin/fix-redirect' into sitemapxml_mu…
Jul 26, 2024
9ab75f9
Merge remote-tracking branch 'origin/master' into sitemapxml_multisit…
mohamed-larbi-jebari Sep 25, 2024
4ed17c2
Migration ibexa 4.6.11 && fix error $fieldTypeRegistry must not be ac…
mohamed-larbi-jebari Sep 26, 2024
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
321 changes: 256 additions & 65 deletions components/SEOBundle/bundle/Controller/SitemapController.php

Large diffs are not rendered by default.

173 changes: 173 additions & 0 deletions components/SEOBundle/bundle/Core/Helper/SiteMapHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<?php

declare(strict_types=1);

namespace Novactive\Bundle\eZSEOBundle\Core\Helper;

use Exception;
use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface;
use Ibexa\Core\MVC\Symfony\Locale\LocaleConverter;
use Ibexa\Core\MVC\Symfony\Routing\Generator\RouteReferenceGenerator;
use Ibexa\Core\MVC\Symfony\Routing\UrlAliasRouter;
use Ibexa\Core\MVC\Symfony\SiteAccess\SiteAccessServiceInterface;
use Ibexa\Migration\Log\LoggerAwareTrait;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
use Throwable;

class SiteMapHelper
{
use LoggerAwareTrait;

/**
* @var ConfigResolverInterface
*/
private $configResolver;

/**
* @var RouteReferenceGenerator
*/
private $routeReferenceGenerator;

/**
* @var RouterInterface
*/
private $router;

/**
* @var LocaleConverter
*/
private $localeConverter;

/**
* @var SiteAccessServiceInterface
*/
private $siteAccessService;

public function __construct(
ConfigResolverInterface $configResolver,
SiteAccessServiceInterface $siteAccessService,
RouteReferenceGenerator $routeReferenceGenerator,
RouterInterface $router,
LocaleConverter $localeConverter,
?LoggerInterface $logger = null
) {
$this->configResolver = $configResolver;
$this->siteAccessService = $siteAccessService;
$this->routeReferenceGenerator = $routeReferenceGenerator;
$this->router = $router;
$this->localeConverter = $localeConverter;
$this->logger = $logger ?? new NullLogger();
}

public function generateLocationUrl(
int $locationId,
string $siteAccess = null
): ?string {
try {
$routeParams['locationId'] = $locationId;
$routeReference = $this->routeReferenceGenerator->generate(
UrlAliasRouter::URL_ALIAS_ROUTE_NAME,
$routeParams
);
if ($siteAccess) {
$routeReference->set('siteaccess', $siteAccess);
}
$url = $this->router->generate(
UrlAliasRouter::URL_ALIAS_ROUTE_NAME,
$routeReference->getParams(),
UrlGeneratorInterface::ABSOLUTE_URL
);
} catch (Throwable $exception) {
$this->logger->error('NovaeZSEO: ' . $exception->getMessage());
$url = null;
}

return $url;
}
public function generateRouteUrl(
string $routeName,
string $siteAccess = null,
array $parameters = []
): ?string {
try {
$url = $this->router->generate(
$routeName,
[...['siteaccess' => $siteAccess], ...$parameters],
UrlGeneratorInterface::ABSOLUTE_URL
);
} catch (Throwable $exception) {
$this->logger->error('NovaeZSEO: ' . $exception->getMessage());
$url = null;
}

return $url;
}
public function getSiteAccessesLocationIdLanguages(): array
{

static $rootLocationLanguages = null;

if (is_array($rootLocationLanguages)) {
return $rootLocationLanguages;
}
mohamed-larbi-jebari marked this conversation as resolved.
Show resolved Hide resolved

$rootLocationLanguages = [];
$siteAccesses = $this->configResolver->getParameter('translation_siteaccesses');
foreach ($siteAccesses as $siteAccess) {
$rootLocationLanguages[$siteAccess] = [
'rootLocationId' => $this->getSiteAccessRootLocationId($siteAccess),
'mainLanguage' => $this->getSiteAccessMainLanguage($siteAccess),
'languages' => $this->getSiteAccessLanguages($siteAccess)
];
}

return $rootLocationLanguages;
}

public function getCurrentSiteAccess(): ?string
{
return $this->siteAccessService->getCurrent()?->name;
}

public function getCurrentSiteAccessRootLocationId(): ?int
{
return $this->getSiteAccessRootLocationId($this->getCurrentSiteAccess());
}
public function getCurrentSiteAccessMainLanguage(): ?string
{
return $this->getSiteAccessMainLanguage($this->getCurrentSiteAccess());
}

public function getSiteAccessRootLocationId(string $siteAccess): ?int
{
return $this->configResolver->getParameter('content.tree_root.location_id', null, $siteAccess);
}

public function getSiteAccessLanguages(string $siteAccess): array
{
return (array) $this->configResolver->getParameter('languages', null, $siteAccess);
}

public function getSiteAccessMainLanguage(string $siteAccess): string
{
$languages = $this->configResolver->getParameter('languages', null, $siteAccess);
return array_shift($languages);
}

public function getHrefLang(string $languageCode): string
{
return str_replace(
'_',
'-',
($this->localeConverter->convertToPOSIX($languageCode) ?? '')
);
}

public function logException(Exception $exception): void
{
$this->logger?->error('NovaeZSEO: ' . $exception->getMessage());
}
}
6 changes: 6 additions & 0 deletions components/SEOBundle/bundle/Core/MetaNameSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ class MetaNameSchema extends NameSchemaService
*/
private $configurationResolver;

/**
* @var FieldTypeRegistry
*/
protected $fieldTypeRegistry;

public function __construct(
ContentTypeHandler $contentTypeHandler,
FieldTypeRegistry $fieldTypeRegistry,
Expand All @@ -83,6 +88,7 @@ public function __construct(
ConfigResolverInterface $configurationResolver,
array $settings = []
) {
$this->fieldTypeRegistry = $fieldTypeRegistry;
$settings['limit'] = $this->fieldContentMaxLength;
$handler = new ContentTypeDomainMapper(
$contentTypeHandler,
Expand Down
22 changes: 18 additions & 4 deletions components/SEOBundle/bundle/Core/Sitemap/QueryFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Ibexa\Bundle\Core\DependencyInjection\Configuration\ConfigResolver;
use Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException;
use Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException;
use Ibexa\Contracts\Core\Repository\Repository;
use Ibexa\Contracts\Core\Repository\Values\Content\Location;
use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery as Query;
Expand Down Expand Up @@ -52,16 +53,28 @@ private function getRootLocation(): Location
);
}

public function __invoke(): Query
{
public function __invoke(
int $rootLocationId = null,
array $languages = [],
bool $matchAlwaysAvailable = true
): Query {
$query = new Query();

// always here, we want visible Contents
$criterions = [new Criterion\Visibility(Criterion\Visibility::VISIBLE)];

// do we want to limit per Root Location, but default we don't
$limitToRootLocation = $this->configResolver->getParameter('limit_to_rootlocation', 'nova_ezseo');
if (true === $limitToRootLocation) {
if ((int) $rootLocationId) {
try {
$rootLocation = $this->repository->getLocationService()->loadLocation($rootLocationId);
} catch (NotFoundException|UnauthorizedException $e) {
$rootLocation = null;
}
if ($rootLocation) {
$criterions[] = new Criterion\Subtree($rootLocation->pathString);
}
} elseif (true === $limitToRootLocation) {
$criterions[] = new Criterion\Subtree($this->getRootLocation()->pathString);
}

Expand All @@ -88,7 +101,8 @@ public function __invoke(): Query
)
);

$criterions[] = new Criterion\LanguageCode($this->configResolver->getParameter('languages'), true);
$languages = empty($languages) ? $this->configResolver->getParameter('languages') : $languages;
$criterions[] = new Criterion\LanguageCode($languages, $matchAlwaysAvailable);

$query->query = new Criterion\LogicalAnd($criterions);
$query->sortClauses = [new SortClause\DatePublished(Query::SORT_DESC)];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ public function getConfigTreeBuilder(): TreeBuilder
->scalarNode('google_gatracker')->defaultValue('~')->end()
->scalarNode('google_anonymizeIp')->defaultValue('~')->end()
->scalarNode('bing_verification')->defaultValue('~')->end()
->booleanNode('limit_to_rootlocation')->defaultValue('~')->end()
->booleanNode('display_images_in_sitemap')->defaultValue('~')->end()
->booleanNode('limit_to_rootlocation')->defaultFalse()->end()
->booleanNode('multi_siteaccess_sitemap')->defaultFalse()->end()
->booleanNode('multi_languages_sitemap')->defaultFalse()->end()
->booleanNode('display_images_in_sitemap')->defaultFalse()->end()
->scalarNode('fieldtype_metas_identifier')->defaultValue('metas')->end()
->arrayNode('fieldtype_metas')
->isRequired()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public function prepend(ContainerBuilder $container): void
'ez_field_templates.yml' => 'ibexa',
'variations.yml' => 'ibexa',
'admin_ui/ez_field_templates.yml' => 'ibexa',
'ibexa_locale_conversion.yml' => 'ibexa',
];

foreach ($configs as $fileName => $extensionName) {
Expand Down Expand Up @@ -68,6 +69,8 @@ public function load(array $configs, ContainerBuilder $container): void
$processor->mapSetting('bing_verification', $config);
$processor->mapSetting('limit_to_rootlocation', $config);
$processor->mapSetting('display_images_in_sitemap', $config);
$processor->mapSetting('multi_siteaccess_sitemap', $config);
$processor->mapSetting('multi_languages_sitemap', $config);
$processor->mapSetting('robots', $config);
$processor->mapConfigArray('fieldtype_metas', $config, ContextualizerInterface::MERGE_FROM_SECOND_LEVEL);
$processor->mapConfigArray('default_metas', $config);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ parameters:
nova_ezseo.default.google_anonymizeIp: ~
nova_ezseo.default.bing_verification: ~
nova_ezseo.default.custom_fallback_service: ~
nova_ezseo.default.limit_to_rootlocation: ~
nova_ezseo.default.display_images_in_sitemap: ~
nova_ezseo.default.limit_to_rootlocation: false
nova_ezseo.default.display_images_in_sitemap: false
nova_ezseo.default.multi_siteaccess_sitemap: false
nova_ezseo.default.multi_languages_sitemap: false
nova_ezseo.default.sitemap_excludes:
locations: []
subtrees: []
Expand Down
mohamed-larbi-jebari marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#list from https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
locale_conversion:
bre-BT: br_BT
rum-RO: ro_RO
mlt-MT: mt_MT
gle-IE: ga_IE
est-EE: et_EE
slv-SI: sl_SI
sla-MK: sl_MK
lav-LV: lv_LV
lit-LT: lt_LT
geo-GE: ka_GE
per-IR: fa_IR
bul-BG: bg_BG
bel-BY: be_BY
8 changes: 5 additions & 3 deletions components/SEOBundle/bundle/Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ services:
Novactive\Bundle\eZSEOBundle\Core\MetaNameSchema:
lazy: true
arguments:
$contentTypeHandler: "@Ibexa\\Contracts\\Core\\Persistence\\Content\\Type\\Handler"
$languageHandler: "@Ibexa\\Core\\Persistence\\Cache\\ContentLanguageHandler"
$translationHelper: "@Ibexa\\Core\\Helper\\TranslationHelper"
$contentTypeHandler: '@Ibexa\Contracts\Core\Persistence\Content\Type\Handler'
$languageHandler: '@Ibexa\Core\Persistence\Cache\ContentLanguageHandler'
$translationHelper: '@Ibexa\Core\Helper\TranslationHelper'
calls:
- [setRichTextConverter, ["@Ibexa\\FieldTypeRichText\\RichText\\Converter\\Html5"]]
# Note: injecting lower layer Variation Handler (AliasGenerator) as a workaround for missing Public API objects context
Expand All @@ -73,6 +73,8 @@ services:
$ioService: '@ezseo_importurls.ibexa.core.io_service'
$cacheDirectory: '%kernel.cache_dir%'

Novactive\Bundle\eZSEOBundle\Core\Helper\SiteMapHelper:

Novactive\Bundle\eZSEOBundle\Core\SiteAccessAwareEntityManagerFactory:
arguments:
$repositoryConfigurationProvider: "@Ibexa\\Bundle\\Core\\ApiLoader\\RepositoryConfigurationProvider"
Expand Down
42 changes: 42 additions & 0 deletions components/SEOBundle/documentation/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,48 @@ nova_ezseo:
contentTypeIdentifiers: ['footer','something']
```
Set `multi_siteaccess_sitemap` to true to automatically generate the index page sitemap.xml per site access.

```yml
nova_ezseo:
system:
default:
multi_siteaccess_sitemap: true
```

```html
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>https://www.example.com/fr/sitemap-1.xml</loc>
<lastmod>2024-05-31T01:04:52+00:00</lastmod>
</sitemap>
<sitemap>
<loc>https://www.example.com/en/sitemap-1.xml</loc>
<lastmod>2024-05-31T01:04:52+00:00</lastmod>
</sitemap>
</sitemapindex>
```

Set `multi_languages_sitemap` to inject the multilingual and multinational site annotations tag
Notice: this doesn't work with `multi_siteaccess_sitemap: false`.
```html
<url xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<loc>https://www.example.com/pageFr</loc>
<xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="en-GB" href="https://www.example.com/en/pageEn" />
<xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="fr-FR" href="https://www.example.com/pageFr" />
<lastmod>2024-05-03T08:48:52+00:00</lastmod>
</url>
```

```yml
nova_ezseo:
system:
default:
multi_siteaccess_sitemap: true
multi_languages_sitemap: true
```

Set "display_images_in_sitemap" to true to inject the image tags.
Notice: this doesn't work with `limit_to_rootlocation: true`.

Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"knplabs/knp-menu": "^3.1",
"behat/behat": "^3.8",
"friends-of-behat/mink-extension": "^2.5",
"ext-pdo": "*"
"ext-pdo": "*",
"ext-dom": "*"
}
}
Loading