├── .github ├── FUNDING.yml └── workflows │ ├── ci.yml │ ├── ci_pipe.yml │ └── pr.yml ├── .gitignore ├── .infection.json ├── .php_cs.cache ├── .php_cs.php ├── .phpstan.neon ├── .shopware-extension.yml ├── AGENTS.md ├── CHANGELOG_de-DE.md ├── CHANGELOG_en-GB.md ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── bin └── fix-cs.sh ├── composer-ci.json ├── composer.json ├── docker-compose.yml ├── easy-coding-standard.php ├── makefile ├── phpunit.autoload.php ├── phpunit.xml ├── src ├── Content │ ├── Blog │ │ ├── Aggregate │ │ │ ├── BlogCategoryMappingDefinition.php │ │ │ └── BlogEntriesTagMappingDefinition.php │ │ ├── BlogEntitiesIndexer.php │ │ ├── BlogEntriesCollection.php │ │ ├── BlogEntriesDefinition.php │ │ ├── BlogEntriesEntity.php │ │ ├── BlogEntriesIndexingMessage.php │ │ ├── BlogEntriesTranslation │ │ │ ├── BlogEntriesTranslationCollection.php │ │ │ ├── BlogEntriesTranslationDefinition.php │ │ │ └── BlogEntriesTranslationEntity.php │ │ ├── BlogListingFilterBuildEvent.php │ │ ├── BlogSeoUrlListener.php │ │ ├── BlogSeoUrlRoute.php │ │ ├── DataResolver │ │ │ ├── BlogCategoriesCmsElementResolver.php │ │ │ ├── BlogCmsElementResolver.php │ │ │ ├── BlogDetailCmsElementResolver.php │ │ │ ├── BlogNewestListingCmsElementResolver.php │ │ │ └── BlogSingleSelectDataResolver.php │ │ ├── Events │ │ │ ├── BlogIndexerEvent.php │ │ │ ├── BlogMainFilterEvent.php │ │ │ ├── CategoriesCriteriaEvent.php │ │ │ └── NewestListingCriteriaEvent.php │ │ └── Subscriber │ │ │ └── BlogSubscriber.php │ ├── BlogAuthor │ │ ├── BlogAuthorCollection.php │ │ ├── BlogAuthorDefinition.php │ │ ├── BlogAuthorEntity.php │ │ └── BlogAuthorTranslation │ │ │ ├── BlogAuthorTranslationCollection.php │ │ │ ├── BlogAuthorTranslationDefinition.php │ │ │ └── BlogAuthorTranslationEntity.php │ ├── BlogCategory │ │ ├── BlogCategoryCollection.php │ │ ├── BlogCategoryDefinition.php │ │ ├── BlogCategoryEntity.php │ │ ├── BlogCategoryIndexer.php │ │ └── BlogCategoryTranslation │ │ │ ├── BlogCategoryTranslationCollection.php │ │ │ ├── BlogCategoryTranslationDefinition.php │ │ │ └── BlogCategoryTranslationEntity.php │ ├── Cms │ │ └── DataResolver │ │ │ └── WerklCmsSlotsDataResolver.php │ ├── Extension │ │ ├── LanguageExtension.php │ │ ├── MediaExtension.php │ │ └── SalutationExtension.php │ └── SalesChannel │ │ └── Suggest │ │ └── ProductSuggestDecorated.php ├── Controller │ ├── BlogController.php │ ├── BlogRssController.php │ ├── BlogSearchController.php │ ├── CachedBlogController.php │ ├── CachedBlogRssController.php │ ├── CachedBlogSearchController.php │ └── StoreApi │ │ ├── AbstractBlogController.php │ │ ├── BlogController.php │ │ └── BlogControllerResponse.php ├── Core │ └── Content │ │ └── Sitemap │ │ └── Provider │ │ └── BlogUrlProvider.php ├── Migration │ ├── Migration1559416986BlogEntries.php │ ├── Migration1602739765AddTeaserImageColumnToBlogEntries.php │ ├── Migration1604519670CreateWerklBlogCategoryTable.php │ ├── Migration1604520733DefaultBlogCategorySeeder.php │ ├── Migration1605031477CreateWerklBlogAuthorTable.php │ ├── Migration1612160298CreatePubslihedDateColumn.php │ ├── Migration1621260479AddVersionIdToBlogCategoryTable.php │ ├── Migration1626760242AddCustomFieldToBlogTranslation.php │ ├── Migration1647338771WerklBlogEntriesUpdate.php │ ├── Migration1649322718CreateCmsPageForBlogEntries.php │ ├── Migration1649580844AddParentVersionId.php │ ├── Migration1702998914SetSalutationIdAuthorToNullable.php │ ├── Migration1736010505Tags.php │ └── Migration1744229687TranslatableTeaserImage.php ├── Page │ ├── Blog │ │ ├── BlogPage.php │ │ ├── BlogPageCriteriaEvent.php │ │ ├── BlogPageLoadedEvent.php │ │ └── BlogPageLoader.php │ └── Search │ │ ├── BlogSearchPage.php │ │ └── BlogSearchPageLoader.php ├── Resources │ ├── app │ │ ├── administration │ │ │ ├── .eslintrc.json │ │ │ ├── babel.config.json │ │ │ ├── build │ │ │ │ └── webpack.config.js │ │ │ ├── package-lock.json │ │ │ ├── package.json │ │ │ └── src │ │ │ │ ├── init │ │ │ │ └── cms-page-type.init.js │ │ │ │ ├── main.js │ │ │ │ └── module │ │ │ │ └── blog-module │ │ │ │ ├── blocks │ │ │ │ ├── categories │ │ │ │ │ ├── component │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── werkl-cms-block-blog.html.twig │ │ │ │ │ ├── index.js │ │ │ │ │ └── preview │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── werkl-cms-preview-blog-categories.html.twig │ │ │ │ │ │ └── werkl-cms-preview-blog-categories.scss │ │ │ │ ├── detail │ │ │ │ │ ├── component │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── werkl-cms-block-blog-detail.html.twig │ │ │ │ │ ├── index.js │ │ │ │ │ └── preview │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── werkl-cms-preview-blog-detail.html.twig │ │ │ │ │ │ └── werkl-cms-preview-blog-detail.scss │ │ │ │ ├── index.js │ │ │ │ ├── listing │ │ │ │ │ ├── component │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── werkl-cms-block-blog.html.twig │ │ │ │ │ ├── index.js │ │ │ │ │ └── preview │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── werkl-cms-preview-blog-listing.html.twig │ │ │ │ │ │ └── werkl-cms-preview-blog-listing.scss │ │ │ │ ├── newest-listing │ │ │ │ │ ├── component │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── werkl-cms-block-newest-listing.html.twig │ │ │ │ │ ├── index.js │ │ │ │ │ └── preview │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── werkl-cms-preview-newest-listing.html.twig │ │ │ │ │ │ └── werkl-cms-preview-newest-listing.scss │ │ │ │ └── single-entry │ │ │ │ │ ├── component │ │ │ │ │ ├── index.js │ │ │ │ │ └── werkl-cms-block-blog-single-entry.html.twig │ │ │ │ │ ├── index.js │ │ │ │ │ └── preview │ │ │ │ │ ├── index.js │ │ │ │ │ ├── werkl-cms-preview-blog-single-entry.html.twig │ │ │ │ │ └── werkl-cms-preview-blog-single-entry.scss │ │ │ │ ├── component │ │ │ │ ├── blog-category-tree-field │ │ │ │ │ └── index.js │ │ │ │ ├── blog-category-tree │ │ │ │ │ ├── index.js │ │ │ │ │ └── werkl-blog-category-tree.html.twig │ │ │ │ ├── blog-extension-component-sections │ │ │ │ │ ├── blog-extension-component-sections.html.twig │ │ │ │ │ └── index.js │ │ │ │ ├── blog-tree-item │ │ │ │ │ ├── blog-tree-item.html.twig │ │ │ │ │ └── index.js │ │ │ │ ├── blog-vertical-tabs │ │ │ │ │ ├── blog-vertical-tabs.html.twig │ │ │ │ │ └── index.js │ │ │ │ └── index.js │ │ │ │ ├── constant │ │ │ │ └── open-blogware.constant.js │ │ │ │ ├── elements │ │ │ │ ├── blog-categories │ │ │ │ │ ├── component │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── sw-cms-el-categories.html.twig │ │ │ │ │ │ └── sw-cms-el-categories.scss │ │ │ │ │ ├── config │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── sw-cms-el-config-categories.html.twig │ │ │ │ │ ├── index.js │ │ │ │ │ └── preview │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── sw-cms-el-preview-categories.html.twig │ │ │ │ │ │ └── sw-cms-el-preview-categories.scss │ │ │ │ ├── blog-detail │ │ │ │ │ ├── component │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── werkl-blog-element-blog-detail.html.twig │ │ │ │ │ │ └── werkl-blog-element-blog-detail.scss │ │ │ │ │ ├── config │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── sw-cms-el-config-blog-detail.html.twig │ │ │ │ │ │ └── sw-cms-el-config-blog-detail.scss │ │ │ │ │ ├── index.js │ │ │ │ │ └── preview │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── werkl-blog-element-preview.html.twig │ │ │ │ │ │ └── werkl-blog-element-preview.scss │ │ │ │ ├── blog-newest-listing │ │ │ │ │ ├── component │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── werkl-cms-el-newest-listing.html.twig │ │ │ │ │ │ └── werkl-cms-el-newest-listing.scss │ │ │ │ │ ├── config │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── werkl-cms-el-config-newest-listing.html.twig │ │ │ │ │ │ └── werkl-cms-el-config-newest-listing.scss │ │ │ │ │ ├── index.js │ │ │ │ │ └── preview │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── werkl-cms-el-preview-newest-listing.html.twig │ │ │ │ │ │ └── werkl-cms-el-preview-newest-listing.scss │ │ │ │ ├── blog-single-select │ │ │ │ │ ├── component │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── sw-cms-el-blog-single-select.html.twig │ │ │ │ │ │ └── sw-cms-el-blog-single-select.scss │ │ │ │ │ ├── config │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── sw-cms-el-config-blog-single-select.html.twig │ │ │ │ │ ├── index.js │ │ │ │ │ └── preview │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── sw-cms-el-preview-blog-single-select.html.twig │ │ │ │ │ │ └── sw-cms-el-preview-blog-single-select.scss │ │ │ │ ├── blog │ │ │ │ │ ├── component │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── sw-cms-el-blog.html.twig │ │ │ │ │ │ └── sw-cms-el-blog.scss │ │ │ │ │ ├── config │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── sw-cms-el-config-blog.html.twig │ │ │ │ │ │ └── sw-cms-el-config-blog.scss │ │ │ │ │ ├── index.js │ │ │ │ │ └── preview │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── sw-cms-el-preview-blog.html.twig │ │ │ │ │ │ └── sw-cms-el-preview-blog.scss │ │ │ │ └── index.js │ │ │ │ ├── error-config.json │ │ │ │ ├── extension │ │ │ │ ├── component │ │ │ │ │ └── cms │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── werkl-cms-sidebar │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── werkl-cms-sidebar.html.twig │ │ │ │ │ │ └── werkl-cms-sidebar.scss │ │ │ │ │ │ └── werkl-cms-slot │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── werkl-cms-slot.html.twig │ │ │ │ │ │ └── werkl-cms-slot.scss │ │ │ │ ├── index.js │ │ │ │ └── sw-cms │ │ │ │ │ ├── component │ │ │ │ │ └── sw-cms-sidebar │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── sw-cms-sidebar.html.twig │ │ │ │ │ ├── index.js │ │ │ │ │ ├── page │ │ │ │ │ └── sw-cms-list │ │ │ │ │ │ └── index.js │ │ │ │ │ └── snippet │ │ │ │ │ ├── de-DE.json │ │ │ │ │ └── en-GB.json │ │ │ │ ├── helper │ │ │ │ └── shopware-version.helper.js │ │ │ │ ├── index.js │ │ │ │ ├── page │ │ │ │ ├── index.js │ │ │ │ ├── werkl-blog-author │ │ │ │ │ ├── acl │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── werkl-blog-author-create │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── werkl-blog-author-detail │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── werkl-blog-author-detail.html.twig │ │ │ │ │ │ └── werkl-blog-author-detail.scss │ │ │ │ │ └── werkl-blog-author-list │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── werkl-blog-author-list.html.twig │ │ │ │ │ │ └── werkl-blog-author-list.scss │ │ │ │ ├── werkl-blog-create │ │ │ │ │ └── index.js │ │ │ │ ├── werkl-blog-detail │ │ │ │ │ ├── acl │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── index.js │ │ │ │ │ └── werkl-blog-detail.html.twig │ │ │ │ └── werkl-blog-list │ │ │ │ │ ├── acl │ │ │ │ │ └── index.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── werkl-blog-list.scss │ │ │ │ │ └── werkl-blog-list.twig │ │ │ │ └── snippet │ │ │ │ ├── de-DE.json │ │ │ │ └── en-GB.json │ │ └── storefront │ │ │ └── src │ │ │ └── scss │ │ │ ├── base.scss │ │ │ └── layout │ │ │ └── header │ │ │ └── _search-suggest.scss │ ├── config │ │ ├── config.xml │ │ ├── plugin.png │ │ ├── routes.xml │ │ ├── routes │ │ │ └── storefront.xml │ │ └── services.xml │ ├── public │ │ ├── administration │ │ │ └── js │ │ │ │ └── werkl-open-blogware.js │ │ └── static │ │ │ ├── css │ │ │ ├── 134.css │ │ │ ├── 156.css │ │ │ ├── 16.css │ │ │ ├── 18.css │ │ │ ├── 384.css │ │ │ ├── 403.css │ │ │ ├── 425.css │ │ │ ├── 44.css │ │ │ ├── 462.css │ │ │ ├── 470.css │ │ │ ├── 485.css │ │ │ ├── 528.css │ │ │ ├── 549.css │ │ │ ├── 618.css │ │ │ ├── 656.css │ │ │ ├── 70.css │ │ │ ├── 725.css │ │ │ ├── 75.css │ │ │ ├── 788.css │ │ │ ├── 859.css │ │ │ ├── 925.css │ │ │ ├── 940.css │ │ │ └── 965.css │ │ │ └── js │ │ │ ├── 046f86b8c54d44503ccc.js │ │ │ ├── 0cac1ae2b237a54b9a41.js │ │ │ ├── 280b68c7d1e5037917db.js │ │ │ ├── 31e758e2ea9d04f41446.js │ │ │ ├── 33c36fd5d76856f33f76.js │ │ │ ├── 369933b2aab52e07a724.js │ │ │ ├── 424dc6d6d4e89dc84e40.js │ │ │ ├── 4a38dd497688ee75a124.js │ │ │ ├── 4c6e82e67679d63a7a6f.js │ │ │ ├── 592d239c99b85801ad8d.js │ │ │ ├── 5ef3c68e64f9eeacfb51.js │ │ │ ├── 728c35d301e5c3ebbd19.js │ │ │ ├── 78d3ae20c78baefc1fc0.js │ │ │ ├── 816e6ead401278aac5c0.js │ │ │ ├── 8647d6fcf498155d9ccc.js │ │ │ ├── 8b2b6c5bb0a41393003a.js │ │ │ ├── 8b4aa1d2f98e1bed6d50.js │ │ │ ├── 915ebe549e746152b355.js │ │ │ ├── 94c20f9caef696e0136f.js │ │ │ ├── 9f6b67d1842fb22e2f89.js │ │ │ ├── a425c54987986cd4842a.js │ │ │ ├── a6b24c82491b2d6f873e.js │ │ │ ├── b5b1227c870757fb6c15.js │ │ │ ├── b89d94e938ef620cefda.js │ │ │ ├── ba9211ae5cb1d9e05a45.js │ │ │ ├── baa196a2bd193a4a577c.js │ │ │ ├── c44c3ea8ca1f550a4b37.js │ │ │ ├── ca06e9e52b00474374b8.js │ │ │ ├── cea856d98329a9dd25f4.js │ │ │ ├── cee2fafb3c215193d171.js │ │ │ ├── cf416c17430c96401b8b.js │ │ │ ├── d3b8f578386315abdd6d.js │ │ │ ├── e000ae4cb18f39cd2e4c.js │ │ │ ├── e3d6829db89e813d1cc3.js │ │ │ ├── e94a84b6264cd6dfcb7f.js │ │ │ ├── ec3c4260240b6a3b8ef7.js │ │ │ ├── f5d4ebc931a30e2014fa.js │ │ │ ├── f925b3b0896cef9ced50.js │ │ │ ├── fbe93fc23dd1cbadee55.js │ │ │ └── fceb9e682485d5fab032.js │ ├── snippet │ │ ├── de_DE │ │ │ └── storefront.de-DE.json │ │ └── en_GB │ │ │ └── storefront.en-GB.json │ └── views │ │ └── storefront │ │ ├── block │ │ ├── cms-block-blog-categories.html.twig │ │ ├── cms-block-blog-detail.html.twig │ │ ├── cms-block-blog-listing.html.twig │ │ ├── cms-block-blog-newest-listing.html.twig │ │ └── cms-block-blog-single-entry.html.twig │ │ ├── component │ │ ├── blog │ │ │ ├── _partials │ │ │ │ ├── _block_author.html.twig │ │ │ │ └── _block_category.html.twig │ │ │ ├── card │ │ │ │ └── box.html.twig │ │ │ ├── listing.html.twig │ │ │ └── newest-listing.html.twig │ │ └── listing │ │ │ ├── blog-filter-panel.html.twig │ │ │ └── filter │ │ │ ├── blog-filter-multi-select-list-item.html.twig │ │ │ └── blog-filter-multi-select.html.twig │ │ ├── element │ │ ├── cms-element-blog-categories.html.twig │ │ ├── cms-element-blog-detail.html.twig │ │ ├── cms-element-blog-newest-listing.html.twig │ │ ├── cms-element-blog-single-select.html.twig │ │ └── cms-element-blog.html.twig │ │ ├── layout │ │ ├── header │ │ │ ├── blog-suggest-tab-content.html.twig │ │ │ ├── search-suggest.html.twig │ │ │ └── search.html.twig │ │ └── meta.html.twig │ │ └── page │ │ ├── blog-search │ │ ├── index.html.twig │ │ └── search-pagelet.html.twig │ │ └── rss.html.twig ├── Storefront │ └── Framework │ │ └── Seo │ │ └── SeoUrlRoute │ │ └── SeoUrlUpdateListener.php ├── Subscriber │ └── BlogCacheInvalidSubscriber.php ├── Util │ ├── Lifecycle.php │ └── Update.php └── WerklOpenBlogware.php └── tests ├── Cypress ├── .gitignore ├── README.md ├── cypress.config.example.js ├── cypress │ ├── config │ │ └── dev.json │ ├── fixtures │ │ └── example.json │ ├── integration │ │ └── administration │ │ │ ├── cms.spec.js │ │ │ └── edit.spec.js │ ├── plugins │ │ └── index.js │ └── support │ │ ├── actions │ │ └── admin │ │ │ └── BlogDetailAction.js │ │ ├── commands.js │ │ ├── index.js │ │ ├── repositories │ │ └── admin │ │ │ ├── blog │ │ │ ├── BlogDetailsRepository.js │ │ │ └── BlogFormRepository.js │ │ │ └── general │ │ │ ├── CmsPageRepository.js │ │ │ └── DatePickerRepository.js │ │ └── services │ │ └── shopware │ │ └── Shopware.js ├── makefile ├── package-lock.json └── package.json └── PHPUnit ├── Content ├── Blog │ └── Events │ │ └── BlogMainFilterEventTest.php └── Cms │ └── DataResolver │ └── SasCmsSlotsDataResolverTest.php ├── Core └── Content │ └── Sitemap │ └── Provider │ └── BlogUrlProviderTest.php ├── Fakes └── FakeEntityRepository.php ├── Page ├── Blog │ ├── BlogPageCriteriaEventTest.php │ ├── BlogPageLoadedEventTest.php │ └── BlogPageLoaderTest.php └── Search │ └── BlogSearchPageLoaderTest.php ├── Traits └── ContextTrait.php └── Util ├── LifecycleTest.php └── UpdateTest.php /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [7underlines] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### OSX 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | coverage 7 | src/Resources/app/administration/coverage 8 | src/Resources/app/administration/node_modules 9 | 10 | ## other stuff 11 | /.vscode 12 | /.idea 13 | /vendor 14 | composer.lock 15 | 16 | src/Resources/app/administration/node_modules 17 | 18 | src/Resources/app/storefront/dist/ 19 | src/Resources/app/storefront/node_modules 20 | 21 | src/Resources/public/administration/css/ 22 | src/Resources/public/administration/js/ -------------------------------------------------------------------------------- /.infection.json: -------------------------------------------------------------------------------- 1 | { 2 | "bootstrap": "./phpunit.autoload.php", 3 | "minMsi": 10, 4 | "minCoveredMsi": 10, 5 | "source": { 6 | "directories": [ 7 | "src" 8 | ], 9 | "excludes": [ 10 | "/\\Definition\\.php/", 11 | "/\\Entity\\.php/", 12 | "/\\Collection\\.php/", 13 | "Resources", 14 | "Migration" 15 | ] 16 | }, 17 | "mutators": { 18 | "@default": true 19 | }, 20 | "$schema": "vendor/infection/infection/resources/schema.json" 21 | } 22 | -------------------------------------------------------------------------------- /.php_cs.php: -------------------------------------------------------------------------------- 1 | in('src') 6 | ->exclude('vendor') 7 | ->exclude(['Resources']); 8 | 9 | return PhpCsFixer\Config::create() 10 | ->setRules([ 11 | '@PSR2' => true, 12 | 'single_quote' => true, 13 | 'function_typehint_space' => true, 14 | 'hash_to_slash_comment' => true, 15 | 'method_separation' => true, 16 | 'no_blank_lines_after_phpdoc' => true, 17 | 'no_unused_imports' => true, 18 | 'no_useless_else' => true, 19 | 'phpdoc_align' => true, 20 | 'phpdoc_order' => true, 21 | 'phpdoc_scalar' => true, 22 | 'pre_increment' => true, 23 | 'short_scalar_cast' => true, 24 | 'space_after_semicolon' => true, 25 | 'ternary_operator_spaces' => true, 26 | 'trailing_comma_in_multiline_array' => true, 27 | 'semicolon_after_instruction' => true, 28 | 'trim_array_spaces' => true, 29 | 'whitespace_after_comma_in_array' => true, 30 | 'phpdoc_add_missing_param_annotation' => true, 31 | 'ordered_imports' => true, 32 | 'binary_operator_spaces' => ['align_equals' => false, 'align_double_arrow' => true], 33 | 'concat_space' => ['spacing' => 'one'], 34 | 'array_syntax' => ['syntax' => 'short'], 35 | ]) 36 | ->setFinder($finder); 37 | -------------------------------------------------------------------------------- /.phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 8 3 | inferPrivatePropertyTypeFromConstructor: true 4 | checkMissingIterableValueType: false 5 | reportUnmatchedIgnoredErrors: false 6 | checkGenericClassInNonGenericObjectType: false 7 | paths: 8 | - ./src 9 | excludes_analyse: 10 | - ./src/Resources/app/administration/node_modules/* 11 | - ./src/Resources/app/storefront/node_modules/* 12 | - ./src/WerklOpenBlogware.php 13 | -------------------------------------------------------------------------------- /.shopware-extension.yml: -------------------------------------------------------------------------------- 1 | build: 2 | zip: 3 | composer: 4 | enabled: true 5 | assets: 6 | enabled: true 7 | enable_es_build_for_admin: true 8 | enable_es_build_for_storefront: true 9 | pack: 10 | excludes: 11 | paths: 12 | - .idea 13 | - var 14 | - .gitignore -------------------------------------------------------------------------------- /AGENTS.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Werkstattl/OpenBlogware/ba3f7ab908e3501a2a8434ebfea3344cdd19d53a/AGENTS.md -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | Be nice and respectful. 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 SMK SHAPE & SHIFT LTD 4 | Copyright (c) 2024 Werkstattl 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /bin/fix-cs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | php ../../../../dev-ops/analyze/vendor/bin/ecs check --fix --config=../../../vendor/shopware/platform/easy-coding-standard.yml 3 | -------------------------------------------------------------------------------- /composer-ci.json: -------------------------------------------------------------------------------- 1 | { 2 | "autoload": { 3 | "psr-4": { 4 | "Werkl\\OpenBlogware\\": "src/" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | shop: 3 | image: dockware/dev:latest 4 | ports: 5 | - "80:80" 6 | volumes: 7 | - .:/var/www/html/custom/plugins/WerklOpenBlogware 8 | -------------------------------------------------------------------------------- /phpunit.autoload.php: -------------------------------------------------------------------------------- 1 | addPsr4('Werkl\\OpenBlogware\\', __DIR__ . '/src', true); 8 | $classLoader->addPsr4('OpenBlogware\\Tests\\', __DIR__ . '/tests/PHPUnit', true); 9 | $classLoader->register(); 10 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | ./tests/PHPUnit/ 14 | 15 | 16 | 17 | 18 | 19 | ./src 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Content/Blog/Aggregate/BlogCategoryMappingDefinition.php: -------------------------------------------------------------------------------- 1 | addFlags(new PrimaryKey(), new Required()), 29 | (new FkField('werkl_blog_category_id', 'blogCategoryId', BlogCategoryDefinition::class))->addFlags(new PrimaryKey(), new Required()), 30 | (new ReferenceVersionField(BlogCategoryDefinition::class))->addFlags(new PrimaryKey(), new Required()), 31 | 32 | new ManyToOneAssociationField('blog', 'werkl_blog_entries_id', BlogEntriesDefinition::class, 'id', false), 33 | new ManyToOneAssociationField('blogCategory', 'werkl_blog_category_id', BlogCategoryDefinition::class, 'id', false), 34 | ]); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Content/Blog/Aggregate/BlogEntriesTagMappingDefinition.php: -------------------------------------------------------------------------------- 1 | addFlags(new PrimaryKey(), new Required()), 28 | (new FkField('tag_id', 'tagId', TagDefinition::class))->addFlags(new PrimaryKey(), new Required()), 29 | 30 | new ManyToOneAssociationField('blog', 'werkl_blog_entries_id', BlogEntriesDefinition::class, 'id', false), 31 | new ManyToOneAssociationField('tag', 'tag_id', TagDefinition::class, 'id', false), 32 | ]); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Content/Blog/BlogEntriesCollection.php: -------------------------------------------------------------------------------- 1 | addFlags(new Required()), 47 | (new StringField('slug', 'slug'))->addFlags(new Required()), 48 | new StringField('teaser', 'teaser'), 49 | new StringField('meta_title', 'metaTitle'), 50 | new StringField('meta_description', 'metaDescription'), 51 | (new LongTextField('content', 'content'))->addFlags(new AllowHtml()), 52 | (new CustomFields())->addFlags(new ApiAware()), 53 | ]); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Content/Blog/BlogListingFilterBuildEvent.php: -------------------------------------------------------------------------------- 1 | seoUrlUpdater = $seoUrlUpdater; 17 | } 18 | 19 | public static function getSubscribedEvents(): array 20 | { 21 | return [ 22 | 'werkl_blog_entries.written' => 'onBlogUpdated', 23 | ]; 24 | } 25 | 26 | public function onBlogUpdated(EntityWrittenEvent $event): void 27 | { 28 | $this->seoUrlUpdater->update(BlogSeoUrlRoute::ROUTE_NAME, $event->getIds()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Content/Blog/BlogSeoUrlRoute.php: -------------------------------------------------------------------------------- 1 | definition = $definition; 26 | } 27 | 28 | public function getConfig(): SeoUrlRouteConfig 29 | { 30 | return new SeoUrlRouteConfig( 31 | $this->definition, 32 | self::ROUTE_NAME, 33 | self::DEFAULT_TEMPLATE, 34 | true 35 | ); 36 | } 37 | 38 | public function prepareCriteria(Criteria $criteria, SalesChannelEntity $salesChannel): void 39 | { 40 | $criteria->addAssociations([ 41 | 'blogCategories', 42 | 'blogAuthor', 43 | 'tags', 44 | ]); 45 | } 46 | 47 | public function getMapping(Entity $entry, ?SalesChannelEntity $salesChannel): SeoUrlMapping 48 | { 49 | if (!$entry instanceof BlogEntriesEntity) { 50 | throw new \InvalidArgumentException('Expected BlogEntriesEntity'); 51 | } 52 | 53 | return new SeoUrlMapping( 54 | $entry, 55 | ['articleId' => $entry->getId()], 56 | [ 57 | 'entry' => $entry, 58 | ] 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Content/Blog/Events/BlogIndexerEvent.php: -------------------------------------------------------------------------------- 1 | ids = $ids; 26 | $this->context = $context; 27 | $this->skip = $skip; 28 | } 29 | 30 | public function getIds(): array 31 | { 32 | return $this->ids; 33 | } 34 | 35 | public function getContext(): Context 36 | { 37 | return $this->context; 38 | } 39 | 40 | public function getSkip(): array 41 | { 42 | return $this->skip; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Content/Blog/Events/BlogMainFilterEvent.php: -------------------------------------------------------------------------------- 1 | request = $request; 24 | $this->criteria = $criteria; 25 | $this->context = $context; 26 | } 27 | 28 | public function getRequest(): Request 29 | { 30 | return $this->request; 31 | } 32 | 33 | public function getCriteria(): Criteria 34 | { 35 | return $this->criteria; 36 | } 37 | 38 | public function getContext(): Context 39 | { 40 | return $this->context->getContext(); 41 | } 42 | 43 | public function getSalesChannelContext(): SalesChannelContext 44 | { 45 | return $this->context; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Content/Blog/Events/CategoriesCriteriaEvent.php: -------------------------------------------------------------------------------- 1 | request = $request; 24 | $this->criteria = $criteria; 25 | $this->context = $context; 26 | } 27 | 28 | public function getRequest(): Request 29 | { 30 | return $this->request; 31 | } 32 | 33 | public function getCriteria(): Criteria 34 | { 35 | return $this->criteria; 36 | } 37 | 38 | public function getContext(): Context 39 | { 40 | return $this->context->getContext(); 41 | } 42 | 43 | public function getSalesChannelContext(): SalesChannelContext 44 | { 45 | return $this->context; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Content/Blog/Events/NewestListingCriteriaEvent.php: -------------------------------------------------------------------------------- 1 | request = $request; 24 | $this->criteria = $criteria; 25 | $this->context = $context; 26 | } 27 | 28 | public function getRequest(): Request 29 | { 30 | return $this->request; 31 | } 32 | 33 | public function getCriteria(): Criteria 34 | { 35 | return $this->criteria; 36 | } 37 | 38 | public function getContext(): Context 39 | { 40 | return $this->context->getContext(); 41 | } 42 | 43 | public function getSalesChannelContext(): SalesChannelContext 44 | { 45 | return $this->context; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Content/BlogAuthor/BlogAuthorCollection.php: -------------------------------------------------------------------------------- 1 | werklBlogAuthorId; 22 | } 23 | 24 | public function setWerklBlogAuthorId(string $werklBlogAuthorId): void 25 | { 26 | $this->werklBlogAuthorId = $werklBlogAuthorId; 27 | } 28 | 29 | public function getWerklBlogAuthor(): ?BlogAuthorEntity 30 | { 31 | return $this->werklBlogAuthor; 32 | } 33 | 34 | public function setWerklBlogAuthor(BlogAuthorEntity $werklBlogAuthor): void 35 | { 36 | $this->werklBlogAuthor = $werklBlogAuthor; 37 | } 38 | 39 | public function getDescription(): ?string 40 | { 41 | return $this->description; 42 | } 43 | 44 | public function setDescription(string $description): void 45 | { 46 | $this->description = $description; 47 | } 48 | 49 | public function getCustomFields(): ?array 50 | { 51 | return $this->customFields; 52 | } 53 | 54 | public function setCustomFields(?array $customFields): void 55 | { 56 | $this->customFields = $customFields; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Content/BlogCategory/BlogCategoryCollection.php: -------------------------------------------------------------------------------- 1 | addFlags(new Required()), 41 | new CustomFields(), 42 | ]); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Content/BlogCategory/BlogCategoryTranslation/BlogCategoryTranslationEntity.php: -------------------------------------------------------------------------------- 1 | name; 22 | } 23 | 24 | public function setName(string $name): void 25 | { 26 | $this->name = $name; 27 | } 28 | 29 | public function getCustomFields(): ?array 30 | { 31 | return $this->customFields; 32 | } 33 | 34 | public function setCustomFields(?array $customFields): void 35 | { 36 | $this->customFields = $customFields; 37 | } 38 | 39 | public function getWerklBlogCategoryId(): string 40 | { 41 | return $this->werklBlogCategoryId; 42 | } 43 | 44 | public function setWerklBlogCategoryId(string $werklBlogCategoryId): void 45 | { 46 | $this->werklBlogCategoryId = $werklBlogCategoryId; 47 | } 48 | 49 | public function getWerklBlogCategory(): ?BlogCategoryEntity 50 | { 51 | return $this->werklBlogCategory; 52 | } 53 | 54 | public function setWerklBlogCategory(BlogCategoryEntity $werklBlogCategory): void 55 | { 56 | $this->werklBlogCategory = $werklBlogCategory; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Content/Extension/LanguageExtension.php: -------------------------------------------------------------------------------- 1 | add( 20 | (new OneToManyAssociationField('blogTranslations', BlogEntriesTranslationDefinition::class, 'language_id'))->addFlags(new CascadeDelete()), 21 | ); 22 | $collection->add( 23 | (new OneToManyAssociationField('blogCategoryTranslations', BlogCategoryTranslationDefinition::class, 'language_id'))->addFlags(new CascadeDelete()), 24 | ); 25 | $collection->add( 26 | (new OneToManyAssociationField('blogAuthorTranslations', BlogAuthorTranslationDefinition::class, 'language_id'))->addFlags(new CascadeDelete()), 27 | ); 28 | } 29 | 30 | public function getDefinitionClass(): string 31 | { 32 | return LanguageDefinition::class; 33 | } 34 | 35 | public function getEntityName(): string 36 | { 37 | return LanguageDefinition::ENTITY_NAME; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Content/Extension/MediaExtension.php: -------------------------------------------------------------------------------- 1 | add( 18 | new OneToOneAssociationField('blogEntriesTranslation', 'id', 'media_id', BlogEntriesTranslationDefinition::class, false), 19 | ); 20 | $collection->add( 21 | new OneToOneAssociationField('blogAuthor', 'id', 'media_id', BlogAuthorDefinition::class, false), 22 | ); 23 | } 24 | 25 | public function getDefinitionClass(): string 26 | { 27 | return MediaDefinition::class; 28 | } 29 | 30 | public function getEntityName(): string 31 | { 32 | return MediaDefinition::ENTITY_NAME; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Content/Extension/SalutationExtension.php: -------------------------------------------------------------------------------- 1 | add( 18 | (new OneToManyAssociationField('blogAuthors', BlogAuthorDefinition::class, 'salutation_id', 'id'))->addFlags(new SetNullOnDelete()), 19 | ); 20 | } 21 | 22 | public function getDefinitionClass(): string 23 | { 24 | return SalutationDefinition::class; 25 | } 26 | 27 | public function getEntityName(): string 28 | { 29 | return SalutationDefinition::ENTITY_NAME; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Controller/BlogController.php: -------------------------------------------------------------------------------- 1 | ['storefront']])] 17 | class BlogController extends StorefrontController 18 | { 19 | private BlogPageLoader $blogPageLoader; 20 | 21 | public function __construct(BlogPageLoader $blogPageLoader) 22 | { 23 | $this->blogPageLoader = $blogPageLoader; 24 | } 25 | 26 | #[Route(path: '/werkl_blog/{articleId}', name: 'werkl.frontend.blog.detail', methods: ['GET'])] 27 | public function detailAction(Request $request, SalesChannelContext $context): Response 28 | { 29 | $page = $this->blogPageLoader->load($request, $context); 30 | 31 | return $this->renderStorefront('@Storefront/storefront/page/content/index.html.twig', ['page' => $page]); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Controller/BlogSearchController.php: -------------------------------------------------------------------------------- 1 | ['storefront']])] 18 | class BlogSearchController extends StorefrontController 19 | { 20 | private BlogSearchPageLoader $blogSearchPageLoader; 21 | 22 | public function __construct( 23 | BlogSearchPageLoader $blogSearchPageLoader 24 | ) { 25 | $this->blogSearchPageLoader = $blogSearchPageLoader; 26 | } 27 | 28 | #[Route(path: '/werkl_blog_search', name: 'werkl.frontend.blog.search', methods: ['GET'])] 29 | public function search(Request $request, SalesChannelContext $context): Response 30 | { 31 | try { 32 | $page = $this->blogSearchPageLoader->load($request, $context); 33 | } catch (RoutingException $routingException) { 34 | return $this->forwardToRoute('frontend.home.page'); 35 | } 36 | 37 | return $this->renderStorefront('@Storefront/storefront/page/blog-search/index.html.twig', ['page' => $page]); 38 | } 39 | 40 | /** 41 | * @throws RoutingException 42 | */ 43 | #[Route(path: '/widgets/blog-search', name: 'widgets.blog.search.pagelet', methods: ['GET', 'POST'], defaults: ['XmlHttpRequest' => true])] 44 | public function ajax(Request $request, SalesChannelContext $context): Response 45 | { 46 | $request->request->set('no-aggregations', true); 47 | 48 | $page = $this->blogSearchPageLoader->load($request, $context); 49 | 50 | $response = $this->renderStorefront('@Storefront/storefront/page/blog-search/search-pagelet.html.twig', ['page' => $page]); 51 | $response->headers->set('x-robots-tag', 'noindex'); 52 | 53 | return $response; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Controller/StoreApi/AbstractBlogController.php: -------------------------------------------------------------------------------- 1 | object->getEntities(); 26 | 27 | return $collection; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Migration/Migration1602739765AddTeaserImageColumnToBlogEntries.php: -------------------------------------------------------------------------------- 1 | executeStatement(' 19 | ALTER TABLE 20 | werkl_blog_entries 21 | ADD 22 | COLUMN media_id BINARY(16) DEFAULT NULL 23 | AFTER 24 | id 25 | '); 26 | } 27 | 28 | public function updateDestructive(Connection $connection): void 29 | { 30 | // implement update destructive 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Migration/Migration1612160298CreatePubslihedDateColumn.php: -------------------------------------------------------------------------------- 1 | executeStatement(' 19 | ALTER TABLE 20 | werkl_blog_entries 21 | ADD 22 | COLUMN published_at DATETIME(3) NOT NULL 23 | AFTER 24 | created_at 25 | '); 26 | 27 | $connection->executeStatement(' 28 | UPDATE werkl_blog_entries SET published_at = created_at 29 | '); 30 | } 31 | 32 | public function updateDestructive(Connection $connection): void 33 | { 34 | // implement update destructive 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Migration/Migration1626760242AddCustomFieldToBlogTranslation.php: -------------------------------------------------------------------------------- 1 | executeStatement(' 19 | ALTER TABLE `werkl_blog_entries_translation` 20 | ADD COLUMN `custom_fields` json DEFAULT NULL AFTER `content`; 21 | '); 22 | } 23 | 24 | public function updateDestructive(Connection $connection): void 25 | { 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Migration/Migration1647338771WerklBlogEntriesUpdate.php: -------------------------------------------------------------------------------- 1 | updateSchema($connection); 19 | $this->createDeleteTrigger($connection); 20 | } 21 | 22 | public function updateDestructive(Connection $connection): void 23 | { 24 | // implement update destructive 25 | } 26 | 27 | public function updateSchema(Connection $connection): void 28 | { 29 | $connection->executeStatement(' 30 | ALTER TABLE `werkl_blog_entries` 31 | ADD `cms_page_id` BINARY(16) NULL AFTER `id`, 32 | ADD `cms_page_version_id` binary(16) NULL AFTER `cms_page_id`, 33 | 34 | ADD CONSTRAINT `fk.werkl_blog_entries.cms_page_id` 35 | FOREIGN KEY (`cms_page_id`, `cms_page_version_id`) 36 | REFERENCES `cms_page` (`id`, `version_id`) 37 | ON DELETE RESTRICT ON UPDATE CASCADE; 38 | '); 39 | } 40 | 41 | private function createDeleteTrigger(Connection $connection): void 42 | { 43 | $query 44 | = 'CREATE TRIGGER werkl_blog_entries_delete AFTER DELETE ON werkl_blog_entries 45 | FOR EACH ROW 46 | BEGIN 47 | IF @TRIGGER_DISABLED IS NULL OR @TRIGGER_DISABLED = 0 THEN 48 | IF (OLD.cms_page_id IS NOT NULL) THEN 49 | DELETE FROM cms_page WHERE id = OLD.cms_page_id; 50 | END IF; 51 | END IF; 52 | END;'; 53 | 54 | $this->createTrigger($connection, $query); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Migration/Migration1649580844AddParentVersionId.php: -------------------------------------------------------------------------------- 1 | executeStatement(' 21 | ALTER TABLE `werkl_blog_category` 22 | ADD `parent_version_id` BINARY(16) NULL AFTER `parent_id`, 23 | DROP FOREIGN KEY `fk.werkl_blog_category.parent_id`, 24 | DROP INDEX `fk.werkl_blog_category.parent_id`; 25 | '); 26 | $connection->executeStatement(' 27 | ALTER TABLE `werkl_blog_category` 28 | ADD CONSTRAINT `fk.werkl_blog_category.parent_id` 29 | FOREIGN KEY (`parent_id`, `parent_version_id`) 30 | REFERENCES `werkl_blog_category` (`id`, `version_id`) 31 | ON DELETE CASCADE ON UPDATE CASCADE; 32 | '); 33 | $connection->executeStatement( 34 | ' 35 | UPDATE `werkl_blog_category` SET parent_version_id = unhex(:version) 36 | ', 37 | ['version' => $version] 38 | ); 39 | } 40 | 41 | public function updateDestructive(Connection $connection): void 42 | { 43 | // implement update destructive 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Migration/Migration1702998914SetSalutationIdAuthorToNullable.php: -------------------------------------------------------------------------------- 1 | executeStatement('ALTER TABLE `werkl_blog_author` MODIFY `salutation_id` BINARY(16) NULL;'); 19 | $connection->executeStatement('ALTER TABLE `werkl_blog_author` DROP FOREIGN KEY `fk.werkl_blog_author.salutation_id`;'); 20 | $connection->executeStatement('ALTER TABLE `werkl_blog_author` ADD CONSTRAINT `fk.werkl_blog_author.salutation_id` FOREIGN KEY (`salutation_id`) REFERENCES `salutation` (`id`) ON DELETE SET NULL ON UPDATE CASCADE;'); 21 | } 22 | 23 | public function updateDestructive(Connection $connection): void 24 | { 25 | // implement update destructive 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Migration/Migration1736010505Tags.php: -------------------------------------------------------------------------------- 1 | executeStatement(' 19 | CREATE TABLE IF NOT EXISTS `werkl_blog_entries_tag` ( 20 | `werkl_blog_entries_id` BINARY(16) NOT NULL, 21 | `tag_id` BINARY(16) NOT NULL, 22 | PRIMARY KEY (`werkl_blog_entries_id`,`tag_id`), 23 | KEY `fk.werkl_blog_entries_tag.werkl_blog_entries_id` (`werkl_blog_entries_id`), 24 | KEY `fk.werkl_blog_entries_tag.tag_id` (`tag_id`), 25 | CONSTRAINT `fk.werkl_blog_entries_tag.werkl_blog_entries_id` FOREIGN KEY (`werkl_blog_entries_id`) REFERENCES `werkl_blog_entries` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, 26 | CONSTRAINT `fk.werkl_blog_entries_tag.tag_id` FOREIGN KEY (`tag_id`) REFERENCES `tag` (`id`) ON DELETE CASCADE ON UPDATE CASCADE 27 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 28 | '); 29 | } 30 | 31 | public function updateDestructive(Connection $connection): void 32 | { 33 | // implement update destructive 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Migration/Migration1744229687TranslatableTeaserImage.php: -------------------------------------------------------------------------------- 1 | addColumnToTranslationTable($connection); 21 | $this->migrateMediaIdToTranslationTable($connection); 22 | $this->removeColumnFromTable($connection); 23 | } 24 | 25 | private function addColumnToTranslationTable(Connection $connection): void 26 | { 27 | $connection->executeStatement(' 28 | ALTER TABLE `werkl_blog_entries_translation` 29 | ADD COLUMN `media_id` BINARY(16) DEFAULT NULL AFTER `language_id`; 30 | '); 31 | } 32 | 33 | private function migrateMediaIdToTranslationTable(Connection $connection): void 34 | { 35 | $connection->executeStatement(' 36 | UPDATE `werkl_blog_entries_translation` 37 | SET `media_id` = ( 38 | SELECT `media_id` 39 | FROM `werkl_blog_entries` 40 | WHERE `werkl_blog_entries`.`id` = `werkl_blog_entries_translation`.`werkl_blog_entries_id` 41 | ) 42 | WHERE `werkl_blog_entries_translation`.`language_id` = :languageId; 43 | ', [ 44 | 'languageId' => Uuid::fromHexToBytes(Defaults::LANGUAGE_SYSTEM), 45 | ]); 46 | } 47 | 48 | private function removeColumnFromTable(Connection $connection): void 49 | { 50 | $connection->executeStatement(' 51 | ALTER TABLE `werkl_blog_entries` 52 | DROP COLUMN `media_id`; 53 | '); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Page/Blog/BlogPage.php: -------------------------------------------------------------------------------- 1 | blogEntry; 19 | } 20 | 21 | public function setBlogEntry(BlogEntriesEntity $blogEntry): void 22 | { 23 | $this->blogEntry = $blogEntry; 24 | } 25 | 26 | public function getNavigationId(): ?string 27 | { 28 | return $this->navigationId; 29 | } 30 | 31 | public function setNavigationId(?string $navigationId): void 32 | { 33 | $this->navigationId = $navigationId; 34 | } 35 | 36 | public function getEntityName(): string 37 | { 38 | return BlogEntriesDefinition::ENTITY_NAME; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Page/Blog/BlogPageCriteriaEvent.php: -------------------------------------------------------------------------------- 1 | articleId = $articleId; 23 | $this->criteria = $criteria; 24 | $this->salesChannelContext = $context; 25 | } 26 | 27 | public function getArticleId(): string 28 | { 29 | return $this->articleId; 30 | } 31 | 32 | public function getCriteria(): Criteria 33 | { 34 | return $this->criteria; 35 | } 36 | 37 | public function getContext(): Context 38 | { 39 | return $this->salesChannelContext->getContext(); 40 | } 41 | 42 | public function getSalesChannelContext(): SalesChannelContext 43 | { 44 | return $this->salesChannelContext; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Page/Blog/BlogPageLoadedEvent.php: -------------------------------------------------------------------------------- 1 | page = $page; 17 | parent::__construct($salesChannelContext, $request); 18 | } 19 | 20 | public function getPage(): BlogPage 21 | { 22 | return $this->page; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Page/Search/BlogSearchPage.php: -------------------------------------------------------------------------------- 1 | searchTerm; 18 | } 19 | 20 | public function setSearchTerm(string $searchTerm): void 21 | { 22 | $this->searchTerm = $searchTerm; 23 | } 24 | 25 | public function getListing(): EntitySearchResult 26 | { 27 | return $this->listing; 28 | } 29 | 30 | public function setListing(EntitySearchResult $listing): void 31 | { 32 | $this->listing = $listing; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Resources/app/administration/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "jquery": true, 5 | "node": true, 6 | "es6": true 7 | }, 8 | "extends": [ 9 | "eslint:recommended" 10 | ], 11 | "parser": "@babel/eslint-parser", 12 | "parserOptions": { 13 | "ecmaVersion": 6, 14 | "sourceType": "module" 15 | }, 16 | "globals": { 17 | "Shopware": true, 18 | "warn": true 19 | }, 20 | "rules": { 21 | "comma-dangle": [ 22 | "error", 23 | "always-multiline" 24 | ], 25 | "one-var": [ 26 | "error", 27 | "never" 28 | ], 29 | "no-console": [ 30 | "error", 31 | { 32 | "allow": [ 33 | "warn", 34 | "error" 35 | ] 36 | } 37 | ], 38 | "no-debugger": 2, 39 | "prefer-const": "warn", 40 | "quotes": [ 41 | "warn", 42 | "single" 43 | ], 44 | "indent": [ 45 | "warn", 46 | 4, 47 | { 48 | "SwitchCase": 1 49 | } 50 | ] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Resources/app/administration/babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "plugins": [ 4 | "@babel/plugin-transform-runtime", 5 | "@babel/plugin-proposal-class-properties" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /src/Resources/app/administration/build/webpack.config.js: -------------------------------------------------------------------------------- 1 | const { join, resolve } = require('path'); 2 | 3 | module.exports = () => { 4 | return { 5 | resolve: { 6 | alias: { 7 | '@slugify': resolve( 8 | join(__dirname, '..', 'node_modules', 'slugify') 9 | ) 10 | } 11 | } 12 | }; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/Resources/app/administration/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "administration", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "slugify": "^1.4.6" 8 | }, 9 | "devDependencies": { 10 | "@babel/plugin-proposal-class-properties": "^7.16.7", 11 | "@babel/plugin-transform-runtime": "7.13.15", 12 | "@babel/preset-env": "7.13.15", 13 | "@babel/eslint-parser": "7.24.8", 14 | "babel-loader": "8.0.6", 15 | "eslint": "8.36.0", 16 | "eslint-config-standard": "17.1.0", 17 | "eslint-plugin-import": "2.27.5", 18 | "eslint-plugin-promise": "6.1.1", 19 | "eslint-plugin-standard": "^5.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/init/cms-page-type.init.js: -------------------------------------------------------------------------------- 1 | const cmsPageTypeService = Shopware.Service('cmsPageTypeService'); 2 | import BLOG from '../module/blog-module/constant/open-blogware.constant'; 3 | 4 | cmsPageTypeService.register({ 5 | name: BLOG.PAGE_TYPES.BLOG_DETAIL, 6 | icon: 'regular-file-text', 7 | }); 8 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/main.js: -------------------------------------------------------------------------------- 1 | import './module/blog-module'; 2 | import './init/cms-page-type.init'; 3 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/categories/component/index.js: -------------------------------------------------------------------------------- 1 | import template from './werkl-cms-block-blog.html.twig'; 2 | 3 | export default { 4 | template, 5 | }; 6 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/categories/component/werkl-cms-block-blog.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_block_categories %} 2 |
3 | 4 |
5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/categories/index.js: -------------------------------------------------------------------------------- 1 | const { Component } = Shopware; 2 | 3 | Component.register('sw-cms-block-blog-categories', () => import('./component')); 4 | Component.register('werkl-cms-preview-blog-categories', () => import('./preview')); 5 | 6 | Shopware.Service('cmsService').registerCmsBlock({ 7 | name: 'blog-categories', 8 | label: 'werkl-blog.blocks.blog.categories.label', 9 | category: 'werkl-blog', 10 | component: 'werkl-cms-block-categories', 11 | previewComponent: 'werkl-cms-preview-blog-categories', 12 | defaultConfig: { 13 | marginBottom: '0px', 14 | marginTop: '0px', 15 | marginLeft: '0px', 16 | marginRight: '0px', 17 | sizingMode: 'boxed', 18 | }, 19 | slots: { 20 | categories: 'blog-categories', 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/categories/preview/index.js: -------------------------------------------------------------------------------- 1 | import template from './werkl-cms-preview-blog-categories.html.twig'; 2 | import './werkl-cms-preview-blog-categories.scss'; 3 | 4 | export default { 5 | template, 6 | 7 | computed: { 8 | today() { 9 | return new Date().toLocaleDateString(); 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/categories/preview/werkl-cms-preview-blog-categories.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_preview_blog_categories %} 2 |
3 |
4 |

{{ $tc('werkl-blog.blocks.blog.categories.previewTitle') }}

5 |
6 | 7 |
8 |
9 |
10 |
11 | 12 |
13 |
14 |
15 |
16 |
17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/categories/preview/werkl-cms-preview-blog-categories.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .werkl-cms-preview-blog-categories { 4 | width: 100%; 5 | background: $color-white; 6 | font-size: 22px; 7 | color: $color-darkgray-200; 8 | font-weight: 600; 9 | border-radius: 5px; 10 | padding: 20px; 11 | 12 | h2 { 13 | grid-column: span 2; 14 | font-size: 16px; 15 | line-height: 18px; 16 | margin: 0 0 2px 0; 17 | } 18 | 19 | .werkl-cms-preview-blog-categories-item { 20 | display: grid; 21 | grid-template-columns: 1fr 1fr; 22 | grid-gap: 20px; 23 | row-gap: 0; 24 | 25 | div > div { 26 | margin: 10px 0; 27 | height: 0.7em; 28 | border-radius: 4px; 29 | background-color: $color-gray-100; 30 | } 31 | 32 | hr { 33 | max-width: 90%; 34 | margin: 10px auto; 35 | border: 1px solid $color-gray-300; 36 | } 37 | 38 | time { 39 | font-size: 12px; 40 | line-height: 14px; 41 | font-weight: normal; 42 | margin: 0 0 6px 0; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/detail/component/index.js: -------------------------------------------------------------------------------- 1 | import template from './werkl-cms-block-blog-detail.html.twig'; 2 | 3 | export default { 4 | template, 5 | }; 6 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/detail/component/werkl-cms-block-blog-detail.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_block_detail %} 2 |
3 | 4 |
5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/detail/index.js: -------------------------------------------------------------------------------- 1 | const { Component } = Shopware; 2 | 3 | Component.register('sw-cms-block-blog-detail', () => import('./component')); 4 | Component.register('werkl-cms-preview-blog-detail', () => import('./preview')); 5 | 6 | Shopware.Service('cmsService').registerCmsBlock({ 7 | name: 'blog-detail', 8 | label: 'werkl-blog.blocks.blog.detail.label', 9 | category: 'werkl-blog', 10 | component: 'werkl-cms-block-blog-detail', 11 | previewComponent: 'werkl-cms-preview-blog-detail', 12 | defaultConfig: { 13 | marginBottom: '0px', 14 | marginTop: '0px', 15 | marginLeft: '0px', 16 | marginRight: '0px', 17 | sizingMode: 'boxed', 18 | }, 19 | slots: { 20 | blogDetail: 'blog-detail', 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/detail/preview/index.js: -------------------------------------------------------------------------------- 1 | import template from './werkl-cms-preview-blog-detail.html.twig'; 2 | import './werkl-cms-preview-blog-detail.scss'; 3 | 4 | export default { 5 | template, 6 | 7 | computed: { 8 | today() { 9 | return new Date().toLocaleDateString(); 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/detail/preview/werkl-cms-preview-blog-detail.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_preview_blog_detail %} 2 |
3 |
4 |

{{ $tc('werkl-blog.blocks.blog.detail.previewTitle') }}

5 |
6 | 7 |

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, 8 | sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, 9 | sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.

10 |
11 |
12 |
13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/detail/preview/werkl-cms-preview-blog-detail.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .werkl-cms-preview-blog-detail { 4 | width: 100%; 5 | background: $color-white; 6 | font-size: 22px; 7 | color: $color-darkgray-200; 8 | font-weight: 600; 9 | border-radius: 5px; 10 | padding: 20px; 11 | 12 | h2 { 13 | grid-column: span 2; 14 | font-size: 16px; 15 | line-height: 18px; 16 | margin: 0 0 2px 0; 17 | } 18 | 19 | .werkl-cms-preview-blog-detail-item { 20 | 21 | div > div { 22 | margin: 10px 0; 23 | height: 0.7em; 24 | border-radius: 4px; 25 | background-color: $color-gray-100; 26 | } 27 | 28 | hr { 29 | max-width: 90%; 30 | margin: 10px auto; 31 | border: 1px solid $color-gray-300; 32 | } 33 | 34 | time { 35 | font-size: 12px; 36 | line-height: 14px; 37 | font-weight: normal; 38 | margin: 0 0 6px 0; 39 | } 40 | 41 | p { 42 | font-size: 12px; 43 | line-height: 14px; 44 | font-weight: normal; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/index.js: -------------------------------------------------------------------------------- 1 | import './categories'; 2 | import './detail'; 3 | import './listing'; 4 | import './newest-listing'; 5 | import './single-entry'; 6 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/listing/component/index.js: -------------------------------------------------------------------------------- 1 | import template from './werkl-cms-block-blog.html.twig'; 2 | 3 | export default { 4 | template, 5 | }; 6 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/listing/component/werkl-cms-block-blog.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_block_listing %} 2 |
3 | 4 |
5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/listing/index.js: -------------------------------------------------------------------------------- 1 | const { Component } = Shopware; 2 | 3 | Component.register('sw-cms-block-blog-listing', () => import('./component')); 4 | Component.register('werkl-cms-preview-blog-listing', () => import('./preview')); 5 | 6 | Shopware.Service('cmsService').registerCmsBlock({ 7 | name: 'blog-listing', 8 | label: 'werkl-blog.blocks.blog.listing.label', 9 | category: 'werkl-blog', 10 | component: 'werkl-cms-block-blog', 11 | previewComponent: 'werkl-cms-preview-blog-listing', 12 | defaultConfig: { 13 | marginBottom: '0px', 14 | marginTop: '0px', 15 | marginLeft: '0px', 16 | marginRight: '0px', 17 | sizingMode: 'boxed', 18 | }, 19 | slots: { 20 | listing: 'blog', 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/listing/preview/index.js: -------------------------------------------------------------------------------- 1 | import template from './werkl-cms-preview-blog-listing.html.twig'; 2 | import './werkl-cms-preview-blog-listing.scss'; 3 | 4 | export default { 5 | template, 6 | 7 | computed: { 8 | today() { 9 | return new Date().toLocaleDateString(); 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/listing/preview/werkl-cms-preview-blog-listing.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_preview_blog_listing %} 2 |
3 |
4 |

{{ $tc('werkl-blog.blocks.blog.listing.previewTitle') }}

5 |
6 | 7 |
8 |
9 |
10 |
11 | 12 |
13 |
14 |
15 |
16 |
17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/listing/preview/werkl-cms-preview-blog-listing.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .werkl-cms-preview-blog-listing { 4 | width: 100%; 5 | background: $color-white; 6 | font-size: 22px; 7 | color: $color-darkgray-200; 8 | font-weight: 600; 9 | border-radius: 5px; 10 | padding: 20px; 11 | 12 | h2 { 13 | grid-column: span 2; 14 | font-size: 16px; 15 | line-height: 18px; 16 | margin: 0 0 2px 0; 17 | } 18 | 19 | .werkl-cms-preview-blog-listing-item { 20 | display: grid; 21 | grid-template-columns: 1fr 1fr; 22 | grid-gap: 20px; 23 | row-gap: 0; 24 | 25 | div > div { 26 | margin: 10px 0; 27 | height: 0.7em; 28 | border-radius: 4px; 29 | background-color: $color-gray-100; 30 | } 31 | 32 | hr { 33 | max-width: 90%; 34 | margin: 10px auto; 35 | border: 1px solid $color-gray-300; 36 | } 37 | 38 | time { 39 | font-size: 12px; 40 | line-height: 14px; 41 | font-weight: normal; 42 | margin: 0 0 6px 0; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/newest-listing/component/index.js: -------------------------------------------------------------------------------- 1 | import template from './werkl-cms-block-newest-listing.html.twig'; 2 | 3 | export default { 4 | template, 5 | }; 6 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/newest-listing/component/werkl-cms-block-newest-listing.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_block_newest_listing %} 2 |
3 | 4 |
5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/newest-listing/index.js: -------------------------------------------------------------------------------- 1 | const { Component } = Shopware; 2 | 3 | Component.register('sw-cms-block-blog-newest-listing', () => import('./component')); 4 | Component.register('werkl-cms-preview-newest-listing', () => import('./preview')); 5 | 6 | Shopware.Service('cmsService').registerCmsBlock({ 7 | name: 'blog-newest-listing', 8 | label: 'werkl-blog.blocks.blog.newestListing.label', 9 | category: 'werkl-blog', 10 | component: 'werkl-cms-block-newest-listing', 11 | previewComponent: 'werkl-cms-preview-newest-listing', 12 | defaultConfig: { 13 | marginBottom: '0px', 14 | marginTop: '0px', 15 | marginLeft: '0px', 16 | marginRight: '0px', 17 | sizingMode: 'boxed', 18 | }, 19 | slots: { 20 | listing: 'blog-newest-listing', 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/newest-listing/preview/index.js: -------------------------------------------------------------------------------- 1 | import template from './werkl-cms-preview-newest-listing.html.twig'; 2 | import './werkl-cms-preview-newest-listing.scss'; 3 | 4 | export default { 5 | template, 6 | }; 7 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/newest-listing/preview/werkl-cms-preview-newest-listing.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_preview_newest_listing %} 2 |
3 |
4 |

{{ $tc('werkl-blog.blocks.blog.newestListing.previewTitle') }}

5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/newest-listing/preview/werkl-cms-preview-newest-listing.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .werkl-cms-preview-newest-listing { 4 | width: 100%; 5 | background: $color-white; 6 | font-size: 22px; 7 | color: $color-darkgray-200; 8 | font-weight: 600; 9 | border-radius: 5px; 10 | padding: 20px; 11 | 12 | h2 { 13 | grid-column: span 2; 14 | font-size: 16px; 15 | line-height: 18px; 16 | margin: 0 0 2px 0; 17 | } 18 | 19 | .werkl-cms-preview-newest-listing-item { 20 | display: grid; 21 | grid-template-columns: 1fr 1fr; 22 | grid-gap: 20px; 23 | row-gap: 0; 24 | 25 | div > div { 26 | margin: 10px 0; 27 | height: 0.7em; 28 | border-radius: 4px; 29 | background-color: $color-gray-100; 30 | } 31 | 32 | hr { 33 | max-width: 90%; 34 | margin: 10px auto; 35 | border: 1px solid $color-gray-300; 36 | } 37 | 38 | time { 39 | font-size: 12px; 40 | line-height: 14px; 41 | font-weight: normal; 42 | margin: 0 0 6px 0; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/single-entry/component/index.js: -------------------------------------------------------------------------------- 1 | import template from './werkl-cms-block-blog-single-entry.html.twig'; 2 | 3 | export default { 4 | template, 5 | }; 6 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/single-entry/component/werkl-cms-block-blog-single-entry.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_block_blog_single_entry %} 2 |
3 | 4 |
5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/single-entry/index.js: -------------------------------------------------------------------------------- 1 | const { Component } = Shopware; 2 | 3 | Component.register('sw-cms-block-blog-single-entry', () => import('./component')); 4 | Component.register('werkl-cms-preview-blog-single-entry', () => import('./preview')); 5 | 6 | Shopware.Service('cmsService').registerCmsBlock({ 7 | name: 'blog-single-entry', 8 | label: 'werkl-blog.blocks.blog.singleEntry.label', 9 | category: 'werkl-blog', 10 | component: 'werkl-cms-block-blog-single-entry', 11 | previewComponent: 'werkl-cms-preview-blog-single-entry', 12 | defaultConfig: { 13 | marginBottom: '0px', 14 | marginTop: '0px', 15 | marginLeft: '0px', 16 | marginRight: '0px', 17 | sizingMode: 'boxed', 18 | }, 19 | slots: { 20 | singleEntry: { 21 | type: 'blog-single-select', 22 | default: { 23 | config: { 24 | blogEntry: { 25 | source: 'static', 26 | value: null, 27 | }, 28 | }, 29 | }, 30 | }, 31 | }, 32 | }); 33 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/single-entry/preview/index.js: -------------------------------------------------------------------------------- 1 | import template from './werkl-cms-preview-blog-single-entry.html.twig'; 2 | import './werkl-cms-preview-blog-single-entry.scss'; 3 | 4 | export default { 5 | template, 6 | 7 | computed: { 8 | today() { 9 | return new Date().toLocaleDateString(); 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/single-entry/preview/werkl-cms-preview-blog-single-entry.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_preview_blog_single_entry %} 2 |
3 |
4 |

{{ $tc('werkl-blog.blocks.blog.singleEntry.previewTitle') }}

5 |
6 | 7 |
8 |
9 |
10 |
11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/blocks/single-entry/preview/werkl-cms-preview-blog-single-entry.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .werkl-cms-preview-blog-single-entry { 4 | width: 100%; 5 | background: $color-white; 6 | font-size: 22px; 7 | color: $color-darkgray-200; 8 | font-weight: 600; 9 | border-radius: 5px; 10 | padding: 20px; 11 | 12 | h2 { 13 | grid-column: span 2; 14 | font-size: 16px; 15 | line-height: 18px; 16 | margin: 0 0 2px 0; 17 | } 18 | 19 | .werkl-cms-preview-blog-single-entry-item { 20 | width: 100%; 21 | 22 | div > div { 23 | margin: 10px 0; 24 | height: 0.7em; 25 | border-radius: 4px; 26 | background-color: $color-gray-100; 27 | } 28 | 29 | hr { 30 | max-width: 90%; 31 | margin: 10px auto; 32 | border: 1px solid $color-gray-300; 33 | } 34 | 35 | time { 36 | font-size: 12px; 37 | line-height: 14px; 38 | font-weight: normal; 39 | margin: 0 0 6px 0; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/component/blog-category-tree-field/index.js: -------------------------------------------------------------------------------- 1 | const { Criteria } = Shopware.Data; 2 | 3 | export default { 4 | computed: { 5 | globalCategoryRepository() { 6 | return this.repositoryFactory.create('werkl_blog_category'); 7 | }, 8 | }, 9 | methods: { 10 | searchCategories(term) { 11 | // create criteria 12 | const categorySearchCriteria = new Criteria(1, 500); 13 | categorySearchCriteria.setTerm(term); 14 | 15 | // search for categories 16 | return this.globalCategoryRepository.search(categorySearchCriteria, Shopware.Context.api); 17 | }, 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/component/blog-category-tree/index.js: -------------------------------------------------------------------------------- 1 | import template from './werkl-blog-category-tree.html.twig'; 2 | 3 | export default { 4 | template, 5 | 6 | data() { 7 | return { 8 | blogCategory: null, 9 | translationContext: 'werkl-blog-category', 10 | }; 11 | }, 12 | 13 | methods: { 14 | changeCategory(category) { 15 | this.$emit('change-category-id', category.id); 16 | }, 17 | }, 18 | 19 | computed: { 20 | category() { 21 | return this.blogCategory; 22 | }, 23 | 24 | categoryRepository() { 25 | return this.repositoryFactory.create('werkl_blog_category'); 26 | }, 27 | 28 | disableContextMenu() { 29 | if (!this.allowEdit) { 30 | return true; 31 | } 32 | 33 | return this.currentLanguageId !== Shopware.Context.api.systemLanguageId; 34 | }, 35 | syncProducts() { 36 | return; 37 | }, 38 | }, 39 | }; 40 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/component/blog-extension-component-sections/blog-extension-component-sections.html.twig: -------------------------------------------------------------------------------- 1 |
2 | 5 |
6 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/component/blog-extension-component-sections/index.js: -------------------------------------------------------------------------------- 1 | import template from './blog-extension-component-sections.html.twig'; 2 | 3 | const { State } = Shopware; 4 | 5 | export default { 6 | template, 7 | 8 | props: { 9 | positionIdentifier: { 10 | type: String, 11 | required: true, 12 | }, 13 | }, 14 | 15 | computed: { 16 | componentSections() { 17 | return State.get('extensionComponentSections').identifier[this.positionIdentifier] ?? []; 18 | }, 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/component/blog-tree-item/blog-tree-item.html.twig: -------------------------------------------------------------------------------- 1 | {% block sw_tree_item_children_items %} 2 | 20 | {% block sw_tree_item_children_items_slots %} 21 | {% parent %} 22 | {% endblock %} 23 | 24 | {% endblock %} 25 | 26 | {% block sw_tree_items_actions_edit %} 27 | 28 | {{ $tc('werkl-blog-tree-item.actions.edit') }} 29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/component/blog-tree-item/index.js: -------------------------------------------------------------------------------- 1 | import template from './blog-tree-item.html.twig'; 2 | 3 | export default { 4 | template, 5 | 6 | computed: { 7 | parentScope() { 8 | let parentNode = this.$parent; 9 | // eslint-disable-next-line 10 | while (parentNode.$options.name !== 'sw-tree') { 11 | parentNode = parentNode.$parent; 12 | } 13 | 14 | return parentNode; 15 | }, 16 | }, 17 | 18 | data() { 19 | return { 20 | editingCategory: null, 21 | }; 22 | }, 23 | 24 | methods: { 25 | onEditCategory(category) { 26 | this.editingCategory = category; 27 | this.currentEditElement = category.id; 28 | this.editElementName(); 29 | }, 30 | 31 | onBlurTreeItemInput(item) { 32 | this.abortCreateElement(item); 33 | }, 34 | 35 | onCancelSubmit(item) { 36 | this.abortCreateElement(item); 37 | }, 38 | 39 | abortCreateElement(item) { 40 | this.currentEditElement = null; 41 | this.editingCategory = null; 42 | this.$super('abortCreateElement', item); 43 | }, 44 | }, 45 | }; 46 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/component/blog-vertical-tabs/blog-vertical-tabs.html.twig: -------------------------------------------------------------------------------- 1 | 9 | 36 | 37 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/component/blog-vertical-tabs/index.js: -------------------------------------------------------------------------------- 1 | import template from './blog-vertical-tabs.html.twig'; 2 | 3 | export default { 4 | template, 5 | 6 | props: { 7 | defaultItem: { 8 | type: String, 9 | default: 'blog', 10 | }, 11 | }, 12 | 13 | methods: { 14 | onChangeTab(name) { 15 | this.currentTab = name; 16 | }, 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/component/index.js: -------------------------------------------------------------------------------- 1 | const { Component } = Shopware; 2 | 3 | Component.extend('werkl-blog-category-tree', 'sw-category-tree', () => import('./blog-category-tree')); 4 | Component.extend('werkl-blog-category-tree-field', 'sw-category-tree-field', () => import('./blog-category-tree-field')); 5 | Component.register('werkl-blog-extension-component-sections', () => import('./blog-extension-component-sections')); 6 | Component.extend('werkl-blog-tree-item', 'sw-tree-item', () => import('./blog-tree-item')); 7 | Component.register('werkl-blog-vertical-tabs', () => import('./blog-vertical-tabs')); 8 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/constant/open-blogware.constant.js: -------------------------------------------------------------------------------- 1 | export default Object.freeze({ 2 | REQUIRED_FIELD_ERROR_CODE: 'c1051bb4-d103-4f74-8988-acbcafc7fdc3', 3 | PAGE_TYPES: { 4 | BLOG_DETAIL: 'blog_detail', 5 | }, 6 | }); 7 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-categories/component/index.js: -------------------------------------------------------------------------------- 1 | import template from './sw-cms-el-categories.html.twig'; 2 | import './sw-cms-el-categories.scss'; 3 | 4 | const { Mixin } = Shopware; 5 | 6 | export default { 7 | template, 8 | 9 | mixins: [ 10 | Mixin.getByName('cms-element'), 11 | ], 12 | 13 | created() { 14 | this.createdComponent(); 15 | }, 16 | 17 | methods: { 18 | createdComponent() { 19 | this.initElementConfig('blog-categories'); 20 | }, 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-categories/component/sw-cms-el-categories.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_element_categories_listing %} 2 |
3 |

{{ $tc('werkl-blog.elements.categories.component.elementHeadline') }}

4 | 5 | {{ $tc('werkl-blog.elements.categories.component.infoText') }} 6 | 7 |
8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-categories/component/sw-cms-el-categories.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .werkl-cms-el-categories-listing { 4 | width: 100%; 5 | border: 1px solid #dadee5; 6 | border-radius: 4px; 7 | background: $color-white; 8 | padding: 10px; 9 | 10 | .werkl-cms-el-blog-placeholder div { 11 | margin: 15px 30px; 12 | height: 1.5em; 13 | border-radius: 4px; 14 | background-color: $color-gray-100; 15 | 16 | &.werkl-cms-el-werkl-cms-el-blog__placeholder { 17 | margin: 15px 30px 15px 70px; 18 | } 19 | } 20 | 21 | hr { 22 | max-width: 90%; 23 | margin: 10px auto; 24 | border: 1px solid $color-gray-300; 25 | } 26 | 27 | h2 { 28 | margin: 10px; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-categories/config/sw-cms-el-config-categories.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_element_blog_listing_config %} 2 |
3 | {% endblock %} 4 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-categories/index.js: -------------------------------------------------------------------------------- 1 | const { Component } = Shopware; 2 | 3 | Component.register('sw-cms-el-categories', () => import('./component')); 4 | Component.register('sw-cms-el-config-categories', () => import('./config')); 5 | Component.register('sw-cms-el-preview-categories', () => import('./preview')); 6 | 7 | Shopware.Service('cmsService').registerCmsElement({ 8 | name: 'blog-categories', 9 | label: 'Blog Categories', 10 | component: 'sw-cms-el-categories', 11 | configComponent: 'sw-cms-el-config-categories', 12 | previewComponent: 'sw-cms-el-preview-categories', 13 | defaultConfig: { 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-categories/preview/index.js: -------------------------------------------------------------------------------- 1 | import template from './sw-cms-el-preview-categories.html.twig'; 2 | import './sw-cms-el-preview-categories.scss'; 3 | 4 | export default { 5 | template, 6 | }; 7 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-categories/preview/sw-cms-el-preview-categories.html.twig: -------------------------------------------------------------------------------- 1 | {% block sw_cms_element_categories_preview %} 2 |
3 |

Categories Element

4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-categories/preview/sw-cms-el-preview-categories.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .sw-cms-el-preview-categories { 4 | width: 100%; 5 | background: $color-white; 6 | font-size: 22px; 7 | color: $color-darkgray-200; 8 | font-weight: $font-weight-semi-bold; 9 | 10 | .sw-cms-el-category-placeholder-listing div { 11 | margin: 10px 0; 12 | height: 0.4em; 13 | border-radius: 25px; 14 | background-color: $color-gray-100; 15 | 16 | &.sw-cms-el-category-navigation__placeholder--subcategory { 17 | margin: 7px 20px; 18 | 19 | &:last-of-type { 20 | margin-right: 10px; 21 | } 22 | } 23 | } 24 | 25 | hr { 26 | max-width: 100%; 27 | margin: 10px auto; 28 | height: 1px; 29 | border: 0 none; 30 | background-color: $color-gray-300; 31 | } 32 | 33 | p { 34 | font-size: 14px; 35 | margin: auto 10px auto 0; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-detail/component/index.js: -------------------------------------------------------------------------------- 1 | import template from './werkl-blog-element-blog-detail.html.twig'; 2 | import './werkl-blog-element-blog-detail.scss'; 3 | 4 | const { Mixin } = Shopware; 5 | 6 | export default { 7 | template, 8 | 9 | mixins: [ 10 | Mixin.getByName('cms-element'), 11 | ], 12 | 13 | created() { 14 | this.createdComponent(); 15 | }, 16 | 17 | methods: { 18 | createdComponent() { 19 | this.initElementConfig('blog-detail'); 20 | }, 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-detail/component/werkl-blog-element-blog-detail.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_element_blog_detail %} 2 |
3 |

{{ $tc('werkl-blog.elements.detail.component.elementHeadline') }}

4 | 5 | {{ $tc('werkl-blog.elements.detail.component.infoText') }} 6 | 7 |
8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-detail/component/werkl-blog-element-blog-detail.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .werkl-cms-el-blog-detail { 4 | width: 100%; 5 | border: 1px solid #dadee5; 6 | border-radius: 4px; 7 | background: $color-white; 8 | padding: 10px; 9 | 10 | .werkl-cms-el-blog-placeholder div { 11 | margin: 15px 30px; 12 | height: 1.5em; 13 | border-radius: 4px; 14 | background-color: $color-gray-100; 15 | 16 | &.werkl-cms-el-werkl-cms-el-blog__placeholder { 17 | margin: 15px 30px 15px 70px; 18 | } 19 | } 20 | 21 | hr { 22 | max-width: 90%; 23 | margin: 10px auto; 24 | border: 1px solid $color-gray-300; 25 | } 26 | 27 | h2 { 28 | margin: 10px; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-detail/config/index.js: -------------------------------------------------------------------------------- 1 | import template from './sw-cms-el-config-blog-detail.html.twig'; 2 | import './sw-cms-el-config-blog-detail.scss'; 3 | 4 | const { Mixin } = Shopware; 5 | 6 | export default { 7 | template, 8 | 9 | inject: ['repositoryFactory'], 10 | 11 | mixins: [ 12 | Mixin.getByName('cms-element'), 13 | ], 14 | 15 | created() { 16 | this.createdComponent(); 17 | }, 18 | 19 | methods: { 20 | createdComponent() { 21 | this.initElementConfig('blog'); 22 | }, 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-detail/config/sw-cms-el-config-blog-detail.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_element_blog_detail_config %} 2 |
3 | 4 | {% block werkl_cms_element_blog_detail_config_show_meta %} 5 | 11 | 12 | 15 | 16 | 17 | 20 | 21 | 22 | 25 | 26 | 27 | {% endblock %} 28 | 29 |
30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-detail/config/sw-cms-el-config-blog-detail.scss: -------------------------------------------------------------------------------- 1 | .sw-blog-detail-config-filter { 2 | 3 | .sw-field--checkbox { 4 | &:last-child { 5 | margin-bottom: 0; 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-detail/index.js: -------------------------------------------------------------------------------- 1 | const { Component } = Shopware; 2 | 3 | Component.register('werkl-blog-el-blog-detail', () => import('./component')); 4 | Component.register('sw-cms-el-config-blog-detail', () => import('./config')); 5 | Component.register('werkl-blog-el-blog-detail-preview', () => import('./preview')); 6 | 7 | Shopware.Service('cmsService').registerCmsElement({ 8 | name: 'blog-detail', 9 | label: 'Blog Detail', 10 | component: 'werkl-blog-el-blog-detail', 11 | configComponent: 'sw-cms-el-config-blog-detail', 12 | previewComponent: 'werkl-blog-el-blog-detail-preview', 13 | defaultConfig: { 14 | showCategory: { 15 | source: 'static', 16 | value: true, 17 | }, 18 | showAuthor: { 19 | source: 'static', 20 | value: true, 21 | }, 22 | fullWidth: { 23 | source: 'static', 24 | value: false, 25 | }, 26 | }, 27 | }); 28 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-detail/preview/index.js: -------------------------------------------------------------------------------- 1 | import template from './werkl-blog-element-preview.html.twig'; 2 | import './werkl-blog-element-preview.scss'; 3 | 4 | export default { 5 | template, 6 | }; 7 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-detail/preview/werkl-blog-element-preview.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_blog_element_previews %} 2 |
3 |

Lorem ipsum dolor

4 |

5 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, 6 | sed diam nonumy eirmod tempor invidunt ut labore et dolore magna. 7 |

8 |
9 | {% endblock %} 10 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-detail/preview/werkl-blog-element-preview.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .sw-cms-el-preview-blog { 4 | width: 100%; 5 | background: $color-white; 6 | font-size: 22px; 7 | color: $color-darkgray-200; 8 | font-weight: 600; 9 | 10 | .sw-cms-el-category-placeholder-listing div { 11 | margin: 10px 0; 12 | height: 0.4em; 13 | border-radius: 25px; 14 | background-color: $color-gray-100; 15 | 16 | &.sw-cms-el-category-navigation__placeholder--subcategory { 17 | margin: 7px 20px 7px 20px; 18 | 19 | &:last-of-type { 20 | margin-right: 10px; 21 | } 22 | } 23 | } 24 | 25 | hr { 26 | max-width: 100%; 27 | margin: 10px auto; 28 | height: 1px; 29 | border: 0 none; 30 | background-color: $color-gray-300; 31 | } 32 | 33 | p { 34 | font-size: 14px; 35 | margin: auto 10px auto 0; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-newest-listing/component/index.js: -------------------------------------------------------------------------------- 1 | import template from './werkl-cms-el-newest-listing.html.twig'; 2 | import './werkl-cms-el-newest-listing.scss'; 3 | 4 | const { Mixin } = Shopware; 5 | 6 | export default { 7 | template, 8 | 9 | mixins: [ 10 | Mixin.getByName('cms-element'), 11 | ], 12 | 13 | created() { 14 | this.createdComponent(); 15 | }, 16 | 17 | methods: { 18 | createdComponent() { 19 | this.initElementConfig('blog-newest-listing'); 20 | this.initElementData('blog-newest-listing'); 21 | }, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-newest-listing/component/werkl-cms-el-newest-listing.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_el_newest_listing %} 2 |
3 |

{{ $tc('werkl-blog.elements.newestListing.component.elementHeadline') }}

4 | 5 | {{ $tc('werkl-blog.elements.newestListing.component.infoText') }} 6 | 7 |
8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-newest-listing/component/werkl-cms-el-newest-listing.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .werkl-cms-el-newest-listing { 4 | width: 100%; 5 | border: 1px solid #dadee5; 6 | border-radius: 4px; 7 | background: $color-white; 8 | padding: 10px; 9 | 10 | h2 { 11 | margin: 10px; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-newest-listing/config/werkl-cms-el-config-newest-listing.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .werkl-cms-el-config-newest-listing { 4 | width: 100%; 5 | } 6 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-newest-listing/index.js: -------------------------------------------------------------------------------- 1 | const { Component } = Shopware; 2 | 3 | Component.register('werkl-cms-el-newest-listing', () => import('./component')); 4 | Component.register('werkl-cms-el-config-newest-listing', () => import('./config')); 5 | Component.register('werkl-cms-el-preview-newest-listing', () => import('./preview')); 6 | 7 | Shopware.Service('cmsService').registerCmsElement({ 8 | name: 'blog-newest-listing', 9 | label: 'werkl-blog.elements.newestListing.preview.label', 10 | component: 'werkl-cms-el-newest-listing', 11 | configComponent: 'werkl-cms-el-config-newest-listing', 12 | previewComponent: 'werkl-cms-el-preview-newest-listing', 13 | defaultConfig: { 14 | itemCount: { 15 | source: 'static', 16 | value: 5, 17 | }, 18 | offsetCount: { 19 | source: 'static', 20 | value: 0, 21 | }, 22 | showType: { 23 | source: 'static', 24 | value: 'all', 25 | }, 26 | blogCategories: { 27 | source: 'static', 28 | value: null, 29 | entity: { 30 | name: 'werkl_blog_categories', 31 | }, 32 | }, 33 | }, 34 | }); 35 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-newest-listing/preview/index.js: -------------------------------------------------------------------------------- 1 | import template from './werkl-cms-el-preview-newest-listing.html.twig'; 2 | import './werkl-cms-el-preview-newest-listing.scss'; 3 | 4 | export default { 5 | template, 6 | }; 7 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-newest-listing/preview/werkl-cms-el-preview-newest-listing.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_element_newest_listing_preview %} 2 |
3 |

Newest Listing Element

4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-newest-listing/preview/werkl-cms-el-preview-newest-listing.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .werkl-cms-el-preview-newest-listing { 4 | width: 100%; 5 | background: $color-white; 6 | font-size: 22px; 7 | color: $color-darkgray-200; 8 | font-weight: $font-weight-semi-bold; 9 | 10 | .werkl-cms-el-category-placeholder-listing div { 11 | margin: 10px 0; 12 | height: 0.4em; 13 | border-radius: 25px; 14 | background-color: $color-gray-100; 15 | 16 | &.werkl-cms-el-category-navigation__placeholder--subcategory { 17 | margin: 7px 20px; 18 | 19 | &:last-of-type { 20 | margin-right: 10px; 21 | } 22 | } 23 | } 24 | 25 | hr { 26 | max-width: 100%; 27 | margin: 10px auto; 28 | height: 1px; 29 | border: 0 none; 30 | background-color: $color-gray-300; 31 | } 32 | 33 | p { 34 | font-size: 14px; 35 | margin: auto 10px auto 0; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-single-select/component/sw-cms-el-blog-single-select.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_element_blog_single_select %} 2 |
3 |
{{ categoryName }}
4 |

{{ title }}

5 | 6 |

{{ teaser }}

7 |
8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-single-select/component/sw-cms-el-blog-single-select.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .werkl-cms-el-blog-single-select { 4 | width: 100%; 5 | padding: 20px; 6 | 7 | h6 { 8 | color: #0063AE; 9 | font-size: 14px; 10 | text-transform: uppercase; 11 | margin-bottom: 0; 12 | line-height: 1.2; 13 | } 14 | 15 | h3 { 16 | margin: 7px 0 18px; 17 | color: #343434; 18 | font-size: 23px; 19 | line-height: 1.2; 20 | } 21 | 22 | img { 23 | width: 100%; 24 | height: 100%; 25 | max-height: 225px; 26 | object-fit: cover; 27 | } 28 | 29 | p { 30 | margin: 18px 0; 31 | display: block; 32 | } 33 | } -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-single-select/config/index.js: -------------------------------------------------------------------------------- 1 | import template from './sw-cms-el-config-blog-single-select.html.twig'; 2 | 3 | const { Mixin } = Shopware; 4 | 5 | export default { 6 | template, 7 | 8 | inject: ['repositoryFactory'], 9 | 10 | mixins: [ 11 | Mixin.getByName('cms-element'), 12 | ], 13 | 14 | data() { 15 | return { 16 | blogEntry: null, 17 | selectedEntry: null, 18 | }; 19 | }, 20 | computed: { 21 | blogEntryRepository() { 22 | return this.repositoryFactory.create('werkl_blog_entries'); 23 | }, 24 | }, 25 | 26 | created() { 27 | this.createdComponent(); 28 | }, 29 | 30 | methods: { 31 | createdComponent() { 32 | this.initElementConfig('blog-single-select'); 33 | }, 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-single-select/config/sw-cms-el-config-blog-single-select.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_element_blog_single_select_config %} 2 |
3 | 8 | 9 | 14 | 15 | 22 | 23 |
24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-single-select/index.js: -------------------------------------------------------------------------------- 1 | const { Component } = Shopware; 2 | 3 | Component.register('sw-cms-el-blog-single-select', () => import('./component')); 4 | Component.register('sw-cms-el-config-blog-single-select', () => import('./config')); 5 | Component.register('sw-cms-el-preview-blog-single-select', () => import('./preview')); 6 | 7 | Shopware.Service('cmsService').registerCmsElement({ 8 | name: 'blog-single-select', 9 | label: 'werkl-blog.elements.single-select.label', 10 | component: 'sw-cms-el-blog-single-select', 11 | configComponent: 'sw-cms-el-config-blog-single-select', 12 | previewComponent: 'sw-cms-el-preview-blog-single-select', 13 | defaultConfig: { 14 | blogEntry: { 15 | source: 'static', 16 | value: null, 17 | entity: { 18 | name: 'werkl_blog_entries', 19 | }, 20 | }, 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-single-select/preview/index.js: -------------------------------------------------------------------------------- 1 | import template from './sw-cms-el-preview-blog-single-select.html.twig'; 2 | import './sw-cms-el-preview-blog-single-select.scss'; 3 | 4 | const { Filter } = Shopware; 5 | 6 | export default { 7 | template, 8 | 9 | computed: { 10 | assetFilter() { 11 | return Filter.getByName('asset'); 12 | }, 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-single-select/preview/sw-cms-el-preview-blog-single-select.html.twig: -------------------------------------------------------------------------------- 1 | {% block sw_cms_element_blog_single_select_preview %} 2 |
3 |
{{ $tc('werkl-blog.elements.single-select.previewText') }}
4 | 5 |
6 |
7 |
8 |
9 |
10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog-single-select/preview/sw-cms-el-preview-blog-single-select.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .sw-cms-el-preview-blog-single-select { 4 | width: 100%; 5 | background: $color-white; 6 | font-size: 22px; 7 | color: $color-darkgray-200; 8 | font-weight: 600; 9 | 10 | h6 { 11 | font-size: 14px; 12 | margin: auto 10px auto 0; 13 | } 14 | 15 | .sw-cms-el-category-placeholder-listing div { 16 | margin: 7px 0; 17 | height: 0.4em; 18 | border-radius: 25px; 19 | background-color: $color-gray-100; 20 | } 21 | 22 | img { 23 | width: 100%; 24 | height: 50px; 25 | object-fit: cover; 26 | margin-top: 5px; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog/component/index.js: -------------------------------------------------------------------------------- 1 | import template from './sw-cms-el-blog.html.twig'; 2 | import './sw-cms-el-blog.scss'; 3 | 4 | const { Mixin } = Shopware; 5 | 6 | export default { 7 | template, 8 | 9 | mixins: [ 10 | Mixin.getByName('cms-element'), 11 | ], 12 | 13 | created() { 14 | this.createdComponent(); 15 | }, 16 | 17 | methods: { 18 | createdComponent() { 19 | this.initElementConfig('blog'); 20 | }, 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog/component/sw-cms-el-blog.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_cms_element_blog_listing %} 2 |
3 |

{{ $tc('werkl-blog.elements.listing.component.elementHeadline') }}

4 | 5 | {{ $tc('werkl-blog.elements.listing.component.infoText') }} 6 | 7 |
8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog/component/sw-cms-el-blog.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .werkl-cms-el-blog-listing { 4 | width: 100%; 5 | border: 1px solid #dadee5; 6 | border-radius: 4px; 7 | background: $color-white; 8 | padding: 10px; 9 | 10 | .werkl-cms-el-blog-placeholder div { 11 | margin: 15px 30px; 12 | height: 1.5em; 13 | border-radius: 4px; 14 | background-color: $color-gray-100; 15 | 16 | &.werkl-cms-el-werkl-cms-el-blog__placeholder { 17 | margin: 15px 30px 15px 70px; 18 | } 19 | } 20 | 21 | hr { 22 | max-width: 90%; 23 | margin: 10px auto; 24 | border: 1px solid $color-gray-300; 25 | } 26 | 27 | h2 { 28 | margin: 10px; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog/config/sw-cms-el-config-blog.scss: -------------------------------------------------------------------------------- 1 | .sw-blog-config-filter { 2 | 3 | .sw-field--checkbox { 4 | &:last-child { 5 | margin-bottom: 0; 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog/index.js: -------------------------------------------------------------------------------- 1 | const { Component } = Shopware; 2 | 3 | Component.register('sw-cms-el-blog', () => import('./component')); 4 | Component.register('sw-cms-el-config-blog', () => import('./config')); 5 | Component.register('sw-cms-el-preview-blog', () => import('./preview')); 6 | 7 | Shopware.Service('cmsService').registerCmsElement({ 8 | name: 'blog', 9 | label: 'Blog', 10 | component: 'sw-cms-el-blog', 11 | configComponent: 'sw-cms-el-config-blog', 12 | previewComponent: 'sw-cms-el-preview-blog', 13 | defaultConfig: { 14 | paginationCount: { 15 | source: 'static', 16 | value: 5, 17 | }, 18 | showType: { 19 | source: 'static', 20 | value: 'all', 21 | }, 22 | showCategoryFilter: { 23 | source: 'static', 24 | value: true, 25 | }, 26 | showAuthorFilter: { 27 | source: 'static', 28 | value: true, 29 | }, 30 | blogCategories: { 31 | source: 'static', 32 | value: null, 33 | entity: { 34 | name: 'werkl_blog_categories', 35 | }, 36 | }, 37 | showTags: { 38 | source: 'static', 39 | value: 'all', 40 | }, 41 | blogTags: { 42 | source: 'static', 43 | value: null, 44 | entity: { 45 | name: 'tag', 46 | }, 47 | }, 48 | }, 49 | }); 50 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog/preview/index.js: -------------------------------------------------------------------------------- 1 | import template from './sw-cms-el-preview-blog.html.twig'; 2 | import './sw-cms-el-preview-blog.scss'; 3 | 4 | export default { 5 | template, 6 | }; 7 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog/preview/sw-cms-el-preview-blog.html.twig: -------------------------------------------------------------------------------- 1 | {% block sw_cms_element_blog_preview %} 2 |
3 |

Blog Listing Element

4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/blog/preview/sw-cms-el-preview-blog.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .sw-cms-el-preview-blog { 4 | width: 100%; 5 | background: $color-white; 6 | font-size: 22px; 7 | color: $color-darkgray-200; 8 | font-weight: $font-weight-semi-bold; 9 | 10 | .sw-cms-el-category-placeholder-listing div { 11 | margin: 10px 0; 12 | height: 0.4em; 13 | border-radius: 25px; 14 | background-color: $color-gray-100; 15 | 16 | &.sw-cms-el-category-navigation__placeholder--subcategory { 17 | margin: 7px 20px; 18 | 19 | &:last-of-type { 20 | margin-right: 10px; 21 | } 22 | } 23 | } 24 | 25 | hr { 26 | max-width: 100%; 27 | margin: 10px auto; 28 | height: 1px; 29 | border: 0 none; 30 | background-color: $color-gray-300; 31 | } 32 | 33 | p { 34 | font-size: 14px; 35 | margin: auto 10px auto 0; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/elements/index.js: -------------------------------------------------------------------------------- 1 | import './blog'; 2 | import './blog-categories'; 3 | import './blog-detail'; 4 | import './blog-newest-listing'; 5 | import './blog-single-select'; 6 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/error-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "blog.module.detail": { 3 | "werkl_blog_entries": [ 4 | "title", 5 | "slug", 6 | "teaser", 7 | "authorId", 8 | "publishedAt", 9 | "blogCategories" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/extension/component/cms/index.js: -------------------------------------------------------------------------------- 1 | const { Component } = Shopware; 2 | 3 | Component.extend('werkl-cms-sidebar', 'sw-cms-sidebar', () => import('./werkl-cms-sidebar')); 4 | Component.extend('werkl-cms-slot', 'sw-cms-slot', () => import('./werkl-cms-slot')); 5 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/extension/component/cms/werkl-cms-sidebar/werkl-cms-sidebar.scss: -------------------------------------------------------------------------------- 1 | .werkl-field--switch { 2 | margin-top: 0; 3 | margin-bottom: 0; 4 | } 5 | 6 | .werkl-extension-component { 7 | width: 100%; 8 | height: 100%; 9 | } 10 | 11 | .serp-preview-card { 12 | .serp-preview { 13 | margin-bottom: 20px; 14 | 15 | h3 { 16 | font-family: arial, sans-serif !important; 17 | margin: 0; 18 | color: rgb(26, 13, 171); 19 | font-size: 18px; 20 | font-weight: 400; 21 | line-height: 1.2; 22 | word-break: break-all; 23 | } 24 | 25 | p { 26 | font-family: arial, sans-serif !important; 27 | color: #4d5156; 28 | font-size: 13px; 29 | line-height: 1.4; 30 | margin-top: 5px; 31 | word-break: break-all; 32 | } 33 | 34 | cite { 35 | font-family: arial, sans-serif !important; 36 | margin: 0; 37 | font-style: normal; 38 | height: 18px; 39 | color: rgb(0, 102, 33); 40 | font-size: 14px; 41 | line-height: 16px; 42 | display: block; 43 | white-space: nowrap; 44 | overflow: hidden; 45 | text-overflow: ellipsis; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/extension/component/cms/werkl-cms-slot/index.js: -------------------------------------------------------------------------------- 1 | import template from './werkl-cms-slot.html.twig'; 2 | import './werkl-cms-slot.scss'; 3 | 4 | export default { 5 | template, 6 | }; 7 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/extension/component/cms/werkl-cms-slot/werkl-cms-slot.html.twig: -------------------------------------------------------------------------------- 1 | {% block sw_cms_slot_content_overlay_action_swap %}{% endblock %} 2 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/extension/component/cms/werkl-cms-slot/werkl-cms-slot.scss: -------------------------------------------------------------------------------- 1 | .werkl-blog-cms-stage-section { 2 | .sw-cms-slot { 3 | .sw-cms-slot__actions { 4 | grid-template-columns: auto; 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/extension/index.js: -------------------------------------------------------------------------------- 1 | import './component/cms'; 2 | import './sw-cms'; 3 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/extension/sw-cms/component/sw-cms-sidebar/index.js: -------------------------------------------------------------------------------- 1 | import template from './sw-cms-sidebar.html.twig'; 2 | import BLOG from '../../../../constant/open-blogware.constant'; 3 | 4 | export default { 5 | template, 6 | 7 | computed: { 8 | isBlogDetail() { 9 | return this.page.type === BLOG.PAGE_TYPES.BLOG_DETAIL; 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/extension/sw-cms/component/sw-cms-sidebar/sw-cms-sidebar.html.twig: -------------------------------------------------------------------------------- 1 | {% block sw_cms_sidebar_block_overview_category_options %} 2 | {% parent %} 3 | 4 | {% endblock %} 5 | 6 | {% block sw_cms_sidebar_page_settings_type_field_options %} 7 | {% parent %} 8 | 14 | {% endblock %} 15 | 16 | {% block sw_cms_sidebar_page_settings_type_field %} 17 | {% parent %} 18 | 24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/extension/sw-cms/index.js: -------------------------------------------------------------------------------- 1 | const { Component } = Shopware; 2 | 3 | Component.override('sw-cms-sidebar', () => import('./component/sw-cms-sidebar')); 4 | Component.override('sw-cms-list', () => import('./page/sw-cms-list')); 5 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/extension/sw-cms/page/sw-cms-list/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | computed: { 3 | sortPageTypes() { 4 | const sortPageTypes = this.$super('sortPageTypes'); 5 | 6 | sortPageTypes.push({ 7 | value: 'blog_detail', 8 | name: this.$tc('sw-cms.sorting.labelSortByBlogPages'), 9 | }); 10 | 11 | return sortPageTypes; 12 | }, 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/extension/sw-cms/snippet/de-DE.json: -------------------------------------------------------------------------------- 1 | { 2 | "sw-cms": { 3 | "sorting": { 4 | "labelSortByBlogPages": "Blogseiten" 5 | }, 6 | "detail": { 7 | "label": { 8 | "pageType": { 9 | "blogDetail": "Blogseite" 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/extension/sw-cms/snippet/en-GB.json: -------------------------------------------------------------------------------- 1 | { 2 | "sw-cms": { 3 | "sorting": { 4 | "labelSortByBlogPages": "Blog pages" 5 | }, 6 | "detail": { 7 | "label": { 8 | "pageType": { 9 | "blogDetail": "Blog page" 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/page/index.js: -------------------------------------------------------------------------------- 1 | import './werkl-blog-author'; 2 | import './werkl-blog-detail/acl'; 3 | import './werkl-blog-list/acl'; 4 | 5 | const { Component } = Shopware; 6 | 7 | Component.extend('werkl-blog-create', 'werkl-blog-detail', () => import('./werkl-blog-create')); 8 | Component.extend('werkl-blog-detail', 'sw-cms-detail', () => import('./werkl-blog-detail')); 9 | Component.register('werkl-blog-list', () => import('./werkl-blog-list')); 10 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/page/werkl-blog-author/acl/index.js: -------------------------------------------------------------------------------- 1 | Shopware.Service('privileges').addPrivilegeMappingEntry({ 2 | category: 'permissions', 3 | parent: 'content', 4 | key: 'werkl-blog-author', 5 | roles: { 6 | viewer: { 7 | privileges: [ 8 | 'werkl_blog_author:read', 9 | 'werkl_blog_author_translation:read', 10 | ], 11 | dependencies: [], 12 | }, 13 | editor: { 14 | privileges: [ 15 | 'werkl_blog_author:update', 16 | 'werkl_blog_author_translation:update', 17 | ], 18 | dependencies: [], 19 | }, 20 | creator: { 21 | privileges: [ 22 | 'werkl_blog_author:create', 23 | 'werkl_blog_author_translation:create', 24 | ], 25 | dependencies: [], 26 | }, 27 | deleter: { 28 | privileges: [ 29 | 'werkl_blog_author:delete', 30 | 'werkl_blog_author_translation:delete', 31 | ], 32 | dependencies: [], 33 | }, 34 | }, 35 | }); 36 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/page/werkl-blog-author/index.js: -------------------------------------------------------------------------------- 1 | import './acl'; 2 | 3 | const { Component } = Shopware; 4 | 5 | Component.extend('werkl-blog-author-create', 'werkl-blog-author-detail', () => import('./werkl-blog-author-create')); 6 | Component.register('werkl-blog-author-detail', () => import('./werkl-blog-author-detail')); 7 | Component.register('werkl-blog-author-list', () => import('./werkl-blog-author-list')); 8 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/page/werkl-blog-author/werkl-blog-author-create/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | methods: { 3 | createdComponent() { 4 | Shopware.State.commit('context/resetLanguageToDefault'); 5 | 6 | this.blogAuthor = this.blogAuthorRepository.create(Shopware.Context.api); 7 | }, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/page/werkl-blog-author/werkl-blog-author-detail/werkl-blog-author-detail.scss: -------------------------------------------------------------------------------- 1 | .sw-blog-author-detail { 2 | .smart-bar__actions { 3 | span { 4 | display: flex; 5 | } 6 | 7 | .sw-tooltip--wrapper { 8 | margin-left: 8px; 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/page/werkl-blog-author/werkl-blog-author-list/werkl-blog-author-list.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | .werkl-blog-author-list { 4 | 5 | .sw-data-grid__cell--title { 6 | width: 82%; 7 | } 8 | 9 | .sw-page__content { 10 | .sw-page__main-content { 11 | grid-area: b; 12 | border-left: 1px solid $color-gray-300; 13 | } 14 | 15 | .sw-page__sidebar { 16 | grid-area: a; 17 | padding: 40px 15px; 18 | } 19 | 20 | &.has--smart-bar.has--side-bar { 21 | grid-template-columns: 120px auto; 22 | grid-template-areas: "a b"; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/page/werkl-blog-create/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | methods: { 3 | async createdComponent() { 4 | Shopware.Store.get('adminMenu').collapseSidebar(); 5 | 6 | const isSystemDefaultLanguage = Shopware.State.getters['context/isSystemDefaultLanguage']; 7 | this.cmsPageState.setIsSystemDefaultLanguage(isSystemDefaultLanguage); 8 | if (!isSystemDefaultLanguage) { 9 | Shopware.State.commit('context/resetLanguageToDefault'); 10 | } 11 | 12 | if (Shopware.Context.api.languageId !== Shopware.Context.api.systemLanguageId) { 13 | Shopware.State.commit('context/setApiLanguageId', Shopware.Context.api.languageId); 14 | } 15 | 16 | this.resetCmsPageState(); 17 | 18 | this.createPage(); 19 | this.createBlog(this.page.id); 20 | this.isLoading = false; 21 | 22 | this.setPageContext(); 23 | }, 24 | 25 | createBlog(pageId) { 26 | this.blog = this.blogRepository.create(); 27 | this.blog.cmsPageId = pageId; 28 | this.blogId = this.blog.id; 29 | }, 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/page/werkl-blog-detail/acl/index.js: -------------------------------------------------------------------------------- 1 | Shopware.Service('privileges').addPrivilegeMappingEntry({ 2 | category: 'permissions', 3 | parent: 'content', 4 | key: 'werkl-blog', 5 | roles: { 6 | viewer: { 7 | privileges: [ 8 | 'werkl_blog_entries:read', 9 | 'werkl_blog_entries_translation:read', 10 | 'werkl_blog_blog_category:read', 11 | ], 12 | dependencies: [], 13 | }, 14 | editor: { 15 | privileges: [ 16 | 'werkl_blog_entries:update', 17 | 'werkl_blog_entries_translation:update', 18 | 'system_config:read', 19 | ], 20 | dependencies: [], 21 | }, 22 | creator: { 23 | privileges: [ 24 | 'werkl_blog_entries:create', 25 | 'werkl_blog_entries_translation:create', 26 | 'werkl_blog_blog_category:create', 27 | 'system_config:read', 28 | ], 29 | dependencies: [], 30 | }, 31 | deleter: { 32 | privileges: [ 33 | 'werkl_blog_entries:delete', 34 | 'werkl_blog_entries_translation:delete', 35 | ], 36 | dependencies: [], 37 | }, 38 | }, 39 | }); 40 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/page/werkl-blog-list/acl/index.js: -------------------------------------------------------------------------------- 1 | Shopware.Service('privileges').addPrivilegeMappingEntry({ 2 | category: 'permissions', 3 | parent: 'content', 4 | key: 'werkl-blog-category', 5 | roles: { 6 | viewer: { 7 | privileges: [ 8 | 'werkl_blog_category:read', 9 | 'werkl_blog_category_translation:read', 10 | ], 11 | dependencies: [], 12 | }, 13 | editor: { 14 | privileges: [ 15 | 'werkl_blog_category:update', 16 | 'werkl_blog_category_translation:update', 17 | ], 18 | dependencies: [], 19 | }, 20 | creator: { 21 | privileges: [ 22 | 'werkl_blog_category:create', 23 | 'werkl_blog_category_translation:create', 24 | ], 25 | dependencies: [], 26 | }, 27 | deleter: { 28 | privileges: [ 29 | 'werkl_blog_category:delete', 30 | 'werkl_blog_category_translation:delete', 31 | ], 32 | dependencies: [], 33 | }, 34 | }, 35 | }); 36 | -------------------------------------------------------------------------------- /src/Resources/app/administration/src/module/blog-module/page/werkl-blog-list/werkl-blog-list.scss: -------------------------------------------------------------------------------- 1 | @import "~scss/variables"; 2 | 3 | $sw-property-list-color-error: $color-crimson-500; 4 | $sw-property-list-color-success: $color-emerald-500; 5 | 6 | .werkl-blog-list { 7 | 8 | .is--inactive { 9 | color: $sw-property-list-color-error; 10 | } 11 | 12 | .is--active { 13 | color: $sw-property-list-color-success; 14 | } 15 | 16 | .sw-data-grid__cell--title { 17 | width: 82%; 18 | } 19 | 20 | .sw-page__content { 21 | .sw-page__side-content { 22 | grid-area: a; 23 | 24 | .sw-tree .sw-tree-actions__headline { 25 | font-size: 14px; 26 | font-weight: bold; 27 | height: 64px; 28 | color: $color-darkgray-200; 29 | } 30 | 31 | .sw-tree__content, .sw-tree .sw-tree-actions__headline { 32 | border-left: 1px solid $color-gray-300; 33 | } 34 | } 35 | 36 | .sw-page__main-content { 37 | grid-area: b; 38 | } 39 | 40 | .sw-page__sidebar { 41 | grid-area: c; 42 | padding: 40px 15px; 43 | } 44 | 45 | &.has--smart-bar.has--side-content { 46 | grid-template-columns: 120px 440px auto; 47 | grid-template-areas: "c a b"; 48 | } 49 | 50 | .sw-data-grid__cell--active { 51 | .sw-data-grid__cell-content { 52 | justify-content: center; 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Resources/app/storefront/src/scss/base.scss: -------------------------------------------------------------------------------- 1 | @import 'layout/header/_search-suggest'; 2 | 3 | .blog-image, 4 | .blog-image-placeholder { 5 | object-fit: cover; 6 | width: 100%; 7 | height: 250px; 8 | } 9 | 10 | .blog-card { 11 | 12 | .card-text { 13 | height: 85px; 14 | overflow: hidden; 15 | } 16 | 17 | .card-footer { 18 | display: flex; 19 | align-items: center; 20 | background: none; 21 | padding: 0; 22 | margin-top: 25px; 23 | 24 | .blog-author-avatar, 25 | .blog-image-placeholder { 26 | width: 50px; 27 | height: 50px; 28 | border-radius: 50%; 29 | object-fit: cover; 30 | margin-right: 20px; 31 | } 32 | 33 | .blog-author-display-name { 34 | font-weight: $font-weight-bold; 35 | margin-bottom: 0; 36 | } 37 | } 38 | } 39 | 40 | .has-element-loader .cms-element-product-listing { 41 | .blog-image-link span.icon{ 42 | opacity: 0; 43 | } 44 | 45 | .blog-date, 46 | .blog-title a, 47 | .blog-image-link { 48 | border-radius: $border-radius; 49 | color: transparent; 50 | animation: skeletonShimmer 1.5s linear 0s infinite normal forwards running; 51 | background: linear-gradient(to right, $gray-300 8%, $gray-100 18%, $gray-300 28%); 52 | background-size: 800px 100px; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Resources/app/storefront/src/scss/layout/header/_search-suggest.scss: -------------------------------------------------------------------------------- 1 | @include media-breakpoint-up(md) { 2 | .search-suggest-container { 3 | width: 700px; 4 | left: 50%; 5 | transform: translateX(-50%); 6 | } 7 | .search-suggest-container-width { 8 | width: 500px; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Resources/config/plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Werkstattl/OpenBlogware/ba3f7ab908e3501a2a8434ebfea3344cdd19d53a/src/Resources/config/plugin.png -------------------------------------------------------------------------------- /src/Resources/config/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Resources/config/routes/storefront.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 10 | true 11 | storefront 12 | true 13 | landingpage 14 | index 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/134.css: -------------------------------------------------------------------------------- 1 | .werkl-cms-el-blog-listing{width:100%;border:1px solid #dadee5;border-radius:4px;background:#fff;padding:10px}.werkl-cms-el-blog-listing .werkl-cms-el-blog-placeholder div{margin:15px 30px;height:1.5em;border-radius:4px;background-color:#f0f2f5}.werkl-cms-el-blog-listing .werkl-cms-el-blog-placeholder div.werkl-cms-el-werkl-cms-el-blog__placeholder{margin:15px 30px 15px 70px}.werkl-cms-el-blog-listing hr{max-width:90%;margin:10px auto;border:1px solid #d1d9e0}.werkl-cms-el-blog-listing h2{margin:10px} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/156.css: -------------------------------------------------------------------------------- 1 | .sw-cms-el-preview-blog{width:100%;background:#fff;font-size:22px;color:#52667a;font-weight:600}.sw-cms-el-preview-blog .sw-cms-el-category-placeholder-listing div{margin:10px 0;height:.4em;border-radius:25px;background-color:#f0f2f5}.sw-cms-el-preview-blog .sw-cms-el-category-placeholder-listing div.sw-cms-el-category-navigation__placeholder--subcategory{margin:7px 20px}.sw-cms-el-preview-blog .sw-cms-el-category-placeholder-listing div.sw-cms-el-category-navigation__placeholder--subcategory:last-of-type{margin-right:10px}.sw-cms-el-preview-blog hr{max-width:100%;margin:10px auto;height:1px;border:0 none;background-color:#d1d9e0}.sw-cms-el-preview-blog p{font-size:14px;margin:auto 10px auto 0} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/16.css: -------------------------------------------------------------------------------- 1 | .werkl-cms-el-preview-newest-listing{width:100%;background:#fff;font-size:22px;color:#52667a;font-weight:600}.werkl-cms-el-preview-newest-listing .werkl-cms-el-category-placeholder-listing div{margin:10px 0;height:.4em;border-radius:25px;background-color:#f0f2f5}.werkl-cms-el-preview-newest-listing .werkl-cms-el-category-placeholder-listing div.werkl-cms-el-category-navigation__placeholder--subcategory{margin:7px 20px}.werkl-cms-el-preview-newest-listing .werkl-cms-el-category-placeholder-listing div.werkl-cms-el-category-navigation__placeholder--subcategory:last-of-type{margin-right:10px}.werkl-cms-el-preview-newest-listing hr{max-width:100%;margin:10px auto;height:1px;border:0 none;background-color:#d1d9e0}.werkl-cms-el-preview-newest-listing p{font-size:14px;margin:auto 10px auto 0} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/18.css: -------------------------------------------------------------------------------- 1 | .sw-cms-el-preview-blog-single-select{width:100%;background:#fff;font-size:22px;color:#52667a;font-weight:600}.sw-cms-el-preview-blog-single-select h6{font-size:14px;margin:auto 10px auto 0}.sw-cms-el-preview-blog-single-select .sw-cms-el-category-placeholder-listing div{margin:7px 0;height:.4em;border-radius:25px;background-color:#f0f2f5}.sw-cms-el-preview-blog-single-select img{width:100%;height:50px;object-fit:cover;margin-top:5px} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/384.css: -------------------------------------------------------------------------------- 1 | .sw-cms-el-preview-blog{width:100%;background:#fff;font-size:22px;color:#52667a;font-weight:600}.sw-cms-el-preview-blog .sw-cms-el-category-placeholder-listing div{margin:10px 0;height:.4em;border-radius:25px;background-color:#f0f2f5}.sw-cms-el-preview-blog .sw-cms-el-category-placeholder-listing div.sw-cms-el-category-navigation__placeholder--subcategory{margin:7px 20px 7px 20px}.sw-cms-el-preview-blog .sw-cms-el-category-placeholder-listing div.sw-cms-el-category-navigation__placeholder--subcategory:last-of-type{margin-right:10px}.sw-cms-el-preview-blog hr{max-width:100%;margin:10px auto;height:1px;border:0 none;background-color:#d1d9e0}.sw-cms-el-preview-blog p{font-size:14px;margin:auto 10px auto 0} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/403.css: -------------------------------------------------------------------------------- 1 | .werkl-cms-el-categories-listing{width:100%;border:1px solid #dadee5;border-radius:4px;background:#fff;padding:10px}.werkl-cms-el-categories-listing .werkl-cms-el-blog-placeholder div{margin:15px 30px;height:1.5em;border-radius:4px;background-color:#f0f2f5}.werkl-cms-el-categories-listing .werkl-cms-el-blog-placeholder div.werkl-cms-el-werkl-cms-el-blog__placeholder{margin:15px 30px 15px 70px}.werkl-cms-el-categories-listing hr{max-width:90%;margin:10px auto;border:1px solid #d1d9e0}.werkl-cms-el-categories-listing h2{margin:10px} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/425.css: -------------------------------------------------------------------------------- 1 | .werkl-cms-preview-newest-listing{width:100%;background:#fff;font-size:22px;color:#52667a;font-weight:600;border-radius:5px;padding:20px}.werkl-cms-preview-newest-listing h2{grid-column:span 2;font-size:16px;line-height:18px;margin:0 0 2px 0}.werkl-cms-preview-newest-listing .werkl-cms-preview-newest-listing-item{display:grid;grid-template-columns:1fr 1fr;grid-gap:20px;row-gap:0}.werkl-cms-preview-newest-listing .werkl-cms-preview-newest-listing-item div>div{margin:10px 0;height:.7em;border-radius:4px;background-color:#f0f2f5}.werkl-cms-preview-newest-listing .werkl-cms-preview-newest-listing-item hr{max-width:90%;margin:10px auto;border:1px solid #d1d9e0}.werkl-cms-preview-newest-listing .werkl-cms-preview-newest-listing-item time{font-size:12px;line-height:14px;font-weight:normal;margin:0 0 6px 0} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/44.css: -------------------------------------------------------------------------------- 1 | .sw-blog-author-detail .smart-bar__actions span{display:flex}.sw-blog-author-detail .smart-bar__actions .sw-tooltip--wrapper{margin-left:8px} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/462.css: -------------------------------------------------------------------------------- 1 | .werkl-field--switch{margin-top:0;margin-bottom:0}.werkl-extension-component{width:100%;height:100%}.serp-preview-card .serp-preview{margin-bottom:20px}.serp-preview-card .serp-preview h3{font-family:arial,sans-serif !important;margin:0;color:#1a0dab;font-size:18px;font-weight:400;line-height:1.2;word-break:break-all}.serp-preview-card .serp-preview p{font-family:arial,sans-serif !important;color:#4d5156;font-size:13px;line-height:1.4;margin-top:5px;word-break:break-all}.serp-preview-card .serp-preview cite{font-family:arial,sans-serif !important;margin:0;font-style:normal;height:18px;color:#006621;font-size:14px;line-height:16px;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/470.css: -------------------------------------------------------------------------------- 1 | .werkl-cms-preview-blog-listing{width:100%;background:#fff;font-size:22px;color:#52667a;font-weight:600;border-radius:5px;padding:20px}.werkl-cms-preview-blog-listing h2{grid-column:span 2;font-size:16px;line-height:18px;margin:0 0 2px 0}.werkl-cms-preview-blog-listing .werkl-cms-preview-blog-listing-item{display:grid;grid-template-columns:1fr 1fr;grid-gap:20px;row-gap:0}.werkl-cms-preview-blog-listing .werkl-cms-preview-blog-listing-item div>div{margin:10px 0;height:.7em;border-radius:4px;background-color:#f0f2f5}.werkl-cms-preview-blog-listing .werkl-cms-preview-blog-listing-item hr{max-width:90%;margin:10px auto;border:1px solid #d1d9e0}.werkl-cms-preview-blog-listing .werkl-cms-preview-blog-listing-item time{font-size:12px;line-height:14px;font-weight:normal;margin:0 0 6px 0} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/485.css: -------------------------------------------------------------------------------- 1 | .sw-blog-detail-config-filter .sw-field--checkbox:last-child{margin-bottom:0} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/528.css: -------------------------------------------------------------------------------- 1 | .werkl-cms-el-newest-listing{width:100%;border:1px solid #dadee5;border-radius:4px;background:#fff;padding:10px}.werkl-cms-el-newest-listing h2{margin:10px} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/549.css: -------------------------------------------------------------------------------- 1 | .werkl-cms-el-config-newest-listing{width:100%} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/618.css: -------------------------------------------------------------------------------- 1 | .werkl-cms-el-blog-detail{width:100%;border:1px solid #dadee5;border-radius:4px;background:#fff;padding:10px}.werkl-cms-el-blog-detail .werkl-cms-el-blog-placeholder div{margin:15px 30px;height:1.5em;border-radius:4px;background-color:#f0f2f5}.werkl-cms-el-blog-detail .werkl-cms-el-blog-placeholder div.werkl-cms-el-werkl-cms-el-blog__placeholder{margin:15px 30px 15px 70px}.werkl-cms-el-blog-detail hr{max-width:90%;margin:10px auto;border:1px solid #d1d9e0}.werkl-cms-el-blog-detail h2{margin:10px} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/656.css: -------------------------------------------------------------------------------- 1 | .werkl-blog-list .is--inactive{color:#de294c}.werkl-blog-list .is--active{color:#37d046}.werkl-blog-list .sw-data-grid__cell--title{width:82%}.werkl-blog-list .sw-page__content .sw-page__side-content{grid-area:a}.werkl-blog-list .sw-page__content .sw-page__side-content .sw-tree .sw-tree-actions__headline{font-size:14px;font-weight:bold;height:64px;color:#52667a}.werkl-blog-list .sw-page__content .sw-page__side-content .sw-tree__content,.werkl-blog-list .sw-page__content .sw-page__side-content .sw-tree .sw-tree-actions__headline{border-left:1px solid #d1d9e0}.werkl-blog-list .sw-page__content .sw-page__main-content{grid-area:b}.werkl-blog-list .sw-page__content .sw-page__sidebar{grid-area:c;padding:40px 15px}.werkl-blog-list .sw-page__content.has--smart-bar.has--side-content{grid-template-columns:120px 440px auto;grid-template-areas:"c a b"}.werkl-blog-list .sw-page__content .sw-data-grid__cell--active .sw-data-grid__cell-content{justify-content:center} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/70.css: -------------------------------------------------------------------------------- 1 | .werkl-cms-preview-blog-detail{width:100%;background:#fff;font-size:22px;color:#52667a;font-weight:600;border-radius:5px;padding:20px}.werkl-cms-preview-blog-detail h2{grid-column:span 2;font-size:16px;line-height:18px;margin:0 0 2px 0}.werkl-cms-preview-blog-detail .werkl-cms-preview-blog-detail-item div>div{margin:10px 0;height:.7em;border-radius:4px;background-color:#f0f2f5}.werkl-cms-preview-blog-detail .werkl-cms-preview-blog-detail-item hr{max-width:90%;margin:10px auto;border:1px solid #d1d9e0}.werkl-cms-preview-blog-detail .werkl-cms-preview-blog-detail-item time{font-size:12px;line-height:14px;font-weight:normal;margin:0 0 6px 0}.werkl-cms-preview-blog-detail .werkl-cms-preview-blog-detail-item p{font-size:12px;line-height:14px;font-weight:normal} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/725.css: -------------------------------------------------------------------------------- 1 | .werkl-cms-preview-blog-categories{width:100%;background:#fff;font-size:22px;color:#52667a;font-weight:600;border-radius:5px;padding:20px}.werkl-cms-preview-blog-categories h2{grid-column:span 2;font-size:16px;line-height:18px;margin:0 0 2px 0}.werkl-cms-preview-blog-categories .werkl-cms-preview-blog-categories-item{display:grid;grid-template-columns:1fr 1fr;grid-gap:20px;row-gap:0}.werkl-cms-preview-blog-categories .werkl-cms-preview-blog-categories-item div>div{margin:10px 0;height:.7em;border-radius:4px;background-color:#f0f2f5}.werkl-cms-preview-blog-categories .werkl-cms-preview-blog-categories-item hr{max-width:90%;margin:10px auto;border:1px solid #d1d9e0}.werkl-cms-preview-blog-categories .werkl-cms-preview-blog-categories-item time{font-size:12px;line-height:14px;font-weight:normal;margin:0 0 6px 0} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/75.css: -------------------------------------------------------------------------------- 1 | .werkl-cms-el-blog-single-select{width:100%;padding:20px}.werkl-cms-el-blog-single-select h6{color:#0063ae;font-size:14px;text-transform:uppercase;margin-bottom:0;line-height:1.2}.werkl-cms-el-blog-single-select h3{margin:7px 0 18px;color:#343434;font-size:23px;line-height:1.2}.werkl-cms-el-blog-single-select img{width:100%;height:100%;max-height:225px;object-fit:cover}.werkl-cms-el-blog-single-select p{margin:18px 0;display:block} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/788.css: -------------------------------------------------------------------------------- 1 | .werkl-cms-preview-blog-single-entry{width:100%;background:#fff;font-size:22px;color:#52667a;font-weight:600;border-radius:5px;padding:20px}.werkl-cms-preview-blog-single-entry h2{grid-column:span 2;font-size:16px;line-height:18px;margin:0 0 2px 0}.werkl-cms-preview-blog-single-entry .werkl-cms-preview-blog-single-entry-item{width:100%}.werkl-cms-preview-blog-single-entry .werkl-cms-preview-blog-single-entry-item div>div{margin:10px 0;height:.7em;border-radius:4px;background-color:#f0f2f5}.werkl-cms-preview-blog-single-entry .werkl-cms-preview-blog-single-entry-item hr{max-width:90%;margin:10px auto;border:1px solid #d1d9e0}.werkl-cms-preview-blog-single-entry .werkl-cms-preview-blog-single-entry-item time{font-size:12px;line-height:14px;font-weight:normal;margin:0 0 6px 0} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/859.css: -------------------------------------------------------------------------------- 1 | .werkl-blog-author-list .sw-data-grid__cell--title{width:82%}.werkl-blog-author-list .sw-page__content .sw-page__main-content{grid-area:b;border-left:1px solid #d1d9e0}.werkl-blog-author-list .sw-page__content .sw-page__sidebar{grid-area:a;padding:40px 15px}.werkl-blog-author-list .sw-page__content.has--smart-bar.has--side-bar{grid-template-columns:120px auto;grid-template-areas:"a b"} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/925.css: -------------------------------------------------------------------------------- 1 | .sw-blog-config-filter .sw-field--checkbox:last-child{margin-bottom:0} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/940.css: -------------------------------------------------------------------------------- 1 | .sw-cms-el-preview-categories{width:100%;background:#fff;font-size:22px;color:#52667a;font-weight:600}.sw-cms-el-preview-categories .sw-cms-el-category-placeholder-listing div{margin:10px 0;height:.4em;border-radius:25px;background-color:#f0f2f5}.sw-cms-el-preview-categories .sw-cms-el-category-placeholder-listing div.sw-cms-el-category-navigation__placeholder--subcategory{margin:7px 20px}.sw-cms-el-preview-categories .sw-cms-el-category-placeholder-listing div.sw-cms-el-category-navigation__placeholder--subcategory:last-of-type{margin-right:10px}.sw-cms-el-preview-categories hr{max-width:100%;margin:10px auto;height:1px;border:0 none;background-color:#d1d9e0}.sw-cms-el-preview-categories p{font-size:14px;margin:auto 10px auto 0} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/css/965.css: -------------------------------------------------------------------------------- 1 | .werkl-blog-cms-stage-section .sw-cms-slot .sw-cms-slot__actions{grid-template-columns:auto} 2 | -------------------------------------------------------------------------------- /src/Resources/public/static/js/33c36fd5d76856f33f76.js: -------------------------------------------------------------------------------- 1 | "use strict";(window["webpackJsonpPluginwerkl-open-blogware"]=window["webpackJsonpPluginwerkl-open-blogware"]||[]).push([[968],{1968:function(e,o,r){r.r(o);let{Criteria:t}=Shopware.Data;o.default={computed:{globalCategoryRepository(){return this.repositoryFactory.create("werkl_blog_category")}},methods:{searchCategories(e){let o=new t(1,500);return o.setTerm(e),this.globalCategoryRepository.search(o,Shopware.Context.api)}}}}}]); -------------------------------------------------------------------------------- /src/Resources/public/static/js/369933b2aab52e07a724.js: -------------------------------------------------------------------------------- 1 | "use strict";(window["webpackJsonpPluginwerkl-open-blogware"]=window["webpackJsonpPluginwerkl-open-blogware"]||[]).push([[359],{9359:function(e,t,l){l.r(t),l.d(t,{default:function(){return i}});let{Mixin:n}=Shopware;var i={template:'{% block werkl_cms_element_blog_single_select_config %}\n
\n \n\n \n\n \n \n
\n{% endblock %}\n',inject:["repositoryFactory"],mixins:[n.getByName("cms-element")],data(){return{blogEntry:null,selectedEntry:null}},computed:{blogEntryRepository(){return this.repositoryFactory.create("werkl_blog_entries")}},created(){this.createdComponent()},methods:{createdComponent(){this.initElementConfig("blog-single-select")}}}}}]); -------------------------------------------------------------------------------- /src/Resources/public/static/js/4a38dd497688ee75a124.js: -------------------------------------------------------------------------------- 1 | "use strict";(window["webpackJsonpPluginwerkl-open-blogware"]=window["webpackJsonpPluginwerkl-open-blogware"]||[]).push([[347],{6347:function(n,l,e){e.r(l),e.d(l,{default:function(){return o}});var o={template:'{% block werkl_cms_block_listing %}\n
\n \n
\n{% endblock %}\n'}}}]); -------------------------------------------------------------------------------- /src/Resources/public/static/js/4c6e82e67679d63a7a6f.js: -------------------------------------------------------------------------------- 1 | "use strict";(window["webpackJsonpPluginwerkl-open-blogware"]=window["webpackJsonpPluginwerkl-open-blogware"]||[]).push([[973],{6973:function(n,e,t){t.r(e),t.d(e,{default:function(){return i}});let{State:o}=Shopware;var i={template:'
\n \n
\n',props:{positionIdentifier:{type:String,required:!0}},computed:{componentSections(){return o.get("extensionComponentSections").identifier[this.positionIdentifier]??[]}}}}}]); -------------------------------------------------------------------------------- /src/Resources/public/static/js/5ef3c68e64f9eeacfb51.js: -------------------------------------------------------------------------------- 1 | "use strict";(window["webpackJsonpPluginwerkl-open-blogware"]=window["webpackJsonpPluginwerkl-open-blogware"]||[]).push([[768],{8768:function(e,t,n){n.r(t),n.d(t,{default:function(){return i}});let{Mixin:o}=Shopware;var i={template:'{% block werkl_cms_element_blog_listing_config %}\n
\n{% endblock %}\n',inject:["repositoryFactory"],mixins:[o.getByName("cms-element")],data(){return{}},computed:{},watch:{},created(){this.createdComponent()},methods:{async createdComponent(){this.initElementConfig("blog-categories")},getSelectedCategories(){}}}}}]); -------------------------------------------------------------------------------- /src/Resources/public/static/js/8b2b6c5bb0a41393003a.js: -------------------------------------------------------------------------------- 1 | "use strict";(window["webpackJsonpPluginwerkl-open-blogware"]=window["webpackJsonpPluginwerkl-open-blogware"]||[]).push([[185],{8185:function(n,e,l){l.r(e),l.d(e,{default:function(){return o}});var o={template:'{% block werkl_cms_block_newest_listing %}\n
\n \n
\n{% endblock %}\n'}}}]); -------------------------------------------------------------------------------- /src/Resources/public/static/js/915ebe549e746152b355.js: -------------------------------------------------------------------------------- 1 | "use strict";(window["webpackJsonpPluginwerkl-open-blogware"]=window["webpackJsonpPluginwerkl-open-blogware"]||[]).push([[984],{1984:function(e,t,a){a.r(t),t.default={methods:{async createdComponent(){Shopware.Store.get("adminMenu").collapseSidebar();let e=Shopware.State.getters["context/isSystemDefaultLanguage"];this.cmsPageState.setIsSystemDefaultLanguage(e),e||Shopware.State.commit("context/resetLanguageToDefault"),Shopware.Context.api.languageId!==Shopware.Context.api.systemLanguageId&&Shopware.State.commit("context/setApiLanguageId",Shopware.Context.api.languageId),this.resetCmsPageState(),this.createPage(),this.createBlog(this.page.id),this.isLoading=!1,this.setPageContext()},createBlog(e){this.blog=this.blogRepository.create(),this.blog.cmsPageId=e,this.blogId=this.blog.id}}}}}]); -------------------------------------------------------------------------------- /src/Resources/public/static/js/94c20f9caef696e0136f.js: -------------------------------------------------------------------------------- 1 | "use strict";(window["webpackJsonpPluginwerkl-open-blogware"]=window["webpackJsonpPluginwerkl-open-blogware"]||[]).push([[622],{7622:function(l,e,n){n.r(e),n.d(e,{default:function(){return o}});var o={template:'{% block werkl_cms_block_detail %}\n
\n \n
\n{% endblock %}\n'}}}]); -------------------------------------------------------------------------------- /src/Resources/public/static/js/b5b1227c870757fb6c15.js: -------------------------------------------------------------------------------- 1 | "use strict";(window["webpackJsonpPluginwerkl-open-blogware"]=window["webpackJsonpPluginwerkl-open-blogware"]||[]).push([[182],{2182:function(n,e,l){l.r(e),l.d(e,{default:function(){return o}});var o={template:'{% block werkl_cms_block_blog_single_entry %}\n
\n \n
\n{% endblock %}\n'}}}]); -------------------------------------------------------------------------------- /src/Resources/public/static/js/baa196a2bd193a4a577c.js: -------------------------------------------------------------------------------- 1 | "use strict";(window["webpackJsonpPluginwerkl-open-blogware"]=window["webpackJsonpPluginwerkl-open-blogware"]||[]).push([[565],{9565:function(e,s,o){o.r(s),s.default={computed:{sortPageTypes(){let e=this.$super("sortPageTypes");return e.push({value:"blog_detail",name:this.$tc("sw-cms.sorting.labelSortByBlogPages")}),e}}}}}]); -------------------------------------------------------------------------------- /src/Resources/public/static/js/ca06e9e52b00474374b8.js: -------------------------------------------------------------------------------- 1 | "use strict";(window["webpackJsonpPluginwerkl-open-blogware"]=window["webpackJsonpPluginwerkl-open-blogware"]||[]).push([[291],{8291:function(e,o,t){t.r(o),o.default={methods:{createdComponent(){Shopware.State.commit("context/resetLanguageToDefault"),this.blogAuthor=this.blogAuthorRepository.create(Shopware.Context.api)}}}}}]); -------------------------------------------------------------------------------- /src/Resources/public/static/js/d3b8f578386315abdd6d.js: -------------------------------------------------------------------------------- 1 | "use strict";(window["webpackJsonpPluginwerkl-open-blogware"]=window["webpackJsonpPluginwerkl-open-blogware"]||[]).push([[939],{5939:function(e,n,o){o.r(n),o.d(n,{default:function(){return l}});var l={template:'{% block werkl_cms_block_categories %}\n
\n \n
\n{% endblock %}\n'}}}]); -------------------------------------------------------------------------------- /src/Resources/public/static/js/ec3c4260240b6a3b8ef7.js: -------------------------------------------------------------------------------- 1 | "use strict";(window["webpackJsonpPluginwerkl-open-blogware"]=window["webpackJsonpPluginwerkl-open-blogware"]||[]).push([[262],{7262:function(e,n,t){t.r(n),t.d(n,{default:function(){return a}});var a={template:'\n \n\n',props:{defaultItem:{type:String,default:"blog"}},methods:{onChangeTab(e){this.currentTab=e}}}}}]); -------------------------------------------------------------------------------- /src/Resources/public/static/js/fbe93fc23dd1cbadee55.js: -------------------------------------------------------------------------------- 1 | "use strict";(window["webpackJsonpPluginwerkl-open-blogware"]=window["webpackJsonpPluginwerkl-open-blogware"]||[]).push([[778],{4778:function(e,t,n){n.r(t),n.d(t,{default:function(){return i}});var i={template:'{% block sw_tree_item_children_items %}\n\n {% block sw_tree_item_children_items_slots %}\n {% parent %}\n {% endblock %}\n\n{% endblock %}\n\n{% block sw_tree_items_actions_edit %}\n\n {{ $tc(\'werkl-blog-tree-item.actions.edit\') }}\n\n{% endblock %}\n',computed:{parentScope(){let e=this.$parent;for(;"sw-tree"!==e.$options.name;)e=e.$parent;return e}},data(){return{editingCategory:null}},methods:{onEditCategory(e){this.editingCategory=e,this.currentEditElement=e.id,this.editElementName()},onBlurTreeItemInput(e){this.abortCreateElement(e)},onCancelSubmit(e){this.abortCreateElement(e)},abortCreateElement(e){this.currentEditElement=null,this.editingCategory=null,this.$super("abortCreateElement",e)}}}}}]); -------------------------------------------------------------------------------- /src/Resources/public/static/js/fceb9e682485d5fab032.js: -------------------------------------------------------------------------------- 1 | "use strict";(window["webpackJsonpPluginwerkl-open-blogware"]=window["webpackJsonpPluginwerkl-open-blogware"]||[]).push([[990],{7990:function(e,n,l){l.r(n),l.d(n,{default:function(){return a}});var o=l(2059),a={template:'{% block sw_cms_sidebar_block_overview_category_options %}\n{% parent %}\n\n{% endblock %}\n\n{% block sw_cms_sidebar_page_settings_type_field_options %}\n{% parent %}\n\n {{ $tc(\'sw-cms.detail.label.pageTypeBlog\') }}\n\n{% endblock %}\n\n{% block sw_cms_sidebar_page_settings_type_field %}\n{% parent %}\n\n{% endblock %}\n',computed:{isBlogDetail(){return this.page.type===o.A.PAGE_TYPES.BLOG_DETAIL}}}}}]); -------------------------------------------------------------------------------- /src/Resources/snippet/de_DE/storefront.de-DE.json: -------------------------------------------------------------------------------- 1 | { 2 | "werkl-blog": { 3 | "detail": { 4 | "meta": { 5 | "author": "Autor", 6 | "category": "Kategorien" 7 | } 8 | }, 9 | "element": { 10 | "detail": { 11 | "warning": { 12 | "heading": "Fehler beim laden der Blog Detail Ansicht", 13 | "content": "Vielleicht hast du das Blog Detail CMS Element auf derselben Seite wie das CMS Listing Element?" 14 | } 15 | }, 16 | "singleSelect": { 17 | "emptyResult": "Es ist kein Blog Eintrag ausgewählt." 18 | } 19 | }, 20 | "box": { 21 | "author": { 22 | "countEntries": "Beiträge" 23 | } 24 | }, 25 | "listing": { 26 | "readMoreLabel": "mehr lesen", 27 | "emptyResultMessage": "Wir konnten leider keine Suchergebnisse finden ...", 28 | "filterPanelResetAll": "Zurück setzen", 29 | "filterBlogCategoriesDisplayName": "Kategorien", 30 | "filterBlogAuthorDisplayName": "Autor", 31 | "filterBlogTagsDisplayName": "Tags" 32 | }, 33 | "search": { 34 | "tabs": { 35 | "product": "Produkt", 36 | "blog": "Blog Eintrag" 37 | }, 38 | "in": "In", 39 | "searchAllResults": "Suchergebnis für Blogs anzeigen", 40 | "searchResults": "{1} 1 Eintrag|]1,Inf[ %count% Eingaben", 41 | "headline": "{0} Zu \"%searchTerm%\" wurde kein Blog gefunden | {1} Zu \"%searchTerm%\" wurde 1 Blog gefunden | ]1,Inf[ Zu \"%searchTerm%\" wurden %count% Blogs gefunden", 42 | "emptyResult": "Wir konnten leider keine Suchergebnisse finden ..." 43 | } 44 | }, 45 | "header": { 46 | "searchAllResults": "Alle Produkte anzeigen Suchergebnis", 47 | "searchPlaceholder": "Suche nach Produkten, Blogeinträgen, Autoren..." 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Resources/snippet/en_GB/storefront.en-GB.json: -------------------------------------------------------------------------------- 1 | { 2 | "werkl-blog": { 3 | "detail": { 4 | "meta": { 5 | "author": "Author", 6 | "category": "Categories" 7 | } 8 | }, 9 | "element": { 10 | "detail": { 11 | "warning": { 12 | "heading": "Error while loading the detail page", 13 | "content": "There seems to be an issue while loading the blog detail page. Maybe you have the Blog detail CMS element within the same page as the Blog listing CMS element?" 14 | } 15 | }, 16 | "singleSelect": { 17 | "emptyResult": "No blog entry was chosen" 18 | } 19 | }, 20 | "box": { 21 | "author": { 22 | "countEntries": "Entries" 23 | } 24 | }, 25 | "listing": { 26 | "readMoreLabel": "read more", 27 | "emptyResultMessage": "We couldn't find any results for your search request", 28 | "filterPanelResetAll": "Reset", 29 | "filterBlogCategoriesDisplayName": "Categories", 30 | "filterBlogAuthorDisplayName": "Author", 31 | "filterBlogTagsDisplayName": "Tags" 32 | }, 33 | "search": { 34 | "tabs": { 35 | "product": "Product", 36 | "blog": "Blog" 37 | }, 38 | "in": "In", 39 | "searchAllResults": "Show all blogs search result", 40 | "searchResults": "{1} 1 Entry|]1,Inf[ %count% Entries", 41 | "emptyResult": "No blog entries found with the request keyword", 42 | "headline": "{0} 0 blogs found for \"%searchTerm%\" | {1} One blog found for \"%searchTerm%\" | ]1,Inf[ %count% blogs found for \"%searchTerm%\"" 43 | } 44 | }, 45 | "header": { 46 | "searchAllResults": "Show all products search result", 47 | "searchPlaceholder": "Search products, blog entries, authors" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/block/cms-block-blog-categories.html.twig: -------------------------------------------------------------------------------- 1 | {% block block_werkl_blog_categories %} 2 | {% set element = block.slots.getSlot('categories') %} 3 | 4 |
5 | {% sw_include "@Storefront/storefront/element/cms-element-" ~ element.type ~ ".html.twig" ignore missing %} 6 |
7 | 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/block/cms-block-blog-detail.html.twig: -------------------------------------------------------------------------------- 1 | {% block block_werkl_blog_detail %} 2 | {% set element = block.slots.getSlot('blogDetail') %} 3 | 4 |
5 | {% sw_include "@Storefront/storefront/element/cms-element-" ~ element.type ~ ".html.twig" ignore missing %} 6 |
7 | 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/block/cms-block-blog-listing.html.twig: -------------------------------------------------------------------------------- 1 | {% block block_werkl_blog_listing %} 2 | {% set element = block.slots.getSlot('listing') %} 3 | 4 |
5 | {% sw_include "@Storefront/storefront/element/cms-element-" ~ element.type ~ ".html.twig" ignore missing %} 6 |
7 | 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/block/cms-block-blog-newest-listing.html.twig: -------------------------------------------------------------------------------- 1 | {% block block_newest_listing %} 2 | {% set element = block.slots.getSlot('listing') %} 3 | 4 |
5 | {% sw_include "@Storefront/storefront/element/cms-element-" ~ element.type ~ ".html.twig" ignore missing %} 6 |
7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/block/cms-block-blog-single-entry.html.twig: -------------------------------------------------------------------------------- 1 | {% block block_werkl_blog_single_entry %} 2 | {% set element = block.slots.getSlot('singleEntry') %} 3 | 4 |
5 | {% sw_include "@Storefront/storefront/element/cms-element-" ~ element.type ~ ".html.twig" ignore missing %} 6 |
7 | 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/component/blog/_partials/_block_author.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_block_partials_author %} 2 |
3 |
{% sw_icon 'avatar' style { 'size': 'sm' } %} 4 | 8 | {{ author.displayName ?: author.firstName ~ ' ' ~ author.lastName }} 9 | 10 |
11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/component/blog/_partials/_block_category.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_block_partials_category %} 2 | {% set categoriesName = [] %} 3 | {% for category in categories %} 4 | {% set categoriesName = categoriesName|merge([category.translated.name]) %} 5 | {% endfor %} 6 |
7 |
{% sw_icon 'folder-thumbnail' style { 'size': 'sm' } %} 8 | 12 | {{ categoriesName|join(', ') }} 13 | 14 |
15 |
16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/component/blog/newest-listing.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_element_blog_newest_listing_row %} 2 |
3 | {% if searchResult.total > 0 %} 4 | {% block werkl_element_blog_newest_listing_col %} 5 |
6 | {% for article in searchResult %} 7 | {% block werkl_element_blog_newest_listing_box %} 8 |
9 | {% sw_include '@Storefront/storefront/component/blog/card/box.html.twig' %} 10 |
11 | {% endblock %} 12 | {% endfor %} 13 |
14 | {% endblock %} 15 | {% else %} 16 | {% block werkl_element_blog_newest_listing_col_empty %} 17 |
18 | {% block werkl_element_blog_newest_listing_col_empty_alert %} 19 | {% sw_include '@Storefront/storefront/utilities/alert.html.twig' with { 20 | type: 'info', 21 | content: 'werkl-blog.search.emptyResult'|trans|sw_sanitize 22 | } %} 23 | {% endblock %} 24 |
25 | {% endblock %} 26 | {% endif %} 27 |
28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/component/listing/filter/blog-filter-multi-select-list-item.html.twig: -------------------------------------------------------------------------------- 1 | {% sw_extends '@Storefront/storefront/component/listing/filter/filter-multi-select-list-item.html.twig' %} 2 | 3 | {% block component_filter_multi_select_list_item %} 4 |
5 | {% set id = element.id %} 6 | 7 | {# 8 | Some entities (e.g. BlogAuthorEntity) provide a getFullName method 9 | which should be used for display. Others, like TagEntity, only have 10 | a name property. Fallback to the name attribute if getFullName does 11 | not exist to avoid empty labels in the filter. 12 | #} 13 | {% if element.getFullName is defined %} 14 | {% set name = element.getFullName() %} 15 | {% else %} 16 | {% set name = element.name %} 17 | {% endif %} 18 | 19 | {% block component_filter_multi_select_list_item_checkbox_input %} 20 | {{ parent() }} 21 | {% endblock %} 22 | 23 | {% block component_filter_multi_select_list_item_label_element %} 24 | {{ parent() }} 25 | {% endblock %} 26 |
27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/component/listing/filter/blog-filter-multi-select.html.twig: -------------------------------------------------------------------------------- 1 | {% sw_extends '@Storefront/storefront/component/listing/filter/filter-multi-select.html.twig' %} 2 | 3 | {% block component_filter_multi_select_list_item_inner %} 4 | {% sw_include '@Storefront/storefront/component/listing/filter/blog-filter-multi-select-list-item.html.twig' %} 5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/element/cms-element-blog-categories.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_element_blog_categories %} 2 | {% set searchResult = element.data %} 3 |
4 |
    5 | {% for category in searchResult.entities.elements %} 6 |
  • 7 | {{ category.translated.name ? category.name }} 8 |
  • 9 | {% endfor %} 10 |
11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/element/cms-element-blog-newest-listing.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_element_blog_newest_listing %} 2 | 3 | {% block werkl_element_blog_newest_listing_wrapper %} 4 | {% sw_include '@Storefront/storefront/component/blog/newest-listing.html.twig' with { 5 | searchResult: element.data, 6 | } %} 7 | {% endblock %} 8 | 9 | {% endblock %} 10 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/element/cms-element-blog-single-select.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_element_blog_single_select %} 2 | {% set article = element.data %} 3 | 4 | {% if article|length %} 5 | {% sw_include '@Storefront/storefront/component/blog/card/box.html.twig' %} 6 | {% else %} 7 | {% sw_include '@Storefront/storefront/utilities/alert.html.twig' with { 8 | type: "primary", 9 | content: "werkl-blog.element.singleSelect.emptyResult"|trans|sw_sanitize, 10 | icon: false 11 | } %} 12 | {% endif %} 13 | 14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/element/cms-element-blog.html.twig: -------------------------------------------------------------------------------- 1 | {% block werkl_element_blog_listing %} 2 | {% set cmsPage = page.landingPage ? page.landingPage.cmsPage : page.cmsPage %} 3 | {# @var result \Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult #} 4 | {% set searchResult = element.data %} 5 | {% set config = element.fieldConfig.elements %} 6 | 7 | {% set slot = cmsPage.firstElementOfType('blog') %} 8 | 9 | {% set filterUrl = null %} 10 | {% set dataUrl = null %} 11 | 12 | {% if page.landingPage %} 13 | {% set dataUrl = url('frontend.landing.page', { landingPageId: page.landingPage.id }) %} 14 | {% elseif page.header.navigation.active.id %} 15 | {% set dataUrl = url('frontend.cms.navigation.page', { navigationId: page.header.navigation.active.id }) %} 16 | {% endif %} 17 | 18 | {% set params = { slots: slot.id, 'no-aggregations': 1 } %} 19 | 20 | {% block werkl_element_blog_listing_wrapper %} 21 | {% block werkl_block_filter_panel %} 22 | {% if config.showCategoryFilter.value or config.showAuthorFilter.value %} 23 |
26 | {% sw_include '@Storefront/storefront/component/listing/blog-filter-panel.html.twig' with { 27 | listing: searchResult, 28 | sidebar: false 29 | } %} 30 |
31 | {% endif %} 32 | {% endblock %} 33 | 34 | {% sw_include '@Storefront/storefront/component/blog/listing.html.twig' with { 35 | searchResult: searchResult, 36 | dataUrl: dataUrl, 37 | filterUrl: filterUrl, 38 | params: params, 39 | config: config 40 | } %} 41 | {% endblock %} 42 | {% endblock %} 43 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/layout/header/search.html.twig: -------------------------------------------------------------------------------- 1 | {% sw_extends '@Storefront/storefront/layout/header/search.html.twig' %} 2 | 3 | {% block layout_header_search %} 4 | {% if app.request.attributes.get('_route') == 'werkl.frontend.blog.search' %} 5 |
7 | 18 |
19 | {% else %} 20 | {{ parent() }} 21 | {% endif %} 22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/page/blog-search/index.html.twig: -------------------------------------------------------------------------------- 1 | {% sw_extends '@Storefront/storefront/page/search/index.html.twig' %} 2 | 3 | {% block page_search %} 4 |
5 | {% block page_search_headline %} 6 |

7 | {% block page_search_headline_text %} 8 | {{ "werkl-blog.search.headline"|trans({ 9 | '%count%': page.listing.total, 10 | '%searchTerm%': page.searchTerm, 11 | }) }} 12 | {% endblock %} 13 |

14 | {% endblock %} 15 | 16 | {% sw_include '@Storefront/storefront/page/blog-search/search-pagelet.html.twig' with { page: page } %} 17 |
18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/page/blog-search/search-pagelet.html.twig: -------------------------------------------------------------------------------- 1 | {% set listingColumns = 'col-sm-6 col-lg-4 col-xl-3' %} 2 | 3 | {% block element_product_listing_wrapper %} 4 |
5 |
8 | {% sw_include '@Storefront/storefront/component/listing/blog-filter-panel.html.twig' with { 9 | listing: page.listing, 10 | sidebar: false 11 | } %} 12 |
13 | 14 | {% sw_include '@Storefront/storefront/component/blog/listing.html.twig' with { 15 | searchResult: page.listing, 16 | dataUrl: url('widgets.blog.search.pagelet'), 17 | params: { search: page.searchTerm }, 18 | sidebar: 0, 19 | boxLayout: 'minimal', 20 | displayMode: '' 21 | } %} 22 |
23 | {% endblock %} 24 | -------------------------------------------------------------------------------- /src/Resources/views/storefront/page/rss.html.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% if page.header.navigation.active.translated.metaTitle %} 5 | {{ page.header.navigation.active.translated.metaTitle|striptags|trim }} 6 | {% else %} 7 | Blog 8 | {% endif %} 9 | {{ app.request.schemeAndHttpHost }} 10 | {{ app.request.locale }} 11 | {% if page.header.navigation.active.translated.metaDescription %} 12 | {{ page.header.navigation.active.translated.metaDescription|striptags|trim|u.truncate(maxLength ?? 160, '…') }} 13 | {% endif %} 14 | {% for result in results %} 15 | 16 | {% set title = result.translated.metaTitle ?? result.translated.title %} 17 | {{ title|striptags|trim }} 18 | {{ app.request.schemeAndHttpHost ~ "/blog/" ~ result.translated.slug }} 19 | {{ app.request.schemeAndHttpHost ~ "/blog/" ~ result.translated.slug }} 20 | {{ result.translated.metaDescription|striptags|trim|u.truncate(maxLength ?? 160, '…') }} 21 | {% if result.blogAuthor.email != "N/A" %} 22 | {{ result.blogAuthor.email ~ " (" ~ result.blogAuthor.displayName ~ ")"}} 23 | {% endif %} 24 | {{ result.publishedAt | date("d M Y H:i:s T") }} 25 | 26 | {% endfor %} 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Util/Update.php: -------------------------------------------------------------------------------- 1 | getCurrentPluginVersion(), '1.1.0', '<')) { 18 | $this->updateTo110($container); 19 | } 20 | 21 | if (version_compare($updateContext->getCurrentPluginVersion(), '1.3.0', '<')) { 22 | $this->updateTo130($container); 23 | } 24 | } 25 | 26 | private function updateTo110(ContainerInterface $container): void 27 | { 28 | /** @var Connection $connection */ 29 | $connection = $container->get(Connection::class); 30 | 31 | $blogEntriesEntityName = BlogEntriesDefinition::ENTITY_NAME; 32 | if (!$connection->getSchemaManager()->tablesExist([$blogEntriesEntityName])) { 33 | $blogEntriesMigration = new Migration1602739765AddTeaserImageColumnToBlogEntries(); 34 | $blogEntriesMigration->update($connection); 35 | } 36 | } 37 | 38 | private function updateTo130(ContainerInterface $container): void 39 | { 40 | /** @var Connection $connection */ 41 | $connection = $container->get(Connection::class); 42 | 43 | $blogEntriesEntityName = BlogEntriesDefinition::ENTITY_NAME; 44 | if (!$connection->getSchemaManager()->tablesExist([$blogEntriesEntityName])) { 45 | $blogEntriesMigration = new Migration1612160298CreatePubslihedDateColumn(); 46 | $blogEntriesMigration->update($connection); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests/Cypress/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | .idea 4 | /node_modules 5 | 6 | /cypress/videos 7 | /cypress/screenshots 8 | 9 | -------------------------------------------------------------------------------- /tests/Cypress/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Easy Testing 3 | 4 | Running Cypress tests is easy! 5 | Just install it by using the built in makefile commands 6 | and either open your tests in the Cypress UI, or run them directly from your CLI. 7 | 8 | 9 | ### Installation 10 | 11 | This folder contains a `makefile` with all required commands. 12 | Run the installation command to install Cypress and all its dependencies on your machine 13 | 14 | ```ruby 15 | make install 16 | ``` 17 | 18 | 19 | ### Cypress UI 20 | If you want to run your Cypress UI, just open it with the following command. 21 | Please note, because this is an Open Source project, we cannot include a 22 | shop URL in the configuration. Thus you need to provide it on your own. 23 | The tests might differ between Shopware versions, though the baseline is always the same. 24 | So there is an additional parameter to tell Cypress what Shopware version should be tested. 25 | This parameter is optional and its default is always the latest supported Shopware version. 26 | 27 | ```ruby 28 | make open-ui url=https://my-local-or-remote-domain 29 | 30 | make open-ui url=https://my-local-or-remote-domain shopware=6.3 31 | ``` 32 | 33 | ### Run in CLI 34 | You can also use the CLI command to run Cypress on your machine or directly in your build pipeline. 35 | Cypress will then test your local or remote shop with the tests of the provided Shopware version. 36 | 37 | ```ruby 38 | make run url=https://my-local-or-remote-domain shopware=6.x 39 | ``` 40 | 41 | ### Troubleshooting 42 | 43 | Shopware 6.4.4.0 introduced LAX cookies. 44 | The tests have been adjusted to work with that change, but you need to use HTTPS! 45 | Once changed, it should all work as expected. -------------------------------------------------------------------------------- /tests/Cypress/cypress.config.example.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('cypress') 2 | 3 | module.exports = defineConfig({ 4 | e2e: { 5 | experimentalSessionAndOrigin: true, 6 | }, 7 | responseTimeout: 80000, 8 | env: { 9 | user: 'admin', 10 | pass: 'shopware', 11 | salesChannelName: 'Storefront', 12 | admin: '/admin', 13 | apiPath: 'api', 14 | locale: 'en-GB', 15 | shopwareRoot: "../../../../..", 16 | localUsage: false, 17 | usePercy: false, 18 | minAuthTokenLifetime: 60, 19 | acceptLanguage: 'en-GB,en;q=0.5', 20 | expectedVersion: '6.6.', 21 | grepOmitFiltered: true, 22 | grepFilterSpecs: true, 23 | }, 24 | }) -------------------------------------------------------------------------------- /tests/Cypress/cypress/config/dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "chromeWebSecurity": false, 3 | "watchForFileChanges": false, 4 | "trashAssetsBeforeRuns": true, 5 | "screenshotOnRunFailure": true, 6 | "experimentalSessionAndOrigin": true, 7 | "video": false, 8 | "retries": 1, 9 | "devices": [ 10 | { 11 | "key": "desktop", 12 | "name": "Desktop", 13 | "width": 1920, 14 | "height": 1080, 15 | "userAgent": "" 16 | }, 17 | { 18 | "key": "ipad-landscape", 19 | "name": "iPad (Landscape)", 20 | "width": 1024, 21 | "height": 768, 22 | "userAgent": "Mozilla/5.0 (iPad; CPU OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B176 Safari/7534.48.3" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /tests/Cypress/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /tests/Cypress/cypress/integration/administration/cms.spec.js: -------------------------------------------------------------------------------- 1 | import blogDetailAction from '../../support/actions/admin/BlogDetailAction'; 2 | import repoCmsPage from '../../support/repositories/admin/general/CmsPageRepository'; 3 | 4 | const blogTitle = 'Blog Entry Title'; 5 | 6 | describe('Blog CMS: content with cms blocks', () => { 7 | beforeEach(() => { 8 | cy.authenticate() 9 | .then(() => { 10 | cy.viewport(1920, 1080); 11 | cy.openInitialPage(`${Cypress.env('admin')}#/blog/module/create`); 12 | }); 13 | }); 14 | 15 | it('@content: should not show werkl-blog block category', () => { 16 | 17 | blogDetailAction.openBlockSidebar(); 18 | 19 | repoCmsPage.getBlockCategoryWerklBlogOption().should('not.exist'); 20 | }); 21 | 22 | it.only('@content: can drag block to stage', () => { 23 | blogDetailAction.openSidebar(); 24 | 25 | blogDetailAction.fillBlogForm(blogTitle, true, true, true); 26 | 27 | blogDetailAction.addFullWidthCmsSection(); 28 | 29 | blogDetailAction.setBlockCategory('Text'); 30 | 31 | repoCmsPage.getCmsTextBlock().should('be.visible'); 32 | 33 | repoCmsPage.getCmsTextBlock().dragTo(repoCmsPage.getEmptySectionSelector()); 34 | 35 | repoCmsPage.getCmsBlockConfigOverlay().should('exist'); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /tests/Cypress/cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************************** 3 | // This example plugins/index.js can be used to load plugins 4 | // 5 | // You can change the location of this file or turn off loading 6 | // the plugins file with the 'pluginsFile' configuration option. 7 | // 8 | // You can read more here: 9 | // https://on.cypress.io/plugins-guide 10 | // *********************************************************** 11 | 12 | // This function is called when a project is opened or re-opened (e.g. due to 13 | // the project's config changing) 14 | 15 | /** 16 | * @type {Cypress.PluginConfig} 17 | */ 18 | // eslint-disable-next-line no-unused-vars 19 | module.exports = (on, config) => { 20 | // `on` is used to hook into various events Cypress emits 21 | // `config` is the resolved Cypress config 22 | } 23 | -------------------------------------------------------------------------------- /tests/Cypress/cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | 27 | /** 28 | * Performs a drag and drop operation 29 | * @memberOf Cypress.Chainable# 30 | * @name dragTo 31 | * @param {String} targetEl - The target element to drag source to 32 | * @function 33 | */ 34 | Cypress.Commands.add( 35 | "dragTo", 36 | {prevSubject: 'element'}, 37 | (subject, targetEl) => { 38 | cy.wrap(subject).trigger("mousedown"); 39 | cy.wait(200); 40 | 41 | cy.get('.is--draggable').should('be.visible'); 42 | cy.get(targetEl) 43 | .should('be.visible') 44 | .trigger('mouseenter') 45 | .trigger('mousemove', 'center') 46 | .should('have.class', 'is--droppable') 47 | .trigger('mouseup'); 48 | } 49 | ); 50 | -------------------------------------------------------------------------------- /tests/Cypress/cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | require('@shopware-ag/e2e-testsuite-platform/cypress/support'); 17 | require('./commands'); 18 | 19 | Cypress.on('uncaught:exception', (err, runnable) => { 20 | // returning false here prevents Cypress from 21 | // failing the test because some third party apps 22 | // cause an error in the console which stops the test 23 | return false; 24 | }); 25 | -------------------------------------------------------------------------------- /tests/Cypress/cypress/support/repositories/admin/blog/BlogDetailsRepository.js: -------------------------------------------------------------------------------- 1 | class BlogDetailsRepository { 2 | 3 | /** 4 | * @returns {Cypress.Chainable>} 5 | */ 6 | getPageHeadline() { 7 | return cy.get('.sw-sidebar-item__headline'); 8 | } 9 | 10 | /** 11 | * @returns {Cypress.Chainable>} 12 | */ 13 | getSaveButton() { 14 | return cy.get('.sw-cms-detail__save-action'); 15 | } 16 | 17 | /** 18 | * @returns {Cypress.Chainable>} 19 | */ 20 | getBlogDetailNavItem() { 21 | return cy.get(':nth-child(1) > .sw-sidebar-navigation-item'); 22 | } 23 | 24 | /** 25 | * @returns {Cypress.Chainable>} 26 | */ 27 | getBlogDetailNavItemBadge() { 28 | return this.getBlogDetailNavItem().children('.sidebar-item-badge'); 29 | } 30 | } 31 | 32 | export default new BlogDetailsRepository(); 33 | -------------------------------------------------------------------------------- /tests/Cypress/cypress/support/repositories/admin/general/DatePickerRepository.js: -------------------------------------------------------------------------------- 1 | class DatePickerRepository { 2 | 3 | /** 4 | * Get today's date 5 | * @returns {Cypress.Chainable>} 6 | */ 7 | getDatePickerToday() { 8 | return cy.get('.flatpickr-day.today'); 9 | } 10 | 11 | /** 12 | * Get first day of the month in the date picker 13 | * @returns {Cypress.Chainable>} 14 | */ 15 | getDatePickerStartOfMonth() { 16 | return cy.get('.flatpickr-day:first-child'); 17 | } 18 | 19 | /** 20 | * Get last day of the month in the date picker 21 | * @returns {Cypress.Chainable>} 22 | */ 23 | getDatePickerEndOfMonth() { 24 | return cy.get('.flatpickr-day:last-child'); 25 | } 26 | 27 | /** 28 | * Get the previous month button in the date picker 29 | * @returns {Cypress.Chainable>} 30 | */ 31 | getDatePickerPrevMonth() { 32 | return cy.get('.flatpickr-prev-month'); 33 | } 34 | 35 | /** 36 | * Get the next month button in the date picker 37 | * @returns {Cypress.Chainable>} 38 | */ 39 | getDatePickerNextMonth() { 40 | return cy.get('.flatpickr-next-month'); 41 | } 42 | } 43 | 44 | export default new DatePickerRepository(); 45 | -------------------------------------------------------------------------------- /tests/Cypress/cypress/support/services/shopware/Shopware.js: -------------------------------------------------------------------------------- 1 | export default class Shopware { 2 | 3 | /** 4 | * 5 | * @returns {*} 6 | */ 7 | getVersion() { 8 | return Cypress.env().SHOPWARE; 9 | } 10 | 11 | /** 12 | * 13 | * @param version 14 | * @returns {boolean} 15 | */ 16 | isVersionLower(version) { 17 | const diff = this._cmpVersions(this.getVersion(), version); 18 | return (diff < 0); 19 | } 20 | 21 | /** 22 | * 23 | * @param version 24 | * @returns {boolean} 25 | */ 26 | isVersionLowerEqual(version) { 27 | const diff = this._cmpVersions(this.getVersion(), version); 28 | return (diff <= 0); 29 | } 30 | 31 | /** 32 | * 33 | * @param version 34 | * @returns {boolean} 35 | */ 36 | isVersionEqual(version) { 37 | const diff = this._cmpVersions(this.getVersion(), version); 38 | return (diff === 0); 39 | } 40 | 41 | /** 42 | * 43 | * @param version 44 | * @returns {boolean} 45 | */ 46 | isVersionGreater(version) { 47 | const diff = this._cmpVersions(this.getVersion(), version); 48 | return (diff > 0); 49 | } 50 | 51 | /** 52 | * 53 | * @param version 54 | * @returns {boolean} 55 | */ 56 | isVersionGreaterEqual(version) { 57 | const diff = this._cmpVersions(this.getVersion(), version); 58 | return (diff >= 0); 59 | } 60 | 61 | /** 62 | * 63 | * @param a 64 | * @param b 65 | * @returns {number} 66 | */ 67 | _cmpVersions(a, b) { 68 | 69 | a = a.toString(); 70 | b = b.toString(); 71 | 72 | var i, diff; 73 | var regExStrip0 = /(\.0+)+$/; 74 | var segmentsA = a.replace(regExStrip0, '').split('.'); 75 | var segmentsB = b.replace(regExStrip0, '').split('.'); 76 | var l = Math.min(segmentsA.length, segmentsB.length); 77 | 78 | for (i = 0; i < l; i++) { 79 | diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10); 80 | if (diff) { 81 | return diff; 82 | } 83 | } 84 | return segmentsA.length - segmentsB.length; 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /tests/Cypress/makefile: -------------------------------------------------------------------------------- 1 | .PHONY: help 2 | .DEFAULT_GOAL := help 3 | 4 | 5 | help: 6 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' 7 | 8 | # --------------------------------------------------------------------------------------------- 9 | 10 | install: ## Installs all dependencies 11 | npm install cypress --save-dev --save . 12 | npm install webpack@5.88.2 --save-dev --save . 13 | npm install @cypress/webpack-preprocessor --save-dev --save . 14 | npm install @cucumber/tag-expressions --save-dev --save . 15 | npm install axios --save-dev --save . 16 | 17 | clean: ## Clean all dependencies 18 | rm -rf node_modules 19 | rm -rf package.json 20 | rm -rf package-lock.json 21 | 22 | # --------------------------------------------------------------------------------------------- 23 | 24 | open-ui: ## Opens Cypress UI 25 | ifndef url 26 | $(warning Please provide the URL argument to Start Cypress!) 27 | @exit 1 28 | endif 29 | ifndef shopware 30 | CYPRESS_BASE_URL=$(url) CYPRESS_SHOPWARE=6.6.4.0 ./node_modules/.bin/cypress open --env conf=dev 31 | else 32 | CYPRESS_BASE_URL=$(url) CYPRESS_SHOPWARE=$(shopware) ./node_modules/.bin/cypress open --env conf=dev 33 | endif 34 | 35 | # --------------------------------------------------------------------------------------------- 36 | 37 | run: ## Runs all E2E tests for Shopware 38 | ifndef url 39 | $(warning Please provide the URL argument to Start Cypress!) 40 | @exit 1 41 | endif 42 | ifndef shopware 43 | $(warning Please provide the Shopware Version as argument to Start Cypress!) 44 | @exit 1 45 | endif 46 | CYPRESS_BASE_URL=$(url) CYPRESS_SHOPWARE=$(shopware) ./node_modules/.bin/cypress run --env conf=dev --headless 47 | -------------------------------------------------------------------------------- /tests/Cypress/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@shopware-ag/e2e-testsuite-platform": "^8.0.0", 4 | "uuid": "3.3.3" 5 | }, 6 | "devDependencies": { 7 | "@cucumber/tag-expressions": "^4.1.0", 8 | "@cypress/webpack-preprocessor": "^5.17.1", 9 | "axios": "^0.27.2", 10 | "cypress": "^9.7.0", 11 | "webpack": "^5.88.2" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/PHPUnit/Content/Blog/Events/BlogMainFilterEventTest.php: -------------------------------------------------------------------------------- 1 | createMock(Request::class); 23 | $fakeSalesChannelContext = $this->getMockBuilder(SalesChannelContext::class)->disableOriginalConstructor()->getMock(); 24 | 25 | $criteria = new Criteria(); 26 | $event = new BlogMainFilterEvent( 27 | $request, 28 | $criteria, 29 | $fakeSalesChannelContext 30 | ); 31 | 32 | static::assertEquals($criteria, $event->getCriteria()); 33 | static::assertEquals($fakeSalesChannelContext, $event->getSalesChannelContext()); 34 | static::assertEquals($fakeSalesChannelContext->getContext(), $event->getContext()); 35 | static::assertInstanceOf(Criteria::class, $event->getCriteria()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/PHPUnit/Page/Blog/BlogPageCriteriaEventTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder(SalesChannelContext::class)->disableOriginalConstructor()->getMock(); 23 | 24 | $criteria = new Criteria(); 25 | $event = new BlogPageCriteriaEvent( 26 | $articleId, 27 | $criteria, 28 | $fakeSalesChannelContext 29 | ); 30 | 31 | static::assertEquals($criteria, $event->getCriteria()); 32 | static::assertEquals($fakeSalesChannelContext, $event->getSalesChannelContext()); 33 | static::assertEquals($fakeSalesChannelContext->getContext(), $event->getContext()); 34 | static::assertInstanceOf(Criteria::class, $event->getCriteria()); 35 | static::assertSame($articleId, $event->getArticleId()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/PHPUnit/Page/Blog/BlogPageLoadedEventTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder(SalesChannelContext::class)->disableOriginalConstructor()->getMock(); 22 | 23 | $page = $this->createMock(BlogPage::class); 24 | 25 | $event = new BlogPageLoadedEvent( 26 | $page, 27 | $fakeSalesChannelContext, 28 | new Request() 29 | ); 30 | 31 | static::assertEquals($page, $event->getPage()); 32 | static::assertEquals($fakeSalesChannelContext, $event->getSalesChannelContext()); 33 | static::assertInstanceOf(BlogPage::class, $event->getPage()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/PHPUnit/Traits/ContextTrait.php: -------------------------------------------------------------------------------- 1 | getContext($testCase); 20 | 21 | $salesChannel = $testCase->createConfiguredMock(SalesChannelEntity::class, [ 22 | 'getId' => '12345678901234567890123456789012', 23 | ]); 24 | 25 | return $testCase->createConfiguredMock(SalesChannelContext::class, [ 26 | 'getLanguageId' => '12345678901234567890123456789012', 27 | 'getSalesChannelId' => $salesChannel->getId(), 28 | 'getSalesChannel' => $salesChannel, 29 | 'getContext' => $context, 30 | ]); 31 | } 32 | 33 | /** 34 | * @return MockObject|Context 35 | */ 36 | protected function getContext(TestCase $testCase) 37 | { 38 | return $testCase->createMock(Context::class); 39 | } 40 | } 41 | --------------------------------------------------------------------------------