Pagebuilder in a specific controller
aledevil opened this issue · 23 comments
good evening,
I have a project already started and running with Laravel 5.7.
I would like to give my users the possibility to create web pages through this page builder and therefore I would like to integrate this page builder into a specific controller of my project.
I tried to install it with the composer, but I can't edit the files to apply it only to a controller because they all files remain in the vendor folder and are not published in my project
Hi, I would suggest you in the pagebuilder.php
config file to set use_login
, use_website_manager
and use_router
to false. Now the default PHPageBuilder login area and the frontend routes are disabled. Next you will need to implement your own controller actions for launching the pagebuilder and for serving all created pages. I am planning to make this easier and integrate it into the Laravel-Pagebuilder project, but at the moment this is what I used in another project:
To manage pages
Create a basic table view that shows pages that are stored in a pagebuilder__pages
table in your database. Add basic functionality to create/edit/delete a page and a button for each page to launch the pagebuilder.
To launch the pagebuilder
routes\web.php
Route::any('/admin/pages/{id}/build', 'App\Http\Controllers\PageBuilderController@build')->name('pagebuilder.build');
Route::any('/admin/pages/build', 'App\Http\Controllers\PageBuilderController@build');
config\pagebuilder.php
'pagebuilder' => [
'class' => PHPageBuilder\Modules\GrapesJS\PageBuilder::class,
'url' => '/admin/pages/build', // the route you created for your pagebuilder controller
'actions' => [
'back' => '/admin/pages' // URL to a table overview of all pages
]
],
App\Providers\AppServiceProvider.php boot method
// register singleton phppagebuilder (this ensures all phpb_ helpers have the right config without first manually creating a pagebuilder instance)
$this->app->singleton('phpPageBuilder', function($app) {
return new PHPageBuilder(config('pagebuilder'));
});
$this->app->make('phpPageBuilder');
resources\views\pagebuilder\scripts.blade.php
<script type="text/javascript">
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
}
});
window.customConfig = {
assetManager: {
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
}
}
};
</script>
App\Http\Controllers\PageBuilderController.php
/**
* Edit the given page with the page builder.
*
* @param int|null $pageId
* @throws Throwable
*/
public function build($pageId = null)
{
$route = $_GET['route'] ?? null;
$action = $_GET['action'] ?? null;
$pageId = is_numeric($pageId) ? $pageId : ($_GET['page'] ?? null);
$pageRepository = new \PHPageBuilder\Repositories\PageRepository;
$page = $pageRepository->findWithId($pageId);
$phpPageBuilder = app()->make('phpPageBuilder');
$pageBuilder = $phpPageBuilder->getPageBuilder();
$customScripts = view("pagebuilder.scripts")->render();
$pageBuilder->customScripts('head', $customScripts);
$pageBuilder->handleRequest($route, $action, $page);
}
To publicly serve all pages
routes\web.php
Add this at the bottom of your routes file
Route::any('{uri}', [
'uses' => 'App\Http\Controllers\WebsiteController@uri',
'as' => 'page',
])->where('uri', '.*');
App\Http\Controllers\WebsiteController.php
/**
* Show the website page that corresponds with the current URI.
*/
public function uri()
{
$pageBuilder = app()->make('phpPageBuilder');
$pageBuilder->handlePublicRequest();
}
Hello there, thank you very much for your help
i've setup all page for index/create/delete my pages
i've setup the "edit" button that call your build function but i got always this error
Error
"Argument 3 passed to PHPageBuilder\Modules\GrapesJS\PageBuilder::handleRequest() must implement interface PHPageBuilder\Contracts\PageContract or be null, instance of App\PageBuilder given, called in C:\xampp\htdocs\crmhotel\app\Http\Controllers\PageBuilderController.php on line 166 "
This my function build
` /**
* Edit the given page with the page builder.
*
* @param int|null $pageId
* @throws Throwable
* @throws \Throwable
*/
public function build($pageId = null)
{
$pageId = is_numeric($pageId) ? $pageId : ($_GET['page'] ?? null);
$page = PageBuilder::find($pageId);
$route = $_GET['route'] ?? null;
$action = $_GET['action'] ?? null;
$phpPageBuilder = app()->make('phpPageBuilder');
$pageBuilder = $phpPageBuilder->getPageBuilder();
$customScripts = view("pagebuilder.scripts")->render();
$pageBuilder->customScripts('head', $customScripts);
$pageBuilder->handleRequest($route, $action, $page);
}
`
the variable $page call the method PageBuilder, it's correct? where i'm doing wrong?
This is my model
class PageBuilder extends Model { protected $table = "pagebuilder_pages"; protected $fillable = ['name', 'layout', 'data']; }
$pageBuilder->handleRequest($route, $action, $page);
expects the $page
argument to implement the PHPageBuilder\Contracts\PageContract
to ensure all methods that the pagebuilder will call are present on the Page instance. So it should not be your created eloquent model, but a PHPageBuilder\Page
instance (with the same id as your eloquent model instance would have). In the code I gave I did not explain where my $page
came from, so I will update that in a minute to make my snippet complete. It should be:
$pageRepository = new \PHPageBuilder\Repositories\PageRepository;
$page = $pageRepository->findWithId($pageId);
Ok perfetct!
i add this function to my controller
public function page($pageId = null) { $pageRepository = new \PHPageBuilder\Repositories\PageRepository; $page = $pageRepository->findWithId($pageId); return $page; }
now if i call the url "/pagebuilder/1/build" (1 is id of my page), i got the loader, but it keeps spinning forever
another question:
when i create a new page, i add a row in db in table pagebuilder_pages with name and data, what i have to pass to "layout"? (using demo theme)
i have to add a row in pagebuilder_page_translations with page id, locale, title and route?
thank you again
A layout is a default html structure in which all your page blocks will be loaded. The layouts are stored in the themes\[theme-name]\layouts
folder. I added a default "master" layout which just includes the default html structure with all style and script tags. But you could also create for example a "header-footer" layout which also includes a header and footer by default to any of your pages that have this layout. So the layout field of a page should be the name of the folder in which you store your layout's view.php
file.
You indeed need to also have a record in the pagebuilder__page_translations
table, with the page id, the locale (probably en
) and the route (which is the URL you access that page on in that language). Hopefully that will solve the spinner issue.
now miss the assets
i got an error in console log for "/assets/pagebuilder/page-injections.js:1"
with "Uncaught ReferenceError: $ is not defined" at Object.15 and Object.16
if i try to open "/assets/pagebuilder/grapesjs-touch.min.js.map"
i got "Asset not found"
I know that error and have fixed it in the PHPageBuilder project. For now can you try a different browser than Chrome or do an extra page reload if the error occurs? I will soon create a new release.
the error of asset not found disappear, thank you
but got alway this
page-injection.js:1
Uncaught ReferenceError: $ is not defined
at Object.16 (page-injection.js:1)
at e (page-injection.js:1)
at Object.15 (page-injection.js:1)
at e (page-injection.js:1)
at page-injection.js:1
at page-injection.js:1
and loading pagebuilder never stopped
I just made a v0.10.1 release. Could try a composer update
and see if the latest PHPageBuilder solves the issue.
yep! now works!
thank you very much for your help
Great! You're welcome
this is not a issue, but a request
there is a way to include a plugin of grapejs?
for example if i want to include the plugin: gjs-preset-webpage
how i can do? i have to create all blocks?
The way grapesjs-blocks-basic
as part of gjs-preset-webpage
is created it takes a very long time to create custom blocks (it is fully JS instead of just a piece of html in a file) and it is next to impossible to easily augment it with dynamic functionality (PHP that adds additional values and html structure), so therefore PHPageBuilder works completely different without any user supplied JS. Imagine you would be writing this for each of your blocks. It takes a lot of effort to build it and to learn how the syntax works. As this project has a heavily customized version of GrapesJS, unfortunately we cannot use the basic blocks of GrapesJS.
However, in this project each block has just a simple .html or a .php file and that's it. Creating blocks is now just a matter of tearing an awesome HTML5 theme apart into small snipets (i.e. blocks) and you're done.
That being said, I can imagine that is still not always pleasant to do this for each new website so I am planning to create a default theme based on bootstrap that has blocks for each bootstrap component.
That being said, I can imagine that is still not always pleasant to do this for each new website so I am planning to create a default theme based on bootstrap that has blocks for each bootstrap component.
that would be really cool! if I can help you let me know
I'll start by creating theme that i need and then I'll show you if you want
thank you very much again for your help
Awesome! It would be cool to have some example material somewhere, for others to quickly get started. The bootstrap theme is getting there, as well as better documentation, but at the moment I was still busy improving the system and build it while directly using it for some projects.
For reference, this is what I recently quickly build: https://www.gambiabirdingtours.com using PHPageBuilder and the boilerplate (not even Laravel), based on this theme. It was really just cutting up the template, create the pages with the desired blocks, add texts, improve styling and done. I was thinking about sharing the code, but it uses a paid template so I guess I just have to do a bootstrap version in the near future.
What I can share already, is an example of the theme structure I used:
I use a cronjob to automatically take screenshots of the rendered blocks once a block has changed: https://github.com/HansSchouten/PHPageBuilder-Laravel-Screenshots. Each file contains the segment that should be added into your own project and you should run composer require spatie/browsershot
.
To assign a block to another group, create a config.php
in the folder of your block and add the following:
<?php
return [
'category' => 'Group name',
];
i'm still tring to create some block, but some block created with view.html can't be edited in page builder
for example if i create a block "link" with insile view.html only the some text this have setting and can be edited in pagebuilder
but if i create a block input with label, the label can't be edit in pagebuilder
could you say why this? thank you
That is correct, at the moment I did not create a sidebar settings for the input placeholder attributes, but I did create settings for a Link. So that explains this behaviour, this will be further extended.
Or do you mean an actual <label></label>
is not text editable?
i create a block like this
<div class="form-group"><label for="text">Label input</label><input type="text" class="form-control" id="text" name="text" placeholder="Placeholder" /></div>
and the text "label input" is not editable
if i put text on a p tag is editable
Ah ok, that is an obvious bug, I will make it editable in the next release. About the placeholder I was already aware that it still had to be implemented.
Hi,
I have updated the grapesjs version from 0.15.9 provided in the package to 0.17.27 by updating the import of CDN in the package due to the unavailability of many events in older grapesjs version. After updating the version I am getting error in the app.js file which is in the public/assets/pagebuilder folder, the same file which is in the dist folder of phpagebuilder package. The error is "Uncaught TypeError: Cannot read properties of null (reading 'attributes')". It occurs in other basic functionalities like changing button text or uploading image. The component is removed so accessing its attribute property is giving the error.
Is there any way to generate this app.js file for the latest version of grapesjs or any other proper way to update grapesjs version? Your feedback in this regard will be highly appreciated.