eolica / laravel-content-tools
A Laravel package for editing your web frontend translations directly on the page
Installs: 3 701
Dependents: 0
Suggesters: 0
Security: 0
Stars: 3
Watchers: 0
Forks: 0
Open Issues: 0
Requires
- php: ^8.0
- brick/varexporter: ^0.3.7
- illuminate/contracts: ^8.0 || ^9.0 || ^10.0
- illuminate/filesystem: ^8.0 || ^9.0 || ^10.0
- illuminate/http: ^8.0 || ^9.0 || ^10.0
- illuminate/support: ^8.0 || ^9.0 || ^10.0
- illuminate/view: ^8.0 || ^9.0 || ^10.0
Requires (Dev)
- orchestra/testbench: ^6.0 || ^7.0 || ^8.0
- phpunit/phpunit: ^9.0 || ^10.0
README
A Laravel package for editing your web frontend translations directly on the page. It uses ContentTools, a Javascript library that provides a WYSIWYG editor that can be added to any page so we can edit the HTML content inline.
Installation
You can install the package via Composer:
composer require eolica/laravel-content-tools
Once installed, if you are not using automatic package discovery, then you need to register the Eolica\LaravelContentTools\ContentToolsServiceProvider
service provider in your config/app.php
.
'providers' => [ ... /* * Package Service Providers... */ Eolica\LaravelContentTools\ContentToolsServiceProvider::class, ... ],
Or, alternatively, you may register it in your App\Providers\AppServiceProvider
:
namespace App\Providers; use Eolica\LaravelContentTools\ContentToolsServiceProvider; final class AppServiceProvider extends ServiceProvider { public function register(): void { $this->app->register(ContentToolsServiceProvider::class); } ... }
Public assets
Since this package uses public assets you must publish them by using the following artisan command:
php artisan vendor:publish --tag=content-tools:assets --force
To keep the assets up-to-date and avoid issues in future updates, we recommend adding the command to the post-autoload-dump
scripts in your composer.json file:
"scripts": { "post-autoload-dump": [ "@php artisan vendor:publish --tag=content-tools:assets --force --ansi" ] }
The package will inject the published assets into the styles
and scripts
stacks, so you must add these to your layout:
<html> <head> ... @stack('styles') </head> <body> ... @stack('scripts') </body> </html>
Configuration
You may publish the content-tools
config file with the following command:
php artisan vendor:publish --tag=content-tools:config
This will create a config/content-tools.php
file in your app that you can modify to set your configuration.
This is the config file with the default values:
<?php return [ 'routes' => [ 'prefix' => 'content-tools', 'middleware' => ['web'], ], 'editor' => [ 'default_tools' => [ [ 'bold', 'italic', 'link', 'align-left', 'align-center', 'align-right', ], [ 'heading', 'subheading', 'paragraph', 'unordered-list', 'ordered-list', 'table', 'indent', 'unindent', 'line-break', ], [ 'preformatted', ], [ 'undo', 'redo', 'remove', ], ], 'default_video_width' => 400, 'default_video_height' => 300, 'highlight_hold_duration' => 2000, 'min_crop' => 10, 'restricted_attributes' => [ '*' => [], 'img' => ['height', 'width', 'src', 'data-ce-max-width', 'data-ce-min-width'], 'iframe' => ['height', 'width'], ], ], ];
Routes
The routes
option is where you may specify the prefix applied to the package routes if for some reason conflicts with other routes in your application, also you may specify a list of middleware for these routes, by default the web
group middleware is applied.
Editor
The editor
option is where you may specify the ContentTools settings.
Usage
All you need to do is to add the content-tools-translation
component to your Blade view.
<x-content-tools-translation key="web.pages.home.content" />
The key
property maps to a short key defined in your translation files.
You may forward any extra attributes to the component, for example, we could add the class
attribute to style the content:
<x-content-tools-translation key="web.pages.home.content" class="content" />
Fixtures
Imagine we have a home page in our website with a title inside an h1
html tag, we want this title to be translatable but we don't want our users to potentially break the h1
tag, affecting SEO negatively.
This is what fixtures allow us to do. Just add the fixture
attribute with the html tag that you want to be fixed as the value:
<x-content-tools-translation key="web.pages.home.title" fixture="h1" />
We recommend always using fixtures to prevent users from breaking the page layout, and use non-fixture translations only when necessary.
Permissions
By default this package uses the Eolica\LaravelContentTools\PermissionHandler\TruePermissionHandler
that allows anyone that enters your website to edit your translations. This is very useful in local development but in a production environment you will most likely need some kind of authentication check.
This package ships with the Eolica\LaravelContentTools\PermissionHandler\AuthGuardCheckPermissionHandler
that checks if a user of a particular authentication guard is authenticated.
With that in mind, we could bind this implementation in our App\Providers\AppServiceProvider
only when the application is not running in the local environment:
namespace App\Providers; use Eolica\LaravelContentTools\PermissionHandler\AuthGuardCheckPermissionHandler; use Eolica\LaravelContentTools\PermissionHandler\PermissionHandler; final class AppServiceProvider extends ServiceProvider { public function register(): void { if (!$this->app->isLocal()) { $this->app->bind(PermissionHandler::class, function ($app): PermissionHandler { return new AuthGuardCheckPermissionHandler( $app->make('auth')->guard('backend') ); }); } } ... }
Now, in production, only users authenticated via the backend
guard will be able to edit translations. In local development, it will fallback to the Eolica\LaravelContentTools\PermissionHandler\TruePermissionHandler
implementation so we can test easily without the need of authenticating.
Creating your own permission handler
If the Eolica\LaravelContentTools\PermissionHandler\AuthGuardCheckPermissionHandler
is not enough for your use case, you can make your own permission handler implementation.
A permission handler can be any class that implements the Eolica\LaravelContentTools\PermissionHandler\PermissionHandler
interface:
namespace Eolica\LaravelContentTools\PermissionHandler; interface PermissionHandler { public function check(): bool; }
For registering your own permission handler, you may override our default implementation from the service container in your App\Providers\AppServiceProvider
:
namespace App\Providers; use App\ContentTools\PermissionHandler\YourOwnPermissionHandler; use Eolica\LaravelContentTools\PermissionHandler\PermissionHandler; final class AppServiceProvider extends ServiceProvider { public function register(): void { $this->app->bind(PermissionHandler::class, function ($app): PermissionHandler { return new YourOwnPermissionHandler(); }); } ... }
Since our package uses the bindIf
method that registers a binding if it hasn't already been registered, your custom permission handler will take precedence over our default implementation.
Combine multiple permission handlers
Maybe the Eolica\LaravelContentTools\PermissionHandler\AuthGuardCheckPermissionHandler
is good for you, but you want to perform an additional type of check so you made your own permission handler for that specific case and you don't want to copy and paste the built in permission handler code.
For these scenarios this package ships with the Eolica\LaravelContentTools\PermissionHandler\CompositePermissionHandler
that accepts a list of PermissionHandler
.
As always, you may bind this implementation in your App\Providers\AppServiceProvider
:
namespace App\Providers; use App\ContentTools\PermissionHandler\YourOwnPermissionHandler; use Eolica\LaravelContentTools\PermissionHandler\AuthGuardCheckPermissionHandler; use Eolica\LaravelContentTools\PermissionHandler\CompositePermissionHandler; use Eolica\LaravelContentTools\PermissionHandler\PermissionHandler; final class AppServiceProvider extends ServiceProvider { public function register(): void { $this->app->bind(PermissionHandler::class, function ($app): PermissionHandler { return new CompositePermissionHandler( new AuthGuardCheckPermissionHandler($app->make('auth')), new YourOwnPermissionHandler(), ); }); } ... }
Using this approach, instead of potentially creating a big permission handler that performs all kind of different checks, you could create small handlers for every one of them, making the code more flexible and reusable.
Creating your own translation repository
This package ships with the Eolica\LaravelContentTools\Repository\FileTranslationRepository
that persists and loads the translations from php files inside the storage/app/resources/lang
folder. If you want to persist your translations in another source (database, csv, yaml, etc...), you can create your own translation repository.
A translation repository can be any class that implements the Eolica\LaravelContentTools\Repository\TranslationRepository
interface:
namespace Eolica\LaravelContentTools\Repository; interface TranslationRepository { public function save(string $locale, string $group, string $key, string $value): void; public function load(string $locale, string $group): array; }
For registering your own translation repository, you may override our default implementation from the service container in your App\Providers\AppServiceProvider
:
namespace App\Providers; use App\ContentTools\Repository\YourOwnTranslationRepository; use Eolica\LaravelContentTools\Repository\TranslationRepository; final class AppServiceProvider extends ServiceProvider { public function register(): void { $this->app->bind(TranslationRepository::class, function ($app): TranslationRepository { return new YourOwnTranslationRepository(); }); } ... }
Since our package uses the bindIf
method that registers a binding if it hasn't already been registered, your custom repository will take precedence over our default implementation.
Currently missing features
- Translations with parameters support, we still have to come with a good solution for this, any help would be appreciated
- Image upload support for more complex translations
Changelog
Please see CHANGELOG for more information what has changed recently.
Security
If you discover a security vulnerability within this package, please send an email at info@eolicadigital.com instead of using the issue tracker.
License
The MIT License (MIT). Please see License File for more information.