├── .nvmrc ├── .gitignore ├── docs ├── .vuepress │ ├── style.styl │ ├── override.styl │ └── config.js ├── eel-helpers.md ├── how-tos.md ├── configuration.md ├── flowquery.md ├── nodetypes.md ├── index.md └── fusion-prototypes.md ├── Configuration ├── NodeTypes.Collection.PostContent.yaml ├── NodeTypes.Mixin.Limit.yaml ├── NodeTypes.Document.Category.yaml ├── NodeTypes.Mixin.Paginate.yaml ├── NodeTypes.Document.Tag.yaml ├── NodeTypes.Mixin.PublicationDate.yaml ├── NodeTypes.Mixin.SelectedPosts.yaml ├── NodeTypes.Mixin.RelatedPosts.yaml ├── NodeTypes.Mixin.SelectedCategories.yaml ├── NodeTypes.Mixin.Taggable.yaml ├── NodeTypes.Mixin.Excerpt.yaml ├── NodeTypes.Mixin.Categorisable.yaml ├── NodeTypes.Content.PostListing.yaml ├── NodeTypes.Mixin.Authorable.yaml ├── Settings.Neos.yaml ├── Settings.yaml ├── NodeTypes.Document.Post.yaml └── NodeTypes.Document.Author.yaml ├── Resources └── Private │ ├── Fusion │ ├── Helper │ │ └── ConvertToArray.fusion │ ├── Document │ │ ├── Tag.fusion │ │ ├── Author.fusion │ │ ├── Category.fusion │ │ └── Post.fusion │ ├── Component │ │ ├── PostList.fusion │ │ ├── PostContent.fusion │ │ ├── PostList.Item.fusion │ │ ├── CommentSection.fusion │ │ ├── PostList.Author.fusion │ │ ├── PostList.Tag.fusion │ │ └── PostList.Category.fusion │ ├── Root.fusion │ ├── Content │ │ └── PostListing.fusion │ └── Form │ │ └── BlogComment.fusion │ ├── Translations │ ├── en │ │ ├── NodeTypes │ │ │ ├── Collection │ │ │ │ └── PostContent.xlf │ │ │ ├── Document │ │ │ │ ├── CategoryBlog.xlf │ │ │ │ ├── Post.xlf │ │ │ │ ├── Tag.xlf │ │ │ │ └── Author.xlf │ │ │ ├── Mixin │ │ │ │ ├── Excerpt.xlf │ │ │ │ ├── Authorable.xlf │ │ │ │ ├── Limit.xlf │ │ │ │ ├── Paginate.xlf │ │ │ │ ├── RelatedPosts.xlf │ │ │ │ ├── SelectedPosts.xlf │ │ │ │ ├── PublicationDate.xlf │ │ │ │ ├── SelectedCategories.xlf │ │ │ │ ├── Taggable.xlf │ │ │ │ └── Categorisable.xlf │ │ │ └── Content │ │ │ │ └── PostListing.xlf │ │ ├── Form │ │ │ └── BlogComment.xlf │ │ └── Main.xlf │ └── de │ │ ├── NodeTypes │ │ ├── Collection │ │ │ └── PostContent.xlf │ │ ├── Document │ │ │ ├── CategoryBlog.xlf │ │ │ ├── Post.xlf │ │ │ ├── Tag.xlf │ │ │ └── Author.xlf │ │ ├── Mixin │ │ │ ├── Excerpt.xlf │ │ │ ├── Authorable.xlf │ │ │ ├── Paginate.xlf │ │ │ ├── Limit.xlf │ │ │ ├── RelatedPosts.xlf │ │ │ ├── SelectedPosts.xlf │ │ │ ├── SelectedCategories.xlf │ │ │ ├── PublicationDate.xlf │ │ │ ├── Taggable.xlf │ │ │ └── Categorisable.xlf │ │ └── Content │ │ │ └── PostListing.xlf │ │ ├── Form │ │ └── BlogComment.xlf │ │ └── Main.xlf │ └── Email │ └── comment_notification.html ├── .editorconfig ├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── Classes ├── FlowQuery │ └── Operations │ │ ├── FilterByTagsOperation.php │ │ ├── FilterByCategoriesOperation.php │ │ ├── FilterByReferencesOperation.php │ │ └── FilterByAuthorOperation.php ├── Eel │ └── Helper │ │ └── BlogHelper.php ├── Package.php ├── DataSource │ └── UserDataSource.php ├── NodeCreationHandler │ └── AuthorNodeCreationHandler.php └── Service │ └── PostNodePreparationService.php ├── .travis.yml ├── package.json ├── .releaserc ├── LICENSE ├── composer.json ├── README.md └── CHANGELOG.md /.nvmrc: -------------------------------------------------------------------------------- 1 | 8.11.0 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .idea/ 3 | .vscode/ 4 | .DS_STORE 5 | -------------------------------------------------------------------------------- /docs/.vuepress/style.styl: -------------------------------------------------------------------------------- 1 | #app 2 | .content:not(.custom) 3 | max-width: 920px 4 | line-height: 1.6rem 5 | -------------------------------------------------------------------------------- /docs/.vuepress/override.styl: -------------------------------------------------------------------------------- 1 | $neos-light-blue = #00adee 2 | $accentColor = $neos-light-blue 3 | $textColor = #2c3e50 4 | $codeBgColor = #282c34 5 | -------------------------------------------------------------------------------- /docs/eel-helpers.md: -------------------------------------------------------------------------------- 1 | # Eel Helpers 2 | 3 | ## Blog.getUserByIdentifier(*<user-identifier>*) 4 | For querying users, e.g. the author. 5 | 6 | ```fusion 7 | ${ Blog.getUserByIdentifier(q(blogPost).property('author')) } 8 | ``` -------------------------------------------------------------------------------- /Configuration/NodeTypes.Collection.PostContent.yaml: -------------------------------------------------------------------------------- 1 | 'Breadlesscode.Blog:Collection.PostContent': 2 | superTypes: 3 | 'Neos.Neos:ContentCollection': true 4 | label: '${ I18n.translate(node.nodeType.label) }' 5 | ui: 6 | icon: 'icon-folder-open' 7 | label: 'i18n' 8 | -------------------------------------------------------------------------------- /Resources/Private/Fusion/Helper/ConvertToArray.fusion: -------------------------------------------------------------------------------- 1 | prototype(Breadlesscode.Blog:Helper.ConvertToArray) < prototype(Neos.Fusion:Value) { 2 | value = ${ value } 3 | value.@process{ 4 | convertToArray = ${ [ value ] } 5 | convertToArray.@if.isNoArray = ${ Type.isArray(value) } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Configuration/NodeTypes.Mixin.Limit.yaml: -------------------------------------------------------------------------------- 1 | 'Breadlesscode.Blog:Mixin.Limit': 2 | abstract: true 3 | properties: 4 | limit: 5 | type: integer 6 | defaultValue: 15 7 | ui: 8 | label: 'i18n' 9 | reloadIfChanged: true 10 | inspector: 11 | group: 'blogPost' 12 | -------------------------------------------------------------------------------- /Configuration/NodeTypes.Document.Category.yaml: -------------------------------------------------------------------------------- 1 | # I wish I could name it category, but there is a fusion bug… 2 | 'Breadlesscode.Blog:Document.CategoryBlog': 3 | superTypes: 4 | 'Neos.Neos:Document': true 5 | ui: 6 | label: 'i18n' 7 | position: 300 8 | group: 'blog' 9 | icon: 'folder-open-o' 10 | -------------------------------------------------------------------------------- /Configuration/NodeTypes.Mixin.Paginate.yaml: -------------------------------------------------------------------------------- 1 | 'Breadlesscode.Blog:Mixin.Paginate': 2 | abstract: true 3 | properties: 4 | isPaginated: 5 | type: boolean 6 | defaultValue: false 7 | ui: 8 | label: 'i18n' 9 | reloadIfChanged: true 10 | inspector: 11 | group: 'blogPost' 12 | -------------------------------------------------------------------------------- /Resources/Private/Fusion/Document/Tag.fusion: -------------------------------------------------------------------------------- 1 | prototype(Breadlesscode.Blog:Document.Tag) > 2 | prototype(Breadlesscode.Blog:Document.Tag) < prototype(Neos.Neos:Page) { 3 | body > 4 | body = afx` 5 |
6 | 7 |
8 | ` 9 | } 10 | -------------------------------------------------------------------------------- /Resources/Private/Fusion/Document/Author.fusion: -------------------------------------------------------------------------------- 1 | prototype(Breadlesscode.Blog:Document.Author) > 2 | prototype(Breadlesscode.Blog:Document.Author) < prototype(Neos.Neos:Page) { 3 | body > 4 | body = afx` 5 |
6 | 7 |
8 | ` 9 | } 10 | -------------------------------------------------------------------------------- /Resources/Private/Fusion/Component/PostList.fusion: -------------------------------------------------------------------------------- 1 | prototype(Breadlesscode.Blog:Component.PostList) < prototype(Breadlesscode.Listable:List) { 2 | itemRenderer = 'Breadlesscode.Blog:Component.PostListItem' 3 | itemsPerPage = 10 4 | paginated = ${ true } 5 | collection = ${ q(site).find('[instanceof Breadlesscode.Blog:Document.Post]').get() } 6 | } 7 | -------------------------------------------------------------------------------- /Resources/Private/Fusion/Document/Category.fusion: -------------------------------------------------------------------------------- 1 | prototype(Breadlesscode.Blog:Document.CategoryBlog) > 2 | prototype(Breadlesscode.Blog:Document.CategoryBlog) < prototype(Neos.Neos:Page) { 3 | body > 4 | body = afx` 5 |
6 | 7 |
8 | ` 9 | } 10 | -------------------------------------------------------------------------------- /Configuration/NodeTypes.Document.Tag.yaml: -------------------------------------------------------------------------------- 1 | 'Breadlesscode.Blog:Document.Tag': 2 | superTypes: 3 | 'Neos.Neos:Document': true 4 | 5 | ui: 6 | label: 'i18n' 7 | group: 'blog' 8 | position: 400 9 | help: 10 | message: 'i18n' 11 | icon: 'tag' 12 | inspector: 13 | groups: 14 | blogPost: 15 | label: 'i18n' 16 | -------------------------------------------------------------------------------- /Configuration/NodeTypes.Mixin.PublicationDate.yaml: -------------------------------------------------------------------------------- 1 | 'Breadlesscode.Blog:Mixin.PublicationDate': 2 | abstract: true 3 | properties: 4 | datePublished: 5 | type: DateTime 6 | defaultValue: 'now' 7 | ui: 8 | label: 'i18n' 9 | reloadIfChanged: true 10 | inspector: 11 | position: 12 12 | group: blogPost 13 | -------------------------------------------------------------------------------- /Configuration/NodeTypes.Mixin.SelectedPosts.yaml: -------------------------------------------------------------------------------- 1 | 'Breadlesscode.Blog:Mixin.SelectedPosts': 2 | abstract: true 3 | properties: 4 | selectedPosts: 5 | type: references 6 | ui: 7 | label: 'i18n' 8 | reloadIfChanged: true 9 | inspector: 10 | group: 'blogPost' 11 | editorOptions: 12 | nodeTypes: ['Breadlesscode.Blog:Document.Post'] 13 | -------------------------------------------------------------------------------- /Configuration/NodeTypes.Mixin.RelatedPosts.yaml: -------------------------------------------------------------------------------- 1 | 'Breadlesscode.Blog:Mixin.RelatedPosts': 2 | abstract: true 3 | properties: 4 | relatedPosts: 5 | type: references 6 | ui: 7 | label: 'i18n' 8 | reloadIfChanged: true 9 | inspector: 10 | group: 'blogPost' 11 | position: 20 12 | editorOptions: 13 | nodeTypes: ['Breadlesscode.Blog:Document.Post'] 14 | -------------------------------------------------------------------------------- /Configuration/NodeTypes.Mixin.SelectedCategories.yaml: -------------------------------------------------------------------------------- 1 | 'Breadlesscode.Blog:Mixin.SelectedCategories': 2 | abstract: true 3 | properties: 4 | selectedCategories: 5 | type: references 6 | ui: 7 | label: 'i18n' 8 | reloadIfChanged: true 9 | inspector: 10 | group: 'blogPost' 11 | editorOptions: 12 | nodeTypes: ['Breadlesscode.Blog:Document.CategoryBlog'] 13 | -------------------------------------------------------------------------------- /Configuration/NodeTypes.Mixin.Taggable.yaml: -------------------------------------------------------------------------------- 1 | 'Breadlesscode.Blog:Mixin.Taggable': 2 | abstract: true 3 | properties: 4 | tags: 5 | type: references 6 | ui: 7 | label: 'i18n' 8 | help: 9 | message: 'i18n' 10 | inspector: 11 | position: 15 12 | group: blogPost 13 | editorOptions: 14 | nodeTypes: ['Breadlesscode.Blog:Document.Tag'] 15 | 16 | -------------------------------------------------------------------------------- /Resources/Private/Fusion/Root.fusion: -------------------------------------------------------------------------------- 1 | include: Helper/**/*.fusion 2 | include: Component/**/*.fusion 3 | include: Content/**/*.fusion 4 | include: Form/**/*.fusion 5 | include: Document/**/*.fusion 6 | 7 | # 8 | # Have fun by using this package 9 | # If you see an issue please report it here: 10 | # https://github.com/breadlesscode/neos-blog/issues 11 | # Documentation: 12 | # https://breadlesscode.github.io/neos-blog 13 | # 14 | -------------------------------------------------------------------------------- /Configuration/NodeTypes.Mixin.Excerpt.yaml: -------------------------------------------------------------------------------- 1 | 'Breadlesscode.Blog:Mixin.Excerpt': 2 | abstract: true 3 | properties: 4 | excerpt: 5 | type: string 6 | defaultValue: '' 7 | ui: 8 | label: 'i18n' 9 | reloadIfChanged: true 10 | inspector: 11 | group: 'blogPost' 12 | editor: 'Neos.Neos/Inspector/Editors/TextAreaEditor' 13 | editorOptions: 14 | rows: 6 15 | -------------------------------------------------------------------------------- /Configuration/NodeTypes.Mixin.Categorisable.yaml: -------------------------------------------------------------------------------- 1 | 'Breadlesscode.Blog:Mixin.Categorisable': 2 | abstract: true 3 | properties: 4 | categories: 5 | type: references 6 | ui: 7 | label: 'i18n' 8 | help: 9 | message: 'i18n' 10 | inspector: 11 | position: 15 12 | group: blogPost 13 | editorOptions: 14 | nodeTypes: ['Breadlesscode.Blog:Document.CategoryBlog'] 15 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/NodeTypes/Collection/PostContent.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Content 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/NodeTypes/Document/CategoryBlog.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Category 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/NodeTypes/Mixin/Excerpt.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Excerpt 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/NodeTypes/Mixin/Authorable.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Author 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/NodeTypes/Mixin/Limit.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Number of Posts 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_size = 4 9 | indent_style = space 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.{html,yml,yaml,js}] 15 | indent_size = 2 16 | 17 | [*.xlf] 18 | insert_final_newline = false 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/NodeTypes/Mixin/Paginate.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Pagination? 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Configuration/NodeTypes.Content.PostListing.yaml: -------------------------------------------------------------------------------- 1 | 'Breadlesscode.Blog:Content.PostListing': 2 | superTypes: 3 | 'Neos.Neos:Content': true 4 | 'Breadlesscode.Blog:Mixin.Limit': true 5 | 'Breadlesscode.Blog:Mixin.Paginate': true 6 | 'Breadlesscode.Blog:Mixin.SelectedPosts': true 7 | 'Breadlesscode.Blog:Mixin.SelectedCategories': true 8 | ui: 9 | label: 'i18n' 10 | icon: 'th-list' 11 | inspector: 12 | groups: 13 | blogPost: 14 | label: 'i18n' 15 | -------------------------------------------------------------------------------- /Configuration/NodeTypes.Mixin.Authorable.yaml: -------------------------------------------------------------------------------- 1 | 'Breadlesscode.Blog:Mixin.Authorable': 2 | abstract: true 3 | properties: 4 | author: 5 | type: string 6 | ui: 7 | label: 'i18n' 8 | inspector: 9 | position: 10 10 | group: blogPost 11 | editor: 'Content/Inspector/Editors/SelectBoxEditor' 12 | editorOptions: 13 | dataSourceIdentifier: 'breadlesscode-blog-user-datasource' 14 | minimumResultsForSearch: 3 15 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/NodeTypes/Mixin/RelatedPosts.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Related Posts 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/NodeTypes/Mixin/SelectedPosts.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Posts to show 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/NodeTypes/Mixin/PublicationDate.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Publication Date 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/NodeTypes/Mixin/SelectedCategories.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Selected categories 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Resources/Private/Fusion/Component/PostContent.fusion: -------------------------------------------------------------------------------- 1 | prototype(Breadlesscode.Blog:Component.PostContent) < prototype(Neos.Fusion:Component) { 2 | headline = ${ q(documentNode).property('title') } 3 | nodePath = 'main' 4 | 5 | renderer = afx` 6 |
7 |

{props.headline}

8 | 11 |
12 | ` 13 | } 14 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/Form/BlogComment.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Thank you! Your comment will be live as soon as possible. 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/NodeTypes/Collection/PostContent.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Content 7 | Inhalt 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/NodeTypes/Document/CategoryBlog.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Category 7 | Kategorie 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/NodeTypes/Mixin/Excerpt.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Excerpt 7 | Auszug 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/NodeTypes/Mixin/Authorable.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Author 7 | Autor 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/NodeTypes/Mixin/Paginate.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Pagination? 7 | Blätterfunktion? 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/NodeTypes/Mixin/Limit.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Number of Posts 7 | Maximale Anzahl an Posts 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/NodeTypes/Mixin/RelatedPosts.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Related Posts 7 | Ähnliche Posts 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/NodeTypes/Mixin/SelectedPosts.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Posts to show 7 | Anzuzeigende Posts 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/NodeTypes/Mixin/SelectedCategories.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Selected categories 7 | Anzuzeigende Kategorien 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/NodeTypes/Mixin/PublicationDate.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Publication Date 7 | Veröffentlichungs Datum 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/how-tos.md: -------------------------------------------------------------------------------- 1 | # How-Tos 2 | *more coming soon* 3 | 4 | ## How to add a finisher to the comment form? 5 | This packages uses the [breadlesscode/neos-commentable](https://github.com/breadlesscode/neos-commentable) package which is using the [neos/form-fusionrenderer](https://github.com/neos/form-fusionrenderer) package. You can easily add finishers like this: 6 | 7 | ```fusion 8 | prototype(Breadlesscode.Blog:Form.BlogComment) [ 9 | finisher { 10 | hereYourOwnFinisher = Neos.Form.Builder:EmailFinisher.Definition { 11 | // … the finisher options 12 | } 13 | } 14 | ] 15 | ``` -------------------------------------------------------------------------------- /Resources/Private/Translations/en/NodeTypes/Document/Post.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Article 7 | 8 | 9 | Article 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Resources/Private/Fusion/Component/PostList.Item.fusion: -------------------------------------------------------------------------------- 1 | prototype(Breadlesscode.Blog:Component.PostList.Item) < prototype(Neos.Fusion:Component) { 2 | excerpt = ${ q(item).property('excerpt') } 3 | 4 | renderer = afx` 5 |
6 |

7 | 8 |

9 |

{props.excerpt}

10 |
11 | ` 12 | } 13 | // for better backwards compablity 14 | prototype(Breadlesscode.Blog:Component.PostListItem) < prototype(Breadlesscode.Blog:Component.PostList.Item) 15 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/NodeTypes/Content/PostListing.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Blog post listing 7 | 8 | 9 | Blog post listing 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/Form/BlogComment.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Thank you! Your comment will be live as soon as possible. 7 | Danke! Dein Kommentar wird bald möglich freigeschaltet. 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/NodeTypes/Document/Tag.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tag 7 | 8 | 9 | You can create Tags for tagging your blog articles. 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Configuration/Settings.Neos.yaml: -------------------------------------------------------------------------------- 1 | Neos: 2 | Neos: 3 | userInterface: 4 | translation: 5 | autoInclude: 6 | 'Breadlesscode.Blog': 7 | - 'Form/*' 8 | - 'NodeTypes/*' 9 | - 'NodeTypes/Collection/*' 10 | - 'NodeTypes/Content/*' 11 | - 'NodeTypes/Document/*' 12 | - 'NodeTypes/Mixin/*' 13 | fusion: 14 | autoInclude: 15 | Breadlesscode.Blog: true 16 | nodeTypes: 17 | groups: 18 | blog: 19 | label: 'Blog' 20 | icon: 'newspaper' 21 | Fusion: 22 | defaultContext: 23 | 'Blog': 'Breadlesscode\Blog\Eel\Helper\BlogHelper' 24 | -------------------------------------------------------------------------------- /Configuration/Settings.yaml: -------------------------------------------------------------------------------- 1 | Breadlesscode: 2 | Blog: 3 | comments: 4 | confirmation: 5 | # Confirmation message, if null confirmation message is disabled 6 | message: 'Breadlesscode.Blog:Form.BlogComment:confirmation.message' 7 | notification: 8 | # enable mail on new comment 9 | sendMail: false 10 | # email subject 11 | subject: 'New Comment!' 12 | # the notification mail template path 13 | template: 'resource://Breadlesscode.Blog/Private/Email/comment_notification.html' 14 | # which is the recipient of the notification email 15 | recipient: 16 | email: null 17 | name: null 18 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/Main.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Category 7 | 8 | 9 | Tag 10 | 11 | 12 | Author 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/NodeTypes/Document/Post.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Article 7 | Blogpost 8 | 9 | 10 | Article 11 | Blogpost 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/NodeTypes/Mixin/Taggable.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tags 7 | 8 | 9 | Select a tags for your blog post. If you cant select a tag, you havent created one.Create a new tag by creating a new tag page. 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: "Neos-Blog Documentation", 3 | base: "/neos-blog/", 4 | themeConfig: { 5 | nav: [ 6 | { 7 | text: "Github", 8 | link: "https://github.com/breadlesscode/neos-blog" 9 | }, 10 | { 11 | text: "Example", 12 | link: "https://github.com/breadlesscode/neos-blog-example" 13 | }, 14 | ], 15 | sidebar: [ 16 | ["/", "Home"], 17 | ["/configuration.html", "Configuration"], 18 | ["/fusion-prototypes.html", "Fusion prototypes"], 19 | ["/nodetypes.html", "NodeTypes"], 20 | ["/flowquery.html", "FlowQuery"], 21 | ["/eel-helpers.html", "Eel Helpers"], 22 | ["/how-tos.md", "How-Tos"] 23 | ] 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /Resources/Private/Fusion/Document/Post.fusion: -------------------------------------------------------------------------------- 1 | prototype(Breadlesscode.Blog:Document.Post) > 2 | prototype(Breadlesscode.Blog:Document.Post) < prototype(Neos.Neos:Page) { 3 | @context { 4 | author = ${ Blog.getUserByIdentifier(q(node).property('author')) } 5 | publishDate = ${ Date.formatCldr(q(node).property('datePublished'), 'E, dd. MMMM y H:mm:ss (zzzz)') } 6 | } 7 | 8 | body > 9 | body = afx` 10 |
11 | 12 |
13 | {author.label} • 14 |
15 | 16 |
17 | ` 18 | body.@position = 'after bodyTag' 19 | } 20 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/NodeTypes/Content/PostListing.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Blog post listing 7 | Blogpost Liste 8 | 9 | 10 | Blog post listing 11 | Blogpost Liste 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Resources/Private/Fusion/Component/CommentSection.fusion: -------------------------------------------------------------------------------- 1 | prototype(Breadlesscode.Blog:Component.CommentSection) < prototype(Neos.Fusion:Component) { 2 | formPosition = 'top' 3 | 4 | renderer = afx` 5 |
6 |
8 | 9 |
10 | 11 |
13 | 14 |
15 |
16 | ` 17 | } 18 | -------------------------------------------------------------------------------- /Resources/Private/Fusion/Component/PostList.Author.fusion: -------------------------------------------------------------------------------- 1 | prototype(Breadlesscode.Blog:Component.PostList.Author) < prototype(Neos.Fusion:Component) { 2 | author = ${ documentNode } 3 | headline = ${ Translation.translate('Breadlesscode.Blog:Main:author.title') + ': ' + q(this.author).property('title') } 4 | itemsPerPage = 10 5 | paginated = true 6 | 7 | @context.collection = ${ q(site).find('[instanceof Breadlesscode.Blog:Document.Post]').filterByAuthor(this.author).get() } 8 | 9 | renderer = afx` 10 |

{ props.headline }

11 | 15 | ` 16 | } 17 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/NodeTypes/Document/Tag.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tag 7 | Tag 8 | 9 | 10 | You can create Tags for tagging your blog articles. 11 | Tags sind für das Tagging der Blog-Artikel nötig. 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Configuration/NodeTypes.Document.Post.yaml: -------------------------------------------------------------------------------- 1 | 'Breadlesscode.Blog:Document.Post': 2 | superTypes: 3 | 'Neos.Neos:Document': true 4 | 'Breadlesscode.Blog:Mixin.Authorable': true 5 | 'Breadlesscode.Blog:Mixin.Excerpt': true 6 | 'Breadlesscode.Blog:Mixin.PublicationDate': true 7 | 'Breadlesscode.Blog:Mixin.RelatedPosts': false 8 | 'Breadlesscode.Blog:Mixin.Taggable': true 9 | 'Breadlesscode.Blog:Mixin.Categorisable': true 10 | 'Breadlesscode.Commentable:Mixin.Commentable': true 11 | 12 | ui: 13 | label: 'i18n' 14 | group: 'blog' 15 | position: 200 16 | icon: 'newspaper' 17 | inspector: 18 | groups: 19 | blogPost: 20 | label: 'i18n' 21 | icon: 'newspaper' 22 | 23 | childNodes: 24 | main: 25 | type: 'Breadlesscode.Blog:Collection.PostContent' 26 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/NodeTypes/Mixin/Categorisable.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Categories 7 | 8 | 9 | 10 | Select a category for your blog post. If you cant select a category, you havent create one. 11 | Create a new category by creating a new category page. 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Resources/Private/Fusion/Component/PostList.Tag.fusion: -------------------------------------------------------------------------------- 1 | prototype(Breadlesscode.Blog:Component.PostList.Tag) < prototype(Neos.Fusion:Component) { 2 | tag = ${ documentNode } 3 | tag.@process.convertToArray = Breadlesscode.Blog:Helper.ConvertToArray 4 | headline = ${ Translation.translate('Breadlesscode.Blog:Main:tag.title') + ': ' + q(documentNode).property('title') } 5 | itemsPerPage = 10 6 | paginated = true 7 | 8 | renderer = afx` 9 |

{ props.headline }

10 | 14 | ` 15 | renderer.@context.posts = ${ q(site).find('[instanceof Breadlesscode.Blog:Document.Post]').filterByTags(props.tag).get() } 16 | } 17 | -------------------------------------------------------------------------------- /Resources/Private/Fusion/Component/PostList.Category.fusion: -------------------------------------------------------------------------------- 1 | prototype(Breadlesscode.Blog:Component.PostList.Category) < prototype(Neos.Fusion:Component) { 2 | category = ${ documentNode } 3 | category.@process.convertToArray = Breadlesscode.Blog:Helper.ConvertToArray 4 | headline = ${ Translation.translate('Breadlesscode.Blog:Main:category.title') + ': ' + q(this.category).property('title') } 5 | itemsPerPage = 10 6 | paginated = true 7 | 8 | renderer = afx` 9 |

{ props.headline }

10 | 14 | ` 15 | renderer.@context.posts = ${ q(site).find('[instanceof Breadlesscode.Blog:Document.Post]').filterByCategories(props.category).get() } 16 | } 17 | -------------------------------------------------------------------------------- /Resources/Private/Translations/en/NodeTypes/Document/Author.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Author 7 | 8 | 9 | Author 10 | 11 | 12 | User 13 | 14 | 15 | User 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/Main.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Category 7 | Kategorie 8 | 9 | 10 | Tag 11 | Tag 12 | 13 | 14 | Author 15 | Autor 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | 13 | 14 | ### Description 15 | 16 | [Description of the bug or feature] 17 | 18 | ### Steps to Reproduce 19 | 20 | 1. [First Step] 21 | 2. [Second Step] 22 | 3. [and so on...] 23 | 24 | #### Expected behavior 25 | 26 | [What you expected to happen] 27 | 28 | #### Actual behavior 29 | 30 | 33 | 34 | [What actually happened] 35 | 36 | ### Affected Versions 37 | 38 | Neos: 39 | 40 | You can get this information by running `composer show` or using the package management module within Neos. 41 | -------------------------------------------------------------------------------- /Classes/FlowQuery/Operations/FilterByTagsOperation.php: -------------------------------------------------------------------------------- 1 | getContext(), $this->getReferenceFilter('tags', $arguments[0])); 30 | $flowQuery->setContext($context); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: false 3 | node_js: 4 | - "10" 5 | env: 6 | - CXX=g++-4.8 7 | addons: 8 | apt: 9 | sources: 10 | - ubuntu-toolchain-r-test 11 | packages: 12 | - g++-4.8 13 | cache: 14 | directories: 15 | - ~/.npm 16 | - node_modules 17 | notifications: 18 | email: false 19 | before_install: 20 | - nvm install && nvm use 21 | - curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.9.4 22 | - export PATH="$HOME/.yarn/bin:$PATH" 23 | - yarn install 24 | install: 25 | - yarn global add vuepress 26 | script: yarn run docs:build 27 | after_success: 28 | - yarn semantic-release 29 | branches: 30 | except: 31 | - /^v\d+\.\d+\.\d+$/ 32 | deploy: 33 | provider: pages 34 | skip-cleanup: true 35 | local_dir: docs/.vuepress/dist 36 | github-token: $GITHUB_TOKEN # Set in the settings page of your repository, as a secure variable 37 | repo: breadlesscode/neos-blog 38 | keep-history: true 39 | on: 40 | branch: master 41 | -------------------------------------------------------------------------------- /Classes/Eel/Helper/BlogHelper.php: -------------------------------------------------------------------------------- 1 | userRepo->findByIdentifier($userIdentifier); 25 | } 26 | 27 | /** 28 | * All methods are considered safe, i.e. can be executed from within Eel 29 | * 30 | * @param string $methodName 31 | * @return boolean 32 | */ 33 | public function allowsCallOfMethod($methodName) 34 | { 35 | return true; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "neos-blog", 3 | "version": "2.0.5", 4 | "repository": "git@github.com:breadlesscode/neos-blog.git", 5 | "license": "MIT", 6 | "dependencies": {}, 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 0", 9 | "semantic-release": "semantic-release", 10 | "docs:dev": "vuepress dev docs", 11 | "docs:build": "vuepress build docs", 12 | "commit": "git-cz" 13 | }, 14 | "devDependencies": { 15 | "@semantic-release/changelog": "^3.0.2", 16 | "@semantic-release/git": "^7.0.8", 17 | "@semantic-release/release-notes-generator": "^7.1.4", 18 | "commitizen": "^3.0.7", 19 | "conventional-changelog-eslint": "^3.0.1", 20 | "cz-adapter-eslint": "^0.2.0", 21 | "semantic-release": "^15.13.3", 22 | "vuepress": "^0.14.10" 23 | }, 24 | "config": { 25 | "commitizen": { 26 | "path": "./node_modules/cz-adapter-eslint" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Classes/FlowQuery/Operations/FilterByCategoriesOperation.php: -------------------------------------------------------------------------------- 1 | getContext(), $this->getReferenceFilter('categories', $arguments[0])); 30 | $flowQuery->setContext($context); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.releaserc: -------------------------------------------------------------------------------- 1 | { 2 | "branch": "master", 3 | "analyzeCommits": { 4 | "preset": "eslint", 5 | "releaseRules": [ 6 | {"tag": "Upgrade", "release": "patch"} 7 | ] 8 | }, 9 | "verifyConditions": [ 10 | { 11 | "path": "@semantic-release/changelog", 12 | "changelogFile": "CHANGELOG.md", 13 | "changelogTitle": "Changelog breadlesscode/neos-blog" 14 | }, 15 | "@semantic-release/github" 16 | ], 17 | "prepare": [ 18 | "@semantic-release/changelog", 19 | "@semantic-release/npm", 20 | { 21 | "path": "@semantic-release/git", 22 | "assets": ["package.json", "Resources/Public", "CHANGELOG.md"], 23 | "message": "Build: Release ${nextRelease.version} [skip ci]" 24 | } 25 | ], 26 | "generateNotes": { 27 | "preset": "eslint", 28 | "writerOpts": { 29 | "commitsSort": ["subject", "scope"], 30 | } 31 | }, 32 | "publish": ["@semantic-release/github"] 33 | } 34 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/NodeTypes/Mixin/Taggable.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tags 7 | Tags 8 | 9 | 10 | Select a tags for your blog post. If you cant select a tag, you havent created one. 11 | Create a new tag by creating a new tag page. 12 | 13 | Wähle Tags für diesen Blogpost aus. Wenn noch keine Tags erstellt wurden, 14 | kann man dies einfach über Seite erstellen erledigen. 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | ```yaml 4 | Breadlesscode: 5 | Blog: 6 | comments: 7 | confirmation: 8 | # Confirmation message, if null confirmation message is disabled 9 | message: 'Breadlesscode.Blog:Form.BlogComment:confirmation.message' 10 | notification: 11 | # enable mail on new comment 12 | sendMail: false 13 | # email subject 14 | subject: 'New Comment!' 15 | # the notification mail template path 16 | template: 'resource://Breadlesscode.Blog/Private/Email/comment_notification.html' 17 | # which is the recipient of the notification email 18 | recipient: 19 | email: null 20 | name: null 21 | ``` 22 | 23 | ## Pagination 24 | 25 | See this documentation: [https://github.com/breadlesscode/neos-listable#configuration](https://github.com/breadlesscode/neos-listable#configuration) 26 | 27 | ## (Swift)Mailer 28 | 29 | See this documentation: [https://swiftmailer-for-flow.readthedocs.io/en/latest/#configuration](https://swiftmailer-for-flow.readthedocs.io/en/latest/#configuration) -------------------------------------------------------------------------------- /Resources/Private/Fusion/Content/PostListing.fusion: -------------------------------------------------------------------------------- 1 | prototype(Breadlesscode.Blog:Content.PostListing) > 2 | prototype(Breadlesscode.Blog:Content.PostListing) < prototype(Neos.Neos:ContentComponent) { 3 | renderer = Breadlesscode.Blog:Component.PostList { 4 | paginated = ${ q(node).property('isPaginated') } 5 | itemsPerPage = ${ q(node).property('limit') } 6 | collection = Neos.Fusion:Case { 7 | selectedPosts { 8 | condition = ${ q(node).property('selectedPosts') } 9 | renderer = ${ q(node).property('selectedPosts') } 10 | } 11 | selectedCategories { 12 | condition = ${ q(node).property('selectedCategories') } 13 | renderer = ${ q(site).find('[instanceof Breadlesscode.Blog:Document.Post]').filterByCategories(q(node).property('selectedCategories')).get() } 14 | } 15 | allPosts { 16 | condition = ${ true } 17 | renderer = ${ q(site).find('[instanceof Breadlesscode.Blog:Document.Post]') } 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Marvin Kuhn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/NodeTypes/Document/Author.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Author 7 | Autor 8 | 9 | 10 | Author 11 | Autor 12 | 13 | 14 | User 15 | Benutzer 16 | 17 | 18 | User 19 | Benutzer 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Resources/Private/Translations/de/NodeTypes/Mixin/Categorisable.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Categories 7 | Kategorien 8 | 9 | 10 | 11 | Select a category for your blog post. If you cant select a category, you havent create one. 12 | Create a new category by creating a new category page. 13 | 14 | 15 | Wähle eine Kategorie für deinen Blogpost aus. Wenn noch keiner erstellt wurde, kann man über 16 | Seite anlegen eine neue Kategorie erstellen. 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/flowquery.md: -------------------------------------------------------------------------------- 1 | # FlowQuery-Oprations 2 | 3 | ## filterByTags(*<tags>*) 4 | You can filter a collection of nodes by tags. Example: 5 | 6 | ```fusion 7 | ${ q(site) 8 | .find('[instanceof Breadlesscode.Blog:Document.Post]') 9 | .fliterByTags(q(node).property('tags')) 10 | .get() } 11 | ``` 12 | 13 | ## filterByCategories(*<categories>*) 14 | You can filter a collection of nodes by tags. Example: 15 | 16 | ```fusion 17 | ${ q(site) 18 | .find('[instanceof Breadlesscode.Blog:Document.Post]') 19 | .filterByCategories(q(node).property('categories')) 20 | .get() } 21 | ``` 22 | 23 | ## filterByAuthor(*<user-identifier>*) 24 | You can filter a collection of nodes by the author. Example: 25 | 26 | ```fusion 27 | ${ q(site) 28 | .find('[instanceof Breadlesscode.Blog:Document.Post]') 29 | .filterByAuthor(q(node).property('author')) 30 | .get() } 31 | ``` 32 | 33 | ## filterByReferences(*<property-name>*, *<references>*) 34 | You can filter a collection of nodes by a collection of references. Example: 35 | 36 | ```fusion 37 | ${ q(site) 38 | .find('[instanceof Breadlesscode.Blog:Document.Post]') 39 | .filterByReferences('categories', q(node).property('categories')) 40 | .get() } 41 | ``` 42 | -------------------------------------------------------------------------------- /Classes/Package.php: -------------------------------------------------------------------------------- 1 | getSignalSlotDispatcher(); 18 | 19 | $dispatcher->connect( 20 | 'Neos\ContentRepository\Domain\Model\Node', 21 | 'nodeAdded', 22 | 'Breadlesscode\Blog\Service\PostNodePreparationService', 23 | 'afterNodeAdded' 24 | ); 25 | $dispatcher->connect( 26 | 'Neos\ContentRepository\Domain\Model\Node', 27 | 'beforeNodeMove', 28 | 'Breadlesscode\Blog\Service\PostNodePreparationService', 29 | 'beforeNodeMoved' 30 | ); 31 | $dispatcher->connect( 32 | 'Neos\ContentRepository\Domain\Model\Node', 33 | 'afterNodeMove', 34 | 'Breadlesscode\Blog\Service\PostNodePreparationService', 35 | 'afterNodeMoved' 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /docs/nodetypes.md: -------------------------------------------------------------------------------- 1 | # NodeTypes 2 | All node types the package provides. 3 | 4 | ## Document 5 | ### `Breadlesscode.Blog:Document.Post` 6 | ```yaml 7 | 'Breadlesscode.Blog:Document.Post': 8 | superTypes: 9 | 'Neos.Neos:Document': true 10 | 'Breadlesscode.Blog:Mixin.Authorable': true 11 | 'Breadlesscode.Blog:Mixin.PublicationDate': true 12 | 'Breadlesscode.Blog:Mixin.RelatedPosts': false 13 | 'Breadlesscode.Blog:Mixin.Taggable': true 14 | 'Breadlesscode.Blog:Mixin.Categorisable': true 15 | 'Breadlesscode.Commentable:Mixin.Commentable': true 16 | ``` 17 | 18 | ### `Breadlesscode.Blog:Document.Author` 19 | ```yaml 20 | 'Breadlesscode.Blog:Document.Author': 21 | superTypes: 22 | 'Neos.Neos:Document': true 23 | ``` 24 | 25 | 26 | ### `Breadlesscode.Blog:Document.CategoryBlog` 27 | ```yaml 28 | 'Breadlesscode.Blog:Document.CategoryBlog': 29 | superTypes: 30 | 'Neos.Neos:Document': true 31 | ``` 32 | 33 | ### `Breadlesscode.Blog:Document.Tag` 34 | ```yaml 35 | 'Breadlesscode.Blog:Document.Tag': 36 | superTypes: 37 | 'Neos.Neos:Document': true 38 | ``` 39 | 40 | ## Content 41 | ### `Breadlesscode.Blog:Content.PostListing` 42 | ```yaml 43 | 'Breadlesscode.Blog:Content.PostListing': 44 | superTypes: 45 | 'Neos.Neos:Content': true 46 | 'Breadlesscode.Blog:Mixin.Limit': true 47 | 'Breadlesscode.Blog:Mixin.Paginate': true 48 | 'Breadlesscode.Blog:Mixin.SelectedPosts': true 49 | 'Breadlesscode.Blog:Mixin.SelectedCategories': true 50 | ``` -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "neos-plugin", 3 | "name": "breadlesscode/neos-blog", 4 | "license": "MIT", 5 | "description": "Ready to use blog package", 6 | "authors": [ 7 | { 8 | "name": "Marvin Kuhn", 9 | "email": "marvin@kuhnweblab.com", 10 | "homepage": "https://kuhnweblab.com", 11 | "role": "Developer" 12 | } 13 | ], 14 | "keywords": [ 15 | "flow", 16 | "neos", 17 | "blog", 18 | "plugin", 19 | "author", 20 | "category", 21 | "tags" 22 | ], 23 | "require": { 24 | "neos/flow": "*", 25 | "neos/neos": "~4.0", 26 | "neos/fusion-afx": "~1.0", 27 | "neos/swiftmailer": "~6.0", 28 | "breadlesscode/neos-commentable": "~1.1", 29 | "breadlesscode/neos-listable": "~1.2" 30 | }, 31 | "autoload": { 32 | "psr-4": { 33 | "Breadlesscode\\Blog\\": "Classes/" 34 | } 35 | }, 36 | "archive": { 37 | "exclude": [ 38 | ".editorconfig", 39 | ".gitattributes", 40 | ".github", 41 | ".gitignore", 42 | ".releaserc", 43 | ".nvmrc", 44 | ".travis.yml", 45 | "CODE_OF_CONDUCT.md", 46 | "package.json", 47 | "yarn.lock", 48 | "docs" 49 | ] 50 | }, 51 | "extra": { 52 | "neos": { 53 | "package-key": "Breadlesscode.Blog" 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Classes/DataSource/UserDataSource.php: -------------------------------------------------------------------------------- 1 | userRepository->findAll(); 39 | $data = []; 40 | 41 | foreach ($users as $user) 42 | { 43 | $data[] = [ 44 | 'label' => $user->getLabel(), 45 | 'value' => $this->persistenceManager->getIdentifierByObject($user) 46 | ]; 47 | } 48 | 49 | return $data; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Configuration/NodeTypes.Document.Author.yaml: -------------------------------------------------------------------------------- 1 | 'Breadlesscode.Blog:Document.Author': 2 | superTypes: 3 | 'Neos.Neos:Document': true 4 | 5 | ui: 6 | label: 'i18n' 7 | group: 'blog' 8 | position: 500 9 | icon: 'far fa-user-circle' 10 | inspector: 11 | groups: 12 | author: 13 | label: 'i18n' 14 | icon: 'far fa-user-circle' 15 | 16 | creationDialog: 17 | elements: 18 | title: ~ 19 | user: 20 | type: string 21 | ui: 22 | label: 'i18n' 23 | editor: 'Neos.Neos/Inspector/Editors/SelectBoxEditor' 24 | editorOptions: 25 | dataSourceIdentifier: 'breadlesscode-blog-user-datasource' 26 | minimumResultsForSearch: 3 27 | validation: 28 | 'Neos.Flow\Validation\Validator\NumberRangeValidator': ~ 29 | 30 | options: 31 | documentTitle: ~ 32 | nodeCreationHandlers: 33 | user: 34 | nodeCreationHandler: 'Breadlesscode\Blog\NodeCreationHandler\AuthorNodeCreationHandler' 35 | 36 | properties: 37 | user: 38 | type: string 39 | ui: 40 | label: 'i18n' 41 | inspector: 42 | position: 10 43 | group: author 44 | editor: 'Neos.Neos/Inspector/Editors/SelectBoxEditor' 45 | editorOptions: 46 | dataSourceIdentifier: 'breadlesscode-blog-user-datasource' 47 | minimumResultsForSearch: 3 48 | validation: 49 | 'Neos.Flow\Validation\Validator\NumberRangeValidator': ~ 50 | -------------------------------------------------------------------------------- /Resources/Private/Fusion/Form/BlogComment.fusion: -------------------------------------------------------------------------------- 1 | prototype(Breadlesscode.Blog:Form.BlogComment) < prototype(Breadlesscode.Commentable:Form.Comment) { 2 | finishers { 3 | sendNotification = Neos.Form.Builder:EmailFinisher.Definition { 4 | options { 5 | subject = ${ Configuration.setting('Breadlesscode.Blog.comments.notification.subject') } 6 | recipientName = ${ Configuration.setting('Breadlesscode.Blog.comments.notification.recipient.name') } 7 | recipientName.@if.hasName = ${ Configuration.setting('Breadlesscode.Blog.comments.notification.recipient.name') } 8 | recipientAddress = ${ Configuration.setting('Breadlesscode.Blog.comments.notification.recipient.email') } 9 | templatePathAndFilename = ${ Configuration.setting('Breadlesscode.Blog.comments.notification.template') } 10 | senderAddress = '{email}' 11 | senderName = '{name}' 12 | variables = Neos.Fusion:RawArray { 13 | post = ${ documentNode } 14 | } 15 | } 16 | 17 | @if.notificationIsEnabled = ${ Configuration.setting('Breadlesscode.Blog.comments.notification.sendMail') } 18 | @position = 'before addComment' 19 | } 20 | sayThankYou = Neos.Form.Builder:ConfirmationFinisher.Definition { 21 | options { 22 | message = ${ Translation.translate(Configuration.setting('Breadlesscode.Blog.comments.confirmation.message')) } 23 | message.@process.wrapInParagraph = ${ '

' + value + '

' } 24 | } 25 | 26 | @if.hasMessage = ${ Configuration.setting('Breadlesscode.Blog.comments.confirmation.message') } 27 | @position = 'before addComment' 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Neos Blog 2 | 3 | [![Packagist](https://img.shields.io/packagist/v/breadlesscode/neos-blog.svg?style=flat-square)](https://packagist.org/packages/breadlesscode/neos-blog) 4 | [![Downloads](https://img.shields.io/packagist/dt/breadlesscode/neos-blog.svg)](https://packagist.org/packages/breadlesscode/neos-blog) 5 | [![Packagist](https://img.shields.io/packagist/l/breadlesscode/neos-blog.svg?style=flat-square)](https://packagist.org/packages/breadlesscode/neos-blog) 6 | [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) 7 | [![GitHub stars](https://img.shields.io/github/stars/breadlesscode/neos-blog.svg?style=social&label=Stars)](https://github.com/breadlesscode/neos-blog/stargazers) 8 | [![GitHub watchers](https://img.shields.io/github/watchers/breadlesscode/neos-blog.svg?style=social&label=Watch)](https://github.com/breadlesscode/neos-blog/subscription) 9 | 10 | This Neos CMS plugin is for a simple blog functionality. 11 | 12 | ## Features 13 | - Categories 14 | - Tags 15 | - Comments 16 | - Author page 17 | - Listing with pagination 18 | 19 | ## Installation 20 | Most of the time you have to make small adjustments to a package (e.g. the configuration in Settings.yaml). Because of that, it is important to add the corresponding package to the composer from your theme package. Mostly this is the site package located under Packages/Sites/. To install it correctly go to your theme package (e.g.Packages/Sites/Foo.Bar) and run following command: 21 | 22 | ```bash 23 | composer require breadlesscode/neos-blog --no-update 24 | ``` 25 | 26 | The --no-update command prevent the automatic update of the dependencies. After the package was added to your theme composer.json, go back to the root of the Neos installation and run composer update. Your desired package is now installed correctly. 27 | -------------------------------------------------------------------------------- /Classes/NodeCreationHandler/AuthorNodeCreationHandler.php: -------------------------------------------------------------------------------- 1 | getNodeType()->isOfType(PostNodePreparationService::DOCUMENT_AUTHOR_TYPE)) { 47 | return; 48 | } 49 | /** @var User $user */ 50 | $user = $this->userRepo->findByIdentifier($data['user']); 51 | 52 | $node->setProperty('user', $data['user']); 53 | $node->setProperty('title', $user->getLabel()); 54 | $node->setProperty('uriPathSegment', $this->nodeUriPathSegmentGenerator->generateUriPathSegment($node, $user->getLabel())); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Classes/FlowQuery/Operations/FilterByReferencesOperation.php: -------------------------------------------------------------------------------- 1 | getContext(), $this->getReferenceFilter($arguments[0], $arguments[1])); 36 | $flowQuery->setContext($context); 37 | } 38 | 39 | /** 40 | * this method returns a closure which intersect references on a given property 41 | * 42 | * @param string $propertyName 43 | * @param array $references 44 | * @return \Closure 45 | */ 46 | public function getReferenceFilter(string $propertyName, array $references) 47 | { 48 | return function (NodeInterface $node) use ($propertyName, $references) { 49 | $nodeReferences = $node->getProperty($propertyName); 50 | 51 | if ($nodeReferences === null) { 52 | return false; 53 | } 54 | return count(array_intersect($nodeReferences, $references)) > 0; 55 | }; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Classes/FlowQuery/Operations/FilterByAuthorOperation.php: -------------------------------------------------------------------------------- 1 | isAuthorDocumentNode($arguments[0])) { 34 | throw new FlowQueryException('The first parameter of '.self::$shortName.' should be a string or a node of type '.self::AUTHOR_DOCUMENT_NODETYPE.'.'); 35 | } 36 | 37 | if ($arguments[0] instanceof NodeInterface) { 38 | $arguments[0] = $arguments[0]->getProperty('user'); 39 | } 40 | 41 | if ($arguments[0] === false || $arguments[0] === null || $arguments[0] === '') { 42 | return; 43 | } 44 | 45 | $context = \array_filter($flowQuery->getContext(), function (NodeInterface $node) use ($arguments) { 46 | return $node->getProperty('author') === $arguments[0]; 47 | }); 48 | 49 | $flowQuery->setContext($context); 50 | } 51 | 52 | /** 53 | * checks the given argument if its a author page 54 | * 55 | * @param mixed $node 56 | * @return boolean 57 | */ 58 | protected function isAuthorDocumentNode($node) 59 | { 60 | return ( 61 | $node instanceof NodeInterface && 62 | $node->getNodeType()->getName() === self::AUTHOR_DOCUMENT_NODETYPE 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Neos Blog 2 | 3 | [![Packagist](https://img.shields.io/packagist/v/breadlesscode/neos-blog.svg?style=flat-square)](https://packagist.org/packages/breadlesscode/neos-blog) 4 | [![Downloads](https://img.shields.io/packagist/dt/breadlesscode/neos-blog.svg)](https://packagist.org/packages/breadlesscode/neos-blog) 5 | [![Packagist](https://img.shields.io/packagist/l/breadlesscode/neos-blog.svg?style=flat-square)](https://packagist.org/packages/breadlesscode/neos-blog) 6 | [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) 7 | [![GitHub stars](https://img.shields.io/github/stars/breadlesscode/neos-blog.svg?style=social&label=Stars)](https://github.com/breadlesscode/neos-blog/stargazers) 8 | [![GitHub watchers](https://img.shields.io/github/watchers/breadlesscode/neos-blog.svg?style=social&label=Watch)](https://github.com/breadlesscode/neos-blog/subscription) 9 | 10 | This Neos CMS plugin is for a simple blog functionality. 11 | 12 | ## Features 13 | - Categories 14 | - Tags 15 | - Comments 16 | - Author page 17 | - Listing with pagination 18 | 19 | 20 | ## Installation 21 | Most of the time you have to make small adjustments to a package (e.g., the configuration in Settings.yaml). Because of that, it is important to add the corresponding package to the composer from your theme package. Mostly this is the site package located under Packages/Sites/. To install it correctly go to your theme package (e.g.Packages/Sites/Foo.Bar) and run following command: 22 | 23 | ```bash 24 | composer require breadlesscode/neos-blog --no-update 25 | ``` 26 | 27 | The --no-update command prevent the automatic update of the dependencies. After the package was added to your theme composer.json, go back to the root of the Neos installation and run composer update. Your desired package is now installed correctly. 28 | 29 | ## Documentation 30 | 31 | Documentation: https://breadlesscode.github.io/neos-blog 32 | 33 | ## Contribution 34 | 35 | We'd love you to contribute to neos-blog. We try to make it as easy as possible. 36 | We are using semantic-release to have more time to concentrate on important stuff 37 | instead of struggling in the dependency or release hell. 38 | 39 | Therefore the first rule is to follow the [eslint commit message guideline](https://github.com/conventional-changelog-archived-repos/conventional-changelog-eslint/blob/master/convention.md). 40 | It is really easy, when you always commit via `yarn commit`. Commitizen will guide you. 41 | 42 | All PRs will be merged into the master branch. Travis and semantic release will check the commit messages and start 43 | building a new release when the analysis of the latest commits will trigger that. 44 | 45 | If you have questions just ping us on twitter or github. 46 | 47 | 48 | ## License 49 | The MIT License (MIT). Please see [License File](LICENSE) for more information. 50 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [2.0.5](https://github.com/breadlesscode/neos-blog/compare/v2.0.4...v2.0.5) (2019-06-12) 2 | 3 | 4 | ### Fix 5 | 6 | * wired author page listing bug ([e460ddff1404f8151adabbd01c6e4a8ca484ecf8](https://github.com/breadlesscode/neos-blog/commit/e460ddff1404f8151adabbd01c6e4a8ca484ecf8)) 7 | 8 | ## [2.0.4](https://github.com/breadlesscode/neos-blog/compare/v2.0.3...v2.0.4) (2019-06-12) 9 | 10 | 11 | ### Fix 12 | 13 | * fxied silly array index error :confounded: ([6be8dbf55554ac00b1fc9abda3efe1d0c6c4ef6e](https://github.com/breadlesscode/neos-blog/commit/6be8dbf55554ac00b1fc9abda3efe1d0c6c4ef6e)) 14 | 15 | ## [2.0.3](https://github.com/breadlesscode/neos-blog/compare/v2.0.2...v2.0.3) (2019-06-12) 16 | 17 | 18 | ### Fix 19 | 20 | * filter helpers now accepts non array arguments ([292640e919af9314ca6ae5115fec570ab314cecb](https://github.com/breadlesscode/neos-blog/commit/292640e919af9314ca6ae5115fec570ab314cecb)), closes [#7](https://github.com/breadlesscode/neos-blog/issues/7) 21 | 22 | ## [2.0.1](https://github.com/breadlesscode/neos-blog/compare/v2.0.0...v2.0.1) (2019-04-10) 23 | 24 | 25 | ### Upgrade 26 | 27 | * Update commitizen ([d6e429d759197b40f44212b53efa87e249daa5e7](https://github.com/breadlesscode/neos-blog/commit/d6e429d759197b40f44212b53efa87e249daa5e7)) 28 | * Updating vuepress ([292cf4506f05988b33d415fcccf0845a0d58e342](https://github.com/breadlesscode/neos-blog/commit/292cf4506f05988b33d415fcccf0845a0d58e342)) 29 | * Upgrade semantic-release ([ba58f8f7b56e6a1468def6a0e48af18a96c47af0](https://github.com/breadlesscode/neos-blog/commit/ba58f8f7b56e6a1468def6a0e48af18a96c47af0)) 30 | 31 | ## [1.3.2](https://github.com/breadlesscode/neos-blog/compare/v1.3.1...v1.3.2) (2018-11-21) 32 | 33 | 34 | ### Fix 35 | 36 | * fixed exception on create new blog post ([725cb93ce21e10ed14368dda306cc70dcd2bafd5](https://github.com/breadlesscode/neos-blog/commit/725cb93ce21e10ed14368dda306cc70dcd2bafd5)) 37 | 38 | # [1.3.0](https://github.com/breadlesscode/neos-blog/compare/v1.2.0...v1.3.0) (2018-11-16) 39 | 40 | 41 | ### TASK 42 | 43 | * Update category-change on move of posts ([5e01140757e25b92f0912e8a5eb66be56e7f25f1](https://github.com/breadlesscode/neos-blog/commit/5e01140757e25b92f0912e8a5eb66be56e7f25f1)) 44 | 45 | ### Update 46 | 47 | * Update semantic-release packages to the latest version ([7528a4b886cbeddd9b0afc0a396fad8b6d30db7e](https://github.com/breadlesscode/neos-blog/commit/7528a4b886cbeddd9b0afc0a396fad8b6d30db7e)) 48 | 49 | # [1.2.0](https://github.com/breadlesscode/neos-blog/compare/v1.1.1...v1.2.0) (2018-10-11) 50 | 51 | 52 | ### Docs 53 | 54 | * Adjust badges ([72d11093f307b690d44b89cf687a49bdba87d992](https://github.com/breadlesscode/neos-blog/commit/72d11093f307b690d44b89cf687a49bdba87d992)) 55 | 56 | ### New 57 | 58 | * Use translated date formats ([7df3efd85ad3704b7d74b4717e45bf79328a9cc3](https://github.com/breadlesscode/neos-blog/commit/7df3efd85ad3704b7d74b4717e45bf79328a9cc3)), closes [#6](https://github.com/breadlesscode/neos-blog/issues/6) 59 | 60 | ## [1.1.1](https://github.com/breadlesscode/neos-blog/compare/v1.1.0...v1.1.1) (2018-09-29) 61 | 62 | 63 | ### Fix 64 | 65 | * Adjust travis configuration ([0cc294ef17b88e9ce4fb2cccc448ea05a2eaf0c3](https://github.com/breadlesscode/neos-blog/commit/0cc294ef17b88e9ce4fb2cccc448ea05a2eaf0c3)) 66 | * Create missing node config file ([bddbbe1983168e51f7bfe5fa758e57fc40d69c32](https://github.com/breadlesscode/neos-blog/commit/bddbbe1983168e51f7bfe5fa758e57fc40d69c32)) 67 | * Remove unneeded version number ([f7ff1db7254fbc87542129a750c1a65111bda355](https://github.com/breadlesscode/neos-blog/commit/f7ff1db7254fbc87542129a750c1a65111bda355)) 68 | -------------------------------------------------------------------------------- /Classes/Service/PostNodePreparationService.php: -------------------------------------------------------------------------------- 1 | getNodeType()->isOfType(self::DOCUMENT_POST_TYPE)) { 53 | return; 54 | } 55 | 56 | $this->setAuthorOfPostNodeToCurrentUser($node); 57 | $this->addParentCategoryToPostNode($node); 58 | } 59 | 60 | /** 61 | * this functions listens to the nodeMoved event 62 | * 63 | * @param NodeInterface $node 64 | * @throws \Neos\Eel\Exception 65 | */ 66 | public function beforeNodeMoved(NodeInterface $node) 67 | { 68 | if (!$node->getNodeType()->isOfType(self::DOCUMENT_POST_TYPE)) { 69 | return; 70 | } 71 | 72 | $this->removeParentCategoryFromPostNode($node); 73 | } 74 | 75 | /** 76 | * this functions listens to the nodeMoved event 77 | * 78 | * @param NodeInterface $node 79 | * @throws \Neos\Eel\Exception 80 | */ 81 | public function afterNodeMoved(NodeInterface $node) 82 | { 83 | if (!$node->getNodeType()->isOfType(self::DOCUMENT_POST_TYPE)) { 84 | return; 85 | } 86 | 87 | $this->addParentCategoryToPostNode($node); 88 | } 89 | 90 | /** 91 | * sets the current user label to the author property of the blog post node 92 | * 93 | * @param NodeInterface $node 94 | * @return void 95 | */ 96 | protected function setAuthorOfPostNodeToCurrentUser(NodeInterface $node) 97 | { 98 | $currentUser = $this->userDomainService->getCurrentUser(); 99 | $userIdentifier = $this->persistenceManager->getIdentifierByObject($currentUser); 100 | 101 | $node->setProperty('author', $userIdentifier); 102 | } 103 | 104 | /** 105 | * sets the parent category to the category property of the blog post node 106 | * 107 | * @param NodeInterface $node 108 | * @return void 109 | * @throws \Neos\Eel\Exception 110 | */ 111 | protected function removeParentCategoryFromPostNode(NodeInterface $node) 112 | { 113 | $parentCategory = (new FlowQuery([$node])) 114 | ->parent('[instanceof '. self::DOCUMENT_CATEGORY_TYPE .']') 115 | ->get(0); 116 | 117 | if ($parentCategory !== null) { 118 | $categories = $node->getProperty('categories'); 119 | $index = array_search($parentCategory, $categories, true); 120 | if ($index !== false) { 121 | array_splice($categories, $index, 1); 122 | $node->setProperty('categories', $categories); 123 | } 124 | } 125 | } 126 | 127 | /** 128 | * sets the parent category to the category property of the blog post node 129 | * 130 | * @param NodeInterface $node 131 | * @return void 132 | * @throws \Neos\Eel\Exception 133 | */ 134 | protected function addParentCategoryToPostNode(NodeInterface $node) 135 | { 136 | $parentCategory = (new FlowQuery([$node])) 137 | ->parent('[instanceof '. self::DOCUMENT_CATEGORY_TYPE .']') 138 | ->get(0); 139 | 140 | if ($parentCategory !== null) { 141 | $categories = $node->getProperty('categories') ?? []; 142 | if (array_search($parentCategory, $categories, true) === false) { 143 | $categories[] = $parentCategory; 144 | $node->setProperty('categories', $categories); 145 | } 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /docs/fusion-prototypes.md: -------------------------------------------------------------------------------- 1 | # Fusion prototypes 2 | 3 | **Attention:** All Fusion prototypes are prefixed with `Breadlesscode.Blog:`. You can't use `Component.PostList` e.g. in your fusion code. You have to use `Breadlesscode.Blog:Component.PostList`. 4 | 5 | ## `Component.CommentSection` 6 | This prototype displays the comment form and the comments. 7 | 8 | ### Properties 9 | 10 | | Name | Default value | Description | 11 | | ------------ | ------------- | ----------- | 12 | | formPosition | `'top'` | Defines the position of the comment form. If it's set to `'top'` it's displayed on top of the comments. If the value is `'bottom'`, it's the other way round. | 13 | 14 | ## `Component.PostList` 15 | This prototype is for displaying all kind of post lists. 16 | 17 | ### Properties 18 | | Name | Default value | Description | 19 | | ------------ | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | 20 | | collection | `${ q(site).find('[instanceof Breadlesscode.Blog:Document.Post]').get() }` | Should contain all post items you want to display | 21 | | headline | `${q(documentNode).property('title')}` | Headline displayed on top of this list. Can be disabled by setting property to `false` | 22 | | itemsPerPage | `5` | Defines how many items/posts per page are shown | 23 | | paginated | `true` | List pagination flag, if is false, pagination is disabled | 24 | 25 | 26 | ## `Component.PostList.Author` 27 | This prototype is for displaying all kind of post lists. 28 | 29 | ### Properties 30 | | Name | Default value | Description | 31 | | ------------ | -------------------------------------- | -------------------------------------------------------------------------------------- | 32 | | author | `${ documentNode }` | Filters posts by author (user identifier) | 33 | | headline | `${q(documentNode).property('title')}` | Headline displayed on top of this list. Can be disabled by setting property to `false` | 34 | | itemsPerPage | `5` | Defines how many items/posts per page are shown | 35 | | paginated | `true` | List pagination flag, if is false, pagination is disabled | 36 | 37 | ## `Component.PostList.Category` 38 | This prototype is for displaying all kind of post lists. 39 | 40 | ### Properties 41 | | Name | Default value | Description | 42 | | ------------ | -------------------------------------- | ------------------------------------------------------------------------------------- | 43 | | category | `${ documentNode }` | Filters posts by one or more categories | 44 | | headline | `${q(documentNode).property('title')}` | Headline displayed ontop of this list. Can be disabled by setting property to `false` | 45 | | itemsPerPage | `5` | Defines how many items/posts per page are shown | 46 | | paginated | `true` | List pagination flag, if is false, pagination is disabled | 47 | 48 | ## `Component.PostList.Tag` 49 | This prototype is for displaying all kind of post lists. 50 | 51 | ### Properties 52 | | Name | Default value | Description | 53 | | ------------ | -------------------------------------- | -------------------------------------------------------------------------------------- | 54 | | tag | `${ documentNode }` | Filters posts by tag or tags | 55 | | headline | `${q(documentNode).property('title')}` | headline displayed on top of this list. Can be disabled by setting property to `false` | 56 | | itemsPerPage | `5` | Defines how many items/posts per page are shown | 57 | | paginated | `true` | List pagination flag, if is false, pagination is disabled | 58 | 59 | ## `Component.PostList.Item` 60 | This prototype represents one item in the post list. 61 | 62 | ### Properties 63 | | Name | Default value | Description | 64 | | ------------ | -------------------------------------- | -------------------------------------------------------------------------------------- | 65 | | excerpt | `${ q(item).property('excerpt') }` | This property is used for a small sub text under the listitem headline | 66 | | renderer | `${q(documentNode).property('title')}` | Here you can override the complete redering of a single list item | 67 | -------------------------------------------------------------------------------- /Resources/Private/Email/comment_notification.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | New comment 7 | 81 | 82 | 83 | 84 | 85 | 86 | 135 | 136 | 137 |
  87 |
88 | 91 | 92 | 93 | 122 | 123 |
94 | 95 | 96 | 119 | 120 |
97 |

Hi there,

98 |

there is a new comment on the blog post „{post.properties.title}”.

99 | 100 | 101 | 102 | 115 | 116 | 117 |
103 | 104 | 105 | 106 | 111 | 112 | 113 |
107 | 108 | Review comment 109 | 110 |
114 |
118 |
121 |
124 | 133 |
134 |
 
138 | 139 | 140 | --------------------------------------------------------------------------------