diff --git a/src/Resources/app/administration/src/module/blog-module/page/werkl-blog-list/index.js b/src/Resources/app/administration/src/module/blog-module/page/werkl-blog-list/index.js index 15a40dad..866c87b5 100755 --- a/src/Resources/app/administration/src/module/blog-module/page/werkl-blog-list/index.js +++ b/src/Resources/app/administration/src/module/blog-module/page/werkl-blog-list/index.js @@ -1,8 +1,9 @@ import template from './werkl-blog-list.html.twig'; import './werkl-blog-list.scss'; -const { Mixin } = Shopware; +const { Mixin, Context } = Shopware; const Criteria = Shopware.Data.Criteria; +const { cloneDeep } = Shopware.Utils.object; export default { template, @@ -43,6 +44,10 @@ export default { return this.repositoryFactory.create('werkl_blog_category'); }, + pageRepository() { + return this.repositoryFactory.create('cms_page'); + }, + dateFilter() { return Shopware.Filter.getByName('date'); }, @@ -111,5 +116,140 @@ export default { openSponsorPage() { window.open('https://github.com/sponsors/7underlines', '_blank'); }, + + async onDuplicate(blogEntry) { + this.isLoading = true; + + try { + // Create criteria to load the full blog entry with all associations + const criteria = new Criteria(); + const sortCriteria = Criteria.sort('position', 'ASC', true); + + criteria + .addAssociation('blogCategories') + .addAssociation('tags') + .addAssociation('blogAuthor') + .getAssociation('cmsPage') + .getAssociation('sections') + .addSorting(sortCriteria) + .addAssociation('backgroundMedia') + .getAssociation('blocks') + .addSorting(sortCriteria) + .addAssociation('backgroundMedia') + .addAssociation('slots'); + + // Load the full blog entry + const fullBlogEntry = await this.blogEntryRepository.get( + blogEntry.id, + Context.api, + criteria + ); + + // Create a new CMS page (deep copy of the original) + let newCmsPage = null; + if (fullBlogEntry.cmsPage) { + newCmsPage = this.pageRepository.create(); + const originalPage = fullBlogEntry.cmsPage; + + // Copy basic page properties + newCmsPage.name = `${originalPage.name} (Copy)`; + newCmsPage.type = originalPage.type; + newCmsPage.locked = originalPage.locked; + newCmsPage.config = cloneDeep(originalPage.config); + + // Deep copy sections - use cloneDeep and then assign new IDs + if (originalPage.sections && originalPage.sections.length > 0) { + const clonedSections = cloneDeep(originalPage.sections); + newCmsPage.sections = clonedSections.map(section => { + // Remove the ID so Shopware creates a new one + delete section.id; + delete section.cmsPageId; + delete section.versionId; + + if (section.blocks) { + section.blocks = section.blocks.map(block => { + delete block.id; + delete block.sectionId; + delete block.versionId; + + if (block.slots) { + block.slots = block.slots.map(slot => { + delete slot.id; + delete slot.blockId; + delete slot.versionId; + return slot; + }); + } + + return block; + }); + } + + return section; + }); + } + + // Save the new CMS page first + await this.pageRepository.save(newCmsPage, Context.api); + } + + // Create the new blog entry + const newBlogEntry = this.blogEntryRepository.create(); + + // Copy properties from original blog entry + newBlogEntry.title = `${fullBlogEntry.title} (Copy)`; + newBlogEntry.slug = null; // Will be auto-generated from title + newBlogEntry.teaser = fullBlogEntry.teaser; + newBlogEntry.metaTitle = fullBlogEntry.metaTitle; + newBlogEntry.metaDescription = fullBlogEntry.metaDescription; + newBlogEntry.authorId = fullBlogEntry.authorId; + newBlogEntry.publishedAt = null; // Set to null for inactive entry + newBlogEntry.active = false; // Set as inactive by default + newBlogEntry.detailTeaserImage = fullBlogEntry.detailTeaserImage; + newBlogEntry.mediaId = fullBlogEntry.mediaId; + newBlogEntry.cmsPageId = newCmsPage ? newCmsPage.id : null; + + // Copy categories + if (fullBlogEntry.blogCategories && fullBlogEntry.blogCategories.length > 0) { + fullBlogEntry.blogCategories.forEach(category => { + newBlogEntry.blogCategories.add(category); + }); + } + + // Copy tags + if (fullBlogEntry.tags && fullBlogEntry.tags.length > 0) { + fullBlogEntry.tags.forEach(tag => { + newBlogEntry.tags.add(tag); + }); + } + + // Save the new blog entry + await this.blogEntryRepository.save(newBlogEntry, Context.api); + + // Show success notification + this.createNotificationSuccess({ + message: this.$tc('werkl-blog.list.notification.duplicateSuccess', 0, { + title: fullBlogEntry.title, + }), + }); + + // Refresh the list + await this.getList(); + + // Navigate to the duplicated entry + this.$router.push({ + name: 'blog.module.detail', + params: { id: newBlogEntry.id }, + }); + + } catch (error) { + this.createNotificationError({ + message: this.$tc('werkl-blog.list.notification.duplicateError'), + }); + console.error('Error duplicating blog entry:', error); + } finally { + this.isLoading = false; + } + }, }, }; diff --git a/src/Resources/app/administration/src/module/blog-module/page/werkl-blog-list/werkl-blog-list.html.twig b/src/Resources/app/administration/src/module/blog-module/page/werkl-blog-list/werkl-blog-list.html.twig index 29edf516..54b15f18 100644 --- a/src/Resources/app/administration/src/module/blog-module/page/werkl-blog-list/werkl-blog-list.html.twig +++ b/src/Resources/app/administration/src/module/blog-module/page/werkl-blog-list/werkl-blog-list.html.twig @@ -107,6 +107,16 @@ {% endblock %} + {% block werkl_blog_list_grid_actions %} + + {% endblock %} + {% endblock %} diff --git a/src/Resources/app/administration/src/module/blog-module/snippet/de-DE.json b/src/Resources/app/administration/src/module/blog-module/snippet/de-DE.json index fedca910..aee02040 100644 --- a/src/Resources/app/administration/src/module/blog-module/snippet/de-DE.json +++ b/src/Resources/app/administration/src/module/blog-module/snippet/de-DE.json @@ -13,11 +13,18 @@ "buttonAddBlogEntry": "Blog Eintrag erstellen", "buttonSponsor": "Entwicklung unterstützen", "messageEmpty": "Keine Einträge vorhanden", + "buttonDuplicate": "Duplizieren", + "contextMenuDuplicate": "Duplizieren", + "notification": { + "duplicateSuccess": "Blog Eintrag \"{title}\" wurde erfolgreich dupliziert.", + "duplicateError": "Fehler beim Duplizieren des Blog Eintrags." + }, "table": { "title": "Titel", "active": "Aktiv", "author": "Autor", - "publishedAt": "Veröffentlicht am" + "publishedAt": "Veröffentlicht am", + "actions": "Aktionen" } }, "detail": { diff --git a/src/Resources/app/administration/src/module/blog-module/snippet/en-GB.json b/src/Resources/app/administration/src/module/blog-module/snippet/en-GB.json index 55736748..f50f505d 100644 --- a/src/Resources/app/administration/src/module/blog-module/snippet/en-GB.json +++ b/src/Resources/app/administration/src/module/blog-module/snippet/en-GB.json @@ -13,11 +13,18 @@ "buttonAddBlogEntry": "Create blog entry", "buttonSponsor": "Support development", "messageEmpty": "No blog entries ...", + "buttonDuplicate": "Duplicate", + "contextMenuDuplicate": "Duplicate", + "notification": { + "duplicateSuccess": "Blog entry \"{title}\" has been successfully duplicated.", + "duplicateError": "Error duplicating blog entry." + }, "table": { "title": "Title", "active": "Active", "author": "Author", - "publishedAt": "Published at" + "publishedAt": "Published at", + "actions": "Actions" } }, "detail": {