/grav-plugin-add-page-by-form

Creates a new page by submitting a Grav form

Primary LanguagePHPMIT LicenseMIT

Add Page By Form Plugin

Abandonment Notice: Creating and improving my plugins for Grav was fun to do, however times are changing and so am I. My interests have shifted away from coding and so I am abandoning my plugins. If you are interested in taking over please follow the "Abandoned Resource Protocol". Simply skip the first two steps and refer to this statement in step 3.

The Add Page By Form Plugin is for Grav CMS. It allows users to add a new page by filling in a form.

This plugin uses the possibilities of custom frontmatter. By setting your own variables in the form page frontmatter a priori and optionally letting users override these variable values by filling in corresponding form fields you can transport these data into the new page frontmatter.

The passing on of both the default settings and form field values entered by the end user to the new page frontmatter makes for an extremely configurable solution.
By mixing default settings and configuring the page form you can to a large extent control the appearence and behaviour of the newly added page by using the frontmatter variables present in the new page in a Twig template.

For example, a new page can act as a new blog post simply by setting the appropriate template variable in the form page definition (with the AntiMatter theme, this is template: item). That template value is inserted in the new page frontmatter and, so, will be used by Grav to display the new page.

Security Warning

Allowing anonymous visitors to create pages is a potential website security risk. It is strongly advised to use the Grav Login Plugin or the Private Grav Plugin to restrict the page creation to logged in users only.

This plugin itself does not provide any security measures. Please take this in consideration before using this plugin.

Installation and Configuration

Typically the plugin should be installed via GPM (Grav Package Manager):

$ bin/gpm install add-page-by-form

Alternatively it can be installed via the Admin Plugin.

Another option is to manualy install the plugin by downloading the plugin as a zip file. Copy the zip file to your /user/plugins directory, unzip it there and rename the folder to add-page-by-form.

Configuration Defaults

Here is the default configuration in the configuration file add-page-by-form.yaml plus an explanation of the settings:

enabled: true
date_display_format: 'd-m-Y g:ia'
default_title: 'My New Page'
default_content: 'No content.'
overwrite_mode: false
include_username: false
auto_taxonomy_types: false
use_editor_class: true
physical_template_name: true
  • enabled determines whether the plugin is active or not;

  • date_display_format sets a default date and time format;

  • default_title will be used as a fallback for the new page title when no other value is set;

  • default_content will be used as the page content for the new page when no other value is set;

  • include_username sets whether or not the username of the currently logged in frontend user is included in the new page frontmatter;

  • overwrite_mode determines how to act when a page with the same name or slug already exists;

  • auto_taxonomy_types saves any new taxonomy types that were input by the user to the site configuration file site.yaml;

  • use_editor_class determines whether or not to change a textarea field into a Markdown editor when the texture field includes the class "editor" (classes: editor);

  • physical_template_name should normally not be used. For more information see the description in the section 'pageconfig' block variables.

Customizing the default configuration

To keep your custom configuration when updating the plugin you need to use a configuration file which is stored in the user/config/plugins folder.

Simply edit the plugin options in the Admin panel and the changes will be saved to the configuration file in that location. If you don't use the Admin panel, copy the add-page-by-form.yaml default file to your user/config/plugins folder and use that copy to change configuration settings.

Usage

Using this plugin requires:

  • a normal page containing a Grav Form with a unique name that starts with "add_page";
  • optionally, but required for usefulness, one or two blocks of extra page frontmatter variables in that page being:
    • a 'pageconfig' block with variables that are used in the new page creation process;
    • a 'pagefrontmatter' block with variables that are passed on to the new page frontmatter and can be processed by Twig along the way.

Modifying frontmatter variables

Every frontmatter variable value can be changed by the user when an input field with the same name as the variable is included in the form.

The basic method of modifying is overriding or replacing an initial value. An extreme case of overriding a variable which is quite uncommon but illustrates the process well:

  1. overwrite_mode is set in add-page-by-form.yaml
  2. and can be changed in the Plugin configuration in the Admin Panel
  3. can be set in the pageconfig block
  4. and finally may be changed again by the end user when the form contains an overwrite_mode field.

Page Headers / Frontmatter

This plugin makes extensive use of Custom Page Headers. Unfortunately the Grav documentation mixes the terms "frontmatter", "page headers" and simply "headers". This may be confusing at first. They all refer to the optional top part of a Grav page which contains data in YAML syntax.

Form page Frontmatter

The frontmatter in the form page and the way it is handled by the plugin is where the flexibility of this plugin originates.

The form page frontmatter is divided into three sections or blocks:

  1. So called 'root level' variables are intended to act upon the form page itself. They are not passed on to the new page;
  2. the pageconfig block contains variables that are used by the plugin in the new page creation process and do get passed on to the new page frontmatter;
  3. the pagefrontmatter block holds all other variables that must be passed on to the new page frontmatter.

Root level variables

In the examples above the root level configuration options are:

  • title sets the title of the page containing the form;
  • template: form activates the form on this page (not required when the form page is named form.md);
  • form defines the form.

From version 2, the use of parent in the, what is now called, root level block is deprecated. It is however still supported for backwards compatibility.

'pageconfig' block variables

In the optional pageconfig block you can set these, and only these, variables (other variables will be ignored):

  • parent sets the parent page for the new page. This variable may be an absolute route (for example parent: /user_contributions) or a relative route (e.g. parent: articles. In case of an absolute route this route starts from the pages root. A relative route is regarded to start from the form page, so the new page will be a child page of the form page. The form page is also used as the parent page when the set parent page does not exist;
  • subroute defines a route from the (initial) parent value. If one or more folders in the route do not exist they will be created;
  • slug_field tells the plugin what field or fields to use as the new page's slug or folder name. Multiple form field names may be specified either using a comma separated string or as an array. When slug_field is missing the plugin tries to use the value of title;
  • overwrite_mode: true|false|edit (default false) tells the plugin what to do when a page with the same name already exists. With overwrite_mode: true the existing page is overwritten. Any additional (media) files besides the page itself which are stored in the existing page folder are deleted as well. With overwite_mode: false the new page slug gets a sequential number attached at the end (for example "my-new-page-1" in case "my-new-page" exists).
    Using overwite_mode: edit allows for the page being saved to it's existing folder respecting any already present uploaded files;
  • include_username: true|false (default false) determines whether or not to include the username of a logged in frontend user in the new page frontmatter;
  • physical_template_name: true|false (default true) does or does not cause the plugin to use the template name of the new page as that new page's filesystem filename. Defaults to "default" when no template is set in the 'pagefrontmatter' block. When set to true to avoid future confusion the frontmatter variable template is removed from the new page frontmatter.

A note on parent and subroute

Together the variables parent and subroute define the new page's destination. Or, in other words, together they set the path or route of the new page filesystem folder in the page structure.

The difference between parent and subroute worded in another way:

  • Parent: works on a page level; when there is no page at the parent route, the form page is used as the parent;
  • Subroute: works on a folder level; a subroute may consist of empty folders and if a folder in the subroute does not exist it gets created.

'pagefrontmatter' block variables

The content of the optional pagefrontmatter block will be included in the new page frontmatter.

Form usage

The form page needs to use a simple single form.

Two examples are included at the end of this ReadMe file.

Mandatory fields and values

Form Name

It is always a good thing to give each form a unique name, especially when multiple forms are used.

To pre fill form fields with default values the Form name must include the string "add_page". Valid names are for example add_page.blogpost, add_page_profile.

###Form Actions

Custom Form processing ( Important ! )

To let the plugin process the form after a Submit a custom process action must be set like so:

    process:
        -
            add_page: true

Redirect to the new page

To show the new page to the user set the redirect action to the custom value @self or @self-admin.

When using redirect: '@self' the page will be shown as a regular web page, for example:

    process:
        -
            add_page: true
        -
            redirect: '@self'

To open the new page in the Admin panel use redirect: '@self-admin'.
Note that this plugin does not handle the admin user authentication. If the Admin plugin is not installed or is inactive redirection occurs as if @self was used.

Tip: using @self-admin is a very convenient way to learn how to use this plugin as it is easy to view and examine the source of the resulting new page including it's frontmatter in the Admin panel.

Using a Markdown editor in textarea fields

When a textarea field is given the class editor it will use the SimpleMDE Markdown Editor.

Value overrides

The variables which are defined and given a value in the pageconfig and pagefrontmatter blocks may be 'overridden' or in other words replaced by form input fields. In that respect these variables can be seen to hold a set of default values.

There is only one exception to the default variable override behaviour and that is the handling of taxonomy types. Extra taxonomy types and values (for example tags) which are entered via form fields are added to the new page taxonomy.

To override a default value by user input is simply a matter of including a form field by the same name in the page form.
For example in the example 2 - create a new blog post, the default title is set to "My new Blog post". The form contains a form field of type text with name: title. Thus the user is prompted to enter a title for the new page in the form but does not need to do so because filling in the title field is not mandatory. If the user enters a title that value is used as the title for the new page. If he or she does not, the default title "My new Blog post" will be used.

Setting taxonomy categories and tags

The Add Blog Post example shows how to let the user add extra tags via the form. Extra categories may be added in the same way.

Handling extra taxonomy types

By default Grav 'knows' two taxonomy types, category and tag. Extra taxonomy types may be defined and added just like with any other variables you can include a form field. The new type is then added to the list of taxonomy types instead of replacing the existing types.

This can be done in the pagefrontmatter block. For example, to define a new taxonomy type named 'department':

pagefrontmatter:
    taxonomy:
        - department

And/or in the form:

form:
    name: my_form
    fields:
        -
            name: taxonomy
            label: Taxonomy type
            type: text

This is a feature which calls for a solid look-before-you-leap approach because of it's side effects. Using a new taxonomy type requires it to be included in the list of known taxonomy types. This list is in the site configuration file site.yaml.

By setting the plugin configuration option auto_taxonomy_types: true new types get automatically saved and can then be used in a collection.

The side effect and possibly downside is that every modification of the site configuration file causes Grav to rebuild the cache, so this may not be desirable with larger sites.
Use with caution!

Examples

The least error prone way to test and play with the examples is to set up a fresh Grav site and using it's default theme Antimatter.

Form page example 1: create a normal page

The goal of this example is to show how to let a user create a new page where uploaded images and files are saved along the page (in the same folder). After the user clicked Submit he or she will be shown the new page.

Suppose this minimal Grav website structure in user/pages/:

03.submit-assignment/
    default.md
04.assignments/
    cmpt363-e100/
        default.md
        drafts/
            modular.md
        reviewed/
            modular.md

BTW both modular pages are not required but are mentioned as they could be used to display a collection of draft and reviewed assignments.

Then the 'Submit assignment for review' page (with slug submit-assignment) full content (both frontmatter and content) could look like:

---
routable: true
title: 'Submit assignment for review'
template: form
visible: true
pageconfig:
    parent: /submitted-assignments/cmpt363-e100/drafts
pagefrontmatter:
    visible: true
    status: draft
    template: default
    course:
        assignment: 'CMPT363 E100'
    instructor:
        name: 'Jane Doe'
form:
    name: addpage-assignment-cmpt363-e100
    fields:
        -
            name: name
            label: Name
            type: text
            validate:
                required: true
        -
            name: title
            label: Title
            type: text
            validate:
                required: true
        -
            name: content
            label: 'Assignment text'
            type: textarea
            size: long
            classes: editor
            validate:
                required: true
        -
            name: attachments
            label: 'Attachment (PDF only)'
            type: file
            multiple: true
            accept:
                - application/pdf
            validate:
                required: false
        -
            name: honeypot
            type: honeypot
    buttons:
        -
            type: submit
            value: Submit
    process:
        -
            addpage: null
        -
            redirect: '@self'
---

Please write your assignment and attach any images and/or files.

Supposing the user has not changed the pre filled title field, has entered his name "Paul Walker", has entered a simple "q.e.d." as the assignment content and uploaded one PDF document, then the full new page will be:

---
visible: true
status: draft
course:
  assignment: 'CMPT363 E100'
instructor:
  name: 'Jane Doe'
name: 'Paul Walker'
title: 'CMPT363 E100'
attachments:
  /Users/rwgc/devroot/repos/grav-test/htdocs/user/pages/assignments/cmpt363-e100/drafts/cmpt363-e100-1/scrum-guide-sept-2013.pdf
    name: scrum-guide-sept-2013.pdf
    type: application/pdf
    size: 273 KB
    path: /Users/rwgc/devroot/repos/grav-test/htdocs/user/pages/assignments/cmpt363-e100/drafts/cmpt363-e100-1/scrum-guide-sept-2013.pdf
---

q.e.d.

On the file system level the file structure will be:

01.home/
  default.md
02.add-new-article/
  default.md
03.assignments/
  cmpt363-e100/
    default.md
    drafts/
      cmpt363-e100-1/
        default.md
        scrum-guide-sept-2013.pdf
      modular.md
    reviewed/
      modular.md

Form page example 2: create a blog post

In this example the user can add a blog post. To ensure the new page will be treated as a blog post simply set the template variable to be used by the new page to item. BTW the active theme must include the corresponding template item.html.twig. This is why it is best to start with Grav's default theme Antimatter.

---
title: 'Add Blog Post'
template: form
pageconfig:
    parent: '/blog'
    include_username: true
    overwrite_mode: true
pagefrontmatter:
    template: item
    title: My new Blog post
    taxonomy:
        category: blog
        tag: [journal, guest]
form:
    name: add_page.blogpost
    fields:
        -
            name: author
            label: 'Author'
            type: text
        -
            name: title
            label: 'Post Title'
            type: text
        -
            name: taxonomy.tag
            label: 'Tags (comma separated)'
            type: text
        -
            name: content
            label: 'Post Content'
            type: textarea
            size: long
            classes: editor
        -
            name: images
            label: 'Images to upload'
            type: file
            multiple: true
            accept:
                - 'image/*'
        -
            name: honeypot
            type: honeypot
    buttons:
        -
            type: submit
            value: Submit
    process:
        -
            add_page: true
        -
            redirect: '/blog'
---

## New Blog Post

Write your blog post:

After the form has been submitted the user is taken to the blog main page where the new post should show up.

Issues

Grav Form issue

The form on the form page is a standard Grav form. Please note that the Grav Form Plugin currently (latest test using version 4.0.1) has an issue which prevents the form to be submitted when a form field of type file is set to required: true(see issue #106).

Credits