After trying to use the Guestbook plugin in my Agency themed site, witch result as too hard for me, lets try thing differently !
So now my next option is to try Comments plugin.
When searching for the keywords comments + agency, I get only my own post, so no feedback available on the forum for this combination : Did someone already experienced something similar ?
@citoyencandide, Sharing you requirements might be helpful because a ‘guestbook’ could be very simple, or more complex.
A very simple solution could be a ‘contact’-like form that sends a notification email and saves the form into a file, like plugin Guestbook and Comments do. A small plugin can then read the file, pass the reviews into a Twig template that formats the list. No interface in Admin, just manually editing the file containing the feedback and set the ‘approved’ variable to true.
A more complex scenario is that an end-user must be able to approve / disapprove / delete reviews from Admin. Is pagination required for a long list of reviews?
A form where visitor submit a comment, witch is concatenated with previous comments.
Manual edition is fine to me to set the approved messages.
Pagination, you mean several columns ? It’s a good idea ^^
But in my mind, a typical guest book is a blank notebook in which the comments are manually written one below the other …
on internet, comments are more likely written one above the other, so it would be preferable, all on one column.
No, pagination is often used in Blogs where there are many blog-items. By pagination only 5-10 blog items are shown at the same time. Using buttons one can see the next/previous set of 5-10 blog-items.
Ok, I’ve a had a little fun and tried to create a proof-of-concept of my own suggestion… Here is how to get a very simple and unpolished guestbook in theme Agency.
Install Devtools to easily create themes/plugins: $ bin/gpm install devtools
Theme:
To prevent loss of modification when Agency gets updated, create an inheriting (child) theme of Agency: $ bin/plugin devtools new-theme.
Name the theme “MyAgency”
Tell Grav in /user/config/system.yaml to use the new theme:
pages:
theme: my-agency
In our child-theme, we are going to override template /user/themes/agency/templates/modular/form.html.twig, to fix a few things.
Copy file /user/themes/agency/templates/modular/form.html.twig into folder /user/themes/my-agency/templates/modular/
Above line 10, add the following:
{% set form = forms(page.header.form.name) %}
This will fix collisions with the form for the guestbook.
To fix non closing elements, add the following at the bottom of the file:
</div>
</div>
</section>
Plugin:
Create your own custom Guestbook plugin: $ bin/plugin devtools new-plugin.
Name the plugin SimpleGuestbook. The name Guestbook is not possible because it already exists.
Add the following to the configuration file user/plugins/simple-guestbook/simple-guestbook.yaml:
enabled: true
addCss: true # true|false to add css to give Guestbook same styling as Contact
routes: # Add routes on which Guestbook should be displayed
# - / # Home page
Copy above config file into folder user/config/plugins/ and alter for your environment.
Add logic to user/plugins/simple-guestbook/simple-guestbook.php to retrieve the items from the Guestbook. Replace entire contents with the following code:
Content of simple-guestbook.php
<?php
namespace Grav\Plugin;
use Composer\Autoload\ClassLoader;
use Grav\Common\Plugin;
use Grav\Framework\File\File;
use Symfony\Component\Yaml\Yaml;
/**
* Class SimpleGuestbookPlugin
* @package Grav\Plugin
*/
class SimpleGuestbookPlugin extends Plugin
{
/**
* @return array
*
* The getSubscribedEvents() gives the core a list of events
* that the plugin wants to listen to. The key of each
* array section is the event that the plugin listens to
* and the value (in the form of an array) contains the
* callable (or function) as well as the priority. The
* higher the number the higher the priority.
*/
public static function getSubscribedEvents(): array
{
return [
'onPluginsInitialized' => [
// Uncomment following line when plugin requires Grav < 1.7
// ['autoload', 100000],
['onPluginsInitialized', 0]
]
];
}
/**
* Composer autoload
*
* @return ClassLoader
*/
public function autoload(): ClassLoader
{
return require __DIR__ . '/vendor/autoload.php';
}
/**
* Initialize the plugin
*/
public function onPluginsInitialized(): void
{
// Don't proceed if we are in the admin plugin
if ($this->isAdmin()) {
return;
}
// Enable the main events we are interested in
$this->enable([
// Put your main events here
'onAssetsInitialized' => ['onAssetsInitialized', 0],
'onTwigTemplatePaths' => ['onTwigTemplatePaths', 0],
'onTwigSiteVariables' => ['onTwigSiteVariables', 0],
]);
}
public function isOnRoute(): bool
{
$uri = $this->grav['uri']->uri();
$routes = $this->config->get("plugins.$this->name.routes", '');
$enable = $routes && (
(gettype($routes) === 'string' && $routes === $uri) ||
(is_array($routes) && in_array($uri, $routes)));
return $enable;
}
public function onTwigTemplatePaths(): void
{
$this->grav['twig']->twig_paths[] = "plugins://$this->name/templates";
}
public function onTwigSiteVariables(): void
{
$twig = $this->grav['twig'];
$twig->twig_vars['simpleGuestbook'] = $this->readGuestbookEntries();
}
public function readGuestbookEntries(): array
{
/** @var File */
$fileInstance = new File('user-data://simple-guestbook/guestbook.yaml');
if (!$fileInstance->exists()) {
$fileInstance->save('');
}
$content = $fileInstance->load();
$comments = Yaml::parse($content) ?? [];
$approved = array_filter($comments, function ($comment) {
return $comment['approved'];
});
return $approved;
}
public function onAssetsInitialized()
{
if ($this->config->get('plugins.simple-guestbook.addCss', true)) {
$this->grav['assets']->addCss("plugin://simple-guestbook/css/style.css");
}
}
}
Create new template /user/plugins/simple-guestbook/templates/modular/guestbook-form.html.twig to display the Guestbook.
Content of guestbook-form.html.twig
<section id="simple-guestbook">
<div class="container">
<div class="row">
<div class="col-lg-12 text-center">
{{ content|raw }}
</div>
</div>
{% if simpleGuestbook|count > 0 %}
<div class="row">
<div class="col-lg-12 text-center">
{% include "partials/simple-guestbook-list.html.twig" %}
</div>
</div>
{% endif %}
<div class="row">
{% set form = forms('simple-guestbook') %}
{% if form is null %}
{% set form = grav.session.getFlashObject('form') %}
{% endif %}
{% include 'partials/form-messages.html.twig' %}
{% set scope = scope ?: 'data.' %}
{% set multipart = '' %}
{% set method = form.method|upper|default('POST') %}
{% for field in form.fields %}
{% if (method == 'POST' and field.type == 'file') %}
{% set multipart = ' enctype="multipart/form-data"' %}
{% endif %}
{% endfor %}
{% set action = form.action ? base_url ~ form.action : base_url ~ page.route ~ uri.params %}
{% if (action == base_url_relative) %}
{% set action = base_url_relative ~ '/' ~ page.slug %}
{% endif %}
<form name="{{ form.name }}" action="{{ action }}" method="{{ method }}" {{ multipart }} {% if form.id %} id="{{ form.id }}" {% endif %} {% block form_classes %} {% if form.classes %} class="{{ form.classes }}" {% endif %} {% endblock %}> {% block inner_markup_fields_start %}{% endblock %}
<div class="col-md-6">
{% for field in form.fields %}
{% if field.position == 'left' %}
{% set value = form.value(field.name) %}
<div class="form-group">
{% include "forms/fields/#{field.type}/#{field.type}.html.twig" ignore missing %}
</div>
{% endif %}
{% endfor %}
</div>
<div class="col-md-6">
{% for field in form.fields %}
{% if field.position == 'right' %}
{% set value = form.value(field.name) %}
<div class="form-group">
{% include "forms/fields/#{field.type}/#{field.type}.html.twig" ignore missing %}
</div>
{% endif %}
{% endfor %}
</div>
{% include "forms/fields/formname/formname.html.twig" %}
{% block inner_markup_fields_end %}{% endblock %}
{% block inner_markup_buttons_start %}
<div class="buttons">
{% endblock %}
<div class="col-lg-12 text-center">
<div class="form-group">
{% for button in form.buttons %}
{% if button.outerclasses is defined %}
<div class="{{ button.outerclasses }}">
{% endif %}
{% if button.url %}
<a href="{{ button.url starts with 'http' ? button.url : url(button.url) }}">
{% endif %}
<button {% if button.id %} id="{{ button.id }}" {% endif %} {% block button_classes %} class="{{ button.classes|default('button') }}" {% endblock %} {% if button.disabled %} disabled="disabled" {% endif %} type="{{ button.type|default('submit') }}" {% if button.task %} name="task" value="{{ button.task }}" {% endif %}>
{{ button.value|t|default('Submit') }}
</button>
{% if button.url %}
</a>
{% endif %}
{% if button.outerclasses is defined %}
</div>
{% endif %}
{% endfor %}
</div>
</div>
{% block inner_markup_buttons_end %}
</div>
{% endblock %}
{{ nonce_field('form', 'form-nonce')|raw }}
</form>
</div>
</div>
</section>
Create new template /user/plugins/simple-guestbook/templates/forms/data.yaml.twig to save the form in Yaml format.
Create new template user/plugins/simple-guestbook/templates/partials/simple-guestbook-list.html.twig to list the Guestbook entries from /user/data/simple-guestbook/guestbook.yaml:
Content of simple-guestbook-list.html.twig
<p class="count">{{ simpleGuestbook|count }} guest(s) has left a note</p>
<ul>
{% for item in simpleGuestbook %}
<li>
<div class="name">{{ item.name }}</div>
<div class="email">{{ item.email }}</div>
<div class="message">{{ item.message| raw }}</div>
</li>
{% endfor %}
</ul>
Add css file user/plugins/simple-guestbook/css/style.css, to create same format as Contact form. Yes, I know, we should use scss…
This is an environment running PHP and Apache on a local machine i.e. laptop/desktop (Apple, Windows or Linux) and not a remote server over which one has no control.
Does Grav fit your needs?
Please note, Grav has been created with developers in mind. Grav is indeed a breeze to adapt and extend when one has experience with programming languages like PHP, Twig and, to a lesser extent, Javascript.
A non-developer, might use Grav successfully if one can except what Grav themes offer out-of-the-box, maybe extended with plugins which offer extra functionality. But as soon as that does not fit ones needs, experience with PHP, Twig, HTML, CSS/SCSS are essential.
If the skills are not available, maybe other environments like Wix (“Wix is user-friendly and makes it possible to build a professional website without knowing how to code.”) , wordpress.com, or others may be a better choice.
It seems that this issue has been solved or isn’t important any more. But as it’s one of the first search results for ‘grav guestbook’, I wanted to add that integration of the guestbook plugin is quite simple if the desired theme already contains blog pages and the guestbook entries may look like blog entries.
I have just done that for the Future2021 theme without changing anything in the guestbook plugin itself.