Skip to content

Commit

Permalink
Merge branch 'release/3.5.1' into v3
Browse files Browse the repository at this point in the history
  • Loading branch information
khalwat committed Jul 19, 2024
2 parents 11cdfe9 + c20c083 commit 6c8e4b8
Show file tree
Hide file tree
Showing 18 changed files with 78 additions and 58 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# SEOmatic Changelog

## 3.5.1 - 2024.07.19
### Changed
* Renamed the **Regenerate Sitemaps Automatically** setting to **Invalidate Sitemap Caches Automatically** for clarity

### Fixed
* Fixed an issue where getting the sitemaps via GraphQL and meta container endpoint only retrieved the first page since the switch to paginated sitemaps ([#1492](https://github.com/nystudio107/craft-seomatic/issues/1492))
* Fixed an issue where saving an entry could be slow, because SEOmatic was pointlessly trying to regenerate the sitemap cache (which is no longer a thing with paginated sitemaps) ([#1494](https://github.com/nystudio107/craft-seomatic/issues/1494))

## 3.5.0 - 2024.07.12
### Added
* Remove queue generated sitemaps, switch to paginated sitemaps to allow them to be rendered at web response time, but still be managable in size
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "nystudio107/craft-seomatic",
"description": "SEOmatic facilitates modern SEO best practices & implementation for Craft CMS 3. It is a turnkey SEO system that is comprehensive, powerful, and flexible.",
"type": "craft-plugin",
"version": "3.5.0",
"version": "3.5.1",
"keywords": [
"craft",
"cms",
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/configuring/content-seo.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Search engines no longer accept [sitemap pings](https://developers.google.com/se

SEOmatic generates sitemaps on demmand when requested on the frontend, and then caches the sitemap for future requests so they are fast.

Normally SEOmatic will invalidate the cache for a sitemap for a Section, Category Group, or Product any time you save an element. However, if you prefer to regenerate the sitemap manually you can disable the **Regenerate Sitemaps Automatically** option in SEOmatic’s Plugin Settings.
Normally SEOmatic will invalidate the cache for a sitemap for a Section, Category Group, or Product any time you save an element. However, if you prefer to invalidate the sitemap caches manually you can disable the **Invalidate Sitemap Caches Automatically** option in SEOmatic’s Plugin Settings.

![Screenshot of a console running the following command to generate a blog sitemap: `./craft seomatic/sitemap/generate --siteId=1 --handle=blog`](../resources/screenshots/seomatic-sitemap-console-command.png)

Expand Down Expand Up @@ -81,7 +81,7 @@ You can also limit it to a specific Section, Category Group, or Product handle:
```

::: tip Manually Updating Sitemaps
If you disable **Regenerate Sitemaps Automatically**, sitemaps can _only_ be updated via CLI command, or by clearing SEOmatic’s sitemap caches via **Utilities****Clear Caches**.
If you disable **Invalidate Sitemap Caches Automatically**, sitemaps can _only_ be updated via CLI command, or by clearing SEOmatic’s sitemap caches via **Utilities****Clear Caches**.
:::

### Additional Sitemaps
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/configuring/plugin-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Plugin Settings let you control various SEOmatic settings across all sites/langu
* **Plugin name** – The name used for the plugin throughout the control panel.
* **Automatic Render Enabled** – Controls whether SEOmatic automatically renders metadata on your pages. If you turn this off, you will need to manually render the metadata via `seomatic.tag.render()`, `seomatic.link.render()`, etc. Selectively disable rendering via Twig with `{% do seomatic.config.renderEnabled(false) %}`.
* **Sitemaps Enabled** – Controls whether SEOmatic will automatically render front-end sitemaps for your site.
* **Regenerate Sitemaps Automatically** – Controls whether sitemaps will automatically be regenerated when entries are saved.
* **Invalidate Sitemap Caches Automatically** – Controls whether sitemap caches will automatically be invalidated when entries are saved.
* **Include Homepage in Breadcrumbs** – Should the homepage be included in the generated Breadcrumbs JSON-LD?
* **Manually Set SEOmatic Environment** – If off, SEOmatic will automatically attempt to determine the current environment. Turn this on to manually set the environment.
* **Environment** – The server environment, either `live`, `staging`, or `local`. If `devMode` is on, SEOmatic will override this setting to local Development. This setting controls whether certain things render; for instance only in the `live` production environment will Google Analytics and other tracking tags send analytics data. SEOmatic also automatically sets the `robots` tag to `none` for everything but the `live` production environment.
Expand Down
44 changes: 35 additions & 9 deletions src/gql/resolvers/SitemapResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
use GraphQL\Type\Definition\ResolveInfo;
use nystudio107\seomatic\helpers\Gql as GqlHelper;
use nystudio107\seomatic\helpers\PluginTemplate;
use nystudio107\seomatic\helpers\Sitemap;
use nystudio107\seomatic\models\SitemapCustomTemplate;
use nystudio107\seomatic\models\SitemapIndexTemplate;
use nystudio107\seomatic\models\SitemapTemplate;
use nystudio107\seomatic\Seomatic;
use yii\web\NotFoundHttpException;

/**
Expand Down Expand Up @@ -55,15 +57,18 @@ public static function getSitemaps($source, array $arguments, $context, ResolveI
return [];
}

$sitemapList = [];
// If either of the source bundle arguments are present, get the sitemap
if (!empty($arguments['sourceBundleType']) || !empty($arguments['sourceBundleHandle'])) {
$filename = self::createFilenameFromComponents($site->groupId, $arguments['sourceBundleType'] ?? '', $arguments['sourceBundleHandle'] ?? '', $siteId);
$filenames = self::createSitemapFilenamesFromComponents($site->groupId, $arguments['sourceBundleType'] ?? '', $arguments['sourceBundleHandle'] ?? '', $siteId);

return [
self::getSitemapItemByFilename($filename),
];
foreach ($filenames as $filename) {
$sitemapList[] = self::getSitemapItemByFilename($filename);
}

return $sitemapList;
}
$sitemapList = [];

$sitemapIndexItems = [self::getSitemapIndexListEntry($siteId, $site->groupId)];

// Scrape each index for individual entries
Expand Down Expand Up @@ -151,7 +156,7 @@ protected static function getSitemapIndexListEntry($siteId, $groupId): array
*/
protected static function getSitemapItemByFilename($filename)
{
if (!preg_match('/sitemaps-(?P<groupId>\d+)-(?P<type>[\w\.*]+)-(?P<handle>[\w\.*]+)-(?P<siteId>\d+)/i', $filename, $matches)) {
if (!preg_match('/sitemaps-(?P<groupId>\d+)-(?P<type>[\w\.*]+)-(?P<handle>[\w\.*]+)-(?P<siteId>\d+)-sitemap(-p(?P<page>\d+))?/i', $filename, $matches)) {
return null;
}

Expand All @@ -171,10 +176,31 @@ protected static function getSitemapItemByFilename($filename)
* @param string $bundleType
* @param string $bundleHandle
* @param int $siteId
* @return string
* @return array
*/
protected static function createFilenameFromComponents(int $groupId, string $bundleType, string $bundleHandle, int $siteId): string
protected static function createSitemapFilenamesFromComponents(int $groupId, string $bundleType, string $bundleHandle, int $siteId): array
{
return "sitemaps-$groupId-$bundleType-$bundleHandle-$siteId-sitemap.xml";
$metaBundle = Seomatic::$plugin->metaBundles->getMetaBundleBySourceHandle($bundleType, $bundleHandle, $siteId);
if (!$metaBundle) {
return [];
}

$pageSize = $metaBundle->metaSitemapVars->sitemapPageSize ?? null;
if (!$pageSize) {
return ["sitemaps-$groupId-$bundleType-$bundleHandle-$siteId-sitemap.xml"];
}

$sitemapFilenames = [];
$seoElement = Seomatic::$plugin->seoElements->getSeoElementByMetaBundleType($metaBundle->sourceBundleType);
if ($seoElement) {
$totalElements = Sitemap::getTotalElementsInSitemap($seoElement, $metaBundle);
$pageCount = $pageSize > 0 ? ceil($totalElements / $pageSize) : 1;

for ($page = 1; $page <= $pageCount; $page++) {
$sitemapFilenames[] = sprintf('sitemaps-%d-%s-%s-%d-sitemap-p%d.xml', $groupId, $bundleType, $bundleHandle, $siteId, $page);
}
}

return $sitemapFilenames;
}
}
21 changes: 17 additions & 4 deletions src/helpers/Sitemap.php
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,23 @@ public static function generateSitemap(array $params): ?string
return implode('', $lines);
}

/**
* Return the total number of elements in a sitemap, respecting metabundle settings.
*
* @param class-string<SeoElementInterface> $seoElementClass
* @param MetaBundle $metaBundle
* @return int|null
*/
public static function getTotalElementsInSitemap(string $seoElementClass, MetaBundle $metaBundle)
{
$totalElements = $seoElementClass::sitemapElementsQuery($metaBundle)->count();

if ($metaBundle->metaSitemapVars->sitemapLimit && ($totalElements > $metaBundle->metaSitemapVars->sitemapLimit)) {
$totalElements = $metaBundle->metaSitemapVars->sitemapLimit;
}

return $totalElements;
}

/**
* Combine any per-entry type field settings from $element with the passed in
Expand Down Expand Up @@ -616,8 +633,4 @@ protected static function assetFilesSitemapLink(Asset $asset, MetaBundle $metaBu
}
}
}

protected static function getElementListSitemap(array $elements)
{
}
}
7 changes: 2 additions & 5 deletions src/models/SitemapIndexTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use nystudio107\seomatic\events\RegisterSitemapsEvent;
use nystudio107\seomatic\events\RegisterSitemapUrlsEvent;
use nystudio107\seomatic\helpers\MetaValue as MetaValueHelper;
use nystudio107\seomatic\helpers\Sitemap;
use nystudio107\seomatic\Seomatic;
use yii\base\Event;
use yii\caching\TagDependency;
Expand Down Expand Up @@ -189,11 +190,7 @@ public function render(array $params = []): string
$metaBundle->metaSitemapVars->sitemapLimit = null;
}

$totalElements = $seoElement::sitemapElementsQuery($metaBundle)->count();

if ($metaBundle->metaSitemapVars->sitemapLimit && ($totalElements > $metaBundle->metaSitemapVars->sitemapLimit)) {
$totalElements = $metaBundle->metaSitemapVars->sitemapLimit;
}
$totalElements = Sitemap::getTotalElementsInSitemap($seoElement, $metaBundle);

$pageSize = $metaBundle->metaSitemapVars->sitemapPageSize;
$pageCount = (!empty($pageSize) && $pageSize > 0) ? ceil($totalElements / $pageSize) : 1;
Expand Down
1 change: 1 addition & 0 deletions src/models/SitemapTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ public function render(array $params = []): string
$dependency = new TagDependency([
'tags' => [
self::GLOBAL_SITEMAP_CACHE_TAG,
self::SITEMAP_CACHE_TAG . $handle . $siteId,
self::SITEMAP_CACHE_TAG . $handle . $siteId . $pageCacheSuffix,
],
]);
Expand Down
1 change: 0 additions & 1 deletion src/seoelements/SeoCampaign.php
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,6 @@ public static function createContentMetaBundle(Model $sourceModel)
/** @var Site $site */
foreach ($sites as $site) {
$seoElement = self::class;
/** @var SeoElementInterface $seoElement */
Seomatic::$plugin->metaBundles->createMetaBundleFromSeoElement($seoElement, $sourceModel, $site->id);
}
}
Expand Down
1 change: 0 additions & 1 deletion src/seoelements/SeoCategory.php
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,6 @@ public static function createContentMetaBundle(Model $sourceModel)
/** @var Site $site */
foreach ($sites as $site) {
$seoElement = self::class;
/** @var SeoElementInterface $seoElement */
Seomatic::$plugin->metaBundles->createMetaBundleFromSeoElement($seoElement, $sourceModel, $site->id);
}
}
Expand Down
1 change: 0 additions & 1 deletion src/seoelements/SeoDigitalProduct.php
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,6 @@ public static function createContentMetaBundle(Model $sourceModel)
/** @var Site $site */
foreach ($sites as $site) {
$seoElement = self::class;
/** @var SeoElementInterface $seoElement */
Seomatic::$plugin->metaBundles->createMetaBundleFromSeoElement($seoElement, $sourceModel, $site->id);
}
}
Expand Down
1 change: 0 additions & 1 deletion src/seoelements/SeoEntry.php
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,6 @@ public static function createContentMetaBundle(Model $sourceModel)
/** @var Site $site */
foreach ($sites as $site) {
$seoElement = self::class;
/** @var SeoElementInterface $seoElement */
Seomatic::$plugin->metaBundles->createMetaBundleFromSeoElement($seoElement, $sourceModel, $site->id);
}
}
Expand Down
1 change: 0 additions & 1 deletion src/seoelements/SeoEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,6 @@ public static function createContentMetaBundle(Model $sourceModel)
/** @var Site $site */
foreach ($sites as $site) {
$seoElement = self::class;
/** @var SeoElementInterface $seoElement */
Seomatic::$plugin->metaBundles->createMetaBundleFromSeoElement($seoElement, $sourceModel, $site->id);
}
}
Expand Down
1 change: 0 additions & 1 deletion src/seoelements/SeoProduct.php
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,6 @@ public static function createContentMetaBundle(Model $sourceModel)
/** @var Site $site */
foreach ($sites as $site) {
$seoElement = self::class;
/** @var SeoElementInterface $seoElement */
Seomatic::$plugin->metaBundles->createMetaBundleFromSeoElement($seoElement, $sourceModel, $site->id);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/services/MetaBundles.php
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ public function updateMetaBundle(MetaBundle $metaBundle, int $siteId)
}

/**
* @param SeoElementInterface $seoElement
* @param class-string<SeoElementInterface> $seoElement
* @param Model $sourceModel
* @param int $sourceSiteId
* @param MetaBundle|null $baseConfig
Expand Down
5 changes: 2 additions & 3 deletions src/services/SeoElements.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,13 @@ class SeoElements extends Component
/**
* @param null|string $metaBundleType
*
* @return SeoElementInterface|null
* @return class-string<SeoElementInterface>|null
*/
public function getSeoElementByMetaBundleType($metaBundleType)
{
if ($metaBundleType === null) {
return null;
}
/** @var SeoElementInterface[] $seoElements */
$seoElements = $this->getAllSeoElementTypes();

return $seoElements[$metaBundleType] ?? null;
Expand All @@ -95,7 +94,7 @@ public function getSeoElementByMetaBundleType($metaBundleType)
/**
* Returns all available field type classes.
*
* @return string[] The available field type classes
* @return class-string<SeoElementInterface>[] The available field type classes
*/
public function getAllSeoElementTypes(bool $useCache = true): array
{
Expand Down
30 changes: 6 additions & 24 deletions src/services/Sitemaps.php
Original file line number Diff line number Diff line change
Expand Up @@ -522,30 +522,12 @@ public function invalidateCaches()
*/
public function invalidateSitemapCache(string $handle, ?int $siteId, string $type, bool $invalidateCache = true)
{
// Since we want a stale-while-revalidate pattern, only invalidate the cache if we're asked to
if ($invalidateCache) {
$cache = Craft::$app->getCache();
TagDependency::invalidate($cache, SitemapTemplate::SITEMAP_CACHE_TAG . $handle . $siteId);
Craft::info(
'Sitemap cache cleared: ' . $handle,
__METHOD__
);
}
$sites = Craft::$app->getSites();
if ($siteId === null) {
$siteId = $sites->currentSite->id ?? 1;
}
$site = $sites->getSiteById($siteId);
$groupId = $site->groupId;
$sitemapTemplate = SitemapTemplate::create();
$xml = $sitemapTemplate->render(
[
'groupId' => $groupId,
'type' => $type,
'handle' => $handle,
'siteId' => $siteId,
'throwException' => false,
]
// Always just invalidate the sitemap cache now, since we're doing paginated sitemaps
$cache = Craft::$app->getCache();
TagDependency::invalidate($cache, SitemapTemplate::SITEMAP_CACHE_TAG . $handle . $siteId);
Craft::info(
'Sitemap cache cleared: ' . $handle,
__METHOD__
);
}

Expand Down
4 changes: 2 additions & 2 deletions src/templates/settings/plugin/_includes/sitemaps.twig
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
}) }}

{{ forms.lightswitchField({
label: "Regenerate Sitemaps Automatically"|t("seomatic"),
instructions: "Controls whether sitemaps will automatically be regenerated when entries are saved."|t("seomatic"),
label: "Invalidate Sitemap Caches Automatically"|t("seomatic"),
instructions: "Controls whether sitemap caches will automatically be invalidated when entries are saved."|t("seomatic"),
id: "regenerateSitemapsAutomatically",
name: "regenerateSitemapsAutomatically",
on: settings.regenerateSitemapsAutomatically,
Expand Down

0 comments on commit 6c8e4b8

Please sign in to comment.