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
26 changes: 17 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

This plugins allows you to add manage CMS pages using the Rich Editor and the Media Manager.

If you want to know more about our editor, see the [Rich Editor Plugin](https://github.com/monsieurbiz/SyliusRichEditorPlugin)
If you want to know more about our editor, see the [Rich Editor Plugin](https://github.com/monsieurbiz/SyliusRichEditorPlugin)
If you want to know more about our editor, see the [Media Manager Plugin](https://github.com/monsieurbiz/SyliusMediaManagerPlugin)

![Example of CMS Page display](screenshots/front-example.png)
Expand All @@ -34,9 +34,9 @@ composer config --no-plugins --json extra.symfony.endpoint '["https://api.github
composer require monsieurbiz/sylius-cms-page-plugin
```

If you do not use the recipes :
If you do not use the recipes :

Change your `config/bundles.php` file to add the line for the plugin :
Change your `config/bundles.php` file to add the line for the plugin :

```php
<?php
Expand All @@ -54,7 +54,7 @@ imports:
- { resource: "@MonsieurBizSyliusCmsPagePlugin/Resources/config/config.yaml" }
```

Finally import the routes in `config/routes/monsieurbiz_sylius_cms_page_plugin.yaml` :
Finally import the routes in `config/routes/monsieurbiz_sylius_cms_page_plugin.yaml` :

```yaml
monsieurbiz_cms_page_admin:
Expand Down Expand Up @@ -96,7 +96,7 @@ After migration, please create a new diff migration :
bin/console doctrine:migrations:diff
```

Then run it (if any) :
Then run it (if any) :

```php
bin/console doctrine:migrations:migrate
Expand All @@ -114,24 +114,32 @@ bin/console doctrine:migrations:migrate

## Create custom elements

You can customize and create custom elements in your page.
You can customize and create custom elements in your page.
In order to do that, you can check the [Rich Editor custom element creation](https://github.com/monsieurbiz/SyliusRichEditorPlugin#create-your-own-elements)

## Render a link to a CMS Page

You can use the `PageLink` Twig Component to render a link to any CMS Page in any of your templates.

```html
{{ component('MonsieurBizSyliusCmsPagePlugin:PageLink', {pageCode: '<code>'}) }}
```

## SEO Friendly

You can define for every page the meta title, meta description, meta
You can define for every page the meta title, meta description, meta
keywords and meta image.

## Troubleshooting

### Locale not found

We've added a new LocaleContext (`LastChanceLocaleContext`) because the locale isn't set in the request when the
condition on the route is applied.
condition on the route is applied.
Therefore, if you still have an issue with multiple locales in your project, you may need to add another LocaleContext
in order to find out your locale. The system will take care of the rest.

## Contributing

You can open an issue or a Pull Request if you want! 😘
You can open an issue or a Pull Request if you want! 😘
Thank you!
4 changes: 4 additions & 0 deletions src/DependencyInjection/MonsieurBizSyliusCmsPageExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ public function prepend(ContainerBuilder $container): void
'template_directory' => '@MonsieurBizSyliusCmsPagePlugin/components/',
'name_prefix' => 'CmsPage',
],
'MonsieurBiz\SyliusCmsPagePlugin\Twig\Component\\' => [
'template_directory' => '@MonsieurBizSyliusCmsPagePlugin/twig/components/',
'name_prefix' => 'MonsieurBizSyliusCmsPagePlugin',
],
],
]);
}
Expand Down
21 changes: 21 additions & 0 deletions src/Repository/PageRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,27 @@ public function findOneEnabledAndPublishedBySlugAndChannelCode(string $slug, str
;
}

/**
* @throws NonUniqueResultException
*/
public function findOneEnabledAndPublishedByPageCodeAndChannelCode(string $code, string $locale, ChannelInterface $channel, DateTimeInterface $dateTime): ?PageInterface
{
return $this->createQueryBuilder('p')
->innerJoin('p.translations', 'translation', 'WITH', 'translation.locale = :locale')
->andWhere(':channel MEMBER OF p.channels')
->andWhere('p.enabled = true')
->andWhere('p.code = :code')
->andWhere('p.publishAt IS NULL OR p.publishAt <= :now')
->andWhere('p.unpublishAt IS NULL OR p.unpublishAt >= :now')
->setParameter('now', $dateTime)
->setParameter('channel', $channel)
->setParameter('locale', $locale)
->setParameter('code', $code)
->getQuery()
->getOneOrNullResult()
;
}

private function createQueryBuilderExistOne(ChannelInterface $channel, ?string $locale, string $slug): QueryBuilder
{
return $this
Expand Down
2 changes: 2 additions & 0 deletions src/Repository/PageRepositoryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ public function findOneEnabledBySlugAndChannelCode(string $slug, string $localeC
public function existsOneEnabledAndPublishedByChannelAndSlug(ChannelInterface $channel, ?string $locale, string $slug, DateTimeInterface $dateTime): bool;

public function findOneEnabledAndPublishedBySlugAndChannelCode(string $slug, string $localeCode, string $channelCode, DateTimeInterface $dateTime): ?PageInterface;

public function findOneEnabledAndPublishedByPageCodeAndChannelCode(string $code, string $localeCode, ChannelInterface $channel, DateTimeInterface $dateTime): ?PageInterface;
}
3 changes: 3 additions & 0 deletions src/Resources/views/twig/components/PageLink.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{% if href and page_title %}
<a href="{{href}}" {{ attributes }}>{{page_title}}</a>
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Missing spaces around Twig variables. Should be {{ href }} and {{ page_title }} for consistency with Twig formatting standards.

Suggested change
<a href="{{href}}" {{ attributes }}>{{page_title}}</a>
<a href="{{ href }}" {{ attributes }}>{{ page_title }}</a>

Copilot uses AI. Check for mistakes.
{% endif %}
68 changes: 68 additions & 0 deletions src/Twig/Component/PageLink.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace MonsieurBiz\SyliusCmsPagePlugin\Twig\Component;

use MonsieurBiz\SyliusCmsPagePlugin\Entity\PageInterface;
use MonsieurBiz\SyliusCmsPagePlugin\Repository\PageRepositoryInterface;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Locale\Context\LocaleContextInterface;
use Sylius\TwigHooks\Twig\Component\HookableComponentTrait;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use Symfony\UX\TwigComponent\Attribute\ExposeInTemplate;

#[AsTwigComponent]
final class PageLink
{
use HookableComponentTrait;

public string $pageCode;

public function __construct(
protected LocaleContextInterface $localeContext,
protected ChannelContextInterface $channelContext,
protected PageRepositoryInterface $pageRepository,
protected UrlGeneratorInterface $urlGenerator,
) {
}

#[ExposeInTemplate('href')]
public function getHref(): string
{
$page = $this->getPage();
if (!($page instanceof PageInterface)) {
return '';
}
$url = $this->urlGenerator->generate(
'monsieurbiz_cms_page_show',
[
'_locale' => $this->localeContext->getLocaleCode(),
'slug' => $page->getSlug()
]
);
return $url;
}

#[ExposeInTemplate(name: 'page_title')]
public function getPageTitle(): string
{
$page = $this->getPage();
if (!($page instanceof PageInterface)) {
return '';
}
return $page->getTitle();
}

private function getPage(): ?PageInterface
{
$currentLocaleCode = $this->localeContext->getLocaleCode();
$channel = $this->channelContext->getChannel();
$now = new \DateTime();
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a new DateTime object on every call can cause inconsistent results if the method is called multiple times during the same request. Consider injecting a clock service or creating the DateTime once and storing it as a property.

Copilot uses AI. Check for mistakes.
return $this->pageRepository->findOneEnabledAndPublishedByPageCodeAndChannelCode(
$this->pageCode,
$currentLocaleCode,
$channel,
$now
);
}
}