Full Code of rainlab/blog-plugin for AI

master de6b3137cbcd cached
84 files
295.7 KB
75.5k tokens
142 symbols
1 requests
Download .txt
Showing preview only (331K chars total). Download the full file or copy to clipboard to get everything.
Repository: rainlab/blog-plugin
Branch: master
Commit: de6b3137cbcd
Files: 84
Total size: 295.7 KB

Directory structure:
gitextract_104lrz67/

├── .gitignore
├── LICENCE.md
├── Plugin.php
├── README.md
├── assets/
│   ├── css/
│   │   ├── rainlab.blog-export.css
│   │   └── rainlab.blog-preview.css
│   ├── js/
│   │   └── post-form.js
│   └── less/
│       └── rainlab.blog-preview.less
├── classes/
│   └── TagProcessor.php
├── components/
│   ├── Categories.php
│   ├── Post.php
│   ├── Posts.php
│   ├── RssFeed.php
│   ├── categories/
│   │   ├── default.htm
│   │   └── items.htm
│   ├── post/
│   │   └── default.htm
│   ├── posts/
│   │   └── default.htm
│   └── rssfeed/
│       └── default.htm
├── composer.json
├── config/
│   └── config.php
├── controllers/
│   ├── Categories.php
│   ├── Posts.php
│   ├── categories/
│   │   ├── _list_toolbar.htm
│   │   ├── _reorder_toolbar.htm
│   │   ├── config_form.yaml
│   │   ├── config_list.yaml
│   │   ├── config_reorder.yaml
│   │   ├── create.htm
│   │   ├── index.htm
│   │   ├── reorder.htm
│   │   └── update.htm
│   └── posts/
│       ├── _list_toolbar.htm
│       ├── _post_toolbar.htm
│       ├── config_form.yaml
│       ├── config_import_export.yaml
│       ├── config_list.yaml
│       ├── create.htm
│       ├── export.htm
│       ├── import.htm
│       ├── index.htm
│       └── update.htm
├── formwidgets/
│   ├── BlogMarkdown.php
│   └── MLBlogMarkdown.php
├── lang/
│   ├── bg/
│   │   └── lang.php
│   ├── cs/
│   │   └── lang.php
│   ├── de/
│   │   └── lang.php
│   ├── en/
│   │   └── lang.php
│   ├── es/
│   │   └── lang.php
│   ├── fa/
│   │   └── lang.php
│   ├── fi/
│   │   └── lang.php
│   ├── fr/
│   │   └── lang.php
│   ├── hu/
│   │   └── lang.php
│   ├── it/
│   │   └── lang.php
│   ├── ja/
│   │   └── lang.php
│   ├── nb-no/
│   │   └── lang.php
│   ├── nl/
│   │   └── lang.php
│   ├── pl/
│   │   └── lang.php
│   ├── pt-br/
│   │   └── lang.php
│   ├── ru/
│   │   └── lang.php
│   ├── sk/
│   │   └── lang.php
│   ├── sl/
│   │   └── lang.php
│   ├── tr/
│   │   └── lang.php
│   └── zh-cn/
│       └── lang.php
├── models/
│   ├── Category.php
│   ├── Post.php
│   ├── PostExport.php
│   ├── PostImport.php
│   ├── Settings.php
│   ├── category/
│   │   ├── columns.yaml
│   │   └── fields.yaml
│   ├── post/
│   │   ├── columns.yaml
│   │   ├── fields.yaml
│   │   └── scopes.yaml
│   ├── postexport/
│   │   └── columns.yaml
│   ├── postimport/
│   │   ├── columns.yaml
│   │   └── fields.yaml
│   └── settings/
│       └── fields.yaml
└── updates/
    ├── categories_add_nested_fields.php
    ├── create_categories_table.php
    ├── create_posts_table.php
    ├── posts_add_metadata.php
    ├── seed_all_tables.php
    ├── update_timestamp_nullable.php
    └── version.yaml

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.DS_Store

================================================
FILE: LICENCE.md
================================================
# MIT license

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: Plugin.php
================================================
<?php namespace RainLab\Blog;

use Backend;
use Controller;
use RainLab\Blog\Models\Post;
use System\Classes\PluginBase;
use RainLab\Blog\Classes\TagProcessor;
use RainLab\Blog\Models\Category;
use Event;

class Plugin extends PluginBase
{
    public function pluginDetails()
    {
        return [
            'name'        => 'rainlab.blog::lang.plugin.name',
            'description' => 'rainlab.blog::lang.plugin.description',
            'author'      => 'Alexey Bobkov, Samuel Georges',
            'icon'        => 'icon-pencil',
            'homepage'    => 'https://github.com/rainlab/blog-plugin'
        ];
    }

    public function registerComponents()
    {
        return [
            'RainLab\Blog\Components\Post'       => 'blogPost',
            'RainLab\Blog\Components\Posts'      => 'blogPosts',
            'RainLab\Blog\Components\Categories' => 'blogCategories',
            'RainLab\Blog\Components\RssFeed'    => 'blogRssFeed'
        ];
    }

    public function registerPermissions()
    {
        return [
            'rainlab.blog.manage_settings' => [
                'tab'   => 'rainlab.blog::lang.blog.tab',
                'label' => 'rainlab.blog::lang.blog.manage_settings'
            ],
            'rainlab.blog.access_posts' => [
                'tab'   => 'rainlab.blog::lang.blog.tab',
                'label' => 'rainlab.blog::lang.blog.access_posts'
            ],
            'rainlab.blog.access_categories' => [
                'tab'   => 'rainlab.blog::lang.blog.tab',
                'label' => 'rainlab.blog::lang.blog.access_categories'
            ],
            'rainlab.blog.access_other_posts' => [
                'tab'   => 'rainlab.blog::lang.blog.tab',
                'label' => 'rainlab.blog::lang.blog.access_other_posts'
            ],
            'rainlab.blog.access_import_export' => [
                'tab'   => 'rainlab.blog::lang.blog.tab',
                'label' => 'rainlab.blog::lang.blog.access_import_export'
            ],
            'rainlab.blog.access_publish' => [
                'tab'   => 'rainlab.blog::lang.blog.tab',
                'label' => 'rainlab.blog::lang.blog.access_publish'
            ]
        ];
    }

    public function registerNavigation()
    {
        return [
            'blog' => [
                'label'       => 'rainlab.blog::lang.blog.menu_label',
                'url'         => Backend::url('rainlab/blog/posts'),
                'icon'        => 'icon-pencil',
                'iconSvg'     => 'plugins/rainlab/blog/assets/images/blog-icon.svg',
                'permissions' => ['rainlab.blog.*'],
                'order'       => 300,

                'sideMenu' => [
                    'new_post' => [
                        'label'       => 'rainlab.blog::lang.posts.new_post',
                        'icon'        => 'icon-plus',
                        'url'         => Backend::url('rainlab/blog/posts/create'),
                        'permissions' => ['rainlab.blog.access_posts']
                    ],
                    'posts' => [
                        'label'       => 'rainlab.blog::lang.blog.posts',
                        'icon'        => 'icon-copy',
                        'url'         => Backend::url('rainlab/blog/posts'),
                        'permissions' => ['rainlab.blog.access_posts']
                    ],
                    'categories' => [
                        'label'       => 'rainlab.blog::lang.blog.categories',
                        'icon'        => 'icon-list-ul',
                        'url'         => Backend::url('rainlab/blog/categories'),
                        'permissions' => ['rainlab.blog.access_categories']
                    ]
                ]
            ]
        ];
    }

    public function registerSettings()
    {
        return [
            'blog' => [
                'label' => 'rainlab.blog::lang.blog.menu_label',
                'description' => 'rainlab.blog::lang.blog.settings_description',
                'category' => 'rainlab.blog::lang.blog.menu_label',
                'icon' => 'icon-pencil',
                'class' => 'RainLab\Blog\Models\Settings',
                'order' => 500,
                'keywords' => 'blog post category',
                'permissions' => ['rainlab.blog.manage_settings']
            ]
        ];
    }

    /**
     * Register method, called when the plugin is first registered.
     */
    public function register()
    {
        /*
         * Register the image tag processing callback
         */
        TagProcessor::instance()->registerCallback(function($input, $preview) {
            if (!$preview) {
                return $input;
            }

            return preg_replace('|\<img src="image" alt="([0-9]+)"([^>]*)\/>|m',
                '<span class="image-placeholder" data-index="$1">
                    <span class="upload-dropzone">
                        <span class="label">'. trans('rainlab.blog::lang.post.dropzone') .'</span>
                        <span class="indicator"></span>
                    </span>
                </span>',
            $input);
        });
    }

    public function boot()
    {
        /*
         * Register menu items for the RainLab.Pages plugin
         */
        Event::listen('cms.pageLookup.listTypes', function() {
            return [
                'blog-category'       => 'rainlab.blog::lang.menuitem.blog_category',
                'all-blog-categories' => ['rainlab.blog::lang.menuitem.all_blog_categories', true],
                'blog-post'           => 'rainlab.blog::lang.menuitem.blog_post',
                'all-blog-posts'      => ['rainlab.blog::lang.menuitem.all_blog_posts', true],
                'category-blog-posts' => ['rainlab.blog::lang.menuitem.category_blog_posts', true],
            ];
        });

        Event::listen('pages.menuitem.listTypes', function() {
            return [
                'blog-category'       => 'rainlab.blog::lang.menuitem.blog_category',
                'all-blog-categories' => 'rainlab.blog::lang.menuitem.all_blog_categories',
                'blog-post'           => 'rainlab.blog::lang.menuitem.blog_post',
                'all-blog-posts'      => 'rainlab.blog::lang.menuitem.all_blog_posts',
                'category-blog-posts' => 'rainlab.blog::lang.menuitem.category_blog_posts',
            ];
        });

        Event::listen(['cms.pageLookup.getTypeInfo', 'pages.menuitem.getTypeInfo'], function($type) {
            if ($type == 'blog-category' || $type == 'all-blog-categories') {
                return Category::getMenuTypeInfo($type);
            }
            elseif ($type == 'blog-post' || $type == 'all-blog-posts' || $type == 'category-blog-posts') {
                return Post::getMenuTypeInfo($type);
            }
        });

        Event::listen(['cms.pageLookup.resolveItem', 'pages.menuitem.resolveItem'], function($type, $item, $url, $theme) {
            if ($type == 'blog-category' || $type == 'all-blog-categories') {
                return Category::resolveMenuItem($item, $url, $theme);
            }
            elseif ($type == 'blog-post' || $type == 'all-blog-posts' || $type == 'category-blog-posts') {
                return Post::resolveMenuItem($item, $url, $theme);
            }
        });
    }
}


================================================
FILE: README.md
================================================
# Blog Plugin

A simple, extensible blogging platform for October CMS.

[Blog & Forum Building Tutorial Video](https://player.vimeo.com/video/97088926)

## Editing posts

The plugin uses the markdown markup for the posts. You can use any Markdown syntax and some special tags for embedding images and videos (requires RainLab Blog Video plugin). To embed an image use the image placeholder:

    ![1](image)

The number in the first part is the placeholder index. If you use multiple images in a post you should use an unique index for each image:

    ![1](image)

    ![2](image)

You can also add classes or ids to images by using the [markdown extra](http://michelf.ca/projects/php-markdown/extra/) syntax:

    ![1](image){#id .class}

## Excerpt Vs. Read more

Posts are managed by selecting *Blog > Posts* from the menu. Each post can contain an excerpt by entering some text in this field on the *Manage* tab. This content is displayed on the page using the `summary` attribute of the blog post.

    {{ post.summary|raw }}

Alternatively this field can be left blank and the excerpt can be captured from the main content (*Edit* tab). Use the special tag `<!-- more -->` to specify a summary from the main content, all content above this tag will be treated as the summary. For example:

    This is a great introduction to a great blog post. This text is included as part of the excerpt / summary.

    <!-- more -->

    Let's dive in to more detail about why this post is so great. This text will not be included in the summary.

Finally, if no excerpt is specified and the "more" tag is not used, the blog post will capture the first 600 characters of the content and use this for the summary.

## Implementing front-end pages

The plugin provides several components for building the post list page (archive), category page, post details page and category list for the sidebar.

### Post list page

Use the `blogPosts` component to display a list of latest blog posts on a page. The component has the following properties:

* **pageNumber** - this value is used to determine what page the user is on, it should be a routing parameter for the default markup. The default value is **{{ :page }}** to obtain the value from the route parameter `:page`.
* **categoryFilter** - a category slug to filter the posts by. If left blank, all posts are displayed.
* **postsPerPage** - how many posts to display on a single page (the pagination is supported automatically). The default value is 10.
* **noPostsMessage** - message to display in the empty post list.
* **sortOrder** - the column name and direction used for the sort order of the posts. The default value is **published_at desc**.
* **categoryPage** - path to the category page. The default value is **blog/category** - it matches the pages/blog/category.htm file in the theme directory. This property is used in the default component partial for creating links to the blog categories.
* **postPage** - path to the post details page. The default value is **blog/post** - it matches the pages/blog/post.htm file in the theme directory. This property is used in the default component partial for creating links to the blog posts.
* **exceptPost** - ignore a single post by its slug or unique ID. The ignored post will not be included in the list, useful for showing other/related posts.
* **exceptCategories** - ignore posts from a comma-separated list of categories, given by their unique slug. The ignored posts will not be included in the list.

The blogPosts component injects the following variables to the page where it's used:

* **posts** - a list of blog posts loaded from the database.
* **postPage** - contains the value of the `postPage` component's property.
* **category** - the blog category object loaded from the database. If the category is not found, the variable value is **null**.
* **categoryPage** - contains the value of the `categoryPage` component's property.
* **noPostsMessage** - contains the value of the `noPostsMessage` component's property.

The component supports pagination and reads the current page index from the `:page` URL parameter. The next example shows the basic component usage on the blog home page:

    title = "Blog"
    url = "/blog/:page?"

    [blogPosts]
    postsPerPage = "5"
    ==
    {% component 'blogPosts' %}

The next example shows the basic component usage with the category filter:

    title = "Blog Category"
    url = "/blog/category/:slug/:page?"

    [blogPosts]
    categoryFilter = "{{ :slug }}"
    ==
    function onEnd()
    {
        // Optional - set the page title to the category name
        if ($this->category)
            $this->page->title = $this->category->name;
    }
    ==
    {% if not category %}
        <h2>Category not found</h2>
    {% else %}
        <h2>{{ category.name }}</h2>

        {% component 'blogPosts' %}
    {% endif %}

The post list and the pagination are coded in the default component partial `plugins/rainlab/blog/components/posts/default.htm`. If the default markup is not suitable for your website, feel free to copy it from the default partial and replace the `{% component %}` call in the example above with the partial contents.

### Post page

Use the `blogPost` component to display a blog post on a page. The component has the following properties:

* **slug** - the value used for looking up the post by its slug. The default value is **{{ :slug }}** to obtain the value from the route parameter `:slug`.
* **categoryPage** - path to the category page. The default value is **blog/category** - it matches the pages/blog/category.htm file in the theme directory. This property is used in the default component partial for creating links to the blog categories.

The component injects the following variables to the page where it's used:

* **post** - the blog post object loaded from the database. If the post is not found, the variable value is **null**.

The next example shows the basic component usage on the blog page:

    title = "Blog Post"
    url = "/blog/post/:slug"

    [blogPost]
    ==
    <?php
    function onEnd()
    {
        // Optional - set the page title to the post title
        if ($this->post)
            $this->page->title = $this->post->title;
    }
    ?>
    ==
    {% if post %}
        <h2>{{ post.title }}</h2>

        {% component 'blogPost' %}
    {% else %}
        <h2>Post not found</h2>
    {% endif %}

The post details is coded in the default component partial `plugins/rainlab/blog/components/post/default.htm`.

### Category list

Use the `blogCategories` component to display a list of blog post categories with links. The component has the following properties:

* **slug** - the value used for looking up the current category by its slug. The default value is **{{ :slug }}** to obtain the value from the route parameter `:slug`.
* **displayEmpty** - determines if empty categories should be displayed. The default value is false.
* **categoryPage** - path to the category page. The default value is **blog/category** - it matches the pages/blog/category.htm file in the theme directory. This property is used in the default component partial for creating links to the blog categories.

The component injects the following variables to the page where it's used:

* **categoryPage** - contains the value of the `categoryPage` component's property.
* **categories** - a list of blog categories loaded from the database.
* **currentCategorySlug** - slug of the current category. This property is used for marking the current category in the category list.

The component can be used on any page. The next example shows the basic component usage on the blog home page:

    title = "Blog"
    url = "/blog/:page?"

    [blogCategories]
    ==
    ...
    <div class="sidebar">
        {% component 'blogCategories' %}
    </div>
    ...

The category list is coded in the default component partial `plugins/rainlab/blog/components/categories/default.htm`.

### RSS feed

Use the `blogRssFeed` component to display an RSS feed containing the latest blog posts. The following properties are supported:

* **categoryFilter** - a category slug to filter the posts by. If left blank, all posts are displayed.
* **postsPerPage** - how many posts to display on the feed. The default value is 10.
* **blogPage** - path to the main blog page. The default value is **blog** - it matches the pages/blog.htm file in the theme directory. This property is used in the RSS feed for creating links to the main blog page.
* **postPage** - path to the post details page. The default value is **blog/post** - it matches the pages/blog/post.htm file in the theme directory. This property is used in the RSS feed for creating links to the blog posts.

The component can be used on any page, it will hijack the entire page cycle to display the feed in RSS format. The next example shows how to use it:

    title = "RSS Feed"
    url = "/blog/rss.xml"

    [blogRssFeed]
    blogPage = "blog"
    postPage = "blog/post"
    ==
    <!-- This markup will never be displayed -->

## Configuration

To overwrite the default configuration create a `config/rainlab/blog/config.php`. You can return only values you want to override.

### Summary

A summary attribute is generated for each post.

If you enter an excerpt manually, it gets used as summary. Alternatively, you can use the `summary_separator` (default is `<!-- more -->`) to mark the end of the summary. If a post contains no separator, the text gets truncated after the number of characters specified in `summary_default_length` (default is 600 characters).

## Markdown guide

October supports [standard markdown syntax](http://daringfireball.net/projects/markdown/) as well as [extended markdown syntax](http://michelf.ca/projects/php-markdown/extra/)

### Classes and IDs

Classes and IDs can be added to images and other elements as shown below:

```
[link](url){#id .class}
![1](image){#id .class}
# October  {#id .class}
```

### Fenced code blogs

Markdown extra makes it possible to use fenced code blocks. With fenced code blocks you do not need indentation on the areas you want to mark as code:


    ```
    Code goes here
    ```

You can also use the `~` symbol:

    ~~~
    Code goes here
    ~~~

### Tables

A *simple* table can be defined as follows:

```
First Header  | Second Header
------------- | -------------
Content Cell  | Content Cell
Content Cell  | Content Cell
```

If you want to you can also add a leading and tailing pipe:

```
| First Header  | Second Header |
| ------------- | ------------- |
| Content Cell  | Content Cell  |
| Content Cell  | Content Cell  |
```

To add alignment to the cells you simply need to add a `:` either at the start or end of a separator:

```
| First Header  | Second Header |
| :------------ | ------------: |
| Content Cell  | Content Cell  |
| Content Cell  | Content Cell  |
```

To center align cell just add `:` on both sides:

```
| First Header  | Second Header |
| ------------- | :-----------: |
| Content Cell  | Content Cell  |
| Content Cell  | Content Cell  |
```

### Definition lists

Below is an example of a simple definition list:

```
Laravel
:   A popular PHP framework

October
:   Awesome CMS built on Laravel
```

A term can also have multiple definitions:

```
Laravel
:   A popular PHP framework

October
:   Awesome CMS built on Laravel
:   Supports markdown extra
```

You can also associate more than 1 term to a definition:

```
Laravel
October
:   Built using PHP
```

### Footnotes

With markdown extra it is possible to create reference style footnotes:

```
This is some text with a footnote.[^1]

[^1]: And this is the footnote.
```

### Abbreviations

With markdown extra you can add abbreviations to your markup. The use this functionality first create a definition list:

```
*[HTML]: Hyper Text Markup Language
*[PHP]:  Hypertext Preprocessor
```

Now markdown extra will convert all occurrences of `HTML` and `PHP` as follows:

```
<abbr title="Hyper Text Markup Language">HTML</abbr>
<abbr title="Hypertext Preprocessor">PHP</abbr>
```


================================================
FILE: assets/css/rainlab.blog-export.css
================================================
.export-behavior .export-columns {
    max-height: 450px !important;
}


================================================
FILE: assets/css/rainlab.blog-preview.css
================================================
.blog-post-preview .editor-preview .preview-content {
  padding: 20px;
}
.blog-post-preview .editor-preview span.image-placeholder {
  display: block;
}
.blog-post-preview .editor-preview span.image-placeholder .upload-dropzone {
  background: #ecf0f1;
  display: block;
  border: 1px solid #e5e9ec;
  padding: 25px;
  min-height: 123px;
  position: relative;
  text-align: center;
  cursor: pointer;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}
.blog-post-preview .editor-preview span.image-placeholder .upload-dropzone span.label {
  color: #b1b9be;
  font-size: 16px;
  display: inline-block;
  margin-top: 25px;
}
.blog-post-preview .editor-preview span.image-placeholder .upload-dropzone:before {
  display: inline-block;
  font-family: FontAwesome;
  font-weight: normal;
  font-style: normal;
  text-decoration: inherit;
  -webkit-font-smoothing: antialiased;
  *margin-right: .3em;
  content: "\f03e";
  position: absolute;
  left: 25px;
  top: 25px;
  line-height: 100%;
  font-size: 73px;
  color: #d1d3d4;
}
.blog-post-preview .editor-preview span.image-placeholder .upload-dropzone.hover,
.blog-post-preview .editor-preview span.image-placeholder .upload-dropzone:hover {
  background: #2f99da;
}
.blog-post-preview .editor-preview span.image-placeholder .upload-dropzone.hover:before,
.blog-post-preview .editor-preview span.image-placeholder .upload-dropzone:hover:before,
.blog-post-preview .editor-preview span.image-placeholder .upload-dropzone.hover span.label,
.blog-post-preview .editor-preview span.image-placeholder .upload-dropzone:hover span.label {
  color: white;
}
.blog-post-preview .editor-preview span.image-placeholder input[type=file] {
  position: absolute;
  left: -10000em;
}
.blog-post-preview-container .loading-indicator {
  position: absolute;
  display: none;
  width: 20px;
  height: 20px;
  padding: 0!important;
  background: transparent;
  right: 10px;
  left: auto;
  top: 10px;
}
.blog-post-preview-container.loading-indicator-visible .loading-indicator {
  display: block;
}
html.cssanimations .blog-post-preview span.image-placeholder.loading .upload-dropzone:before {
  display: none;
}
html.cssanimations .blog-post-preview span.image-placeholder.loading .upload-dropzone .indicator {
  display: block;
  width: 50px;
  height: 50px;
  position: absolute;
  left: 35px;
  top: 35px;
  background-image: url('../../../../../modules/system/assets/ui/images/loader-transparent.svg');
  background-size: 50px 50px;
  background-position: 50% 50%;
  -webkit-animation: spin 1s linear infinite;
  animation: spin 1s linear infinite;
}


================================================
FILE: assets/js/post-form.js
================================================
+function ($) { "use strict";
    var PostForm = function () {
        this.$form = $('#post-form')
        this.$markdownEditor = $('[data-field-name=content] [data-control=markdowneditor]:first', this.$form)
        this.$preview = $('.editor-preview', this.$markdownEditor)

        this.formAction = this.$form.attr('action')
        this.sessionKey = $('input[name=_session_key]', this.$form).val()

        if (this.$markdownEditor.length > 0 && typeof this.$markdownEditor.markdownEditor === 'function') {
            this.codeEditor = this.$markdownEditor.markdownEditor('getEditorObject')

            this.$markdownEditor.on('initPreview.oc.markdowneditor', $.proxy(this.initPreview, this))

            this.initDropzones()
            this.addToolbarButton()
        }

        this.initFormEvents()
        this.initLayout()
    }

    PostForm.prototype.addToolbarButton = function() {
        this.buttonClickCount = 1

        var self = this,
            $button = this.$markdownEditor.markdownEditor('findToolbarButton', 'image')

        if (!$button.length) return

        $button.data('button-action', 'insertLine')
        $button.data('button-template', '\n\n![1](image)\n')

        $button.on('click', function() {
            $button.data('button-template', '\n\n!['+self.buttonClickCount+'](image)\n')
            self.buttonClickCount++
        })
    }

    PostForm.prototype.initPreview = function() {
        this.initImageUploaders()
    }

    PostForm.prototype.updateScroll = function() {
        // Reserved in case MarkdownEditor uses scrollbar plugin
        // this.$preview.data('oc.scrollbar').update()
    }

    PostForm.prototype.initImageUploaders = function() {
        var self = this
        $('span.image-placeholder .upload-dropzone', this.$preview).each(function(){
            var
                $placeholder = $(this).parent(),
                $link = $('span.label', $placeholder),
                placeholderIndex = $placeholder.data('index')

            var uploaderOptions = {
                url: self.formAction,
                clickable: [$(this).get(0), $link.get(0)],
                previewsContainer: $('<div />').get(0),
                paramName: 'file',
                headers: {}
            }

            /*
             * Add CSRF token to headers
             */
            var token = $('meta[name="csrf-token"]').attr('content')
            if (token) {
                uploaderOptions.headers['X-CSRF-TOKEN'] = token
            }

            var dropzone = new Dropzone($(this).get(0), uploaderOptions)

            dropzone.on('error', function(file, error) {
                alert('Error uploading file: ' + error)
            })
            dropzone.on('success', function(file, data){
                if (data.error)
                    alert(data.error);
                else {
                    self.pauseUpdates();
                    var $img = $('<img src="'+data.path+'" />');
                    $img.one('load', function(){
                        self.updateScroll();
                    });

                    $placeholder.replaceWith($img);

                    self.codeEditor.replace('!['+data.file+']('+data.path+')', {
                        needle: '!['+placeholderIndex+'](image)'
                    });

                    self.resumeUpdates();
                }
            })
            dropzone.on('complete', function(){
                $placeholder.removeClass('loading')
            })
            dropzone.on('sending', function(file, xhr, formData) {
                formData.append('X_BLOG_IMAGE_UPLOAD', 1)
                formData.append('_session_key', self.sessionKey)
                $placeholder.addClass('loading')
            })
        })
    }

    PostForm.prototype.pauseUpdates = function() {
        this.$markdownEditor.markdownEditor('pauseUpdates')
    }

    PostForm.prototype.resumeUpdates = function() {
        this.$markdownEditor.markdownEditor('resumeUpdates')
    }

    PostForm.prototype.initDropzones = function() {
        $(document).bind('dragover', function (e) {
            var dropZone = $('span.image-placeholder .upload-dropzone'),
                foundDropzone,
                timeout = window.dropZoneTimeout

            if (!timeout)
                dropZone.addClass('in');
            else
                clearTimeout(timeout);

            var found = false,
                node = e.target

            do {
                if ($(node).hasClass('dropzone')) {
                    found = true
                    foundDropzone = $(node)
                    break
                }

                node = node.parentNode;

            } while (node != null);

            dropZone.removeClass('in hover')

            if (found)
                foundDropzone.addClass('hover')

            window.dropZoneTimeout = setTimeout(function () {
                window.dropZoneTimeout = null
                dropZone.removeClass('in hover')
            }, 100)
        })
    }

    PostForm.prototype.initFormEvents = function() {
        $(document).on('ajaxSuccess', '#post-form', function(event, context, data){
            if (context.handler == 'onSave' && !data.X_OCTOBER_ERROR_FIELDS) {
                $(this).trigger('unchange.oc.changeMonitor')
            }
        })
    }

    PostForm.prototype.initLayout = function() {
        $('#Form-secondaryTabs .tab-pane.layout-cell:not(:first-child), #Form-secondaryTabs .tab-pane.form-tab-pane:not(:first-child)').addClass('padded-pane')
        $('#Form-secondaryTabs .nav-tabs > li:not(:first-child)').addClass('tab-content-bg')
    }

    PostForm.prototype.replacePlaceholder = function(placeholder, placeholderHtmlReplacement, mdCodePlaceholder, mdCodeReplacement) {
        this.pauseUpdates()
        placeholder.replaceWith(placeholderHtmlReplacement)

        this.codeEditor.replace(mdCodeReplacement, {
            needle: mdCodePlaceholder
        })
        this.updateScroll()
        this.resumeUpdates()
    }

    $(document).ready(function(){
        var form = new PostForm()

        if ($.oc === undefined)
            $.oc = {}

        $.oc.blogPostForm = form
    })

}(window.jQuery);

================================================
FILE: assets/less/rainlab.blog-preview.less
================================================
@import "../../../../../modules/backend/assets/less/core/boot.less";

.blog-post-preview .editor-preview {
    .preview-content {
        padding: 20px;
    }

    span.image-placeholder {
        display: block;

        .upload-dropzone {
            background: #ecf0f1;
            display: block;
            border: 1px solid #e5e9ec;
            padding: 25px;
            min-height: 123px;
            position: relative;
            text-align: center;
            cursor: pointer;
            .box-sizing(border-box);

            span.label {
                color: #b1b9be;
                font-size: 16px;
                display: inline-block;
                margin-top: 25px;
            }

            &:before {
                display: inline-block;
                .icon(@picture-o);
                position: absolute;
                left: 25px;
                top: 25px;
                line-height: 100%;
                font-size: 73px;
                color: #d1d3d4;
            }

            &.hover, &:hover {
                background: #2f99da;

                &:before, span.label {
                    color: white;
                }
            }
        }

        input[type=file] {
            position: absolute;
            left: -10000em;
        }
    }
}

.blog-post-preview-container {
    .loading-indicator {
        position: absolute;
        display: none;
        width: 20px;
        height: 20px;
        padding: 0!important;
        background: transparent;
        right: 10px;
        left: auto;
        top: 10px;
    }

    &.loading-indicator-visible {
        .loading-indicator {
            display: block;
        }
    }
}

html.cssanimations {
    .blog-post-preview {
        span.image-placeholder.loading {
            .upload-dropzone {
                &:before {
                    display: none;
                }

                .indicator {
                    display: block;
                    width: 50px;
                    height: 50px;
                    position: absolute;
                    left: 35px;
                    top: 35px;
                    background-image:url('../../../../../modules/system/assets/ui/images/loader-transparent.svg');
                    background-size: 50px 50px;
                    background-position: 50% 50%;
                    .animation(spin 1s linear infinite);
                }
            }
        }
    }
}

================================================
FILE: classes/TagProcessor.php
================================================
<?php namespace RainLab\Blog\Classes;

/**
 * Blog Markdown tag processor.
 *
 * @package rainlab\blog
 * @author Alexey Bobkov, Samuel Georges
 */
class TagProcessor
{
    use \October\Rain\Support\Traits\Singleton;

    /**
     * @var array Cache of processing callbacks.
     */
    private $callbacks = [];

    /**
     * Registers a callback function that handles blog post markup.
     * The callback function should accept two arguments - the HTML string
     * generated from Markdown contents and the preview flag determining whether
     * the function should return a markup for the blog post preview form or for the
     * front-end.
     * @param callable $callback A callable function.
     */
    public function registerCallback(callable $callback)
    {
        $this->callbacks[] = $callback;
    }

    public function processTags($markup, $preview)
    {
        foreach ($this->callbacks as $callback) {
            $markup = $callback($markup, $preview);
        }

        return $markup;
    }
}


================================================
FILE: components/Categories.php
================================================
<?php namespace RainLab\Blog\Components;

use Db;
use Carbon\Carbon;
use Cms\Classes\Page;
use Cms\Classes\ComponentBase;
use RainLab\Blog\Models\Category as BlogCategory;

class Categories extends ComponentBase
{
    /**
     * @var Collection A collection of categories to display
     */
    public $categories;

    /**
     * @var string Reference to the page name for linking to categories.
     */
    public $categoryPage;

    /**
     * @var string Reference to the current category slug.
     */
    public $currentCategorySlug;

    public function componentDetails()
    {
        return [
            'name'        => 'rainlab.blog::lang.settings.category_title',
            'description' => 'rainlab.blog::lang.settings.category_description'
        ];
    }

    public function defineProperties()
    {
        return [
            'slug' => [
                'title'       => 'rainlab.blog::lang.settings.category_slug',
                'description' => 'rainlab.blog::lang.settings.category_slug_description',
                'default'     => '{{ :slug }}',
                'type'        => 'string',
            ],
            'displayEmpty' => [
                'title'       => 'rainlab.blog::lang.settings.category_display_empty',
                'description' => 'rainlab.blog::lang.settings.category_display_empty_description',
                'type'        => 'checkbox',
                'default'     => 0,
            ],
            'categoryPage' => [
                'title'       => 'rainlab.blog::lang.settings.category_page',
                'description' => 'rainlab.blog::lang.settings.category_page_description',
                'type'        => 'dropdown',
                'default'     => 'blog/category',
                'group'       => 'rainlab.blog::lang.settings.group_links',
            ],
        ];
    }

    public function getCategoryPageOptions()
    {
        return Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
    }

    public function onRun()
    {
        $this->currentCategorySlug = $this->page['currentCategorySlug'] = $this->property('slug');
        $this->categoryPage = $this->page['categoryPage'] = $this->property('categoryPage');
        $this->categories = $this->page['categories'] = $this->loadCategories();
    }

    /**
     * Load all categories or, depending on the <displayEmpty> option, only those that have blog posts
     * @return mixed
     */
    protected function loadCategories()
    {
        $categories = BlogCategory::with('posts_count')->getNested();
        if (!$this->property('displayEmpty')) {
            $iterator = function ($categories) use (&$iterator) {
                return $categories->reject(function ($category) use (&$iterator) {
                    if ($category->getNestedPostCount() == 0) {
                        return true;
                    }
                    if ($category->children) {
                        $category->children = $iterator($category->children);
                    }
                    return false;
                });
            };
            $categories = $iterator($categories);
        }

        /*
         * Add a "url" helper attribute for linking to each category
         */
        return $this->linkCategories($categories);
    }

    /**
     * Sets the URL on each category according to the defined category page
     * @return void
     */
    protected function linkCategories($categories)
    {
        return $categories->each(function ($category) {
            $category->setUrl($this->categoryPage, $this->controller);

            if ($category->children) {
                $this->linkCategories($category->children);
            }
        });
    }
}


================================================
FILE: components/Post.php
================================================
<?php namespace RainLab\Blog\Components;

use Event;
use BackendAuth;
use Cms\Classes\Page;
use Cms\Classes\ComponentBase;
use RainLab\Blog\Models\Post as BlogPost;

class Post extends ComponentBase
{
    /**
     * @var RainLab\Blog\Models\Post The post model used for display.
     */
    public $post;

    /**
     * @var string Reference to the page name for linking to categories.
     */
    public $categoryPage;

    public function componentDetails()
    {
        return [
            'name'        => 'rainlab.blog::lang.settings.post_title',
            'description' => 'rainlab.blog::lang.settings.post_description'
        ];
    }

    public function defineProperties()
    {
        return [
            'slug' => [
                'title'       => 'rainlab.blog::lang.settings.post_slug',
                'description' => 'rainlab.blog::lang.settings.post_slug_description',
                'default'     => '{{ :slug }}',
                'type'        => 'string',
            ],
            'categoryPage' => [
                'title'       => 'rainlab.blog::lang.settings.post_category',
                'description' => 'rainlab.blog::lang.settings.post_category_description',
                'type'        => 'dropdown',
                'default'     => 'blog/category',
            ],
        ];
    }

    public function getCategoryPageOptions()
    {
        return Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
    }

    public function init()
    {
        Event::listen('translate.localePicker.translateParams', function ($page, $params, $oldLocale, $newLocale) {
            $newParams = $params;

            if (isset($params['slug'])) {
                $records = BlogPost::transWhere('slug', $params['slug'], $oldLocale)->first();
                if ($records) {
                    $records->translateContext($newLocale);
                    $newParams['slug'] = $records['slug'];
                }
            }

            return $newParams;
        });

        Event::listen('cms.sitePicker.overrideParams', function ($page, $params, $currentSite, $proposedSite) {
            $newParams = $params;
            $oldLocale = $currentSite->hard_locale;
            $newLocale = $proposedSite->hard_locale;

            if (isset($params['slug'])) {
                $records = BlogPost::transWhere('slug', $params['slug'], $oldLocale)->first();
                if ($records) {
                    $records->translateContext($newLocale);
                    $newParams['slug'] = $records['slug'];
                }
            }

            return $newParams;
        });
    }

    public function onRun()
    {
        $this->categoryPage = $this->page['categoryPage'] = $this->property('categoryPage');
        $this->post = $this->page['post'] = $this->loadPost();
        if (!$this->post) {
            $this->setStatusCode(404);
            return $this->controller->run('404');
        }
    }

    public function onRender()
    {
        if (empty($this->post)) {
            $this->post = $this->page['post'] = $this->loadPost();
        }
    }

    protected function loadPost()
    {
        $slug = $this->property('slug');

        $post = new BlogPost;
        $query = $post->query();

        if ($post->isClassExtendedWith('RainLab.Translate.Behaviors.TranslatableModel')) {
            $query->transWhere('slug', $slug);
        } else {
            $query->where('slug', $slug);
        }

        if (!$this->checkEditor()) {
            $query->isPublished();
        }

        $post = $query->first();

        /*
         * Add a "url" helper attribute for linking to each category
         */
        if ($post && $post->exists && $post->categories->count()) {
            $post->categories->each(function($category) {
                $category->setUrl($this->categoryPage, $this->controller);
            });
        }

        return $post;
    }

    public function previousPost()
    {
        return $this->getPostSibling(-1);
    }

    public function nextPost()
    {
        return $this->getPostSibling(1);
    }

    protected function getPostSibling($direction = 1)
    {
        if (!$this->post) {
            return;
        }

        $method = $direction === -1 ? 'previousPost' : 'nextPost';

        if (!$post = $this->post->$method()) {
            return;
        }

        $postPage = $this->getPage()->getBaseFileName();

        $post->setUrl($postPage, $this->controller);

        $post->categories->each(function($category) {
            $category->setUrl($this->categoryPage, $this->controller);
        });

        return $post;
    }

    protected function checkEditor()
    {
        $backendUser = BackendAuth::getUser();

        return $backendUser && $backendUser->hasAccess('rainlab.blog.access_posts');
    }
}


================================================
FILE: components/Posts.php
================================================
<?php namespace RainLab\Blog\Components;

use Lang;
use Redirect;
use BackendAuth;
use Cms\Classes\Page;
use Cms\Classes\ComponentBase;
use October\Rain\Database\Model;
use October\Rain\Database\Collection;
use RainLab\Blog\Models\Post as BlogPost;
use RainLab\Blog\Models\Category as BlogCategory;
use RainLab\Blog\Models\Settings as BlogSettings;

class Posts extends ComponentBase
{
    /**
     * A collection of posts to display
     *
     * @var Collection
     */
    public $posts;

    /**
     * Parameter to use for the page number
     *
     * @var string
     */
    public $pageParam;

    /**
     * If the post list should be filtered by a category, the model to use
     *
     * @var Model
     */
    public $category;

    /**
     * Message to display when there are no messages
     *
     * @var string
     */
    public $noPostsMessage;

    /**
     * Reference to the page name for linking to posts
     *
     * @var string
     */
    public $postPage;

    /**
     * Reference to the page name for linking to categories
     *
     * @var string
     */
    public $categoryPage;

    /**
     * If the post list should be ordered by another attribute
     *
     * @var string
     */
    public $sortOrder;

    public function componentDetails()
    {
        return [
            'name'        => 'rainlab.blog::lang.settings.posts_title',
            'description' => 'rainlab.blog::lang.settings.posts_description'
        ];
    }

    public function defineProperties()
    {
        return [
            'pageNumber' => [
                'title'       => 'rainlab.blog::lang.settings.posts_pagination',
                'description' => 'rainlab.blog::lang.settings.posts_pagination_description',
                'type'        => 'string',
                'default'     => '{{ :page }}',
            ],
            'categoryFilter' => [
                'title'       => 'rainlab.blog::lang.settings.posts_filter',
                'description' => 'rainlab.blog::lang.settings.posts_filter_description',
                'type'        => 'string',
                'default'     => '',
            ],
            'postsPerPage' => [
                'title'             => 'rainlab.blog::lang.settings.posts_per_page',
                'type'              => 'string',
                'validationPattern' => '^[0-9]+$',
                'validationMessage' => 'rainlab.blog::lang.settings.posts_per_page_validation',
                'default'           => '10',
            ],
            'noPostsMessage' => [
                'title'             => 'rainlab.blog::lang.settings.posts_no_posts',
                'description'       => 'rainlab.blog::lang.settings.posts_no_posts_description',
                'type'              => 'string',
                'default'           => Lang::get('rainlab.blog::lang.settings.posts_no_posts_default'),
                'showExternalParam' => false,
            ],
            'sortOrder' => [
                'title'       => 'rainlab.blog::lang.settings.posts_order',
                'description' => 'rainlab.blog::lang.settings.posts_order_description',
                'type'        => 'dropdown',
                'default'     => 'published_at desc',
            ],
            'categoryPage' => [
                'title'       => 'rainlab.blog::lang.settings.posts_category',
                'description' => 'rainlab.blog::lang.settings.posts_category_description',
                'type'        => 'dropdown',
                'default'     => 'blog/category',
                'group'       => 'rainlab.blog::lang.settings.group_links',
            ],
            'postPage' => [
                'title'       => 'rainlab.blog::lang.settings.posts_post',
                'description' => 'rainlab.blog::lang.settings.posts_post_description',
                'type'        => 'dropdown',
                'default'     => 'blog/post',
                'group'       => 'rainlab.blog::lang.settings.group_links',
            ],
            'exceptPost' => [
                'title'             => 'rainlab.blog::lang.settings.posts_except_post',
                'description'       => 'rainlab.blog::lang.settings.posts_except_post_description',
                'type'              => 'string',
                'validationPattern' => '^[a-z0-9\-_,\s]+$',
                'validationMessage' => 'rainlab.blog::lang.settings.posts_except_post_validation',
                'default'           => '',
                'group'             => 'rainlab.blog::lang.settings.group_exceptions',
            ],
            'exceptCategories' => [
                'title'             => 'rainlab.blog::lang.settings.posts_except_categories',
                'description'       => 'rainlab.blog::lang.settings.posts_except_categories_description',
                'type'              => 'string',
                'validationPattern' => '^[a-z0-9\-_,\s]+$',
                'validationMessage' => 'rainlab.blog::lang.settings.posts_except_categories_validation',
                'default'           => '',
                'group'             => 'rainlab.blog::lang.settings.group_exceptions',
            ],
        ];
    }

    public function getCategoryPageOptions()
    {
        return Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
    }

    public function getPostPageOptions()
    {
        return Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
    }

    public function getSortOrderOptions()
    {
        $options = BlogPost::$allowedSortingOptions;

        foreach ($options as $key => $value) {
            $options[$key] = Lang::get($value);
        }

        return $options;
    }

    public function onRun()
    {
        $this->prepareVars();

        $this->category = $this->page['category'] = $this->loadCategory();
        $this->posts = $this->page['posts'] = $this->listPosts();

        /*
         * If the page number is not valid, redirect
         */
        if ($pageNumberParam = $this->paramName('pageNumber')) {
            $currentPage = $this->property('pageNumber');

            if ($currentPage > ($lastPage = $this->posts->lastPage()) && $currentPage > 1) {
                return Redirect::to($this->currentPageUrl([$pageNumberParam => $lastPage]));
            }
        }
    }

    protected function prepareVars()
    {
        $this->pageParam = $this->page['pageParam'] = $this->paramName('pageNumber');
        $this->noPostsMessage = $this->page['noPostsMessage'] = $this->property('noPostsMessage');

        /*
         * Page links
         */
        $this->postPage = $this->page['postPage'] = $this->property('postPage');
        $this->categoryPage = $this->page['categoryPage'] = $this->property('categoryPage');
    }

    protected function listPosts()
    {
        $category = $this->category ? $this->category->id : null;
        $categorySlug = $this->category ? $this->category->slug : null;

        /*
         * List all the posts, eager load their categories
         */
        $isPublished = !$this->checkEditor();

        $posts = BlogPost::with(['categories', 'featured_images'])->listFrontEnd([
            'page'             => $this->property('pageNumber'),
            'sort'             => $this->property('sortOrder'),
            'perPage'          => $this->property('postsPerPage'),
            'search'           => trim(input('search')),
            'category'         => $category,
            'published'        => $isPublished,
            'exceptPost'       => is_array($this->property('exceptPost'))
                ? $this->property('exceptPost')
                : preg_split('/,\s*/', $this->property('exceptPost'), -1, PREG_SPLIT_NO_EMPTY),
            'exceptCategories' => is_array($this->property('exceptCategories'))
                ? $this->property('exceptCategories')
                : preg_split('/,\s*/', $this->property('exceptCategories'), -1, PREG_SPLIT_NO_EMPTY),
        ]);

        /*
         * Add a "url" helper attribute for linking to each post and category
         */
        $posts->each(function($post) use ($categorySlug) {
            $post->setUrl($this->postPage, $this->controller, ['category' => $categorySlug]);

            $post->categories->each(function($category) {
                $category->setUrl($this->categoryPage, $this->controller);
            });
        });

        return $posts;
    }

    protected function loadCategory()
    {
        if (!$slug = $this->property('categoryFilter')) {
            return null;
        }

        $category = new BlogCategory;

        $category = $category->isClassExtendedWith('RainLab.Translate.Behaviors.TranslatableModel')
            ? $category->transWhere('slug', $slug)
            : $category->where('slug', $slug);

        $category = $category->first();

        return $category ?: null;
    }

    protected function checkEditor()
    {
        $backendUser = BackendAuth::getUser();

        return $backendUser &&
            $backendUser->hasAccess('rainlab.blog.access_posts') &&
            BlogSettings::get('show_all_posts', true);
    }
}


================================================
FILE: components/RssFeed.php
================================================
<?php namespace RainLab\Blog\Components;

use Lang;
use Response;
use Cms\Classes\Page;
use Cms\Classes\ComponentBase;
use RainLab\Blog\Models\Post as BlogPost;
use RainLab\Blog\Models\Category as BlogCategory;

class RssFeed extends ComponentBase
{
    /**
     * A collection of posts to display
     * @var Collection
     */
    public $posts;

    /**
     * If the post list should be filtered by a category, the model to use.
     * @var Model
     */
    public $category;

    /**
     * Reference to the page name for the main blog page.
     * @var string
     */
    public $blogPage;

    /**
     * Reference to the page name for linking to posts.
     * @var string
     */
    public $postPage;

    public function componentDetails()
    {
        return [
            'name'        => 'rainlab.blog::lang.settings.rssfeed_title',
            'description' => 'rainlab.blog::lang.settings.rssfeed_description'
        ];
    }

    public function defineProperties()
    {
        return [
            'categoryFilter' => [
                'title'       => 'rainlab.blog::lang.settings.posts_filter',
                'description' => 'rainlab.blog::lang.settings.posts_filter_description',
                'type'        => 'string',
                'default'     => '',
            ],
            'sortOrder' => [
                'title'       => 'rainlab.blog::lang.settings.posts_order',
                'description' => 'rainlab.blog::lang.settings.posts_order_description',
                'type'        => 'dropdown',
                'default'     => 'created_at desc',
            ],
            'postsPerPage' => [
                'title'             => 'rainlab.blog::lang.settings.posts_per_page',
                'type'              => 'string',
                'validationPattern' => '^[0-9]+$',
                'validationMessage' => 'rainlab.blog::lang.settings.posts_per_page_validation',
                'default'           => '10',
            ],
            'blogPage' => [
                'title'       => 'rainlab.blog::lang.settings.rssfeed_blog',
                'description' => 'rainlab.blog::lang.settings.rssfeed_blog_description',
                'type'        => 'dropdown',
                'default'     => 'blog/post',
                'group'       => 'rainlab.blog::lang.settings.group_links',
            ],
            'postPage' => [
                'title'       => 'rainlab.blog::lang.settings.posts_post',
                'description' => 'rainlab.blog::lang.settings.posts_post_description',
                'type'        => 'dropdown',
                'default'     => 'blog/post',
                'group'       => 'rainlab.blog::lang.settings.group_links',
            ],
        ];
    }

    public function getBlogPageOptions()
    {
        return Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
    }

    public function getPostPageOptions()
    {
        return Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
    }

    public function getSortOrderOptions()
    {
        $options = BlogPost::$allowedSortingOptions;

        foreach ($options as $key => $value) {
            $options[$key] = Lang::get($value);
        }

        return $options;
    }

    public function onRun()
    {
        $this->prepareVars();

        $xmlFeed = $this->renderPartial('@default');

        return Response::make($xmlFeed, '200')->header('Content-Type', 'text/xml');
    }

    protected function prepareVars()
    {
        $this->blogPage = $this->page['blogPage'] = $this->property('blogPage');
        $this->postPage = $this->page['postPage'] = $this->property('postPage');
        $this->category = $this->page['category'] = $this->loadCategory();
        $this->posts = $this->page['posts'] = $this->listPosts();

        $this->page['link'] = $this->pageUrl($this->blogPage);
        $this->page['rssLink'] = $this->currentPageUrl();
    }

    protected function listPosts()
    {
        $category = $this->category ? $this->category->id : null;

        /*
         * List all the posts, eager load their categories
         */
        $posts = BlogPost::with('categories')->listFrontEnd([
            'sort'     => $this->property('sortOrder'),
            'perPage'  => $this->property('postsPerPage'),
            'category' => $category
        ]);

        /*
         * Add a "url" helper attribute for linking to each post and category
         */
        $posts->each(function($post) {
            $post->setUrl($this->postPage, $this->controller);
        });

        return $posts;
    }

    protected function loadCategory()
    {
        if (!$categoryId = $this->property('categoryFilter')) {
            return null;
        }

        if (!$category = BlogCategory::whereSlug($categoryId)->first()) {
            return null;
        }

        return $category;
    }
}


================================================
FILE: components/categories/default.htm
================================================
{% if __SELF__.categories|length > 0 %}
    <ul class="category-list">
        {% partial __SELF__ ~ "::items"
            categories = __SELF__.categories
            currentCategorySlug = __SELF__.currentCategorySlug
        %}
    </ul>
{% else %}
    <p>No categories were found.</p>
{% endif %}


================================================
FILE: components/categories/items.htm
================================================
{% for category in categories %}
    {% set postCount = category.post_count %}
    <li {% if category.slug == currentCategorySlug %}class="active"{% endif %}>
        <a href="{{ category.url }}">{{ category.name }}</a> 
        {% if postCount %}
            <span class="badge">{{ postCount }}</span>
        {% endif %}

        {% if category.children|length > 0 %}
            <ul>
                {% partial __SELF__ ~ "::items"
                    categories=category.children
                    currentCategorySlug=currentCategorySlug
                %}
            </ul>
        {% endif %}
    </li>
{% endfor %}


================================================
FILE: components/post/default.htm
================================================
{% set post = __SELF__.post %}

<div class="content">{{ post.content_html|raw }}</div>

{% if post.featured_images|length %}
    <div class="featured-images text-center">
        {% for image in post.featured_images %}
            <p>
                <img
                    data-src="{{ image.filename }}"
                    src="{{ image.path }}"
                    alt="{{ image.description }}"
                    style="max-width: 100%" />
            </p>
        {% endfor %}
    </div>
{% endif %}

<p class="info">
    Posted
    {% if post.categories|length %} in
        {% for category in post.categories %}
            <a href="{{ category.url }}">{{ category.name }}</a>{% if not loop.last %}, {% endif %}
        {% endfor %}
    {% endif %}
    on {{ post.published_at|date('M d, Y') }}
</p>


================================================
FILE: components/posts/default.htm
================================================
{% set posts = __SELF__.posts %}

<ul class="post-list">
    {% for post in posts %}
        <li>
            <h3><a href="{{ post.url }}">{{ post.title }}</a></h3>

            <p class="info">
                Posted
                {% if post.categories|length %} in {% endif %}
                {% for category in post.categories %}
                    <a href="{{ category.url }}">{{ category.name }}</a>{% if not loop.last %}, {% endif %}
                {% endfor %}
                on {{ post.published_at|date('M d, Y') }}
            </p>

            <p class="excerpt">{{ post.summary|raw }}</p>
        </li>
    {% else %}
        <li class="no-data">{{ __SELF__.noPostsMessage }}</li>
    {% endfor %}
</ul>

{% if posts.lastPage > 1 %}
    <ul class="pagination">
        {% if posts.currentPage > 1 %}
            <li><a href="{{ this.page.baseFileName|page({ (__SELF__.pageParam): (posts.currentPage-1) }) }}">&larr; Prev</a></li>
        {% endif %}

        {% for page in 1..posts.lastPage %}
            <li class="{{ posts.currentPage == page ? 'active' : null }}">
                <a href="{{ this.page.baseFileName|page({ (__SELF__.pageParam): page }) }}">{{ page }}</a>
            </li>
        {% endfor %}

        {% if posts.lastPage > posts.currentPage %}
            <li><a href="{{ this.page.baseFileName|page({ (__SELF__.pageParam): (posts.currentPage+1) }) }}">Next &rarr;</a></li>
        {% endif %}
    </ul>
{% endif %}


================================================
FILE: components/rssfeed/default.htm
================================================
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>{{ this.page.meta_title ?: this.page.title }}</title>
        <link>{{ link }}</link>
        <description>{{ this.page.meta_description ?: this.page.description }}</description>
        <atom:link href="{{ rssLink }}" rel="self" type="application/rss+xml" />
        {% for post in posts %}
        <item>
            <title>{{ post.title }}</title>
            <link>{{ post.url }}</link>
            <guid>{{ post.url }}</guid>
            <pubDate>{{ post.published_at.toRfc2822String }}</pubDate>
            <description>{{ post.summary }}</description>
        </item>
        {% endfor %}
    </channel>
</rss>


================================================
FILE: composer.json
================================================
{
    "name": "rainlab/blog-plugin",
    "type": "october-plugin",
    "description": "Blog plugin for October CMS",
    "homepage": "https://octobercms.com/plugin/rainlab-blog",
    "keywords": ["october", "octobercms", "blog"],
    "license": "MIT",
    "authors": [
        {
            "name": "Alexey Bobkov",
            "email": "aleksey.bobkov@gmail.com",
            "role": "Co-founder"
        },
        {
            "name": "Samuel Georges",
            "email": "daftspunky@gmail.com",
            "role": "Co-founder"
        }
    ],
    "require": {
        "php": ">=7.0",
        "composer/installers": "~1.0"
    },
    "minimum-stability": "dev"
}


================================================
FILE: config/config.php
================================================
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Summary Config
    |--------------------------------------------------------------------------
    |
    | Specify a custom tag and length for blog post summaries
    |
    */

    'summary_separator' => '<!-- more -->',

    'summary_default_length' => 600

];


================================================
FILE: controllers/Categories.php
================================================
<?php namespace RainLab\Blog\Controllers;

use BackendMenu;
use Flash;
use Lang;
use Backend\Classes\Controller;
use RainLab\Blog\Models\Category;

class Categories extends Controller
{
    public $implement = [
        \Backend\Behaviors\FormController::class,
        \Backend\Behaviors\ListController::class,
        \Backend\Behaviors\ReorderController::class
    ];

    public $formConfig = 'config_form.yaml';
    public $listConfig = 'config_list.yaml';
    public $reorderConfig = 'config_reorder.yaml';

    public $requiredPermissions = ['rainlab.blog.access_categories'];

    public function __construct()
    {
        parent::__construct();

        BackendMenu::setContext('RainLab.Blog', 'blog', 'categories');
    }

    public function index_onDelete()
    {
        if (($checkedIds = post('checked')) && is_array($checkedIds) && count($checkedIds)) {

            foreach ($checkedIds as $categoryId) {
                if ((!$category = Category::find($categoryId))) {
                    continue;
                }

                $category->delete();
            }

            Flash::success(Lang::get('rainlab.blog::lang.category.delete_success'));
        }

        return $this->listRefresh();
    }
}


================================================
FILE: controllers/Posts.php
================================================
<?php namespace RainLab\Blog\Controllers;

use Lang;
use Flash;
use BackendMenu;
use RainLab\Blog\Models\Post;
use RainLab\Blog\Models\Settings as BlogSettings;
use Backend\Classes\Controller;
use Cms\Classes\Controller as CmsController;
use Cms\Classes\Theme;

/**
 * Posts
 */
class Posts extends Controller
{
    public $implement = [
        \Backend\Behaviors\FormController::class,
        \Backend\Behaviors\ListController::class,
        \Backend\Behaviors\ImportExportController::class
    ];

    public $formConfig = 'config_form.yaml';
    public $listConfig = 'config_list.yaml';
    public $importExportConfig = 'config_import_export.yaml';

    /**
     * @var array requiredPermissions
     */
    public $requiredPermissions = ['rainlab.blog.access_other_posts', 'rainlab.blog.access_posts'];

    /**
     * @var bool turboVisitControl
     */
    public $turboVisitControl = 'disable';

    /**
     * __construct
     */
    public function __construct()
    {
        parent::__construct();

        BackendMenu::setContext('RainLab.Blog', 'blog', 'posts');
    }

    public function index()
    {
        $this->vars['postsTotal'] = Post::count();
        $this->vars['postsPublished'] = Post::isPublished()->count();
        $this->vars['postsDrafts'] = $this->vars['postsTotal'] - $this->vars['postsPublished'];

        $this->asExtension('ListController')->index();
    }

    public function create()
    {
        BackendMenu::setContextSideMenu('new_post');

        $this->bodyClass = 'compact-container';
        $this->addCss('/plugins/rainlab/blog/assets/css/rainlab.blog-preview.css');
        $this->addJs('/plugins/rainlab/blog/assets/js/post-form.js');

        return $this->asExtension('FormController')->create();
    }

    public function update($recordId = null)
    {
        $this->bodyClass = 'compact-container';
        $this->addCss('/plugins/rainlab/blog/assets/css/rainlab.blog-preview.css');
        $this->addJs('/plugins/rainlab/blog/assets/js/post-form.js');

        $result = $this->asExtension('FormController')->update($recordId);
        $this->setPreviewPageUrlVars();
        return $result;
    }

    /**
     * setPreviewPageUrlVars
     */
    protected function setPreviewPageUrlVars()
    {
        if (
            ($model = $this->formGetModel()) &&
            ($cmsPage = BlogSettings::get('preview_cms_page'))
        ) {
            $controller = new CmsController(Theme::getActiveTheme());
            $model->setUrl($cmsPage, $controller);
            $this->vars['pageUrl'] = $model->url;
        }
    }

    public function export()
    {
        $this->addCss('/plugins/rainlab/blog/assets/css/rainlab.blog-export.css');

        return $this->asExtension('ImportExportController')->export();
    }

    public function listExtendQuery($query)
    {
        if (!$this->user->hasAnyAccess(['rainlab.blog.access_other_posts'])) {
            $query->where('user_id', $this->user->id);
        }
    }

    public function formExtendQuery($query)
    {
        if (!$this->user->hasAnyAccess(['rainlab.blog.access_other_posts'])) {
            $query->where('user_id', $this->user->id);
        }
    }

    public function formExtendFieldsBefore($widget)
    {
        if (!$model = $widget->model) {
            return;
        }

        // Support for October CMS 3.0 and below
        if (!class_exists('Site') && $model instanceof Post && $model->isClassExtendedWith('RainLab.Translate.Behaviors.TranslatableModel')) {
            $widget->secondaryTabs['fields']['content']['type'] = 'RainLab\Blog\FormWidgets\MLBlogMarkdown';
        }

        if (BlogSettings::get('use_legacy_editor', false)) {
            $widget->secondaryTabs['fields']['content']['legacyMode'] = true;
        }

        // Force richeditor by settings
        if ($model instanceof Post && BlogSettings::get('force_richeditor_editor', false)) {
            $widget->secondaryTabs['fields']['content']['type'] = 'richeditor';
        }
    }

    public function index_onDelete()
    {
        if (($checkedIds = post('checked')) && is_array($checkedIds) && count($checkedIds)) {

            foreach ($checkedIds as $postId) {
                if ((!$post = Post::find($postId)) || !$post->canEdit($this->user)) {
                    continue;
                }

                $post->delete();
            }

            Flash::success(Lang::get('rainlab.blog::lang.post.delete_success'));
        }

        return $this->listRefresh();
    }

    /**
     * {@inheritDoc}
     */
    public function listInjectRowClass($record, $definition = null)
    {
        if (!$record->published) {
            return 'safe disabled';
        }
    }

    public function formBeforeCreate($model)
    {
        $model->user_id = $this->user->id;
    }

    public function onRefreshPreview()
    {
        $data = post('Post');

        $previewHtml = Post::formatHtml($data['content'], true);

        return [
            'preview' => $previewHtml
        ];
    }
}


================================================
FILE: controllers/categories/_list_toolbar.htm
================================================
<div data-control="toolbar">
    <a href="<?= Backend::url('rainlab/blog/categories/create') ?>" class="btn btn-primary oc-icon-plus">
        <?= e(trans('rainlab.blog::lang.categories.new_category')) ?>
    </a>
    <button
        class="btn btn-default oc-icon-trash-o"
        disabled="disabled"
        onclick="$(this).data('request-data', {
            checked: $('.control-list').listWidget('getChecked')
        })"
        data-request="onDelete"
        data-request-confirm="<?= e(trans('rainlab.blog::lang.blog.delete_confirm')) ?>"
        data-trigger-action="enable"
        data-trigger=".control-list input[type=checkbox]"
        data-trigger-condition="checked"
        data-request-success="$(this).prop('disabled', false)"
        data-stripe-load-indicator>
        <?= e(trans('backend::lang.list.delete_selected')) ?>
    </button>
    <?php if (!class_exists('System')): ?>
        <a href="<?= Backend::url('rainlab/blog/categories/reorder') ?>" class="btn btn-default oc-icon-sitemap">
            <?= e(trans('rainlab.blog::lang.category.reorder')) ?>
        </a>
    <?php endif ?>
</div>


================================================
FILE: controllers/categories/_reorder_toolbar.htm
================================================
<div data-control="toolbar">
    <a href="<?= Backend::url('rainlab/blog/categories') ?>" class="btn btn-primary oc-icon-caret-left">
        <?= e(trans('rainlab.blog::lang.category.return_to_categories')) ?>
    </a>
</div>

================================================
FILE: controllers/categories/config_form.yaml
================================================
# ===================================
#  Form Behavior Config
# ===================================

name: rainlab.blog::lang.blog.create_category
form: $/rainlab/blog/models/category/fields.yaml
modelClass: RainLab\Blog\Models\Category
defaultRedirect: rainlab/blog/categories

create:
    redirect: rainlab/blog/categories/update/:id
    redirectClose: rainlab/blog/categories

update:
    redirect: rainlab/blog/categories
    redirectClose: rainlab/blog/categories


================================================
FILE: controllers/categories/config_list.yaml
================================================
# ===================================
#  List Behavior Config
# ===================================

# Model List Column configuration
list: $/rainlab/blog/models/category/columns.yaml

# Model Class name
modelClass: RainLab\Blog\Models\Category

# List Title
title: rainlab.blog::lang.categories.list_title

# Link URL for each record
recordUrl: rainlab/blog/categories/update/:id

# Message to display if the list is empty
noRecordsMessage: backend::lang.list.no_records

# Records to display per page
recordsPerPage: 5

# Display checkboxes next to each record
showCheckboxes: true

# Toolbar widget configuration
toolbar:
    # Partial for toolbar buttons
    buttons: list_toolbar

    # Search widget configuration
    search:
        prompt: backend::lang.list.search_prompt

# Legacy (v1)
showTree: true

# Reordering
structure:
    showTree: true
    showReorder: true
    treeExpanded: true
    maxDepth: 0


================================================
FILE: controllers/categories/config_reorder.yaml
================================================
# ===================================
#  Reorder Behavior Config
# ===================================

# Reorder Title
title: rainlab.blog::lang.category.reorder

# Attribute name
nameFrom: name

# Model Class name
modelClass: RainLab\Blog\Models\Category

# Toolbar widget configuration
toolbar:
    # Partial for toolbar buttons
    buttons: reorder_toolbar

================================================
FILE: controllers/categories/create.htm
================================================
<?php Block::put('breadcrumb') ?>
    <ul>
        <li><a href="<?= Backend::url('rainlab/blog/posts') ?>"><?= e(trans('rainlab.blog::lang.blog.menu_label')) ?></a></li>
        <li><?= e(trans($this->pageTitle)) ?></li>
    </ul>
<?php Block::endPut() ?>

<?php if (!$this->fatalError): ?>

    <?= Form::open(['class' => 'layout']) ?>

        <div class="layout-row">
            <?= $this->formRender() ?>
        </div>

        <div class="form-buttons">
            <div class="loading-indicator-container">
                <button
                    type="submit"
                    data-request="onSave"
                    data-hotkey="ctrl+s, cmd+s"
                    data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
                    class="btn btn-primary">
                    <?= e(trans('backend::lang.form.create')) ?>
                </button>
                <button
                    type="button"
                    data-request="onSave"
                    data-request-data="close:1"
                    data-hotkey="ctrl+enter, cmd+enter"
                    data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
                    class="btn btn-default">
                    <?= e(trans('backend::lang.form.create_and_close')) ?>
                </button>
                <span class="btn-text">
                    <?= e(trans('backend::lang.form.or')) ?> <a href="<?= Backend::url('rainlab/blog/categories') ?>"><?= e(trans('backend::lang.form.cancel')) ?></a>
                </span>
            </div>
        </div>

    <?= Form::close() ?>

<?php else: ?>
    <p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
    <p><a href="<?= Backend::url('rainlab/blog/posts') ?>" class="btn btn-default"><?= e(trans('rainlab.blog::lang.category.return_to_categories')) ?></a></p>
<?php endif ?>


================================================
FILE: controllers/categories/index.htm
================================================

<?= $this->listRender() ?>


================================================
FILE: controllers/categories/reorder.htm
================================================
<?= $this->reorderRender() ?>

================================================
FILE: controllers/categories/update.htm
================================================
<?php Block::put('breadcrumb') ?>
    <ul>
        <li><a href="<?= Backend::url('rainlab/blog/posts') ?>"><?= e(trans('rainlab.blog::lang.blog.menu_label')) ?></a></li>
        <li><?= e(trans($this->pageTitle)) ?></li>
    </ul>
<?php Block::endPut() ?>

<?php if (!$this->fatalError): ?>

    <?= Form::open(['class' => 'layout']) ?>

        <div class="layout-row">
            <?= $this->formRender() ?>
        </div>

        <div class="form-buttons">
            <div class="loading-indicator-container">
                <button
                    type="submit"
                    data-request="onSave"
                    data-request-data="redirect:0"
                    data-hotkey="ctrl+s, cmd+s"
                    data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
                    class="btn btn-primary">
                    <?= e(trans('backend::lang.form.save')) ?>
                </button>
                <button
                    type="button"
                    data-request="onSave"
                    data-request-data="close:1"
                    data-hotkey="ctrl+enter, cmd+enter"
                    data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
                    class="btn btn-default">
                    <?= e(trans('backend::lang.form.save_and_close')) ?>
                </button>
                <button
                    type="button"
                    class="oc-icon-trash-o btn-icon danger pull-right"
                    data-request="onDelete"
                    data-load-indicator="<?= e(trans('backend::lang.form.deleting')) ?>"
                    data-request-confirm="<?= e(trans('rainlab.blog::lang.category.delete_confirm')) ?>">
                </button>

                <span class="btn-text">
                    <?= e(trans('backend::lang.form.or')) ?> <a href="<?= Backend::url('rainlab/blog/categories') ?>"><?= e(trans('backend::lang.form.cancel')) ?></a>
                </span>
            </div>
        </div>
    <?= Form::close() ?>

<?php else: ?>
    <p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
    <p><a href="<?= Backend::url('rainlab/blog/posts') ?>" class="btn btn-default"><?= e(trans('rainlab.blog::lang.category.return_to_categories')) ?></a></p>
<?php endif ?>


================================================
FILE: controllers/posts/_list_toolbar.htm
================================================
<div data-control="toolbar">
    <a
        href="<?= Backend::url('rainlab/blog/posts/create') ?>"
        class="btn btn-primary oc-icon-plus">
        <?= e(trans('rainlab.blog::lang.posts.new_post')) ?>
    </a>
    <button
        class="btn btn-default oc-icon-trash-o"
        disabled="disabled"
        onclick="$(this).data('request-data', {
            checked: $('.control-list').listWidget('getChecked')
        })"
        data-request="onDelete"
        data-request-confirm="<?= e(trans('rainlab.blog::lang.blog.delete_confirm')) ?>"
        data-trigger-action="enable"
        data-trigger=".control-list input[type=checkbox]"
        data-trigger-condition="checked"
        data-request-success="$(this).prop('disabled', true)"
        data-stripe-load-indicator>
        <?= e(trans('backend::lang.list.delete_selected')) ?>
    </button>

    <?php if ($this->user->hasAnyAccess(['rainlab.blog.access_import_export'])): ?>
        <div class="btn-group">
            <a
                href="<?= Backend::url('rainlab/blog/posts/export') ?>"
                class="btn btn-default oc-icon-download">
                <?= e(trans('rainlab.blog::lang.posts.export_post')) ?>
            </a>
            <a
                href="<?= Backend::url('rainlab/blog/posts/import') ?>"
                class="btn btn-default oc-icon-upload">
                <?= e(trans('rainlab.blog::lang.posts.import_post')) ?>
            </a>
        </div>
    <?php endif ?>
</div>


================================================
FILE: controllers/posts/_post_toolbar.htm
================================================
<?php
    $isCreate = $this->formGetContext() == 'create';
    $pageUrl = isset($pageUrl) ? $pageUrl : null;
?>
<div class="form-buttons loading-indicator-container">

    <!-- Save -->
    <a
        href="javascript:;"
        class="btn btn-primary oc-icon-check save"
        data-request="onSave"
        data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
        data-load-indicator-size="small"
        data-request-before-update="$(this).trigger('unchange.oc.changeMonitor')"
        <?php if (!$isCreate): ?>data-request-data="redirect:0"<?php endif ?>
        data-hotkey="ctrl+s, cmd+s">
            <?= e(trans('backend::lang.form.save')) ?>
    </a>

    <?php if (!$isCreate): ?>
        <!-- Save and Close -->
        <a
            href="javascript:;"
            class="btn btn-primary oc-icon-check save"
            data-request-before-update="$(this).trigger('unchange.oc.changeMonitor')"
            data-request="onSave"
            data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
            data-load-indicator-size="small">
                <?= e(trans('backend::lang.form.save_and_close')) ?>
        </a>
    <?php endif ?>

    <!-- Cancel -->
    <a
        href="<?= Backend::url('rainlab/blog/posts') ?>"
        class="btn btn-primary oc-icon-arrow-left cancel">
            <?= e(trans('backend::lang.form.cancel')) ?>
    </a>

    <!-- Preview -->
    <a
        href="<?= Url::to($pageUrl) ?>"
        target="_blank"
        class="btn btn-primary oc-icon-crosshairs <?php if (empty($pageUrl)): ?>hide oc-hide<?php endif ?>"
        data-control="preview-button">
            <?= e(trans('rainlab.blog::lang.blog.preview')) ?>
    </a>

    <?php if (!$isCreate): ?>
        <!-- Delete -->
        <button
            type="button"
            class="btn btn-default empty oc-icon-trash-o"
            data-request="onDelete"
            data-request-confirm="<?= e(trans('rainlab.blog::lang.post.delete_confirm')) ?>"
            data-control="delete-button"></button>
    <?php endif ?>
</div>


================================================
FILE: controllers/posts/config_form.yaml
================================================
# ===================================
#  Form Behavior Config
# ===================================

name: rainlab.blog::lang.blog.create_post
form: $/rainlab/blog/models/post/fields.yaml
modelClass: RainLab\Blog\Models\Post
defaultRedirect: rainlab/blog/posts

create:
    redirect: rainlab/blog/posts/update/:id
    redirectClose: rainlab/blog/posts

update:
    redirect: rainlab/blog/posts
    redirectClose: rainlab/blog/posts


================================================
FILE: controllers/posts/config_import_export.yaml
================================================
# ===================================
#  Import/Export Behavior Config
# ===================================

import:
    # Page title
    title: rainlab.blog::lang.posts.import_post

    # Import List Column configuration
    list: $/rainlab/blog/models/postimport/columns.yaml

    # Import Form Field configuration
    form: $/rainlab/blog/models/postimport/fields.yaml

    # Import Model class
    modelClass: RainLab\Blog\Models\PostImport

    # Redirect when finished
    redirect: rainlab/blog/posts

    # Required permissions
    permissions: rainlab.blog.access_import_export

export:
    # Page title
    title: rainlab.blog::lang.posts.export_post

    # Output file name
    fileName: posts.csv

    # Export List Column configuration
    list: $/rainlab/blog/models/postexport/columns.yaml

    # Export Model class
    modelClass: RainLab\Blog\Models\PostExport

    # Redirect when finished
    redirect: rainlab/blog/posts

    # Required permissions
    permissions: rainlab.blog.access_import_export


================================================
FILE: controllers/posts/config_list.yaml
================================================
# ===================================
#  List Behavior Config
# ===================================

# Model List Column configuration
list: $/rainlab/blog/models/post/columns.yaml

# Filter widget configuration
filter: $/rainlab/blog/models/post/scopes.yaml

# Model Class name
modelClass: RainLab\Blog\Models\Post

# List Title
title: rainlab.blog::lang.posts.list_title

# Link URL for each record
recordUrl: rainlab/blog/posts/update/:id

# Message to display if the list is empty
noRecordsMessage: backend::lang.list.no_records

# Records to display per page
recordsPerPage: 25

# Displays the list column set up button
showSetup: true

# Displays the sorting link on each column
showSorting: true

# Default sorting column
defaultSort:
    column: published_at
    direction: desc

# Display checkboxes next to each record
showCheckboxes: true

# Toolbar widget configuration
toolbar:
    # Partial for toolbar buttons
    buttons: list_toolbar

    # Search widget configuration
    search:
        prompt: backend::lang.list.search_prompt


================================================
FILE: controllers/posts/create.htm
================================================
<?php if (!$this->fatalError): ?>

    <div class="layout fancy-layout">
        <?= Form::open([
            'class' => 'layout',
            'data-change-monitor' => 'true',
            'data-window-close-confirm' => e(trans('rainlab.blog::lang.post.close_confirm')),
            'id' => 'post-form'
        ]) ?>
            <?= $this->formRender() ?>

        <?= Form::close() ?>
    </div>

<?php else: ?>
    <div class="control-breadcrumb">
        <?= Block::placeholder('breadcrumb') ?>
    </div>
    <div class="padded-container">
        <p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
        <p><a href="<?= Backend::url('rainlab/blog/posts') ?>" class="btn btn-default"><?= e(trans('rainlab.blog::lang.post.return_to_posts')) ?></a></p>
    </div>
<?php endif ?>


================================================
FILE: controllers/posts/export.htm
================================================
<?php Block::put('breadcrumb') ?>
    <ul>
        <li><a href="<?= Backend::url('rainlab/blog/posts') ?>"><?= e(trans('rainlab.blog::lang.blog.menu_label')) ?></a></li>
        <li><?= e(trans($this->pageTitle)) ?></li>
    </ul>
<?php Block::endPut() ?>

<?= Form::open(['class' => 'layout']) ?>

    <div class="layout-row">
        <?= $this->exportRender() ?>
    </div>

    <div class="form-buttons">
        <div class="loading-indicator-container">
            <button
                type="submit"
                data-control="popup"
                data-handler="onExportLoadForm"
                data-keyboard="false"
                class="btn btn-primary">
                <?= e(trans('rainlab.blog::lang.posts.export_post')) ?>
            </button>
        </div>
    </div>

<?= Form::close() ?>


================================================
FILE: controllers/posts/import.htm
================================================
<?php Block::put('breadcrumb') ?>
    <ul>
        <li><a href="<?= Backend::url('rainlab/blog/posts') ?>"><?= e(trans('rainlab.blog::lang.blog.menu_label')) ?></a></li>
        <li><?= e(trans($this->pageTitle)) ?></li>
    </ul>
<?php Block::endPut() ?>

<?= Form::open(['class' => 'layout']) ?>

    <div class="layout-row">
        <?= $this->importRender() ?>
    </div>

    <div class="form-buttons">
        <button
            type="submit"
            data-control="popup"
            data-handler="onImportLoadForm"
            data-keyboard="false"
            class="btn btn-primary">
            <?= e(trans('rainlab.blog::lang.posts.import_post')) ?>
        </button>
    </div>

<?= Form::close() ?>


================================================
FILE: controllers/posts/index.htm
================================================
<?= $this->listRender() ?>


================================================
FILE: controllers/posts/update.htm
================================================
<?php if (!$this->fatalError): ?>

    <div class="layout fancy-layout">
        <?= Form::open([
            'class' => 'layout',
            'data-change-monitor' => 'true',
            'data-window-close-confirm' => e(trans('rainlab.blog::lang.post.close_confirm')),
            'id' => 'post-form'
        ]) ?>
            <?= $this->formRender() ?>

        <?= Form::close() ?>
    </div>

<?php else: ?>

    <div class="control-breadcrumb">
        <?= Block::placeholder('breadcrumb') ?>
    </div>
    <div class="padded-container">
        <p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
        <p><a href="<?= Backend::url('rainlab/blog/posts') ?>" class="btn btn-default"><?= e(trans('rainlab.blog::lang.post.return_to_posts')) ?></a></p>
    </div>

<?php endif ?>


================================================
FILE: formwidgets/BlogMarkdown.php
================================================
<?php namespace RainLab\Blog\FormWidgets;

use Lang;
use Input;
use Response;
use Validator;
use RainLab\Blog\Models\Post as PostModel;
use Backend\Classes\FormWidgetBase;
use Backend\FormWidgets\MarkdownEditor;
use System\Models\File;
use ValidationException;
use SystemException;
use Exception;

/**
 * Special markdown editor for the Create/Edit Post form.
 *
 * @package rainlab\blog
 * @author Alexey Bobkov, Samuel Georges
 */
class BlogMarkdown extends MarkdownEditor
{
    /**
     * {@inheritDoc}
     */
    public function init()
    {
        $this->viewPath = base_path().'/modules/backend/formwidgets/markdowneditor/partials';

        $this->checkUploadPostback();

        parent::init();
    }

    /**
     * {@inheritDoc}
     */
    protected function loadAssets()
    {
        $this->assetPath = '/modules/backend/formwidgets/markdowneditor/assets';
        parent::loadAssets();
    }

    /**
     * Disable HTML cleaning on the widget level since the PostModel will handle it
     *
     * @return boolean
     */
    protected function shouldCleanHtml()
    {
        return false;
    }

    /**
     * {@inheritDoc}
     */
    public function onRefresh()
    {
        $content = post($this->formField->getName());

        $previewHtml = PostModel::formatHtml($content, true);

        return [
            'preview' => $previewHtml
        ];
    }

    /**
     * Handle images being uploaded to the blog post
     *
     * @return void
     */
    protected function checkUploadPostback()
    {
        if (!post('X_BLOG_IMAGE_UPLOAD')) {
            return;
        }

        $uploadedFileName = null;

        try {
            $uploadedFile = Input::file('file');

            if ($uploadedFile)
                $uploadedFileName = $uploadedFile->getClientOriginalName();

            $validationRules = ['max:'.File::getMaxFilesize()];
            $validationRules[] = 'mimes:jpg,jpeg,bmp,png,gif';

            $validation = Validator::make(
                ['file_data' => $uploadedFile],
                ['file_data' => $validationRules]
            );

            if ($validation->fails()) {
                throw new ValidationException($validation);
            }

            if (!$uploadedFile->isValid()) {
                throw new SystemException(Lang::get('cms::lang.asset.file_not_valid'));
            }

            $fileRelation = $this->model->content_images();

            $file = new File();
            $file->data = $uploadedFile;
            $file->is_public = true;
            $file->save();

            $fileRelation->add($file, $this->sessionKey);
            $result = [
                'file' => $uploadedFileName,
                'path' => $file->getPath()
            ];

            $response = Response::make()->setContent($result);
            $this->controller->setResponse($response);

        } catch (Exception $ex) {
            $message = $uploadedFileName
                ? Lang::get('cms::lang.asset.error_uploading_file', ['name' => $uploadedFileName, 'error' => $ex->getMessage()])
                : $ex->getMessage();

            $result = [
                'error' => $message,
                'file' => $uploadedFileName
            ];

            $response = Response::make()->setContent($result);
            $this->controller->setResponse($response);
        }
    }
}


================================================
FILE: formwidgets/MLBlogMarkdown.php
================================================
<?php namespace RainLab\Blog\FormWidgets;

use RainLab\Blog\Models\Post;
use RainLab\Translate\Models\Locale;

/**
 * A multi-lingual version of the blog markdown editor.
 * This class should never be invoked without the RainLab.Translate plugin.
 *
 * @package rainlab\blog
 * @author Alexey Bobkov, Samuel Georges
 */
class MLBlogMarkdown extends BlogMarkdown
{
    use \RainLab\Translate\Traits\MLControl;

    /**
     * {@inheritDoc}
     */
    protected $defaultAlias = 'mlmarkdowneditor';

    public $originalAssetPath;
    public $originalViewPath;

    /**
     * @var bool legacyMode disables the Vue integration
     */
    public $legacyMode = true;

    /**
     * {@inheritDoc}
     */
    public function init()
    {
        parent::init();
        $this->initLocale();
    }

    /**
     * {@inheritDoc}
     */
    public function render()
    {
        $this->actAsParent();
        $parentContent = parent::render();
        $this->actAsParent(false);

        if (!$this->isAvailable) {
            return $parentContent;
        }

        $this->vars['markdowneditor'] = $parentContent;

        $this->actAsControl(true);

        return $this->makePartial('mlmarkdowneditor');
    }

    public function prepareVars()
    {
        parent::prepareVars();
        $this->prepareLocaleVars();
    }

    /**
     * Returns an array of translated values for this field
     * @param $value
     * @return array
     */
    public function getSaveValue($value)
    {
        $localeData = $this->getLocaleSaveData();

        /*
         * Set the translated values to the model
         */
        if ($this->model->methodExists('setAttributeTranslated')) {
            foreach ($localeData as $locale => $value) {
                $this->model->setAttributeTranslated('content', $value, $locale);

                $this->model->setAttributeTranslated(
                    'content_html',
                    Post::formatHtml($value),
                    $locale
                );
            }
        }

        return array_get($localeData, $this->defaultLocale->code, $value);
    }

    /**
     * {@inheritDoc}
     */
    protected function loadAssets()
    {
        $this->actAsParent();
        parent::loadAssets();
        $this->actAsParent(false);

        if (Locale::isAvailable()) {
            $this->loadLocaleAssets();

            $this->actAsControl(true);
            $this->addJs('js/mlmarkdowneditor.js');
            $this->actAsControl(false);
        }
    }

    protected function actAsParent($switch = true)
    {
        if ($switch) {
            $this->originalAssetPath = $this->assetPath;
            $this->originalViewPath = $this->viewPath;
            $this->assetPath = '/modules/backend/formwidgets/markdowneditor/assets';
            $this->viewPath = base_path('/modules/backend/formwidgets/markdowneditor/partials');
        }
        else {
            $this->assetPath = $this->originalAssetPath;
            $this->viewPath = $this->originalViewPath;
        }
    }

    protected function actAsControl($switch = true)
    {
        if ($switch) {
            $this->originalAssetPath = $this->assetPath;
            $this->originalViewPath = $this->viewPath;
            $this->assetPath = '/plugins/rainlab/translate/formwidgets/mlmarkdowneditor/assets';
            $this->viewPath = base_path('/plugins/rainlab/translate/formwidgets/mlmarkdowneditor/partials');
        }
        else {
            $this->assetPath = $this->originalAssetPath;
            $this->viewPath = $this->originalViewPath;
        }
    }
}


================================================
FILE: lang/bg/lang.php
================================================
<?php

return [
    'plugin' => [
        'name' => 'Блог',
        'description' => 'Стабилната блог платформа.'
    ],
    'blog' => [
        'menu_label' => 'Блог',
        'menu_description' => 'управление на публикациите',
        'posts' => 'публикации',
        'create_post' => 'създай публикация',
        'categories' => 'категории',
        'create_category' => 'създай категория',
        'tab' => 'Блог',
        'access_posts' => 'управление на публикациите',
        'access_categories' => 'управление на категории',
        'access_other_posts' => 'управление на други потребители публикации в блога',
        'delete_confirm' => 'Сигурни ли сте?',
        'chart_published' => 'Публикувано',
        'chart_drafts' => 'Чернови',
        'chart_total' => 'Общо'
    ],
    'posts' => [
        'list_title' => 'Управление публикациите в блога',
        'filter_category' => 'Категория',
        'filter_published' => 'Скрий публикуваните',
        'new_post' => 'Нова публикация'
    ],
    'post' => [
        'title' => 'Заглавие',
        'title_placeholder' => 'Ново заглавие на публикацията',
        'slug' => 'Slug',
        'slug_placeholder' => 'нов slug на публикацията',
        'categories' => 'Категории',
        'created' => 'Създаден',
        'updated' => 'Обновен',
        'published' => 'Публикуван',
        'published_validation' => 'Моля, посочете дата на публикуване',
        'tab_edit' => 'Промяна',
        'tab_categories' => 'Категории',
        'categories_comment' => 'Изберете категории към който пренадлежи публикацията ',
        'categories_placeholder' => 'Няма категирии, Създайте първата?!',
        'tab_manage' => 'Управление',
        'published_on' => 'публикувано в',
        'excerpt' => 'Откъс',
        'featured_images' => 'Избрани снимки',
        'delete_confirm' => 'Наистина ли искате да изтриете тази публикация?',
        'close_confirm' => 'Публикацията не е запазена.',
        'return_to_posts' => 'Върни ме към всички публикации'
    ],
    'categories' => [
        'list_title' => 'Управление категориите в блога',
        'new_category' => 'Нова категория',
        'uncategorized' => 'Без категория'
    ],
    'category' => [
        'name' => 'Име',
        'name_placeholder' => 'Ново име на категорията',
        'slug' => 'Slug',
        'slug_placeholder' => 'нов slug на категотията',
        'posts' => 'публикации',
        'delete_confirm' => 'Наистина ли искате да изтриете тази категория?',
        'return_to_categories' => 'Върни ме към всички категории'
    ],
    'settings' => [
        'category_title' => 'Списък с категории',
        'category_description' => 'Показва списък с категориите на блога.',
        'category_slug' => 'категория slug',
        'category_slug_description' => "Look up the blog category using the supplied slug value. This property is used by the default component partial for marking the currently active category.",
        'category_display_empty' => 'Показване на празни категории',
        'category_display_empty_description' => 'Показване на категории, които нямат никакви публикации.',
        'category_page' => 'Страница на категория',
        'category_page_description' => 'Име на страницата за категирия. Това се използва подразбиране от компонента.',
        'post_title' => 'Публикация',
        'post_description' => 'Показване на Публикациите в блога на страницата.',
        'post_slug' => 'Post slug',
        'post_slug_description' => "Търсене на публикации по зададен slug.",
        'post_category' => 'Страница за Категория',
        'post_category_description' => 'Име на страница за категория за генериране на линк.Това се използва подразбиране от компонента.',
        'posts_title' => 'Лист с Публикации',
        'posts_description' => 'Показване на лист с публикации на страницата.',
        'posts_pagination' => 'Номер на страницата',
        'posts_pagination_description' => 'Тази стойност се използва за определяне на коя страница е потребителя.',
        'posts_filter' => 'Филтер Категория',
        'posts_filter_description' => 'Въведи slug на категория или URL адрес за филтриране по. Оставете празно за да се покажат всички публикации.',
        'posts_per_page' => 'Публикации на страница',
        'posts_per_page_validation' => 'Невалиден формат за публикации на страница',
        'posts_no_posts' => 'Няма публикации',
        'posts_no_posts_description' => 'Съобщение което да се покаже, в случай ,че няма публикации за показване.Това се използва подразбиране от компонента.',
        'posts_order' => 'подреждане на публикации',
        'posts_order_description' => 'Атрибут по който да бъдат подредени публикациите',
        'posts_category' => 'страница на категориите',
        'posts_category_description' => 'Име на страницата за категории , за "публикувано в". Това се използва подразбиране от компонента.',
        'posts_post' => 'Post page',
        'posts_post_description' => 'Име на страницата за публикации "Прочетете повече". Това се използва подразбиране от компонента.',
        'posts_except_post' => 'Except post',
        'posts_except_post_description' => 'Enter ID/URL or variable with post ID/URL you want to except',
    ]
];


================================================
FILE: lang/cs/lang.php
================================================
<?php

return [
    'plugin' => [
        'name' => 'Blog',
        'description' => 'Robustní blogová platforma.'
    ],
    'blog' => [
        'menu_label' => 'Blog',
        'menu_description' => 'Správa blogových příspěvků',
        'posts' => 'Příspěvky',
        'create_post' => 'Příspěvek',
        'categories' => 'Kategorie',
        'create_category' => 'Kategorie příspěvků',
        'tab' => 'Blog',
        'access_posts' => 'Správa blogových příspěvků',
        'access_categories' => 'Správa blogových kategorií',
        'access_other_posts' => 'Správa příspěvků ostatních uživatelů',
        'access_import_export' => 'Možnost importu a exportu příspěvků',
        'access_publish' => 'Možnost publikovat příspěvky',
        'delete_confirm' => 'Jste si jistí?',
        'chart_published' => 'Publikované',
        'chart_drafts' => 'Návrhy',
        'chart_total' => 'Celkem',
        'settings_description' => 'Správa nastavení blogu',
        'show_all_posts_label' => 'Zobrazit všechny příspěvky uživatelům na pozadí',
        'show_all_posts_comment' => 'Zobrazit publikované i nepublikované příspěvky na frontend uživatelům backendu',
        'use_legacy_editor_label' => 'Použít starší editor Markdown',
        'use_legacy_editor_comment' => 'Povolit starší verzi editoru markdown při použití systému October CMS v2 a vyšší',
        'force_richeditor_editor_label' => 'Vynutit WYSIWYG editor',
        'force_richeditor_editor_comment' => 'Použít běžný richtextový editor místo editoru Markdown',
        'preview_cms_page_label' => 'Náhled stránky CMS',
        'preview_cms_page_comment' => 'Vyberte stránku, která se otevře pro tlačítko Náhled',
        'tab_general' => 'Obecné',
        'preview' => 'Náhled'
    ],
    'posts' => [
        'list_title' => 'Správa blogových příspěvků',
        'filter_category' => 'Kategorie',
        'filter_published' => 'Schovat publikované',
        'filter_date' => 'Datum',
        'new_post' => 'Nový příspěvek',
        'export_post' => 'Export příspěvků',
        'import_post' => 'Import příspěvků',
    ],
    'post' => [
        'title' => 'Název',
        'title_placeholder' => 'Zadejte název',
        'content' => 'Obsah',
        'content_html' => 'HTML obsah',
        'slug' => 'URL příspěvku',
        'slug_placeholder' => 'zadejte-url-prispevku',
        'categories' => 'Kategorie',
        'author_email' => 'E-mail autora',
        'created' => 'Vytvořeno',
        'created_date' => 'Vytvořeno dne',
        'updated' => 'Upraveno',
        'updated_date' => 'Upraveno dne',
        'published' => 'Publikováno',
        'published_date' => 'Publikováno dne',
        'published_validation' => 'Zadejte prosím datum publikace příspěvku',
        'tab_edit' => 'Upravit',
        'tab_categories' => 'Kategorie',
        'categories_comment' => 'Vyberte kategorie do kterých příspěvek patří',
        'categories_placeholder' => 'Nejsou zde žádné kategorie, nejdříve musíte nějaké vytvořit!',
        'tab_manage' => 'Nastavení',
        'published_on' => 'Publikováno dne',
        'excerpt' => 'Perex příspěvku',
        'summary' => 'Shrnutí',
        'featured_images' => 'Obrázky',
        'delete_confirm' => 'Opravdu chcete smazat tento příspěvek?',
        'delete_success' => 'Vybrané příspěvky úspěšně odstraněny.',
        'close_confirm' => 'Příspěvek není uložený.',
        'return_to_posts' => 'Zpět na seznam příspěvků',
    ],
    'categories' => [
        'list_title' => 'Správa blogových kategorií',
        'new_category' => 'Nová kategorie',
        'uncategorized' => 'Nezařazeno',
    ],
    'category' => [
        'name' => 'Název',
        'name_placeholder' => 'Název nové kategorie',
        'description' => 'Popis',
        'slug' => 'URL kategorie',
        'slug_placeholder' => 'zadejte-url-kategorie',
        'posts' => 'Počet příspěvků',
        'delete_confirm' => 'Opravdu chcete smazat tuto kategorii?',
        'delete_success' => 'Vybrané kategorie úspěšně odstraněny.',
        'return_to_categories' => 'Zpět na seznam blogových kategorií',
        'reorder' => 'Změnit pořadí',
    ],
    'menuitem' => [
        'blog_category' => 'Blogová kategorie',
        'all_blog_categories' => 'Všechny blogové kategorie',
        'blog_post' => 'Blogový příspěvek',
        'all_blog_posts' => 'Všechny blogové příspěvky',
        'category_blog_posts' => 'Blog category posts'
    ],
    'settings' => [
        'category_title' => 'Seznam kategorií',
        'category_description' => 'Zobrazí na stránce seznam blogových kategorií.',
        'category_slug' => 'URL kategorie',
        'category_slug_description' => "Najde blogovou kategorii s tímto URL. Používá se pro zobrazení aktivní kategorie.",
        'category_display_empty' => 'Zobrazit prázdné kategorie',
        'category_display_empty_description' => 'Zobrazit kategorie bez blogových příspěvků.',
        'category_page' => 'Stránka kategorií',
        'category_page_description' => 'Vyberte stránku která slouží k zobrazení všech kategorií (nebo detailu kategorie).',
        'post_title' => 'Příspěvek',
        'post_description' => 'Zobrazí blogový příspěvek na stránce.',
        'post_slug' => 'URL příspěvku',
        'post_slug_description' => "Najde příspěvek dle zadané URL.",
        'post_category' => 'Stránka kategorie',
        'post_category_description' => 'Vyberte stránku která slouží k zobrazení všech kategorií (nebo detailu kategorie).',
        'posts_title' => 'Seznam příspěvků',
        'posts_description' => 'Zobrazí na stránce seznam posledních příspěvků na stránkách.',
        'posts_pagination' => 'Číslo stránky',
        'posts_pagination_description' => 'Číslo stránky určující na které stránce se uživatel nachází. Použito pro stránkování.',
        'posts_filter' => 'Filtr kategorií',
        'posts_filter_description' => 'Zadejte URL kategorie, nebo URL parametr pro filtrování příspěvků. Nechte prázdné pro zobrazení všech příspěvků.',
        'posts_per_page' => 'Příspěvků na stránku',
        'posts_per_page_validation' => 'Špatný formát počtu příspěvků na stránku, musí být zadáno jako číslo',
        'posts_no_posts' => 'Hláška prázdné stránky',
        'posts_no_posts_description' => 'Zpráva se zobrazí pokud se nepovede najít žádné články.',
        'posts_no_posts_default' => 'Nenalezeny žádné příspěvky',
        'posts_order' => 'Řazení článků',
        'posts_order_decription' => 'Nastaví řazení článků ve výpisu',
        'posts_category' => 'Stránka kategorií',
        'posts_category_description' => 'Vyberte stránku která slouží k zobrazení všech kategorií (nebo detailu kategorie).',
        'posts_post' => 'Stránka příspěvků',
        'posts_post_description' => 'Vyberte stránku která slouží k zobrazení článků (nebo detailu článku).',
        'posts_except_post' => 'Vyloučit příspěvěk',
        'posts_except_post_description' => 'Zadejte ID nebo URL příspěvku který chcete vyloučit',
        'posts_except_categories' => 'Vyloučené kategorie',
        'posts_except_categories_description' => 'Pro vyloučení kategorií zadejte čárkou oddělené URL příspěvků nebo proměnnou, která tento seznam obsahuje.',
        'rssfeed_blog' => 'Blogová stránka',
        'rssfeed_blog_description' => 'Name of the main blog page file for generating links. This property is used by the default component partial.',
        'rssfeed_title' => 'RSS Kanál',
        'rssfeed_description' => 'Vygeneruje RSS kanál který obsahuje blogové příspěvky.',
        'group_links' => 'Odkazy',
        'group_exceptions' => 'Výjimky'
    ],
    'sorting' => [
	    'title_asc' => 'Název (sestupně)',
	    'title_desc' => 'Název (vzestupně)',
	    'created_asc' => 'Vytvořeno (sestupně)',
	    'created_desc' => 'Vytvořeno (vzestupně)',
	    'updated_asc' => 'Upraveno (sestupně)',
	    'updated_desc' => 'Upraveno (vzestupně)',
	    'published_asc' => 'Publikováno (sestupně)',
	    'published_desc' => 'Publikováno (vzestupně)',
	    'random' => 'Náhodně'
    ],
    'import' => [
	    'update_existing_label' => 'Uprav existující příspěvky',
	    'update_existing_comment' => 'Zvolte pokud chcete upravit příspěvky se stejným ID, názvem nebo URL.',
	    'auto_create_categories_label' => 'VYtvořit kategorie ze souboru',
	    'auto_create_categories_comment' => 'Chcete-li tuto funkci použít, měli byste se shodovat se sloupcem Kategorie, jinak vyberte výchozí kategorie, které chcete použít z níže uvedených položek.',
	    'categories_label' => 'Kategorie',
	    'categories_comment' => 'Vyberte kategorie ke kterým budou příspěvky přiřazeny (volitelné).',
	    'default_author_label' => 'Výchozí autor příspěvků (volitelné)',
	    'default_author_comment' => 'Import se pokusí použít existujícího autora, pokud odpovídá sloupci email, jinak se použije výše uvedený autor.',
	    'default_author_placeholder' => '-- vyberte autora --'
    ]
];


================================================
FILE: lang/de/lang.php
================================================
<?php

return [
    'plugin' => [
        'name' => 'Blog',
        'description' => 'Eine robuste Blog Plattform.'
    ],
    'blog' => [
        'menu_label' => 'Blog',
        'menu_description' => 'Blog Artikel bearbeiten',
        'posts' => 'Artikel',
        'create_post' => 'Blog Artikel',
        'categories' => 'Kategorien',
        'create_category' => 'Blog Kategorie',
        'tab' => 'Blog',
        'access_posts' => 'Blog Artikel verwalten',
        'access_categories' => 'Blog Kategorien verwalten',
        'access_other_posts' => 'Blog Artikel anderer Benutzer verwalten',
        'access_import_export' => 'Blog Artikel importieren oder exportieren',
        'access_publish' => 'Kann Artikel veröffentlichen',
        'manage_settings' => 'Blog Einstellungen verwalten',
        'delete_confirm' => 'Bist du sicher?',
        'chart_published' => 'Veröffentlicht',
        'chart_drafts' => 'Entwurf',
        'chart_total' => 'Gesamt',
        'settings_description' => 'Blog Einstellungen verwalten',
        'show_all_posts_label' => 'Zeige Backend Benutzern alle Artikel an',
        'show_all_posts_comment' => 'Zeigt Backend Benutzern sowohl veröffentlichte als auch nicht-veröffentlichte Artikel im Frontend an',
        'use_legacy_editor_label' => 'Veralteten Markdown Editor verwenden',
        'use_legacy_editor_comment' => 'Aktiviere die ältere Version des Markdown Editors bei October CMS v2 und höher',
        'preview_cms_page_label' => 'Vorschau CMS Seite',
        'preview_cms_page_comment' => 'Wähle eine Seite die für den Vorschau Button genutzt werden soll',
        'tab_general' => 'Allgemein',
        'preview' => 'Vorschau'
    ],
    'posts' => [
        'list_title' => 'Blog Artikel verwalten',
        'filter_category' => 'Kategorie',
        'filter_published' => 'Veröffentlichte ausblenden',
        'filter_date' => 'Datum',
        'new_post' => 'Neuer Artikel',
        'export_post' => 'Exportiere Artikel',
        'import_post' => 'Importiere Artikel'
    ],
    'post' => [
        'title' => 'Titel',
        'title_placeholder' => 'Neuer Titel',
        'content' => 'Inhalt',
        'content_html' => 'HTML-Inhalt',
        'slug' => 'Slug',
        'slug_placeholder' => 'neuer-artikel-slug',
        'categories' => 'Kategorien',
        'author_email' => 'Autor E-Mail',
        'created' => 'Erstellt',
        'created_date' => 'Erstellzeitpunkt',
        'updated' => 'Aktualisiert',
        'updated_date' => 'Aktualisierungszeitpunk',
        'published' => 'Veröffentlicht',
        'published_by' => 'Veröffentlicht von',
        'current_user' => 'Aktueller Benutzer',
        'published_date' => 'Veröffentlichungszeitpunkt',
        'published_validation' => 'Bitte gebe das Datum der Veröffentlichung an',
        'tab_edit' => 'Bearbeiten',
        'tab_categories' => 'Kategorien',
        'categories_comment' => 'Wähle die zugehörigen Kategorien',
        'categories_placeholder' => 'Es existieren keine Kategorien. Bitte lege zuerst Kategorien an!',
        'tab_manage' => 'Verwalten',
        'published_on' => 'Veröffentlicht am',
        'excerpt' => 'Textauszug',
        'summary' => 'Zusammenfassung',
        'featured_images' => 'Zugehörige Bilder',
        'delete_confirm' => 'Möchtest du diesen Artikel wirklich löschen?',
        'delete_success' => 'Diese Artikel wurden erfolgreich gelöscht.',
        'close_confirm' => 'Der Artikel ist noch nicht gespeichert.',
        'return_to_posts' => 'Zurück zur Artikel-Übersicht',
        'posted_byline' => 'Veröffentlicht in :categories am :date',
        'posted_byline_no_categories' => 'Veröffentlicht am :date',
        'date_format' => 'd. F Y',
        'dropzone' => 'Klicken oder Bild hier ablegen...'
    ],
    'categories' => [
        'list_title' => 'Blog Kategorien verwalten',
        'new_category' => 'Neue Kategorie',
        'uncategorized' => 'Allgemein'
    ],
    'category' => [
        'name' => 'Name',
        'name_placeholder' => 'Neuer Kategorie Name',
        'description' => 'Beschreibung',
        'slug' => 'Slug',
        'slug_placeholder' => 'neuer-kategorie-slug',
        'posts' => 'Artikel',
        'delete_confirm' => 'Möchtest du die Kategorie wirklich löschen?',
        'delete_success' => 'Diese Kategorien wurden erfolgreich gelöscht.',
        'return_to_categories' => 'Zurück zur Kategorie-Übersicht.',
        'reorder' => 'Kategorien sortieren'
    ],
    'menuitem' => [
        'blog_category' => 'Blog Kategorie',
        'all_blog_categories' => 'Alle Blog Kategorien',
        'blog_post' => 'Blog Artikel',
        'all_blog_posts' => 'Alle Blog Artikel',
        'category_blog_posts' => 'Blog Kategorie Artikel'
    ],
    'settings' => [
        'category_title' => 'Blog Kategorie-Übersicht',
        'category_description' => 'Zeigt eine Blog Kategorien-Übersicht.',
        'category_slug' => 'Slug Parametername',
        'category_slug_description' => 'Der URL-Routen-Parameter welcher verwendet wird um die aktuelle Kategorie zu bestimmen. Wird von der Standard-Komponente benötigt um die aktive Kategorie zu markieren.',
        'category_display_empty' => 'Leere Kategorien anzeigen',
        'category_display_empty_description' => 'Kategorien zeigen welche keine Artikel besitzen.',
        'category_page' => 'Kategorien Seite',
        'category_page_description' => 'Name der Kategorien-Seiten-Datei für die Kategorien Links. Wird von der Standard-Komponente benötigt.',
        'post_title' => 'Blog Artikel',
        'post_description' => 'Zeigt einen Blog Artikel auf der Seite.',
        'post_slug' => 'Slug Parametername',
        'post_slug_description' => 'Der URL-Routen-Parameter um den Post mittels "Slug" zu bestimmen.',
        'post_category' => 'Kategorien-Seite',
        'post_category_description' => 'Name der Kategorien-Seiten-Datei für Kategorie-Links.',
        'posts_title' => 'Blog Artikel-Übersicht',
        'posts_description' => 'Stellt eine Liste der neuesten Artikel auf der Seite dar.',
        'posts_pagination' => 'Blättern Parametername',
        'posts_pagination_description' => 'Der erwartete Parametername welcher für Seiten verwendet wird.',
        'posts_filter' => 'Kategorien-Filter',
        'posts_filter_description' => 'Bitte gebe ein Kategorien-Slug oder URL-Parameter an, mittels den die Artikel gefiltert werden. Wenn der Wert leer ist, werden alle Artikel angezeigt.',
        'posts_per_page' => 'Artikel pro Seite',
        'posts_per_page_validation' => 'Ungültiger "Artikel pro Seiten" Wert',
        'posts_no_posts' => 'Keine Artikel Nachricht',
        'posts_no_posts_description' => 'Nachricht welche dargestellt wird wenn keine Artikel vorhanden sind. Dieser Wert wird von der Standard-Komponente verwendet.',
        'posts_no_posts_default' => 'Keine Artikel gefunden',
        'posts_order' => 'Artikel Sortierung',
        'posts_order_description' => 'Attribute nach welchem Artikel sortiert werden.',
        'posts_category' => 'Kategorien-Seite',
        'posts_category_description' => 'Name der Kategorien-Seiten-Datei für "Veröffentlicht in" Kategorien-Links. Dieser Wert von der Standard-Komponente verwendet.',
        'posts_post' => 'Artikel Seite',
        'posts_post_description' => 'Name der Artikel-Seiten-Datei für die "Erfahre mehr" Links. Dieser Wert für von der Standard-Komponente verwendet.',
        'posts_except_post' => 'Artikel ausschließen',
        'posts_except_post_description' => 'Gebe direkt die ID/URL oder eine Variable mit der Artikel-ID/URL an um diesen Artikel auszuschließen. Dieser Wert für von der Standard-Komponente verwendet.',
        'posts_except_post_validation' => 'Aritkel-Ausnahmen müssen einzelne Slugs oder IDs oder eine kommagetrennte Liste von Slugs und IDs sein',
        'posts_except_categories' => 'Kategorien ausschließen',
        'posts_except_categories_description' => 'Gebe eine kommagetrennte Liste von Kategorie-Slugs oder eine Variable mit einer solchen Liste an um deren Artikel auszuschließen. Die Dieser Wert für von der Standard-Komponente verwendet.',
        'posts_except_categories_validation' => 'Kategorie-Ausnahmen müssen einzelne Slugs oder eine kommagetrennte Liste von Slugs sein',
        'rssfeed_blog' => 'Blog Seite',
        'rssfeed_blog_description' => 'Name der Artikel-Seiten-Datei für die Links. Dieser Wert für von der Standard-Komponente verwendet.',
        'rssfeed_title' => 'RSS-Feed',
        'rssfeed_description' => 'Erstellt einen RSS-Feed mit Artikeln aus dem Blog.',
        'group_links' => 'Links',
        'group_exceptions' => 'Ausnahmen'
    ],
    'sorting' => [
        'title_asc' => 'Titel (aufsteigend)',
        'title_desc' => 'Titel (absteigend)',
        'created_asc' => 'Erstelldatum (aufsteigend)',
        'created_desc' => 'Erstelldatum (absteigend)',
        'updated_asc' => 'Aktualisierungsdatum (aufsteigend)',
        'updated_desc' => 'Aktualisierungsdatum (absteigend)',
        'published_asc' => 'Veröffentlichungsdatum (aufsteigend)',
        'published_desc' => 'Veröffentlichungsdatum (absteigend)',
        'random' => 'Zufällig'
    ],
    'import' => [
        'update_existing_label' => 'Bestehende Artikel aktualisieren',
        'update_existing_comment' => 'Wähle diese Box um Artikel mit derselben ID, Titel oder Slug zu aktualisieren.',
        'auto_create_categories_label' => 'Kategorien wie in der Import-Datei angegeben erstellen',
        'auto_create_categories_comment' => 'Um diese Funktion zu nutzen sollte die Kategorien Spalte gesetzt sein, andernfalls wähle die Standard-Kategorie aus der Liste unterhalb.',
        'categories_label' => 'Kategorien',
        'categories_comment' => 'Wähle die Kategorie die für die importierten Artikel verwendet werden soll (optional).',
        'default_author_label' => 'Standard Artikel-Autor (optional)',
        'default_author_comment' => 'Der Import versucht einen vorhandenen Autor anhand der E-Mail Spalte zu verwenden sofern diese gesetzt ist und übereinstimmt, andernfalls wird der oben angegebene Autor verwendet.',
        'default_author_placeholder' => '-- Autor auswählen --'
    ]
];


================================================
FILE: lang/en/lang.php
================================================
<?php

return [
    'plugin' => [
        'name' => 'Blog',
        'description' => 'A robust blogging platform.'
    ],
    'blog' => [
        'menu_label' => 'Blog',
        'menu_description' => 'Manage Blog Posts',
        'posts' => 'Posts',
        'create_post' => 'Blog post',
        'categories' => 'Categories',
        'create_category' => 'Blog category',
        'tab' => 'Blog',
        'access_posts' => 'Manage the blog posts',
        'access_categories' => 'Manage the blog categories',
        'access_other_posts' => 'Manage other users blog posts',
        'access_import_export' => 'Allowed to import and export posts',
        'access_publish' => 'Allowed to publish posts',
        'manage_settings' => 'Manage blog settings',
        'delete_confirm' => 'Are you sure?',
        'chart_published' => 'Published',
        'chart_drafts' => 'Drafts',
        'chart_total' => 'Total',
        'settings_description' => 'Manage blog settings',
        'show_all_posts_label' => 'Show All Posts to Backend Users',
        'show_all_posts_comment' => 'Display both published and unpublished posts on the frontend to backend users',
        'use_legacy_editor_label' => 'Use the Legacy Markdown Editor',
        'use_legacy_editor_comment' => 'Enable the older version of the markdown editor when using October CMS v2 and above',
        'force_richeditor_editor_label' => 'Force the WYSIWYG editor',
        'force_richeditor_editor_comment' => 'Use common richtext editor instead of the Markdown editor',
        'preview_cms_page_label' => 'Preview CMS Page',
        'preview_cms_page_comment' => 'Select a page to open for the Preview button',
        'tab_general' => 'General',
        'preview' => 'Preview'
    ],
    'posts' => [
        'list_title' => 'Manage the blog posts',
        'filter_category' => 'Category',
        'filter_published' => 'Published',
        'filter_date' => 'Date',
        'new_post' => 'New Post',
        'export_post' => 'Export Posts',
        'import_post' => 'Import Posts'
    ],
    'post' => [
        'title' => 'Title',
        'title_placeholder' => 'New post title',
        'content' => 'Content',
        'content_html' => 'HTML Content',
        'slug' => 'Slug',
        'slug_placeholder' => 'new-post-slug',
        'categories' => 'Categories',
        'author_email' => 'Author Email',
        'created' => 'Created',
        'created_date' => 'Created date',
        'updated' => 'Updated',
        'updated_date' => 'Updated date',
        'published' => 'Published',
        'published_by' => 'Published by',
        'current_user' => 'Current user',
        'published_date' => 'Published date',
        'published_validation' => 'Please specify the published date',
        'tab_edit' => 'Edit',
        'tab_categories' => 'Categories',
        'categories_comment' => 'Select categories the blog post belongs to',
        'categories_placeholder' => 'There are no categories, you should create one first!',
        'tab_manage' => 'Manage',
        'published_on' => 'Published on',
        'excerpt' => 'Excerpt',
        'summary' => 'Summary',
        'featured_images' => 'Featured Images',
        'delete_confirm' => 'Delete this post?',
        'delete_success' => 'Successfully deleted those posts.',
        'close_confirm' => 'The post is not saved.',
        'return_to_posts' => 'Return to posts list',
        'posted_byline' => 'Posted in :categories on :date.',
        'posted_byline_no_categories' => 'Posted on :date.',
        'date_format' => 'M d, Y',
        'dropzone' => 'Click or drop an image...'
    ],
    'categories' => [
        'list_title' => 'Manage the blog categories',
        'new_category' => 'New Category',
        'uncategorized' => 'Uncategorized'
    ],
    'category' => [
        'name' => 'Name',
        'name_placeholder' => 'New category name',
        'description' => 'Description',
        'slug' => 'Slug',
        'slug_placeholder' => 'new-category-slug',
        'posts' => 'Posts',
        'delete_confirm' => 'Delete this category?',
        'delete_success' => 'Successfully deleted those categories.',
        'return_to_categories' => 'Return to the blog category list',
        'reorder' => 'Reorder Categories'
    ],
    'menuitem' => [
        'blog_category' => 'Blog Category',
        'all_blog_categories' => 'All Blog Categories',
        'blog_post' => 'Blog Post',
        'all_blog_posts' => 'All Blog Posts',
        'category_blog_posts' => 'Blog Category Posts'
    ],
    'settings' => [
        'category_title' => 'Category List',
        'category_description' => 'Displays a list of blog categories on the page.',
        'category_slug' => 'Category slug',
        'category_slug_description' => "Look up the blog category using the supplied slug value. This property is used by the default component partial for marking the currently active category.",
        'category_display_empty' => 'Display empty categories',
        'category_display_empty_description' => 'Show categories that do not have any posts.',
        'category_page' => 'Category page',
        'category_page_description' => 'Name of the category page file for the category links. This property is used by the default component partial.',
        'post_title' => 'Post',
        'post_description' => 'Displays a blog post on the page.',
        'post_slug' => 'Post slug',
        'post_slug_description' => "Look up the blog post using the supplied slug value.",
        'post_category' => 'Category page',
        'post_category_description' => 'Name of the category page file for the category links. This property is used by the default component partial.',
        'posts_title' => 'Post List',
        'posts_description' => 'Displays a list of latest blog posts on the page.',
        'posts_pagination' => 'Page number',
        'posts_pagination_description' => 'This value is used to determine what page the user is on.',
        'posts_filter' => 'Category filter',
        'posts_filter_description' => 'Enter a category slug or URL parameter to filter the posts by. Leave empty to show all posts.',
        'posts_per_page' => 'Posts per page',
        'posts_per_page_validation' => 'Invalid format of the posts per page value',
        'posts_no_posts' => 'No posts message',
        'posts_no_posts_description' => 'Message to display in the blog post list in case if there are no posts. This property is used by the default component partial.',
        'posts_no_posts_default' => 'No posts found',
        'posts_order' => 'Post order',
        'posts_order_description' => 'Attribute on which the posts should be ordered',
        'posts_category' => 'Category page',
        'posts_category_description' => 'Name of the category page file for the "Posted into" category links. This property is used by the default component partial.',
        'posts_post' => 'Post page',
        'posts_post_description' => 'Name of the blog post page file for the "Learn more" links. This property is used by the default component partial.',
        'posts_except_post' => 'Except post',
        'posts_except_post_description' => 'Enter ID/URL or variable with post ID/URL you want to exclude. You may use a comma-separated list to specify multiple posts.',
        'posts_except_post_validation' => 'Post exceptions must be a single slug or ID, or a comma-separated list of slugs and IDs',
        'posts_except_categories' => 'Except categories',
        'posts_except_categories_description' => 'Enter a comma-separated list of category slugs or variable with such a list of categories you want to exclude',
        'posts_except_categories_validation' => 'Category exceptions must be a single category slug, or a comma-separated list of slugs',
        'rssfeed_blog' => 'Blog page',
        'rssfeed_blog_description' => 'Name of the main blog page file for generating links. This property is used by the default component partial.',
        'rssfeed_title' => 'RSS Feed',
        'rssfeed_description' => 'Generates an RSS feed containing posts from the blog.',
        'group_links' => 'Links',
        'group_exceptions' => 'Exceptions'
    ],
    'sorting' => [
        'title_asc' => 'Title (ascending)',
        'title_desc' => 'Title (descending)',
        'created_asc' => 'Created (ascending)',
        'created_desc' => 'Created (descending)',
        'updated_asc' => 'Updated (ascending)',
        'updated_desc' => 'Updated (descending)',
        'published_asc' => 'Published (ascending)',
        'published_desc' => 'Published (descending)',
        'random' => 'Random'
    ],
    'import' => [
        'update_existing_label' => 'Update existing posts',
        'update_existing_comment' => 'Check this box to update posts that have exactly the same ID, title or slug.',
        'auto_create_categories_label' => 'Create categories specified in the import file',
        'auto_create_categories_comment' => 'You should match the Categories column to use this feature, otherwise select the default categories to use from the items below.',
        'categories_label' => 'Categories',
        'categories_comment' => 'Select the categories that imported posts will belong to (optional).',
        'default_author_label' => 'Default post author (optional)',
        'default_author_comment' => 'The import will try to use an existing author if you match the Author Email column, otherwise the author specified above is used.',
        'default_author_placeholder' => '-- select author --'
    ]
];


================================================
FILE: lang/es/lang.php
================================================
<?php

return [
    'plugin' => [
        'name' => 'Blog',
        'description' => 'Una plataforma robusta de blogging.'
    ],
    'blog' => [
        'menu_label' => 'Blog',
        'menu_description' => 'Administrar Publicaciones',
        'posts' => 'Publicaciones',
        'create_post' => 'Crear publicación',
        'categories' => 'Categorías',
        'create_category' => 'Categoría',
        'tab' => 'Blog',
        'access_posts' => 'Administrar las publicaciones',
        'access_categories' => 'Administrar las categorías',
        'access_other_posts' => 'Administrar publicaciones de otros usuarios',
        'access_import_export' => 'Autorizado para importar y exportar publicaciones',
        'access_publish' => 'Autorizado para publicar publicaciones',
        'manage_settings' => 'Administrar configuración del blog',
        'delete_confirm' => '¿Está seguro?',
        'chart_published' => 'Publicado',
        'chart_drafts' => 'Borradores',
        'chart_total' => 'Total',
        'settings_description' => 'Administrar configuración del blog',
        'show_all_posts_label' => 'Mostrar todas las publicaciones a los usuarios de backend',
        'show_all_posts_comment' => 'Mostrar las publicaciones publicados y los borradores a los usuarios de backend',
        'tab_general' => 'General'
    ],
    'posts' => [
        'list_title' => 'Administrar publicaciones',
        'filter_category' => 'Categoría',
        'filter_published' => 'Publicado',
        'filter_date' => 'Fecha',
        'new_post' => 'Nueva publicación',
        'export_post' => 'Exportar publicaciones',
        'import_post' => 'Importar publicaciones'
    ],
    'post' => [
        'title' => 'Título',
        'title_placeholder' => 'Título de la publicación',
        'content' => 'Contenido',
        'content_html' => 'Contenido HTML',
        'slug' => 'Identificador',
        'slug_placeholder' => 'nueva-publicacion',
        'categories' => 'Categorías',
        'author_email' => 'Email del Autor',
        'created' => 'Creado',
        'created_date' => 'Fecha de Creación',
        'updated' => 'Actualizado',
        'updated_date' => 'Fecha de Actualización',
        'published' => 'Publicado',
        'published_by' => 'Publicado por',
        'current_user' => 'Usuario actual',
        'published_date' => 'Fecha de publicación',
        'published_validation' => 'Por favor, especifique la fecha de publicación',
        'tab_edit' => 'Editar',
        'tab_categories' => 'Categorías',
        'categories_comment' => 'Seleccione las categorías para la publicación',
        'categories_placeholder' => 'No hay categorías, ¡crea una primero!',
        'tab_manage' => 'Administrar',
        'published_on' => 'Publicado el',
        'excerpt' => 'Resumen',
        'summary' => 'Resumen',
        'featured_images' => 'Imágenes Destacadas',
        'delete_confirm' => '¿Borrar la publicación?',
        'delete_success' => 'Publicación borrada correctamente',
        'close_confirm' => 'La publicación no está guardada.',
        'return_to_posts' => 'Volver a la lista de publicaciones',
        'posted_byline' => 'Publicado en :categories el :date.',
        'posted_byline_no_categories' => 'Publicado el :date.',
        'date_format' => 'd de M de Y',
    ],
    'categories' => [
        'list_title' => 'Administrar las categorías',
        'new_category' => 'Nueva categoría',
        'uncategorized' => 'Sin Categoría'
    ],
    'category' => [
        'name' => 'Nombre',
        'name_placeholder' => 'Nombre de la categoría',
        'description' => 'Descripción',
        'slug' => 'Identificador',
        'slug_placeholder' => 'nueva-categoría',
        'posts' => 'Publicaciones',
        'delete_confirm' => '¿Borrar esta categoría?',
        'delete_success' => 'Categorías borradas correctamente.',
        'return_to_categories' => 'Volver a la lista de categorías',
        'reorder' => 'Re-ordenar Categorías'
    ],
    'menuitem' => [
        'blog_category' => 'Categoría del blog',
        'all_blog_categories' => 'Todas las categorías del blog',
        'blog_post' => 'Publicación del blog',
        'all_blog_posts' => 'Todas las publicaciones del blog',
        'category_blog_posts' => 'Publicaciones del blog por categorías'
    ],
    'settings' => [
        'category_title' => 'Lista de Categorías',
        'category_description' => 'Muestra en la página una lista de las categorías.',
        'category_slug' => 'Identificador de la categoría',
        'category_slug_description' => "Localiza una categoría utilizando el identificador proporcionado. Esta propiedad es utilizada dentro del parcial que viene por defecto en el componente para marcar la categoría activa.",
        'category_display_empty' => 'Mostrar categorías vacías',
        'category_display_empty_description' => 'Mostrar categorías que no tienen ninguna publicación.',
        'category_page' => 'Página de categorías',
        'category_page_description' => 'Nombre del archivo de página utilizado para los enlaces de categorías. Esta propiedad es utilizada dentro del parcial que viene por defecto en el componente.',
        'post_title' => 'Publicación',
        'post_description' => 'Muestra una publicación en la página.',
        'post_slug' => 'Identificador de la publicación',
        'post_slug_description' => "Se buscará la publicación utilizando el valor del identificador proporcionado.",
        'post_category' => 'Página de categoría',
        'post_category_description' => 'Nombre del archivo de página utilizado para los enlaces de categorías. Esta propiedad es utilizada dentro del parcial que viene por defecto en el componente.',
        'posts_title' => 'Lista de publicaciones',
        'posts_description' => 'Muestra una lista de las últimas publicaciones en la página.',
        'posts_pagination' => 'Número de página',
        'posts_pagination_description' => 'Este valor se utiliza para determinar en que página se encuentra el usuario.',
        'posts_filter' => 'Filtro de categoría',
        'posts_filter_description' => 'Ingrese un identificador de categoría o parámetro URL. Se utilizará para filtrar las publicaciones. Deje el campo vacío para mostrar todas las publicaciones.',
        'posts_per_page' => 'Publicaciones por página',
        'posts_per_page_validation' => 'Formato inválido para el valor de publicaciones por página',
        'posts_no_posts' => 'Mensaje cuando no hay publicaciones',
        'posts_no_posts_description' => 'Mensaje que se mostrará en la lista de publicaciones del blog cuando no haya ningúno. Esta propiedad es utilizada dentro del parcial que viene por defecto en el componente.',
        'posts_no_posts_default' => 'No se encontraron publicaciones.',
        'posts_order' => 'Ordenar publicaciones por',
        'posts_order_description' => 'Atributo mediante el cual se deberán ordenar las publicaciones',
        'posts_category' => 'Página de Categoría',
        'posts_category_description' => 'Nombre del archivo de página utilizado para los enlaces de categoría "Publicado en". Esta propiedad es utilizada dentro del parcial que viene por defecto en el componente.',
        'posts_post' => 'Página de las publicaciones',
        'posts_post_description' => 'Nombre del archivo de página utilizado para los enlaces "Saber más". Esta propiedad es utilizada dentro del parcial que viene por defecto en el componente.',
        'posts_except_post' => 'Exceptuar publicación',
        'posts_except_post_description' => 'Ingrese una ID/URL o variable que contenga una ID/URL de la publicación que se quiera excluir',
        'posts_except_post_validation' => 'La publicación a excluir debe ser una ID/URL, o una lista separada por comas de IDs/URLs',
        'posts_except_categories' => 'Excluir categorías',
        'posts_except_categories_description' => 'Introduce una lista separada por comas de IDs/URLs de categorías con las categorías a excluir.',
        'posts_except_categories_validation' => 'Las categorías excluidas deben ser una URL de categoría o una lista separada por comas',
        'rssfeed_blog' => 'Página del blog',
        'rssfeed_blog_description' => 'Nombre del archivo de página principal para generación de enlaces. Esta propiedad es utilizada dentro del parcial que viene por defecto en el componente.',
        'rssfeed_title' => 'RSS Feed',
        'rssfeed_description' => 'Genera un feed de RSS con las publicaciones del blog.',
        'group_links' => 'Enlaces',
        'group_exceptions' => 'Excepciones'
    ],
    'sorting' => [
        'title_asc' => 'Título (ascendiente)',
        'title_desc' => 'Título (descendiente)',
        'created_asc' => 'Creado (ascendiente)',
        'created_desc' => 'Creado (descendiente)',
        'updated_asc' => 'Editado (ascendiente)',
        'updated_desc' => 'Editado (descendiente)',
        'published_asc' => 'Publicado (ascendiente)',
        'published_desc' => 'Publicado (descendiente)',
        'random' => 'Aleatorio'
    ],
    'import' => [
        'update_existing_label' => 'Editar publicaciones existentes',
        'update_existing_comment' => 'Selecciona este check para actualizar las publicaciones con exactamente la misma ID, título o URL.',
        'auto_create_categories_label' => 'Crear categorías especificadas en el archivo a importar',
        'auto_create_categories_comment' => 'Debes hacer coincidir la columna Categoría para usar esta funcionalidad, sino selecciona la categoría por defecto para para usar para los elementos de abajo.',
        'categories_label' => 'Categorías',
        'categories_comment' => 'Selecciona las categorías a las que pertenecerán las publicaciones importadas (opcional).',
        'default_author_label' => 'Autor de publicación por defecto (opcional)',
        'default_author_comment' => 'La importación intentará usar un autor existente si coicide con la columna "Author Email", sino se usará el autor especificado arriba.',
        'default_author_placeholder' => '-- Selecciona Autor/a --'
    ]
];


================================================
FILE: lang/fa/lang.php
================================================
<?php

return [
    'plugin' => [
        'name' => 'وبلاگ',
        'description' => 'پلتفرم قوی برای وبلاگ نویسی'
    ],
    'blog' => [
        'menu_label' => 'وبلاگ',
        'menu_description' => 'مدیریت پست های ارسالی',
        'posts' => 'پست ها',
        'create_post' => 'ایجاد پست جدید',
        'categories' => 'دسته بندی ها',
        'create_category' => 'ایجاد دسته بندی جدید',
        'tab' => 'وبلاگ',
        'access_posts' => 'مدیریت پست های ارسالی',
        'access_categories' => 'مدیریت دسته بندی های وبلاگ',
        'access_other_posts' => 'مدیریت پست های ارسالی سایر کاربران',
        'access_import_export' => 'توانایی واردکردن و خارج کردن پستها',
        'delete_confirm' => 'آیا اطمینان دارید؟',
        'chart_published' => 'منتشر شده',
        'chart_drafts' => 'پیش نویس',
        'chart_total' => 'مجموع'
    ],
    'posts' => [
        'list_title' => 'مدیریت پست های ارسالی',
        'filter_category' => 'دسته بندی',
        'filter_published' => 'مخفی کردن منتشر شده ها',
        'new_post' => 'پست جدید'
    ],
    'post' => [
        'title' => 'عنوان',
        'title_placeholder' => 'عنوان پست جدید',
        'content' => 'محتوی',
        'content_html' => 'محتوی HTML',
        'slug' => 'آدرس',
        'slug_placeholder' => 'آدرس-پست-جدید',
        'categories' => 'دسته بندی ها',
        'author_email' => 'پست الکترونیکی نویسنده',
        'created' => 'ایجاد شده در',
        'created_date' => 'تاریخ ایجاد',
        'updated' => 'به روزرسانی شده در',
        'updated_date' => 'تاریخ به روزرسانی',
        'published' => 'منتشر شده',
        'published_date' => 'تاریخ انتشار',
        'published_validation' => 'لطفا تاریخ انتشار را وارد نمایید',
        'tab_edit' => 'ویرایش',
        'tab_categories' => 'دسته بندی ها',
        'categories_comment' => 'دسته بندی هایی را که پست به آنها تعلق دارد را انتخاب نمایید',
        'categories_placeholder' => 'دسته بندی ای وجود ندارد. ابتدا یک دسته بندی ایجاد نمایید!',
        'tab_manage' => 'مدیریت',
        'published_on' => 'منتشر شده در',
        'excerpt' => 'خلاصه',
        'summary' => 'چکیده',
        'featured_images' => 'تصاویر شاخص',
        'delete_confirm' => 'آیا از حذف این پست اطمینان دارید؟',
        'close_confirm' => 'پست ذخیره نشده است',
        'return_to_posts' => 'بازگشت به لیست پست ها'
    ],
    'categories' => [
        'list_title' => 'مدیریت دسته بندی های وبلاگ',
        'new_category' => 'دسته بندی جدید',
        'uncategorized' => 'بدون دسته بندی'
    ],
    'category' => [
        'name' => 'نام',
        'name_placeholder' => 'نام دسته بندی جدید',
        'slug' => 'آدرس',
        'slug_placeholder' => 'آدرس-جدید-دسته-بندی',
        'posts' => 'پست ها',
        'delete_confirm' => 'آیا از حذف این دسته بندی اطمینان دارید؟',
        'return_to_categories' => 'بازگشت به لیست دسته بندی های وبلاگ',
        'reorder' => 'مرتب سازی دسته بندی ها'
    ],
    'settings' => [
        'category_title' => 'لیست دسته بندی',
        'category_description' => 'نمایش لیست دسته بندی های وبلاگ در صفحه',
        'category_slug' => 'آدرس دسته بندی',
        'category_slug_description' => "دسته بندی وبلاگ توسط آدرس وارد شده جستجو می شود. این عمل توسط ابزار دسته بندی برای برجسته ساختن دسته بندی در حال نمایش استفاده می شود.",
        'category_display_empty' => 'نمایش دسته بندی های خالی',
        'category_display_empty_description' => 'نمایش دسته بندی هایی که هیچ ارسالی در آنها وجود ندارد.',
        'category_page' => 'صفحه دسته بندی',
        'category_page_description' => 'نام صفحه ای که لیست دسته بندی ها در آن نمایش داده می شوند. این گزینه به طور پیشفرض توسط ابزار مورد استفاده قرار میگیرد.',
        'post_title' => 'پست',
        'post_description' => 'نمایش پست در صفحه',
        'post_slug' => 'آدرس پست',
        'post_slug_description' => "پست توسط آدرس وارد شده جستجو میشود.",
        'post_category' => 'صفحه دسته بندی',
        'post_category_description' => 'نام صفحه ای که لیست دسته بندی ها در آن نمایش داده می شوند. این گزینه به طور پیشفرض توسط ابزار مورد استفاده قرار میگیرد.',
        'posts_title' => 'لیست پست ها',
        'posts_description' => 'نمایش لیستی از پستهایی که اخیرا ارسال شده اند در صفحه.',
        'posts_pagination' => 'شماره صفحه',
        'posts_pagination_description' => 'این مقدار جهت تشخیص صفحه ای که کاربر در آن قرار دارد مورد استفاده قرار میگیرد.',
        'posts_filter' => 'فیلتر دسته بندی',
        'posts_filter_description' => 'آدرس دسته بندی ای را که میخواهید پست های آن نمایش داده شوند را وارد نمایید. اگر میخواهید همه پست ها نمایش داده شوند این مقدار را خالی رها کنید.',
        'posts_per_page' => 'تعداد پست ها در هر صفحه',
        'posts_per_page_validation' => 'مقدار ورودی تعداد پست ها در هر صفحه نامعتبر است.',
        'posts_no_posts' => 'پیغام پستی وجود ندارد',
        'posts_no_posts_description' => 'این پیغام در صورتی که پستی جهت نمایش وجود نداشته باشد، نمایش داده می شود.',
        'posts_order' => 'ترتیب پست ها',
        'posts_order_decription' => 'مشخصه ترتیب نمایش پست ها در صفحه',
        'posts_category' => 'صفحه دسته بندی',
        'posts_category_description' => 'نام صفحه دسته بندی برای نمایش پستهای مربوط به آن.',
        'posts_post' => 'صفحه پست',
        'posts_post_description' => 'نام صفحه مربوط به نمایش کامل پست ها جهت لینک ادامه مطلب',
        'posts_except_post' => 'Except post',
        'posts_except_post_description' => 'Enter ID/URL or variable with post ID/URL you want to except',
    ]
];


================================================
FILE: lang/fi/lang.php
================================================
<?php

return [
    'plugin' => [
        'name' => 'Blogi',
        'description' => 'Vankka bloggausalusta.'
    ],
    'blog' => [
        'menu_label' => 'Blogi',
        'menu_description' => 'Hallitse blogipostauksia',
        'posts' => 'Postaukset',
        'create_post' => 'Blogipostaus',
        'categories' => 'Categories',
        'create_category' => 'Blogikategoria',
        'tab' => 'Blogi',
        'access_posts' => 'Hallitse postauksia',
        'access_categories' => 'Hallitse kategorioita',
        'access_other_posts' => 'Hallitse muiden käyttäjien postauksia',
        'access_import_export' => 'Saa tuoda ja viedä postauksia',
        'access_publish' => 'Saa julkaista postauksia',
        'manage_settings' => 'Manage blog settings',
        'delete_confirm' => 'Olteko varma?',
        'chart_published' => 'Julkaistu',
        'chart_drafts' => 'Luonnokset',
        'chart_total' => 'Yhteensä',
        'settings_description' => 'Hallinnoi blogin asetuksia',
        'show_all_posts_label' => 'Näytä kaikki postaukset ylläpitäjille',
        'show_all_posts_comment' => 'Näytä molemmat sekä julkaistut että julkaisemattomat postaukset ylläpitäjille',
        'tab_general' => 'Yleiset'
    ],
    'posts' => [
        'list_title' => 'Hallitse blogipostauksia',
        'filter_category' => 'Kategoria',
        'filter_published' => 'Julkaistu',
        'filter_date' => 'Päivämäärä',
        'new_post' => 'Uusi postaus',
        'export_post' => 'Vie postaukset',
        'import_post' => 'Tuo postauksia'
    ],
    'post' => [
        'title' => 'Otsikko',
        'title_placeholder' => 'Uuden postauksen otsikko',
        'content' => 'Sisältö',
        'content_html' => 'HTML Sisältö',
        'slug' => 'Slugi',
        'slug_placeholder' => 'uuden-postaukse-slugi',
        'categories' => 'Kategoriat',
        'author_email' => 'Tekijän sähköposti',
        'created' => 'Luotu',
        'created_date' => 'Luomispäivämäärä',
        'updated' => 'Muokattu',
        'updated_date' => 'Muokkauspäivämäärä',
        'published' => 'Julkaistu',
        'published_by' => 'Published by',
        'current_user' => 'Current user',
        'published_date' => 'Julkaisupäivämäärä',
        'published_validation' => 'Määrittele julkaisupäivämäärä',
        'tab_edit' => 'Muokkaa',
        'tab_categories' => 'Kategoriat',
        'categories_comment' => 'Valitse kategoriat joihin postaus kuuluu',
        'categories_placeholder' => 'Kategorioita ei ole, sinun pitäisi luoda ensimmäinen ensin!',
        'tab_manage' => 'Hallitse',
        'published_on' => 'Julkaistu',
        'excerpt' => 'Poiminto',
        'summary' => 'Yhteenveto',
        'featured_images' => 'Esittelykuvat',
        'delete_confirm' => 'Poista tämä postaus?',
        'delete_success' => 'Postaukset poistettu onnistuneesti.',
        'close_confirm' => 'Tämä postaus ei ole tallennettu.',
        'return_to_posts' => 'Palaa postauslistaan'
    ],
    'categories' => [
        'list_title' => 'Hallitse blogikategorioita',
        'new_category' => 'Uusi kategoria',
        'uncategorized' => 'Luokittelematon'
    ],
    'category' => [
        'name' => 'Nimi',
        'name_placeholder' => 'Uuden kategorian nimi',
        'description' => 'Kuvaus',
        'slug' => 'Slugi',
        'slug_placeholder' => 'uuden-kategorian-slugi',
        'posts' => 'Julkaisuja',
        'delete_confirm' => 'Poista tämä kategoria?',
        'delete_success' => 'Kategoriat poistettu onnistuneesti.',
        'return_to_categories' => 'Palaa blogikategorialistaan',
        'reorder' => 'Järjestä kategoriat uudelleen'
    ],
    'menuitem' => [
        'blog_category' => 'Blogikategoria',
        'all_blog_categories' => 'Kaikki blogikategoriat',
        'blog_post' => 'Blogipostaukset',
        'all_blog_posts' => 'Kaikki blogipostaukset',
        'category_blog_posts' => 'Blogin kategorian postaukset'
    ],
    'settings' => [
        'category_title' => 'Kategorialista',
        'category_description' => 'Näyttää listan blogikategorioista sivulla.',
        'category_slug' => 'Kategorian slugi',
        'category_slug_description' => 'Etsii blogikategorian käyttämällä annettua slugi-arvoa. Komponentti käyttää tätä merkitsemään aktiivisen kategorian.',
        'category_display_empty' => 'Näytä tyhjät kategoriat',
        'category_display_empty_description' => 'Näytä kategoriat joilla ei ole yhtään postauksia.',
        'category_page' => 'Kategoriasivu',
        'category_page_description' => 'Kategorialistaussivun tiedostonimi. Oletuskomponenttiosa käyttää tätä ominaisuutta.',
        'post_title' => 'Postaus',
        'post_description' => 'Näyttää blogipostauksen sivulla.',
        'post_slug' => 'Postauksen slugi',
        'post_slug_description' => 'Etsii blogipostauksen käyttämällä annettua slugi-arvoa.',
        'post_category' => 'Kategoriasivu',
        'post_category_description' => 'Kategorialistaussivun tiedostonimi. Oletuskomponenttiosa käyttää tätä ominaisuutta.',
        'posts_title' => 'Lista postauksista',
        'posts_description' => 'Näyttää listan uusimmista blogipostauksista sivulla.',
        'posts_pagination' => 'Sivunumero',
        'posts_pagination_description' => 'Tätä arvoa käytetään määrittämään millä sivulla käyttäjä on.',
        'posts_filter' => 'Kategoriasuodatin',
        'posts_filter_description' => 'Lisää kategorian slugi tai URL parametri, jolla suodattaa postauksia. Jätä tyhjäksi näyttääksesi kaikki postaukset.',
        'posts_per_page' => 'Postauksia per sivu',
        'posts_per_page_validation' => 'Postauksia per sivu -kohta sisältää kelvottoman arvon',
        'posts_no_posts' => 'Ei julkaisuja -viesti',
        'posts_no_posts_description' => 'Viesti, joka näytetään silloin kun postauksia ei ole. Oletuskomponenttiosa käyttää tätä ominaisuutta.',
        'posts_no_posts_default' => 'Ei postauksia',
        'posts_order' => 'Postauksien järjestys',
        'posts_order_description' => 'Attribuutti, jonka mukaan postaukset tulisi järjestää',
        'posts_category' => 'Kategoriasivu',
        'posts_category_description' => 'Kategoriasivun tiedosto "Julkaistu kohteeseen" kategorialinkkejä varten. Oletuskomponenttiosa käyttää tätä ominaisuutta.',
        'posts_post' => 'Postaussivu',
        'posts_post_description' => 'Blogisivun tiedostonimi "Lue lisää" linkkejä varten. Oletuskomponenttiosa käyttää tätä ominaisuutta.',
        'posts_except_post' => 'Poissulje postauksia',
        'posts_except_post_description' => 'Lisää postauksen ID/URL tai muuttuja, jonka haluat poissulkea',
        'posts_except_post_validation' => 'Postaukset poikkeukset täytyy olla yksittäinen slugi tai ID, pilkulla erotettu slugi-lista ja ID:t',
        'posts_except_categories' => 'Poikkeavat kategoriat',
        'posts_except_categories_description' => 'Lisää pilkulla erotettu listaus kategoria slugeista tai listaus kategorioista jotka haluat jättää ulkopuolelle',
        'posts_except_categories_validation' => 'Poikkeavat kategoriat ovat oltava yksittäinen kategoria slugi tai pilkulla erotettu listaus slugeista',
        'rssfeed_blog' => 'Blogisivu',
        'rssfeed_blog_description' => 'Blogisivun tiedostonimi linkkien generointia varten. Oletuskomponenttiosa käyttää tätä ominaisuutta.',
        'rssfeed_title' => 'RSS syöte',
        'rssfeed_description' => 'Generoi RSS syötteen sisältäen postaukset blogista.',
        'group_links' => 'Linkit',
        'group_exceptions' => 'Poikkeukset'
    ],
    'sorting' => [
        'title_asc' => 'Otsikko (ascending)',
        'title_desc' => 'Otsikko (descending)',
        'created_asc' => 'Luotu (ascending)',
        'created_desc' => 'Luotu (descending)',
        'updated_asc' => 'Päivitetty (ascending)',
        'updated_desc' => 'Päivitetty (descending)',
        'published_asc' => 'Julkaistu (ascending)',
        'published_desc' => 'Julkaistu (descending)',
        'random' => 'Satunnainen'
    ],
    'import' => [
        'update_existing_label' => 'Päivitä olemassa olevat postaukset',
        'update_existing_comment' => 'Valitse tämä laatikko päivittääksesi postaukset, joissa on täsmälleen sama ID, otsikko tai slugi.',
        'auto_create_categories_label' => 'Luo tuotavassa tiedostossa määritellyt kategoriat.',
        'auto_create_categories_comment' => 'Sinun tulisi yhdistää Kategoriat-sarake käyttääksesi tätä toiminnallisuutta. Muussa tapauksessa valitse oletuskategoria alapuolelta.',
        'categories_label' => 'Kategoriat',
        'categories_comment' => 'Valitse kategoriat, joihin tuotavat postaukset liitetään (option).',
        'default_author_label' => 'Oletuskirjoittaja (optio)',
        'default_author_comment' => 'Tuonti yrittää käyttää Kirjoittaja tiedon sähköpostia yhdistäessään kirjoittajaa. Muussa tapauksessa käytetään ylempänä määriteltyä.',
        'default_author_placeholder' => '-- valitse kirjoittaja --'
    ]
];


================================================
FILE: lang/fr/lang.php
================================================
<?php

return [
    'plugin' => [
        'name' => 'Blog',
        'description' => 'Une plateforme de blog robuste.'
    ],
    'blog' => [
        'menu_label' => 'Blog',
        'menu_description' => 'Gestion d’articles de blog',
        'posts' => 'Articles',
        'create_post' => 'article de blog',
        'categories' => 'Catégories',
        'create_category' => 'catégorie d’articles',
        'tab' => 'Blog',
        'access_posts' => 'Gérer les articles',
        'access_categories' => 'Gérer les catégories',
        'access_other_posts' => 'Gérer les articles d’autres utilisateurs',
        'access_import_export' => 'Autorisé à importer et exporter des articles',
        'access_publish' => 'Autorisé à publier des articles',
        'manage_settings' => 'Gérer les paramètres du blog',
        'delete_confirm' => 'Confirmez-vous la suppression des articles sélectionnés ?',
        'chart_published' => 'Publié',
        'chart_drafts' => 'Brouillons',
        'chart_total' => 'Total',
        'settings_description' => 'Gérer les paramètres du blog',
        'show_all_posts_label' => "Afficher tous les messages aux utilisateurs du panneaux d'administration",
        'show_all_posts_comment' => 'Afficher autant les publications publiées et non publiées sur le site web pour les utilisateurs principaux',
        'tab_general' => 'Général'
    ],
    'posts' => [
        'list_title' => 'Gérer les articles du blog',
        'filter_category' => 'Catégorie',
        'filter_published' => 'Masquer la publication',
        'filter_date' => 'Date',
        'new_post' => 'Nouvel article',
        'export_post' => 'Exporter les articles',
        'import_post' => 'Importer des articles'
    ],
    'post' => [
        'title' => 'Titre',
        'title_placeholder' => 'Titre du nouvel article',
        'content' => 'Contenu',
        'content_html' => 'Contenu HTML',
        'slug' => 'Adresse',
        'slug_placeholder' => 'adresse-du-nouvel-article',
        'categories' => 'Catégories',
        'author_email' => 'Email de l’auteur',
        'created' => 'Créé',
        'created_date' => 'Date de création',
        'updated' => 'Mis a jour',
        'updated_date' => 'Date de mise à jour',
        'published' => 'Publié',
        'published_by' => 'Publié par',
        'current_user' => 'Utilisateur actuel',
        'published_date' => 'Date de publication',
        'published_validation' => 'Veuillez préciser la date de publication',
        'tab_edit' => 'Rédaction',
        'tab_categories' => 'Catégories',
        'categories_comment' => 'Sélectionnez les catégories auxquelles l’article est lié',
        'categories_placeholder' => 'Il n’existe pas encore de catégorie, mais vous pouvez en créer une !',
        'tab_manage' => 'Configuration',
        'published_on' => 'Publié le',
        'excerpt' => 'Extrait',
        'summary' => 'Résumé',
        'featured_images' => 'Image de promotion',
        'delete_confirm' => 'Confirmez-vous la suppression de cet article ?',
        'delete_success' => 'Ces articles ont été supprimés avec succès.',
        'close_confirm' => 'L’article n’est pas enregistré.',
        'return_to_posts' => 'Retour à la liste des articles',
        'posted_byline' => 'Posté dans :categories le :date.',
        'posted_byline_no_categories' => 'Posté le :date.',
        'date_format' => 'd M Y'
    ],
    'categories' => [
        'list_title' => 'Gérer les catégories',
        'new_category' => 'Nouvelle catégorie',
        'uncategorized' => 'Non catégorisé'
    ],
    'category' => [
        'name' => 'Nom',
        'name_placeholder' => 'Nom de la nouvelle catégorie',
        'description' => 'Description',
        'slug' => 'Adresse URL',
        'slug_placeholder' => 'adresse-de-la-nouvelle-catégorie',
        'posts' => 'Articles',
        'delete_confirm' => 'Confirmez-vous la suppression de cette catégorie ?',
        'delete_success' => 'Ces catégories ont été supprimés avec succès.',
        'return_to_categories' => 'Retour à la liste des catégories',
        'reorder' => 'Réorganiser les catégories'
    ],
    'menuitem' => [
        'blog_category' => 'Catégories du blog',
        'all_blog_categories' => 'Toutes les catégories du blog',
        'blog_post' => 'Articles du blog',
        'all_blog_posts' => 'Tous les articles du blog',
        'category_blog_posts' => "Articles d'une catégorie du blog"
    ],
    'settings' => [
        'category_title' => 'Liste des catégories',
        'category_description' => 'Afficher une liste des catégories sur la page.',
        'category_slug' => 'Adresse URL de la catégorie',
        'category_slug_description' => 'Adresse URL d’accès à la catégorie. Cette propriété est utilisée par le partial par défaut du composant pour marquer la catégorie courante comme active.',
        'category_display_empty' => 'Afficher les catégories vides.',
        'category_display_empty_description' => 'Afficher les catégories qui ne sont liés à aucun article.',
        'category_page' => 'Page des catégories',
        'category_page_description' => 'Nom de la page des catégories pour les liens de catégories. Cette propriété est utilisée par le partial par défaut du composant.',
        'post_title' => 'Article',
        'post_description' => 'Affiche un article de blog sur la page.',
        'post_slug' => 'Adresse URL de l’article',
        'post_slug_description' => 'Adresse URL d’accès à l’article.',
        'post_category' => 'Page des catégories',
        'post_category_description' => 'Nom de la page des catégories pour les liens de catégories. Cette propriété est utilisée par le partial par défaut du composant.',
        'posts_title' => 'Liste d’articles',
        'posts_description' => 'Affiche une liste des derniers articles de blog sur la page.',
        'posts_pagination' => 'Numéro de page',
        'posts_pagination_description' => 'Cette valeur est utilisée pour déterminer à quelle page l’utilisateur se trouve.',
        'posts_filter' => 'Filtre des catégories',
        'posts_filter_description' => 'Entrez une adresse de catégorie ou un paramètre d’URL pour filter les articles. Laissez vide pour afficher tous les articles.',
        'posts_per_page' => 'Articles par page',
        'posts_per_page_validation' => 'Format du nombre d’articles par page incorrect',
        'posts_no_posts' => 'Message en l’absence d’articles',
        'posts_no_posts_description' => 'Message à afficher dans la liste d’articles lorsqu’il n’y a aucun article. Cette propriété est utilisée par le partial par défaut du composant.',
        'posts_no_posts_default' => 'Aucun article trouvé',
        'posts_order' => 'Ordre des articles',
        'posts_order_description' => 'Attribut selon lequel les articles seront ordonnés',
        'posts_category' => 'Page de catégorie',
        'posts_category_description' => 'Nom du fichier de la page de catégorie pour les liens de catégorie "Publié dans". Cette propriété est utilisée par le composant par défaut du modèle partiel.',
        'posts_post' => "Page de l'article",
        'posts_post_description' => 'Nom du fichier de la page de l\'article du blog pour les liens "En savoir plus". Cette propriété est utilisée par le composant par défaut du modèle partiel.',
        'posts_except_post' => 'Article exempté',
        'posts_except_post_description' => 'Enter ID/URL or variable with post ID/URL you want to except',
        'posts_category' => 'Page des catégories',
        'posts_category_description' => 'Nom de la page des catégories pour les liens de catégories "Publié dans". Cette propriété est utilisée par le partial par défaut du composant.',
        'posts_post' => 'Page d’article',
        'posts_post_description' => 'Nom de la page d’articles pour les liens "En savoir plus". Cette propriété est utilisée par le partial par défaut du composant.',
        'rssfeed_blog' => 'Page du blog',
        'rssfeed_blog_description' => 'Nom de la page principale du blog pour générer les liens. Cette propriété est utilisé par le composant dans le partial.',
        'rssfeed_title' => 'Flux RSS',
        'rssfeed_description' => 'Génère un Flux RSS contenant les articles du blog.',
        'group_links' => 'Liens',
        'group_exceptions' => 'Exceptions'
    ],
    'sorting' => [
        'title_asc' => 'Titre (ascendant)',
        'title_desc' => 'Titre (descendant)',
        'created_asc' => 'Création le (ascendant)',
        'created_desc' => 'Création (descendant)',
        'updated_asc' => 'Mise à jour (ascendant)',
        'updated_desc' => 'Mise à jour (descendant)',
        'published_asc' => 'Publication (ascendant)',
        'published_desc' => 'Publication (descendant)',
        'random' => 'Aléatoire'
    ],
    'import' => [
        'update_existing_label' => 'Mettre à jour les articles existants',
        'update_existing_comment' => 'Cochez cette case pour mettre à jour les articles qui ont exactement le même identifiant, titre ou slug.',
        'auto_create_categories_label' => "Créer les catégories spécifiées dans le fichier d'importation",
        'auto_create_categories_comment' => 'Vous devez faire correspondre la colonne Catégories pour utiliser cette fonctionnalité. Sinon, sélectionnez les catégories par défaut à utiliser parmi les éléments ci-dessous.',
        'categories_label' => 'Catégories',
        'categories_comment' => 'Sélectionnez les catégories auxquelles appartiendront les articles importées (facultatif).',
        'default_author_label' => 'Auteur par défaut (facultatif)',
        'default_author_comment' => "L'importation tentera d'utiliser un auteur existant si vous correspondez la colonne Email à l'auteur, sinon l'auteur spécifié ci-dessus sera utilisé.",
        'default_author_placeholder' => "-- sélectionnez l'auteur --"
    ]
];


================================================
FILE: lang/hu/lang.php
================================================
<?php

return [
    'plugin' => [
        'name' => 'Blog',
        'description' => 'Teljeskörű blog alkalmazás.'
    ],
    'blog' => [
        'menu_label' => 'Blog',
        'menu_description' => 'Blog bejegyzések kezelése',
        'posts' => 'Bejegyzések',
        'create_post' => 'blog bejegyzés',
        'categories' => 'Kategóriák',
        'create_category' => 'blog kategória',
        'tab' => 'Blog',
        'access_posts' => 'Blog bejegyzések kezelése',
        'access_categories' => 'Blog kategóriák kezelése',
        'access_other_posts' => 'Más felhasználók bejegyzéseinek kezelése',
        'access_import_export' => 'Bejegyzések importálása és exportálása',
        'access_publish' => 'Blog bejegyzések közzététele',
        'manage_settings' => 'Blog beállítások kezelése',
        'delete_confirm' => 'Törölni akarja a kijelölt bejegyzéseket?',
        'chart_published' => 'Közzétéve',
        'chart_drafts' => 'Piszkozatok',
        'chart_total' => 'Összesen',
        'settings_description' => 'Beállítási lehetőségek.',
        'show_all_posts_label' => 'Az összes bejegyzés mutatása az adminisztrátorok számára',
        'show_all_posts_comment' => 'A közzétett és a még nem publikált bejegyzések is egyaránt meg fognak jelenni az oldal szerkesztőinek.',
        'tab_general' => 'Általános'
    ],
    'posts' => [
        'list_title' => 'Blog bejegyzések',
        'filter_category' => 'Kategória',
        'filter_published' => 'Közzétéve',
        'filter_date' => 'Létrehozva',
        'new_post' => 'Új bejegyzés',
        'export_post' => 'Exportálás',
        'import_post' => 'Importálás'
    ],
    'post' => [
        'title' => 'Cím',
        'title_placeholder' => 'Új bejegyzés címe',
        'content' => 'Szöveges tartalom',
        'content_html' => 'HTML tartalom',
        'slug' => 'Keresőbarát cím',
        'slug_placeholder' => 'uj-bejegyzes-cime',
        'categories' => 'Kategóriák',
        'author_email' => 'Szerző e-mail címe',
        'created' => 'Létrehozva',
        'created_date' => 'Létrehozás dátuma',
        'updated' => 'Módosítva',
        'updated_date' => 'Módosítás dátuma',
        'published' => 'Közzétéve',
        'published_by' => 'Szerző:',
        'current_user' => 'Felhasználó',
        'published_date' => 'Közzététel dátuma',
        'published_validation' => 'Adja meg a közzététel dátumát',
        'tab_edit' => 'Szerkesztés',
        'tab_categories' => 'Kategóriák',
        'categories_comment' => 'Jelölje be azokat a kategóriákat, melyekbe be akarja sorolni a bejegyzést',
        'categories_placeholder' => 'Nincsenek kategóriák, előbb létre kell hoznia egyet!',
        'tab_manage' => 'Kezelés',
        'published_on' => 'Közzététel dátuma',
        'excerpt' => 'Kivonat',
        'summary' => 'Összegzés',
        'featured_images' => 'Kiemelt képek',
        'delete_confirm' => 'Valóban törölni akarja ezt a bejegyzést?',
        'delete_success' => 'Sikeresen törölve lettek a bejegyzések.',
        'close_confirm' => 'A bejegyzés nem került mentésre.',
        'return_to_posts' => 'Vissza a bejegyzésekhez',
        'posted_byline' => 'Publikálva: :date, itt: :categories',
        'posted_byline_no_categories' => 'Publikálva: :date.',
        'date_format' => 'Y.M.d.',
    ],
    'categories' => [
        'list_title' => 'Blog kategóriák',
        'new_category' => 'Új kategória',
        'uncategorized' => 'Nincs kategorizálva'
    ],
    'category' => [
        'name' => 'Név',
        'name_placeholder' => 'Új kategória neve',
        'description' => 'Leírás',
        'slug' => 'Keresőbarát cím',
        'slug_placeholder' => 'uj-kategoria-neve',
        'posts' => 'Bejegyzések',
        'delete_confirm' => 'Valóban törölni akarja ezt a kategóriát?',
        'delete_success' => 'Sikeresen törölve lettek a kategóriák.',
        'return_to_categories' => 'Vissza a kategóriákhoz',
        'reorder' => 'Kategóriák sorrendje'
    ],
    'menuitem' => [
        'blog_category' => 'Blog kategória',
        'all_blog_categories' => 'Összes blog kategória',
        'blog_post' => 'Blog bejegyzés',
        'all_blog_posts' => 'Összes blog bejegyzés',
        'category_blog_posts' => 'Blog kategória bejegyzések'
    ],
    'settings' => [
        'category_title' => 'Blog kategória lista',
        'category_description' => 'A blog kategóriákat listázza ki a lapon.',
        'category_slug' => 'Cím paraméter neve',
        'category_slug_description' => 'A webcím útvonal paramétere a jelenlegi kategória keresőbarát címe alapján való kereséséhez. Az alapértelmezett komponensrész ezt a tulajdonságot használja a jelenleg aktív kategória megjelöléséhez.',
        'category_display_empty' => 'Üres kategóriák kijelzése',
        'category_display_empty_description' => 'Azon kategóriák megjelenítése, melyekben nincs egy bejegyzés sem.',
        'category_page' => 'Kategória lap',
        'category_page_description' => 'A kategória hivatkozások kategória lap fájljának neve. Az alapértelmezett komponensrész használja ezt a tulajdonságot.',
        'post_title' => 'Blog bejegyzés',
        'post_description' => 'Egy blog bejegyzést jelez ki a lapon.',
        'post_slug' => 'Cím paraméter neve',
        'post_slug_description' => 'A webcím útvonal paramétere a bejegyzés keresőbarát címe alapján való kereséséhez.',
        'post_category' => 'Kategória lap',
        'post_category_description' => 'A kategória hivatkozások kategória lap fájljának neve. Az alapértelmezett komponensrész használja ezt a tulajdonságot.',
        'posts_title' => 'Blog bejegyzések',
        'posts_description' => 'A közzétett blog bejegyzések listázása a honlapon.',
        'posts_pagination' => 'Lapozósáv paraméter neve',
        'posts_pagination_description' => 'A lapozósáv lapjai által használt, várt paraméter neve.',
        'posts_filter' => 'Kategória szűrő',
        'posts_filter_description' => 'Adja meg egy kategória keresőbarát címét vagy webcím paraméterét a bejegyzések szűréséhez. Hagyja üresen az összes bejegyzés megjelenítéséhez.',
        'posts_per_page' => 'Bejegyzések laponként',
        'posts_per_page_validation' => 'A laponkénti bejegyzések értéke érvénytelen formátumú',
        'posts_no_posts' => 'Üzenet ha nincs bejegyzés',
        'posts_no_posts_description' => 'A blog bejegyzés listában kijelezendő üzenet abban az esetben, ha nincsenek bejegyzések. Az alapértelmezett komponensrész használja ezt a tulajdonságot.',
        'posts_no_posts_default' => 'Nem található bejegyzés',
        'posts_order' => 'Bejegyzések sorrendje',
        'posts_order_description' => 'Jellemző, ami alapján rendezni kell a bejegyzéseket',
        'posts_category' => 'Kategória lap',
        'posts_category_description' => 'A "Kategória" kategória hivatkozások kategória lap fájljának neve. Az alapértelmezett komponensrész használja ezt a tulajdonságot.',
        'posts_post' => 'Bejegyzéslap',
        'posts_post_description' => 'A "Tovább olvasom" hivatkozások blog bejegyzéslap fájljának neve. Az alapértelmezett komponensrész használja ezt a tulajdonságot.',
        'posts_except_post' => 'Bejegyzés kizárása',
        'posts_except_post_description' => 'Adja meg annak a bejegyzésnek az azonosítóját vagy webcímét, amit nem akar megjeleníteni a listázáskor.',
        'posts_except_post_validation' => 'A kivételnek webcímnek, illetve azonosítónak, vagy pedig ezeknek a vesszővel elválasztott felsorolásának kell lennie.',
        'posts_except_categories' => 'Kategória kizárása',
        'posts_except_categories_description' => 'Adja meg azoknak a kategóriáknak a webcímét vesszővel elválasztva, amiket nem akar megjeleníteni a listázáskor.',
        'posts_except_categories_validation' => 'A kivételnek webcímnek, vagy pedig ezeknek a vesszővel elválasztott felsorolásának kell lennie.',
        'rssfeed_blog' => 'Blog oldal',
        'rssfeed_blog_description' => 'Annak a lapnak a neve, ahol listázódnak a blog bejegyzések. Ezt a beállítást használja alapértelmezetten a blog komponens is.',
        'rssfeed_title' => 'RSS hírfolyam',
        'rssfeed_description' => 'A bloghoz tartozó RSS hírfolyam generálása.',
        'group_links' => 'Hivatkozások',
        'group_exceptions' => 'Kivételek'
    ],
    'sorting' => [
        'title_asc' => 'Név (növekvő)',
        'title_desc' => 'Név (csökkenő)',
        'created_asc' => 'Létrehozva (növekvő)',
        'created_desc' => 'Létrehozva (csökkenő)',
        'updated_asc' => 'Frissítve (növekvő)',
        'updated_desc' => 'Frissítve (csökkenő)',
        'published_asc' => 'Publikálva (növekvő)',
        'published_desc' => 'Publikálva (csökkenő)',
        'random' => 'Véletlenszerű'
    ],
    'import' => [
        'update_existing_label' => 'Meglévő bejegyzések frissítése',
        'update_existing_comment' => 'Két bejegyzés akkor számít ugyanannak, ha megegyezik az azonosító számuk, a címük vagy a webcímük.',
        'auto_create_categories_label' => 'Az import fájlban megadott kategóriák létrehozása',
        'auto_create_categories_comment' => 'A funkció használatához meg kell felelnie a Kategóriák oszlopnak, különben az alábbi elemekből válassza ki az alapértelmezett kategóriákat.',
        'categories_label' => 'Kategóriák',
        'categories_comment' => 'Válassza ki azokat a kategóriákat, amelyekhez az importált bejegyzések tartoznak (nem kötelező).',
        'default_author_label' => 'Alapértelmezett szerző (nem kötelező)',
        'default_author_comment' => 'A rendszer megpróbál egy meglévő felhasználót társítani a bejegyzéshez az Email oszlop alapján. Amennyiben ez nem sikerül, az itt megadott szerzőt fogja alapul venni.',
        'default_author_placeholder' => '-- válasszon felhasználót --'
    ]
];


================================================
FILE: lang/it/lang.php
================================================
<?php

return [
    'plugin' => [
        'name' => 'Blog',
        'description' => 'Una solida piattaforma di blogging.'
    ],
    'blog' => [
        'menu_label' => 'Blog',
        'menu_description' => 'Gestisci i post',
        'posts' => 'Post',
        'create_post' => 'post del blog',
        'categories' => 'Categorie',
        'create_category' => 'categorie del blog',
        'tab' => 'Blog',
        'access_posts' => 'Gestisci i post',
        'access_categories' => 'Gestisci le categorie',
        'access_other_posts' => 'Gestisci i post di altri utenti',
        'access_import_export' => 'Permesso ad importare ed esportare i post',
        'delete_confirm' => 'Sei sicuro?',
        'chart_published' => 'Pubblicato',
        'chart_drafts' => 'Bozze',
        'chart_total' => 'Totale'
    ],
    'posts' => [
        'list_title' => 'Gestisci i post',
        'category' => 'Categoria',
        'hide_published' => 'Nascondi pubblicati',
        'new_post' => 'Nuovo post'
    ],
    'post' => [
        'title' => 'Titolo',
        'title_placeholder' => 'Titolo del nuovo post',
        'content' => 'Contenuto',
        'content_html' => 'Contenuto HTML',
        'slug' => 'Slug',
        'slug_placeholder' => 'slug-del-nuovo-post',
        'categories' => 'Categorie',
        'author_email' => 'Email dell\'autore',
        'created' => 'Creato',
        'created_date' => 'Data di creazione',
        'updated' => 'Aggiornato',
        'updated_date' => 'Data di aggiornamento',
        'published' => 'Pubblicato',
        'published_date' => 'Data di pubblicazione',
        'published_validation' => 'Per favore fornisci la data di pubblicazione',
        'tab_edit' => 'Modifica',
        'tab_categories' => 'Categorie',
        'categories_comment' => 'Seleziona le categorie a cui appartiene il post',
        'categories_placeholder' => 'Non ci sono categorie, per iniziare dovresti crearne una!',
        'tab_manage' => 'Gestisci',
        'published_on' => 'Pubblicato il',
        'excerpt' => 'Estratto',
        'summary' => 'Riassunto',
        'featured_images' => 'Immagini in evidenza',
        'delete_confirm' => 'Vuoi veramente cancellare questo post?',
        'close_confirm' => 'Questo post non è salvato.',
        'return_to_posts' => 'Ritorna all\'elenco dei post'
    ],
    'categories' => [
        'list_title' => 'Gestisci le categorie del blog',
        'new_category' => 'Nuova categoria',
        'uncategorized' => 'Non categorizzato'
    ],
    'category' => [
        'name' => 'Nome',
        'name_placeholder' => 'Nome della nuova categoria',
        'slug' => 'Slug',
        'slug_placeholder' => 'slug-nuova-categoria',
        'posts' => 'Post',
        'delete_confirm' => 'Vuoi veramente cancellare questa categoria?',
        'return_to_categories' => 'Ritorna all\'elenco delle categorie del blog',
        'reorder' => 'Riordino Categorie'
    ],
    'settings' => [
        'category_title' => 'Elenco Categorie',
        'category_description' => 'Mostra un\'elenco delle categorie del blog sulla pagina.',
        'category_slug' => 'Slug categoria',
        'category_slug_description' => "Cerca la categoria del blog usando lo slug fornito. Questa proprietà è usata dal componente parziale di default per segnare la categoria attualmente usata.",
        'category_display_empty' => 'Mostra categorie vuote',
        'category_display_empty_description' => 'Mostra categorie che non hanno alcun post.',
        'category_page' => 'Pagina delle categorie',
        'category_page_description' => 'Nome del file della pagina delle categorie contenente i link delle categorie. Questa proprietà è usata dal componente parziale di default.',
        'post_title' => 'Post',
        'post_description' => 'Mostra un post sulla pagina.',
        'post_slug' => 'Slug del post',
        'post_slug_description' => "Cerca il post con lo slug fornito.",
        'post_category' => 'Pagina delle categorie',
        'post_category_description' => 'Nome del file della pagina delle categorie contenente i link delle categorie. Questa proprietà è usata dal componente parziale di default.',
        'posts_title' => 'Elenco dei post',
        'posts_description' => 'Mostra un\'elenco degli ultimi post sulla pagina.',
        'posts_pagination' => 'Numero di pagina',
        'posts_pagination_description' => 'Questo valore è usato per determinare su quale pagina è l\'utente.',
        'posts_filter' => 'Filtro delle categorie',
        'posts_filter_description' => 'Inserisci lo slug di una categoria o un parametro dell\'URL con il quale filtrare i post. Lascia vuoto per mostrare tutti i post.',
        'posts_per_page' => 'Post per pagina',
        'posts_per_page_validation' => 'Il valore di post per pagina ha un formato non valido ',
        'posts_no_posts' => 'Messaggio per l\'assenza di post',
        'posts_no_posts_description' => 'Messaggio da mostrare nell\'elenco dei post in caso non ce ne siano. Questa proprietà è usata dal componente parziale di default.',
        'posts_order' => 'Ordine dei post',
        'posts_order_description' => 'Attributo sul quale i post dovrebbero esser ordinati',
        'posts_category' => 'Pagina delle categorie',
        'posts_category_description' => 'Nome del file per la pagina delle categorie per i link "Postato in" alle categorie. Questa proprietà è usata dal componente parziale di default.',
        'posts_post' => 'Pagina del post',
        'posts_post_description' => 'Nome del file per la pagina del post per i link "Scopri di più". Questa proprietà è usata dal componente parziale di default.'
    ]
];


================================================
FILE: lang/ja/lang.php
================================================
<?php

return [
    'plugin' => [
        'name' => 'ブログ',
        'description' => 'ロバストなブログプラットフォームです。'
    ],
    'blog' => [
        'menu_label' => 'ブログ',
        'menu_description' => 'ブログの投稿管理',
        'posts' => '投稿',
        'create_post' => '投稿の追加',
        'categories' => 'カテゴリ',
        'create_category' => 'カテゴリの追加',
        'tab' => 'ブログ',
        'access_posts' => '投稿の管理',
        'access_categories' => 'カテゴリの管理',
        'access_other_posts' => '他ユーザーの投稿の管理',
        'delete_confirm' => '削除していいですか?',
        'chart_published' => '公開済み',
        'chart_drafts' => '下書き',
        'chart_total' => '合計'
    ],
    'posts' => [
        'list_title' => '投稿の管理',
        'filter_category' => 'カテゴリ',
        'filter_published' => '下書きのみ',
        'new_post' => '投稿を追加'
    ],
    'post' => [
        'title' => 'タイトル',
        'title_placeholder' => 'タイトルを入力してください',
        'slug' => 'スラッグ',
        'slug_placeholder' => 'new-post-slug−123',
        'categories' => 'カテゴリ',
        'created' => '作成日',
        'updated' => '更新日',
        'published' => '公開する',
        'published_validation' => '投稿の公開日を指定してください。',
        'tab_edit' => '編集',
        'tab_categories' => 'カテゴリ',
        'categories_comment' => '投稿を関連付けるカテゴリを選択してください。(複数選択可)',
        'categories_placeholder' => 'まだカテゴリがありません。先に作成してください。',
        'tab_manage' => '管理',
        'published_on' => '公開日',
        'excerpt' => '投稿の抜粋',
        'featured_images' => 'アイキャッチ画像',
        'delete_confirm' => '削除していいですか?',
        'close_confirm' => '投稿は保存されていません。',
        'return_to_posts' => '投稿一覧に戻る'
    ],
    'categories' => [
        'list_title' => 'カテゴリ管理',
        'new_category' => 'カテゴリの追加',
        'uncategorized' => '未分類'
    ],
    'category' => [
        'name' => '名前',
        'name_placeholder' => 'カテゴリ名をつけてください',
        'slug' => 'スラッグ',
        'slug_placeholder' => 'new-category-slug-123',
        'posts' => '投稿数',
        'delete_confirm' => '削除していいですか?',
        'return_to_categories' => 'カテゴリ一覧に戻る'
    ],
    'settings' => [
        'category_title' => 'カテゴリリスト',
        'category_description' => 'ページ内にカテゴリリストを表示します。',
        'category_slug' => 'カテゴリスラッグ',
        'category_slug_description' => "表示するカテゴリのスラッグを指定します。この項目はコンポーネントのデフォルトパーシャルで使用されます。",
        'category_display_empty' => '空のカテゴリの表示',
        'category_display_empty_description' => 'この項目がチェックされている場合、投稿が0件のカテゴリもリストに表示します。',
        'category_page' => 'カテゴリページ',
        'category_page_description' => 'カテゴリページへのリンクを生成するために、カテゴリページのファイル名を指定します。この項目はコンポーネントのデフォルトパーシャルで使用されます。',
        'post_title' => '投稿',
        'post_description' => 'ページ内に投稿を表示します。',
        'post_slug' => '投稿スラッグ',
        'post_slug_description' => "表示する投稿のスラッグを指定します。特定の投稿のスラッグか、URLパラメータ(:slug)を指定できます。",
        'post_category' => 'カテゴリページ',
        'post_category_description' => 'カテゴリリンクを生成するために、カテゴリページのファイル名を指定します。拡張子(.htm)は省いてください。この項目はコンポーネントのデフォルトパーシャルで使用されます。',
        'posts_title' => '投稿リスト',
        'posts_description' => 'ページ内に新しい投稿のリストを表示します。',
        'posts_pagination' => 'ページ番号',
        'posts_pagination_description' => 'ページ番号を指定します。URLパラメータ(:page)を指定できます。',
        'posts_filter' => 'カテゴリフィルタ',
        'posts_filter_description' => '投稿リストのフィルタを指定します。カテゴリのスラッグかURLパラメータ(:slug)を指定できます。空の場合、すべての投稿が表示されます。',
        'posts_per_page' => '1ページに表示する投稿数を指定します。',
        'posts_per_page_validation' => '1ページに表示する投稿数の形式が正しくありません。',
        'posts_no_posts' => '0件時メッセージ',
        'posts_no_posts_description' => 'この投稿リストが0件の場合に表示するメッセージを指定します。この項目はコンポーネントのデフォルトパーシャルで使用されます。',
        'posts_order' => '並び順',
        'posts_order_description' => '投稿リスト内の並び順を指定します。',
        'posts_category' => 'カテゴリページ',
        'posts_category_description' => 'カテゴリリンクを生成するために、カテゴリページのファイル名を指定します。この項目はコンポーネントのデフォルトパーシャルで使用されます。',
        'posts_post' => '投稿ページ',
        'posts_post_description' => '"Learn more"リンクを生成するため、投稿ページのファイル名を指定します。拡張子(.htm)は省いてください。この項目はコンポーネントのデフォルトパーシャルで使用されます。',
        'posts_except_post' => 'Except post',
        'posts_except_post_description' => 'Enter ID/URL or variable with post ID/URL you want to except',
    ]
];


================================================
FILE: lang/nb-no/lang.php
================================================
<?php

return [
    'plugin' => [
        'name' => 'Blogg',
        'description' => 'En robust bloggeplattform.',
    ],
    'blog' => [
        'menu_label' => 'Blogg',
        'menu_description' => 'Administrer blogginnlegg',
        'posts' => 'Innlegg',
        'create_post' => 'innlegg',
        'categories' => 'Kategorier',
        'create_category' => 'kategori',
        'access_posts' => 'Administrer blogginnleggene',
        'access_categories' => 'Administrer bloggkategorier',
        'access_other_posts' => 'Administrere andre brukere sine blogginnlegg',
        'delete_confirm' => 'Er du sikker?',
        'chart_published' => 'Publisert',
        'chart_drafts' => 'Utkast',
        'chart_total' => 'Totalt',
    ],
    'posts' => [
        'list_title' => 'Administrer blogginnlegg',
        'filter_category' => 'Kategori',
        'filter_published' => 'Skjul publiserte',
        'new_post' => 'Nytt innlegg',
    ],
    'post' => [
        'title' => 'Tittel',
        'title_placeholder' => 'Innleggets tittel',
        'slug' => 'Slug',
        'slug_placeholder' => 'innleggets-tittel',
        'categories' => 'Kategorier',
        'created' => 'Opprettet',
        'updated' => 'Oppdatert',
        'published' => 'Publisert',
        'published_validation' => 'Velg en dato når innlegget skal publiseres',
        'tab_edit' => 'Endre',
        'tab_categories' => 'Kategorier',
        'categories_comment' => 'Velg hvilke kategorier innlegget tilhører',
        'categories_placeholder' => 'Det finnes ingen kategorier! Vennligst opprett en først.',
        'tab_manage' => 'Egenskaper',
        'published_on' => 'Publiseringsdato',
        'excerpt' => 'Utdrag',
        'featured_images' => 'Utvalgte bilder',
        'delete_confirm' => 'Vil du virkelig slette dette innlegget?',
        'close_confirm' => 'Innlegget er ikke lagret.',
        'return_to_posts' => 'Tilbake til innleggsliste',
    ],
    'categories' => [
        'list_title' => 'Administrer bloggkategorier',
        'new_category' => 'Ny kategori',
        'uncategorized' => 'Uten kategori',
    ],
    'category' => [
        'name' => 'Navn',
        'name_placeholder' => 'Kategoriens navn',
        'slug' => 'Slug',
        'slug_placeholder' => 'kategoriens-navn',
        'posts' => 'Innlegg',
        'delete_confirm' => 'Vil du virkelig slette denne kategorien?',
        'return_to_categories' => 'Tilbake til kategorilisten',
    ],
    'settings' => [
        'category_title' => 'Category List',
        'category_description' => 'Displays a list of blog categories on the page.',
        'category_slug' => 'Category slug',
        'category_slug_description' => "Look up the blog category using the supplied slug value. This property is used by the default component partial for marking the currently active category.",
        'category_display_empty' => 'Display empty categories',
        'category_display_empty_description' => 'Show categories that do not have any posts.',
        'category_page' => 'Category page',
        'category_page_description' => 'Name of the category page file for the category links. This property is used by the default component partial.',
        'post_title' => 'Post',
        'post_description' => 'Displays a blog post on the page.',
        'post_slug' => 'Post slug',
        'post_slug_description' => "Look up the blog post using the supplied slug value.",
        'post_category' => 'Category page',
        'post_category_description' => 'Name of the category page file for the category links. This property is used by the default component partial.',
        'posts_title' => 'Post List',
        'posts_description' => 'Displays a list of latest blog posts on the page.',
        'posts_pagination' => 'Page number',
        'posts_pagination_description' => 'This value is used to determine what page the user is on.',
        'posts_filter' => 'Category filter',
        'posts_filter_description' => 'Enter a category slug or URL parameter to filter the posts by. Leave empty to show all posts.',
        'posts_per_page' => 'Posts per page',
        'posts_per_page_validation' => 'Invalid format of the posts per page value',
        'posts_no_posts' => 'No posts message',
        'posts_no_posts_description' => 'Message to display in the blog post list in case if there are no posts. This property is used by the default component partial.',
        'posts_order' => 'Post order',
        'posts_order_description' => 'Attribute on which the posts should be ordered',
        'posts_category' => 'Category page',
        'posts_category_description' => 'Name of the category page file for the "Posted into" category links. This property is used by the default component partial.',
        'posts_post' => 'Post page',
        'posts_post_description' => 'Name of the blog post page file for the "Learn more" links. This property is used by the default component partial.',
        'posts_except_post' => 'Except post',
        'posts_except_post_description' => 'Enter ID/URL or variable with post ID/URL you want to except',
    ],
];


================================================
FILE: lang/nl/lang.php
================================================
<?php

return [
    'plugin' => [
        'name' => 'Blog',
        'description' => 'A robust blogging platform.'
    ],
    'blog' => [
        'menu_label' => 'Blog',
        'menu_description' => 'Beheer blog artikelen',
        'posts' => 'Artikelen',
        'create_post' => 'Artikel',
        'categories' => 'Categorieën',
        'create_category' => 'blog categorie',
        'tab' => 'Blog',
        'access_posts' => 'Blog artikelen beheren',
        'access_categories' => 'Blog categorieën beheren',
        'access_other_posts' => 'Beheren van blog artikelen van gebruikers',
        'access_import_export' => 'Toegang tot importeren en exporteren van artikelen',
        'delete_confirm' => 'Weet je het zeker?',
        'chart_published' => 'Gepubliceerd',
        'chart_drafts' => 'Concepten',
        'chart_total' => 'Totaal'
    ],
    'posts' => [
        'list_title' => 'Beheren van blog artikelen',
        'filter_category' => 'Categorie',
        'filter_published' => 'Verberg gepubliceerd',
        'new_post' => 'Nieuw artikel'
    ],
    'post' => [
        'title' => 'Titel',
        'title_placeholder' => 'Titel van artikel',
        'content' => 'Inhoud',
        'content_html' => 'HTML Inhoud',
        'slug' => 'Slug',
        'slug_placeholder' => 'nieuw-artikel-slug',
        'categories' => 'Categorieën',
        'author_email' => 'E-mail auteur',
        'created' => 'Aangemaakt',
        'created_date' => 'Aangemaakt op',
        'updated' => 'Bijgewerkt',
        'updated_date' => 'Bijgewerkt op',
        'published' => 'Gepubliceerd',
        'published_by' => 'Gepubliceerd door',
        'current_user' => 'Huidige gebruiker',
        'published_date' => 'Gepubliceerd op',
        'published_validation' => 'Graag een publicatie datum opgeven',
        'tab_edit' => 'Bewerken',
        'tab_categories' => 'Categorieën',
        'categories_comment' => 'Selecteer een categorie waarbij het artikel hoort',
        'categories_placeholder' => 'Er zijn geen categorieën, maak eerst een categorie aan!',
        'tab_manage' => 'Beheer',
        'published_on' => 'Gepubliceerd op',
        'excerpt' => 'Samenvatting',
        'summary' => 'Samenvatting',
        'featured_images' => 'Uitgelichte afbeelding',
        'delete_confirm' => 'Weet je zeker dat je dit artikel wilt verwijderen?',
        'close_confirm' => 'Artikel is nog niet opgeslagen.',
        'return_to_posts' => 'Terug naar artikel overzicht',
        'posted_byline' => 'Gepubliceerd in :categories op :date.',
        'posted_byline_no_categories' => 'Gepubliceerd op :date.',
        'date_format' => 'd, M, Y',
    ],
    'categories' => [
        'list_title' => 'Beheer blog categorieën',
        'new_category' => 'Nieuwe categorie',
        'uncategorized' => 'Ongecategoriseerd'
    ],
    'category' => [
        'name' => 'Naam',
        'name_placeholder' => 'Naam categorie',
        'slug' => 'Slug',
        'slug_placeholder' => 'nieuw-categorie-slug',
        'posts' => 'Artikelen',
        'delete_confirm' => 'Weet je zeker dat je deze categorie wilt verwijderen?',
        'return_to_categories' => 'Terug naar categorie overzicht'
    ],
    'settings' => [
        'category_title' => 'Categorie overzicht',
        'category_description' => 'Geeft een lijst weer van alle categorieën op de pagina.',
        'category_slug' => 'Categorie slug',
        'category_slug_description' => 'Haal blog categorie op a.h.v. de opgegeven slug. Deze waarde wordt standaard gebruikt voor de partial om de actieve categorie te markeren.',
        'category_display_empty' => 'Geef lege categorieën weer',
        'category_display_empty_description' => 'Geef categorieën weer die geen artikelen hebben.',
        'category_page' => 'Categorie pagina',
        'category_page_description' => 'Naam van categorie pagina bestand voor de categorie links. Deze waarde wordt standaard gebruikt door de partial.',
        'post_title' => 'Artikel',
        'post_description' => 'Geef een artikel weer op de pagina.',
        'post_slug' => 'Artikel slug',
        'post_slug_description' => 'Haal een artikel op a.h.v. de opgegeven slug.',
        'post_category' => 'Categorie pagina',
        'post_category_description' => 'Naam van categorie pagina bestand voor de categorie links. Deze waarde wordt standaard gebruikt door de partial.',
        'posts_title' => 'Artikel overzicht',
        'posts_description' => 'Geeft een lijst van de nieuwste artikelen weer op de pagina.',
        'posts_pagination' => 'Pagina nummer',
        'posts_pagination_description' => 'Deze waarde wordt gebruikt om te kijken op welke pagina de gebruiker is.',
        'posts_filter' => 'Categorie filter',
        'posts_filter_description' => 'Geef een categorie slug of URL param om de artikelen hier op te kunnen filteren. Leeg laten als alle artikelen getoond moeten worden.',
        'posts_per_page' => 'Artikelen per pagina',
        'posts_per_page_validation' => 'Ongeldig formaat voor het aantal artikelen per pagina',
        'posts_no_posts' => 'Geen artikelen melding',
        'posts_no_posts_description' => 'Deze tekst wordt getoond als er geen artikelen zijn. Deze waarde wordt standaard gebruikt door de partial.',
        'posts_order' => 'Volgorde artikelen',
        'posts_order_description' => 'Kolom waar de artikelen op gesorteerd moeten worden',
        'posts_category' => 'Categorie pagina',
        'posts_category_description' => 'Naam van categorie pagina bestand voor gekoppeld artikel overzichts pagina. Deze waarde wordt standaard gebruikt door de partial.',
        'posts_post' => 'Artikel pagina',
        'posts_post_description' => 'Naam van blog pagina bestand voor de "Lees meer" links. Deze waarde wordt standaard gebruikt door de partial.',
        'posts_except_post' => 'Except post',
        'posts_except_post_description' => 'Enter ID/URL or variable with post ID/URL you want to except',
    ]
];


================================================
FILE: lang/pl/lang.php
================================================
<?php return [
    'plugin' => [
        'name' => 'Blog',
        'description' => 'Solidna platforma blogera',
    ],
    'blog' => [
        'menu_label' => 'Blog',
        'menu_description' => 'Zarządzaj postami na blogu',
        'posts' => 'Posty',
        'create_post' => 'Utwórz post',
        'categories' => 'Kategorie',
        'create_category' => 'Utwórz kategorię',
        'tab' => 'Blog',
        'access_posts' => 'Zarządzaj postami',
        'access_categories' => 'Zarządzaj kategoriami na blogu',
        'access_other_posts' => 'Zarządzaj postami innych użytkowników',
        'access_import_export' => 'Zarządzaj importowaniem i eksportowaniem postów',
        'access_publish' => 'Publikuj posty',
        'manage_settings' => 'Zarządzaj ustawieniami bloga',
        'delete_confirm' => 'Czy jesteś pewien?',
        'chart_published' => 'Opublikowane',
        'chart_drafts' => 'Szkice',
        'chart_total' => 'Łącznie',
        'settings_description' => 'Zarządzaj ustawieniami bloga',
        'show_all_posts_label' => 'Pokaż wszystkie posty użytkownikom backendu',
        'show_all_posts_comment' => 'Wyświetl opublikowane i nieopublikowany posty na stronie dla użytkowników backendu',
        'tab_general' => 'Ogólne',
    ],
    'posts' => [
        'list_title' => 'Zarządzaj postami',
        'filter_category' => 'Kategoria',
        'filter_published' => 'Ukryj opublikowane',
        'filter_date' => 'Date',
        'new_post' => 'Nowy post',
        'export_post' => 'Eksportuj posty',
        'import_post' => 'Importuj posty',
    ],
    'post' => [
        'title' => 'Tytuł',
        'title_placeholder' => 'Tytuł nowego posta',
        'content' => 'Zawartość',
        'content_html' => 'Zawartość HTML',
        'slug' => 'Alias',
        'slug_placeholder' => 'alias-nowego-postu',
        'categories' => 'Kategorie',
        'author_email' => 'Email autora',
        'created' => 'Utworzony',
        'created_date' => 'Data utworzenia',
        'updated' => 'Zaktualizowany',
        'updated_date' => 'Data aktualizacji',
        'published' => 'Opublikowany',
        'published_date' => 'Data publikacji',
        'published_validation' => 'Proszę określić datę publikacji',
        'tab_edit' => 'Edytuj',
        'tab_categories' => 'Kategorie',
        'categories_comment' => 'Wybierz kategorie do których post należy',
        'categories_placeholder' => 'Nie ma żadnej kategorii, powinieneś utworzyć przynajmniej jedną.',
        'tab_manage' => 'Zarządzaj',
        'published_on' => 'Opublikowane',
        'excerpt' => 'Zalążek',
        'summary' => 'Summary',
        'featured_images' => 'Załączone grafiki',
        'delete_confirm' => 'Czy naprawdę chcesz usunąć ten post?',
        'delete_success' => 'Posty zostały pomyślnie usunięte.',
        'close_confirm' => 'Ten post nie jest zapisany.',
        'return_to_posts' => 'Wróć do listy postów',
    ],
    'categories' => [
        'list_title' => 'Zarządzaj kategoriami postów',
        'new_category' => 'Nowa kategoria',
        'uncategorized' => 'Bez kategorii',
    ],
    'category' => [
        'name' => 'Nazwa',
        'name_placeholder' => 'Nazwa nowej kategorii',
        'description' => 'Opis',
        'slug' => 'Alias',
        'slug_placeholder' => 'alias-nowej-kategorii',
        'posts' => 'Posty',
    
Download .txt
gitextract_104lrz67/

├── .gitignore
├── LICENCE.md
├── Plugin.php
├── README.md
├── assets/
│   ├── css/
│   │   ├── rainlab.blog-export.css
│   │   └── rainlab.blog-preview.css
│   ├── js/
│   │   └── post-form.js
│   └── less/
│       └── rainlab.blog-preview.less
├── classes/
│   └── TagProcessor.php
├── components/
│   ├── Categories.php
│   ├── Post.php
│   ├── Posts.php
│   ├── RssFeed.php
│   ├── categories/
│   │   ├── default.htm
│   │   └── items.htm
│   ├── post/
│   │   └── default.htm
│   ├── posts/
│   │   └── default.htm
│   └── rssfeed/
│       └── default.htm
├── composer.json
├── config/
│   └── config.php
├── controllers/
│   ├── Categories.php
│   ├── Posts.php
│   ├── categories/
│   │   ├── _list_toolbar.htm
│   │   ├── _reorder_toolbar.htm
│   │   ├── config_form.yaml
│   │   ├── config_list.yaml
│   │   ├── config_reorder.yaml
│   │   ├── create.htm
│   │   ├── index.htm
│   │   ├── reorder.htm
│   │   └── update.htm
│   └── posts/
│       ├── _list_toolbar.htm
│       ├── _post_toolbar.htm
│       ├── config_form.yaml
│       ├── config_import_export.yaml
│       ├── config_list.yaml
│       ├── create.htm
│       ├── export.htm
│       ├── import.htm
│       ├── index.htm
│       └── update.htm
├── formwidgets/
│   ├── BlogMarkdown.php
│   └── MLBlogMarkdown.php
├── lang/
│   ├── bg/
│   │   └── lang.php
│   ├── cs/
│   │   └── lang.php
│   ├── de/
│   │   └── lang.php
│   ├── en/
│   │   └── lang.php
│   ├── es/
│   │   └── lang.php
│   ├── fa/
│   │   └── lang.php
│   ├── fi/
│   │   └── lang.php
│   ├── fr/
│   │   └── lang.php
│   ├── hu/
│   │   └── lang.php
│   ├── it/
│   │   └── lang.php
│   ├── ja/
│   │   └── lang.php
│   ├── nb-no/
│   │   └── lang.php
│   ├── nl/
│   │   └── lang.php
│   ├── pl/
│   │   └── lang.php
│   ├── pt-br/
│   │   └── lang.php
│   ├── ru/
│   │   └── lang.php
│   ├── sk/
│   │   └── lang.php
│   ├── sl/
│   │   └── lang.php
│   ├── tr/
│   │   └── lang.php
│   └── zh-cn/
│       └── lang.php
├── models/
│   ├── Category.php
│   ├── Post.php
│   ├── PostExport.php
│   ├── PostImport.php
│   ├── Settings.php
│   ├── category/
│   │   ├── columns.yaml
│   │   └── fields.yaml
│   ├── post/
│   │   ├── columns.yaml
│   │   ├── fields.yaml
│   │   └── scopes.yaml
│   ├── postexport/
│   │   └── columns.yaml
│   ├── postimport/
│   │   ├── columns.yaml
│   │   └── fields.yaml
│   └── settings/
│       └── fields.yaml
└── updates/
    ├── categories_add_nested_fields.php
    ├── create_categories_table.php
    ├── create_posts_table.php
    ├── posts_add_metadata.php
    ├── seed_all_tables.php
    ├── update_timestamp_nullable.php
    └── version.yaml
Download .txt
SYMBOL INDEX (142 symbols across 21 files)

FILE: Plugin.php
  class Plugin (line 11) | class Plugin extends PluginBase
    method pluginDetails (line 13) | public function pluginDetails()
    method registerComponents (line 24) | public function registerComponents()
    method registerPermissions (line 34) | public function registerPermissions()
    method registerNavigation (line 64) | public function registerNavigation()
    method registerSettings (line 99) | public function registerSettings()
    method register (line 118) | public function register()
    method boot (line 139) | public function boot()

FILE: classes/TagProcessor.php
  class TagProcessor (line 9) | class TagProcessor
    method registerCallback (line 26) | public function registerCallback(callable $callback)
    method processTags (line 31) | public function processTags($markup, $preview)

FILE: components/Categories.php
  class Categories (line 9) | class Categories extends ComponentBase
    method componentDetails (line 26) | public function componentDetails()
    method defineProperties (line 34) | public function defineProperties()
    method getCategoryPageOptions (line 59) | public function getCategoryPageOptions()
    method onRun (line 64) | public function onRun()
    method loadCategories (line 75) | protected function loadCategories()
    method linkCategories (line 103) | protected function linkCategories($categories)

FILE: components/Post.php
  class Post (line 9) | class Post extends ComponentBase
    method componentDetails (line 21) | public function componentDetails()
    method defineProperties (line 29) | public function defineProperties()
    method getCategoryPageOptions (line 47) | public function getCategoryPageOptions()
    method init (line 52) | public function init()
    method onRun (line 85) | public function onRun()
    method onRender (line 95) | public function onRender()
    method loadPost (line 102) | protected function loadPost()
    method previousPost (line 133) | public function previousPost()
    method nextPost (line 138) | public function nextPost()
    method getPostSibling (line 143) | protected function getPostSibling($direction = 1)
    method checkEditor (line 166) | protected function checkEditor()

FILE: components/Posts.php
  class Posts (line 14) | class Posts extends ComponentBase
    method componentDetails (line 65) | public function componentDetails()
    method defineProperties (line 73) | public function defineProperties()
    method getCategoryPageOptions (line 143) | public function getCategoryPageOptions()
    method getPostPageOptions (line 148) | public function getPostPageOptions()
    method getSortOrderOptions (line 153) | public function getSortOrderOptions()
    method onRun (line 164) | public function onRun()
    method prepareVars (line 183) | protected function prepareVars()
    method listPosts (line 195) | protected function listPosts()
    method loadCategory (line 234) | protected function loadCategory()
    method checkEditor (line 251) | protected function checkEditor()

FILE: components/RssFeed.php
  class RssFeed (line 10) | class RssFeed extends ComponentBase
    method componentDetails (line 36) | public function componentDetails()
    method defineProperties (line 44) | public function defineProperties()
    method getBlogPageOptions (line 83) | public function getBlogPageOptions()
    method getPostPageOptions (line 88) | public function getPostPageOptions()
    method getSortOrderOptions (line 93) | public function getSortOrderOptions()
    method onRun (line 104) | public function onRun()
    method prepareVars (line 113) | protected function prepareVars()
    method listPosts (line 124) | protected function listPosts()
    method loadCategory (line 147) | protected function loadCategory()

FILE: controllers/Categories.php
  class Categories (line 9) | class Categories extends Controller
    method __construct (line 23) | public function __construct()
    method index_onDelete (line 30) | public function index_onDelete()

FILE: controllers/Posts.php
  class Posts (line 15) | class Posts extends Controller
    method __construct (line 40) | public function __construct()
    method index (line 47) | public function index()
    method create (line 56) | public function create()
    method update (line 67) | public function update($recordId = null)
    method setPreviewPageUrlVars (line 81) | protected function setPreviewPageUrlVars()
    method export (line 93) | public function export()
    method listExtendQuery (line 100) | public function listExtendQuery($query)
    method formExtendQuery (line 107) | public function formExtendQuery($query)
    method formExtendFieldsBefore (line 114) | public function formExtendFieldsBefore($widget)
    method index_onDelete (line 135) | public function index_onDelete()
    method listInjectRowClass (line 156) | public function listInjectRowClass($record, $definition = null)
    method formBeforeCreate (line 163) | public function formBeforeCreate($model)
    method onRefreshPreview (line 168) | public function onRefreshPreview()

FILE: formwidgets/BlogMarkdown.php
  class BlogMarkdown (line 21) | class BlogMarkdown extends MarkdownEditor
    method init (line 26) | public function init()
    method loadAssets (line 38) | protected function loadAssets()
    method shouldCleanHtml (line 49) | protected function shouldCleanHtml()
    method onRefresh (line 57) | public function onRefresh()
    method checkUploadPostback (line 73) | protected function checkUploadPostback()

FILE: formwidgets/MLBlogMarkdown.php
  class MLBlogMarkdown (line 13) | class MLBlogMarkdown extends BlogMarkdown
    method init (line 33) | public function init()
    method render (line 42) | public function render()
    method prepareVars (line 59) | public function prepareVars()
    method getSaveValue (line 70) | public function getSaveValue($value)
    method loadAssets (line 95) | protected function loadAssets()
    method actAsParent (line 110) | protected function actAsParent($switch = true)
    method actAsControl (line 124) | protected function actAsControl($switch = true)

FILE: models/Category.php
  class Category (line 9) | class Category extends Model
    method beforeValidate (line 50) | public function beforeValidate()
    method afterDelete (line 58) | public function afterDelete()
    method getPostCountAttribute (line 63) | public function getPostCountAttribute()
    method getNestedPostCount (line 72) | public function getNestedPostCount()
    method setUrl (line 87) | public function setUrl($pageName, $controller)
    method getMenuTypeInfo (line 114) | public static function getMenuTypeInfo($type)
    method listSubCategoryOptions (line 160) | protected static function listSubCategoryOptions()
    method resolveMenuItem (line 202) | public static function resolveMenuItem($item, $url, $theme)
    method getCategoryPageUrl (line 290) | protected static function getCategoryPageUrl($pageCode, $category, $th...

FILE: models/Post.php
  class Post (line 23) | class Post extends Model
    method filterFields (line 113) | public function filterFields($fields, $context = null)
    method beforeValidate (line 134) | public function beforeValidate()
    method afterValidate (line 149) | public function afterValidate()
    method getUserOptions (line 161) | public function getUserOptions()
    method setUrl (line 180) | public function setUrl($pageName, $controller, $params = [])
    method canEdit (line 207) | public function canEdit(BackendUser $user)
    method formatHtml (line 215) | public static function formatHtml($input, $preview = false)
    method scopeIsPublished (line 243) | public function scopeIsPublished($query)
    method scopeListFrontEnd (line 260) | public function scopeListFrontEnd($query, $options)
    method scopeFilterCategories (line 380) | public function scopeFilterCategories($query, $categories)
    method getHasSummaryAttribute (line 395) | public function getHasSummaryAttribute()
    method getSummaryAttribute (line 414) | public function getSummaryAttribute()
    method scopeApplySibling (line 454) | public function scopeApplySibling($query, $options = [])
    method nextPost (line 482) | public function nextPost()
    method previousPost (line 491) | public function previousPost()
    method getMenuTypeInfo (line 518) | public static function getMenuTypeInfo($type)
    method resolveMenuItem (line 604) | public static function resolveMenuItem($item, $url, $theme)
    method getPostPageUrl (line 699) | protected static function getPostPageUrl($pageCode, $category, $theme)

FILE: models/PostExport.php
  class PostExport (line 9) | class PostExport extends ExportModel
    method exportData (line 51) | public function exportData($columns, $sessionKey = null)
    method getAuthorEmailAttribute (line 66) | public function getAuthorEmailAttribute()
    method getCategoriesAttribute (line 75) | public function getCategoriesAttribute()
    method getFeaturedImageUrlsAttribute (line 84) | public function getFeaturedImageUrlsAttribute()

FILE: models/PostImport.php
  class PostImport (line 11) | class PostImport extends ImportModel
    method getDefaultAuthorOptions (line 27) | public function getDefaultAuthorOptions()
    method getCategoriesOptions (line 32) | public function getCategoriesOptions()
    method importData (line 37) | public function importData($results, $sessionKey = null)
    method findAuthorFromEmail (line 98) | protected function findAuthorFromEmail($data)
    method findDuplicatePost (line 112) | protected function findDuplicatePost($data)
    method getCategoryIdsForPost (line 128) | protected function getCategoryIdsForPost($data)

FILE: models/Settings.php
  class Settings (line 7) | class Settings extends Model
    method getPreviewCmsPageOptions (line 26) | public function getPreviewCmsPageOptions()

FILE: updates/categories_add_nested_fields.php
  class CategoriesAddNestedFields (line 7) | class CategoriesAddNestedFields extends Migration
    method up (line 10) | public function up()
    method down (line 30) | public function down()

FILE: updates/create_categories_table.php
  class CreateCategoriesTable (line 6) | class CreateCategoriesTable extends Migration
    method up (line 9) | public function up()
    method down (line 35) | public function down()

FILE: updates/create_posts_table.php
  class CreatePostsTable (line 6) | class CreatePostsTable extends Migration
    method up (line 9) | public function up()
    method down (line 27) | public function down()

FILE: updates/posts_add_metadata.php
  class PostsAddMetadata (line 6) | class PostsAddMetadata extends Migration
    method up (line 9) | public function up()
    method down (line 21) | public function down()

FILE: updates/seed_all_tables.php
  class SeedAllTables (line 8) | class SeedAllTables extends Seeder
    method run (line 11) | public function run()

FILE: updates/update_timestamp_nullable.php
  class UpdateTimestampsNullable (line 6) | class UpdateTimestampsNullable extends Migration
    method up (line 8) | public function up()
    method down (line 16) | public function down()
Condensed preview — 84 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (329K chars).
[
  {
    "path": ".gitignore",
    "chars": 9,
    "preview": ".DS_Store"
  },
  {
    "path": "LICENCE.md",
    "chars": 1037,
    "preview": "# MIT license\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associa"
  },
  {
    "path": "Plugin.php",
    "chars": 7330,
    "preview": "<?php namespace RainLab\\Blog;\n\nuse Backend;\nuse Controller;\nuse RainLab\\Blog\\Models\\Post;\nuse System\\Classes\\PluginBase;"
  },
  {
    "path": "README.md",
    "chars": 12109,
    "preview": "# Blog Plugin\n\nA simple, extensible blogging platform for October CMS.\n\n[Blog & Forum Building Tutorial Video](https://p"
  },
  {
    "path": "assets/css/rainlab.blog-export.css",
    "chars": 71,
    "preview": ".export-behavior .export-columns {\n    max-height: 450px !important;\n}\n"
  },
  {
    "path": "assets/css/rainlab.blog-preview.css",
    "chars": 2627,
    "preview": ".blog-post-preview .editor-preview .preview-content {\n  padding: 20px;\n}\n.blog-post-preview .editor-preview span.image-p"
  },
  {
    "path": "assets/js/post-form.js",
    "chars": 6233,
    "preview": "+function ($) { \"use strict\";\n    var PostForm = function () {\n        this.$form = $('#post-form')\n        this.$markdo"
  },
  {
    "path": "assets/less/rainlab.blog-preview.less",
    "chars": 2445,
    "preview": "@import \"../../../../../modules/backend/assets/less/core/boot.less\";\n\n.blog-post-preview .editor-preview {\n    .preview-"
  },
  {
    "path": "classes/TagProcessor.php",
    "chars": 1022,
    "preview": "<?php namespace RainLab\\Blog\\Classes;\n\n/**\n * Blog Markdown tag processor.\n *\n * @package rainlab\\blog\n * @author Alexey"
  },
  {
    "path": "components/Categories.php",
    "chars": 3743,
    "preview": "<?php namespace RainLab\\Blog\\Components;\n\nuse Db;\nuse Carbon\\Carbon;\nuse Cms\\Classes\\Page;\nuse Cms\\Classes\\ComponentBase"
  },
  {
    "path": "components/Post.php",
    "chars": 4845,
    "preview": "<?php namespace RainLab\\Blog\\Components;\n\nuse Event;\nuse BackendAuth;\nuse Cms\\Classes\\Page;\nuse Cms\\Classes\\ComponentBas"
  },
  {
    "path": "components/Posts.php",
    "chars": 9155,
    "preview": "<?php namespace RainLab\\Blog\\Components;\n\nuse Lang;\nuse Redirect;\nuse BackendAuth;\nuse Cms\\Classes\\Page;\nuse Cms\\Classes"
  },
  {
    "path": "components/RssFeed.php",
    "chars": 4897,
    "preview": "<?php namespace RainLab\\Blog\\Components;\n\nuse Lang;\nuse Response;\nuse Cms\\Classes\\Page;\nuse Cms\\Classes\\ComponentBase;\nu"
  },
  {
    "path": "components/categories/default.htm",
    "chars": 300,
    "preview": "{% if __SELF__.categories|length > 0 %}\n    <ul class=\"category-list\">\n        {% partial __SELF__ ~ \"::items\"\n         "
  },
  {
    "path": "components/categories/items.htm",
    "chars": 624,
    "preview": "{% for category in categories %}\n    {% set postCount = category.post_count %}\n    <li {% if category.slug == currentCat"
  },
  {
    "path": "components/post/default.htm",
    "chars": 811,
    "preview": "{% set post = __SELF__.post %}\n\n<div class=\"content\">{{ post.content_html|raw }}</div>\n\n{% if post.featured_images|lengt"
  },
  {
    "path": "components/posts/default.htm",
    "chars": 1458,
    "preview": "{% set posts = __SELF__.posts %}\n\n<ul class=\"post-list\">\n    {% for post in posts %}\n        <li>\n            <h3><a hre"
  },
  {
    "path": "components/rssfeed/default.htm",
    "chars": 748,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\">\n    <channel>\n      "
  },
  {
    "path": "composer.json",
    "chars": 671,
    "preview": "{\n    \"name\": \"rainlab/blog-plugin\",\n    \"type\": \"october-plugin\",\n    \"description\": \"Blog plugin for October CMS\",\n   "
  },
  {
    "path": "config/config.php",
    "chars": 372,
    "preview": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Summary Co"
  },
  {
    "path": "controllers/Categories.php",
    "chars": 1232,
    "preview": "<?php namespace RainLab\\Blog\\Controllers;\n\nuse BackendMenu;\nuse Flash;\nuse Lang;\nuse Backend\\Classes\\Controller;\nuse Rai"
  },
  {
    "path": "controllers/Posts.php",
    "chars": 5024,
    "preview": "<?php namespace RainLab\\Blog\\Controllers;\n\nuse Lang;\nuse Flash;\nuse BackendMenu;\nuse RainLab\\Blog\\Models\\Post;\nuse RainL"
  },
  {
    "path": "controllers/categories/_list_toolbar.htm",
    "chars": 1122,
    "preview": "<div data-control=\"toolbar\">\n    <a href=\"<?= Backend::url('rainlab/blog/categories/create') ?>\" class=\"btn btn-primary "
  },
  {
    "path": "controllers/categories/_reorder_toolbar.htm",
    "chars": 225,
    "preview": "<div data-control=\"toolbar\">\n    <a href=\"<?= Backend::url('rainlab/blog/categories') ?>\" class=\"btn btn-primary oc-icon"
  },
  {
    "path": "controllers/categories/config_form.yaml",
    "chars": 469,
    "preview": "# ===================================\n#  Form Behavior Config\n# ===================================\n\nname: rainlab.blog:"
  },
  {
    "path": "controllers/categories/config_list.yaml",
    "chars": 917,
    "preview": "# ===================================\n#  List Behavior Config\n# ===================================\n\n# Model List Column"
  },
  {
    "path": "controllers/categories/config_reorder.yaml",
    "chars": 360,
    "preview": "# ===================================\n#  Reorder Behavior Config\n# ===================================\n\n# Reorder Title\n"
  },
  {
    "path": "controllers/categories/create.htm",
    "chars": 1885,
    "preview": "<?php Block::put('breadcrumb') ?>\n    <ul>\n        <li><a href=\"<?= Backend::url('rainlab/blog/posts') ?>\"><?= e(trans('"
  },
  {
    "path": "controllers/categories/index.htm",
    "chars": 28,
    "preview": "\n<?= $this->listRender() ?>\n"
  },
  {
    "path": "controllers/categories/reorder.htm",
    "chars": 29,
    "preview": "<?= $this->reorderRender() ?>"
  },
  {
    "path": "controllers/categories/update.htm",
    "chars": 2326,
    "preview": "<?php Block::put('breadcrumb') ?>\n    <ul>\n        <li><a href=\"<?= Backend::url('rainlab/blog/posts') ?>\"><?= e(trans('"
  },
  {
    "path": "controllers/posts/_list_toolbar.htm",
    "chars": 1484,
    "preview": "<div data-control=\"toolbar\">\n    <a\n        href=\"<?= Backend::url('rainlab/blog/posts/create') ?>\"\n        class=\"btn b"
  },
  {
    "path": "controllers/posts/_post_toolbar.htm",
    "chars": 2069,
    "preview": "<?php\n    $isCreate = $this->formGetContext() == 'create';\n    $pageUrl = isset($pageUrl) ? $pageUrl : null;\n?>\n<div cla"
  },
  {
    "path": "controllers/posts/config_form.yaml",
    "chars": 432,
    "preview": "# ===================================\n#  Form Behavior Config\n# ===================================\n\nname: rainlab.blog:"
  },
  {
    "path": "controllers/posts/config_import_export.yaml",
    "chars": 1021,
    "preview": "# ===================================\n#  Import/Export Behavior Config\n# ===================================\n\nimport:\n  "
  },
  {
    "path": "controllers/posts/config_list.yaml",
    "chars": 1047,
    "preview": "# ===================================\n#  List Behavior Config\n# ===================================\n\n# Model List Column"
  },
  {
    "path": "controllers/posts/create.htm",
    "chars": 808,
    "preview": "<?php if (!$this->fatalError): ?>\n\n    <div class=\"layout fancy-layout\">\n        <?= Form::open([\n            'class' =>"
  },
  {
    "path": "controllers/posts/export.htm",
    "chars": 814,
    "preview": "<?php Block::put('breadcrumb') ?>\n    <ul>\n        <li><a href=\"<?= Backend::url('rainlab/blog/posts') ?>\"><?= e(trans('"
  },
  {
    "path": "controllers/posts/import.htm",
    "chars": 717,
    "preview": "<?php Block::put('breadcrumb') ?>\n    <ul>\n        <li><a href=\"<?= Backend::url('rainlab/blog/posts') ?>\"><?= e(trans('"
  },
  {
    "path": "controllers/posts/index.htm",
    "chars": 27,
    "preview": "<?= $this->listRender() ?>\n"
  },
  {
    "path": "controllers/posts/update.htm",
    "chars": 810,
    "preview": "<?php if (!$this->fatalError): ?>\n\n    <div class=\"layout fancy-layout\">\n        <?= Form::open([\n            'class' =>"
  },
  {
    "path": "formwidgets/BlogMarkdown.php",
    "chars": 3361,
    "preview": "<?php namespace RainLab\\Blog\\FormWidgets;\n\nuse Lang;\nuse Input;\nuse Response;\nuse Validator;\nuse RainLab\\Blog\\Models\\Pos"
  },
  {
    "path": "formwidgets/MLBlogMarkdown.php",
    "chars": 3595,
    "preview": "<?php namespace RainLab\\Blog\\FormWidgets;\n\nuse RainLab\\Blog\\Models\\Post;\nuse RainLab\\Translate\\Models\\Locale;\n\n/**\n * A "
  },
  {
    "path": "lang/bg/lang.php",
    "chars": 5222,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'Блог',\n        'description' => 'Стабилната блог платформа.'\n    ],"
  },
  {
    "path": "lang/cs/lang.php",
    "chars": 8890,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'Blog',\n        'description' => 'Robustní blogová platforma.'\n    ]"
  },
  {
    "path": "lang/de/lang.php",
    "chars": 10189,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'Blog',\n        'description' => 'Eine robuste Blog Plattform.'\n    "
  },
  {
    "path": "lang/en/lang.php",
    "chars": 9569,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'Blog',\n        'description' => 'A robust blogging platform.'\n    ]"
  },
  {
    "path": "lang/es/lang.php",
    "chars": 10091,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'Blog',\n        'description' => 'Una plataforma robusta de blogging"
  },
  {
    "path": "lang/fa/lang.php",
    "chars": 5413,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'وبلاگ',\n        'description' => 'پلتفرم قوی برای وبلاگ نویسی'\n    "
  },
  {
    "path": "lang/fi/lang.php",
    "chars": 8944,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'Blogi',\n        'description' => 'Vankka bloggausalusta.'\n    ],\n  "
  },
  {
    "path": "lang/fr/lang.php",
    "chars": 9862,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'Blog',\n        'description' => 'Une plateforme de blog robuste.'\n "
  },
  {
    "path": "lang/hu/lang.php",
    "chars": 9759,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'Blog',\n        'description' => 'Teljeskörű blog alkalmazás.'\n    ]"
  },
  {
    "path": "lang/it/lang.php",
    "chars": 5656,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'Blog',\n        'description' => 'Una solida piattaforma di blogging"
  },
  {
    "path": "lang/ja/lang.php",
    "chars": 4117,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'ブログ',\n        'description' => 'ロバストなブログプラットフォームです。'\n    ],\n    'bl"
  },
  {
    "path": "lang/nb-no/lang.php",
    "chars": 5119,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'Blogg',\n        'description' => 'En robust bloggeplattform.',\n    "
  },
  {
    "path": "lang/nl/lang.php",
    "chars": 5968,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'Blog',\n        'description' => 'A robust blogging platform.'\n    ]"
  },
  {
    "path": "lang/pl/lang.php",
    "chars": 8912,
    "preview": "<?php return [\n    'plugin' => [\n        'name' => 'Blog',\n        'description' => 'Solidna platforma blogera',\n    ],\n"
  },
  {
    "path": "lang/pt-br/lang.php",
    "chars": 6513,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'Blog',\n        'description' => 'A plataforma de blogs robusta.'\n  "
  },
  {
    "path": "lang/ru/lang.php",
    "chars": 8899,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'Блог',\n        'description' => 'Надежная блоговая-платформа.'\n    "
  },
  {
    "path": "lang/sk/lang.php",
    "chars": 8549,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'Blog',\n        'description' => 'Robustná blogová platforma.'\n    ]"
  },
  {
    "path": "lang/sl/lang.php",
    "chars": 9230,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'Blog',\n        'description' => 'Robustna platforma za bloganje.',\n"
  },
  {
    "path": "lang/tr/lang.php",
    "chars": 9310,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => 'Blog',\n        'description' => 'Sağlam blog platformu.',\n    ],\n  "
  },
  {
    "path": "lang/zh-cn/lang.php",
    "chars": 4403,
    "preview": "<?php\n\nreturn [\n    'plugin' => [\n        'name' => '博客',\n        'description' => '一个强大的博客平台.'\n    ],\n    'blog' => [\n "
  },
  {
    "path": "models/Category.php",
    "chars": 10161,
    "preview": "<?php namespace RainLab\\Blog\\Models;\n\nuse Str;\nuse Model;\nuse Url;\nuse Cms\\Classes\\Page as CmsPage;\nuse Cms\\Classes\\Them"
  },
  {
    "path": "models/Post.php",
    "chars": 21886,
    "preview": "<?php namespace RainLab\\Blog\\Models;\n\nuse Url;\nuse Html;\nuse Lang;\nuse Model;\nuse Config;\nuse Markdown;\nuse BackendAuth;"
  },
  {
    "path": "models/PostExport.php",
    "chars": 2116,
    "preview": "<?php namespace RainLab\\Blog\\Models;\n\nuse Backend\\Models\\ExportModel;\nuse ApplicationException;\n\n/**\n * Post Export Mode"
  },
  {
    "path": "models/PostImport.php",
    "chars": 4262,
    "preview": "<?php namespace RainLab\\Blog\\Models;\n\nuse Backend\\Models\\ImportModel;\nuse Backend\\Models\\User as AuthorModel;\nuse Applic"
  },
  {
    "path": "models/Settings.php",
    "chars": 1551,
    "preview": "<?php namespace RainLab\\Blog\\Models;\n\nuse Cms\\Classes\\Page as CmsPage;\nuse Cms\\Classes\\Theme;\nuse October\\Rain\\Database\\"
  },
  {
    "path": "models/category/columns.yaml",
    "chars": 282,
    "preview": "# ===================================\n#  Column Definitions\n# ===================================\n\ncolumns:\n\n    name:\n "
  },
  {
    "path": "models/category/fields.yaml",
    "chars": 584,
    "preview": "# ===================================\n#  Field Definitions\n# ===================================\n\nfields:\n\n    name:\n   "
  },
  {
    "path": "models/post/columns.yaml",
    "chars": 764,
    "preview": "# ===================================\n#  Column Definitions\n# ===================================\n\ncolumns:\n\n    title:\n"
  },
  {
    "path": "models/post/fields.yaml",
    "chars": 2284,
    "preview": "# ===================================\n#  Field Definitions\n# ===================================\n\nfields:\n    title:\n   "
  },
  {
    "path": "models/post/scopes.yaml",
    "chars": 901,
    "preview": "# ===================================\n# Filter Scope Definitions\n# ===================================\n\nscopes:\n\n    cat"
  },
  {
    "path": "models/postexport/columns.yaml",
    "chars": 728,
    "preview": "# ===================================\n#  Column Definitions\n# ===================================\n\ncolumns:\n\n    id: ID\n"
  },
  {
    "path": "models/postimport/columns.yaml",
    "chars": 608,
    "preview": "# ===================================\n#  Column Definitions\n# ===================================\n\ncolumns:\n\n    id: ID\n"
  },
  {
    "path": "models/postimport/fields.yaml",
    "chars": 1165,
    "preview": "# ===================================\n#  Form Field Definitions\n# ===================================\n\nfields:\n\n    upda"
  },
  {
    "path": "models/settings/fields.yaml",
    "chars": 1162,
    "preview": "tabs:\n    fields:\n        show_all_posts:\n            span: full\n            label: rainlab.blog::lang.blog.show_all_pos"
  },
  {
    "path": "updates/categories_add_nested_fields.php",
    "chars": 856,
    "preview": "<?php namespace RainLab\\Blog\\Updates;\n\nuse Schema;\nuse October\\Rain\\Database\\Updates\\Migration;\nuse RainLab\\Blog\\Models\\"
  },
  {
    "path": "updates/create_categories_table.php",
    "chars": 1291,
    "preview": "<?php namespace RainLab\\Blog\\Updates;\n\nuse Schema;\nuse October\\Rain\\Database\\Updates\\Migration;\n\nclass CreateCategoriesT"
  },
  {
    "path": "updates/create_posts_table.php",
    "chars": 912,
    "preview": "<?php namespace RainLab\\Blog\\Updates;\n\nuse Schema;\nuse October\\Rain\\Database\\Updates\\Migration;\n\nclass CreatePostsTable "
  },
  {
    "path": "updates/posts_add_metadata.php",
    "chars": 667,
    "preview": "<?php namespace RainLab\\Blog\\Updates;\n\nuse Schema;\nuse October\\Rain\\Database\\Updates\\Migration;\n\nclass PostsAddMetadata "
  },
  {
    "path": "updates/seed_all_tables.php",
    "chars": 1004,
    "preview": "<?php namespace RainLab\\Blog\\Updates;\n\nuse Carbon\\Carbon;\nuse RainLab\\Blog\\Models\\Post;\nuse RainLab\\Blog\\Models\\Category"
  },
  {
    "path": "updates/update_timestamp_nullable.php",
    "chars": 407,
    "preview": "<?php namespace RainLab\\Blog\\Updates;\n\nuse October\\Rain\\Database\\Updates\\Migration;\nuse DbDongle;\n\nclass UpdateTimestamp"
  },
  {
    "path": "updates/version.yaml",
    "chars": 4297,
    "preview": "v1.0.1:\n    - Initialize plugin.\n    - create_posts_table.php\n    - create_categories_table.php\n    - seed_all_tables.ph"
  }
]

About this extraction

This page contains the full source code of the rainlab/blog-plugin GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 84 files (295.7 KB), approximately 75.5k tokens, and a symbol index with 142 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!