Git Product home page Git Product logo

Comments (8)

HansSchouten avatar HansSchouten commented on June 8, 2024

Hi, I thanks for the feedback. I have to look into editing (un)ordered lists, I think it is because they are not editable as a whole or CKEditor changes it into a paragraph tag or something. What I do is I have in my laravel project a simple menu builder (for example with nestable). Then, I use a .php block that loads all items of the menu stored in the database, so I do not have to edit the menu manually from within the pagebuilder (on every page).

As you can see in this image, it should be possible to edit a css background image.
afbeelding

I think you mean creating custom layouts from within your application (similar to the master layout) and then add some default blocks. That is indeed very helpful. I have it in my platform that integrates the pagebuilder, so it certainly is already possible to build this on top of the pagebuilder.

I have a separate page_layouts table that has the same structure as the pages table. This is the controller action that I am using:

public function buildLayout($pageLayoutId = null)
{
	$route = $_GET['route'] ?? null;
	$action = $_GET['action'] ?? null;

	// override settings to use the pagebuilder on layouts instead of pages
	config([
		'pagebuilder.pagebuilder.url' => '/admin/website/page-layouts/build',
		'pagebuilder.pagebuilder.actions.back' => '/admin/website/page-layouts',
		'pagebuilder.page.class' => \PHPageBuilder\Page::class,
		'pagebuilder.page.translation.class' => \PHPageBuilder\PageTranslation::class,
		'pagebuilder.page.table' => 'page_layouts',
	]);

	// refresh the PhpPageBuilder singleton with the updated config
	app()->extend('phpPageBuilder', function ($command, $app) {
		return new PHPageBuilder(config('pagebuilder'));
	});

	// get the page layout as Page object
	$pageLayoutId = is_numeric($pageLayoutId) ? $pageLayoutId : ($_GET['page'] ?? null);
	$pageRepository = new PageRepository;
	/* @var PageContract $pageLayout */
	$pageLayout = $pageRepository->findWithId($pageLayoutId);

	/* @var PHPageBuilder $phpPageBuilder */
	$phpPageBuilder = app()->make('phpPageBuilder');
	$pageBuilder = $phpPageBuilder->getPageBuilder();

	$customScripts = view("website::pagebuilder.scripts")->render();
	$pageBuilder->customScripts('head', $customScripts);
	$pageBuilder->handleRequest($route, $action, $pageLayout);
}

And I have an class that overrides the PageRenderer, in order to render the layout.
The code is not fully copy pastable, since I am using certain repositories that I created, but it gives an idea of how I use it.

use Exception;
use Falco\Website\Repositories\PageLayoutRepository;
use PHPageBuilder\Contracts\PageContract;
use PHPageBuilder\Page;
use PHPageBuilder\ThemeBlock;

class PageRenderer extends \PHPageBuilder\Modules\GrapesJS\PageRenderer
{
    /**
     * Return the rendered version of the page.
     *
     * @return string
     * @throws Exception
     */
    public function render()
    {
        // init variables that should be accessible in the view
        $renderer = $this;
        $page = $this->page;
        if ($this->forPageBuilder) {
            $body = '<div phpb-content-container="true"></div>';
        } else {
            $body = $this->renderBody();
        }

        // recursively render page layouts in which the page body will be added
        list($layoutPath, $body) = $this->renderLayouts($page, $this->getPageLayoutPath(), $body);

        if ($layoutPath) {
            ob_start();
            require $layoutPath;
            $html = ob_get_contents();
            ob_end_clean();
        } else {
            $html = $body;
        }

        // parse any shortcodes present in the page layout
        $html = $this->parseShortcodes($html);

        return $html;
    }

    /**
     * Recursively render all nested layouts, starting from the outer layout with finally a configured base layout from the current theme.
     *
     * @param PageContract $parent
     * @param $parentLayoutPath
     * @param $renderedParentBody
     * @return array
     * @throws Exception
     */
    protected function renderLayouts(PageContract $parent, $parentLayoutPath, $renderedParentBody)
    {
        // render the layout if a page_layout_id is passed, or the layout field has a numeric value (so it contains reference to a custom page layout)
        if ((is_null($parent->getLayout()) && ! empty($parent->page_layout_id)) || is_numeric($parent->getLayout())) {
            $pageLayoutId = $parent->page_layout_id ?? $parent->getLayout();
            $pageLayout = (new PageLayoutRepository)->findOneByField('id', $pageLayoutId);

            // create a new page renderer to render the page layout (in an empty parent layout)
            $layoutPage = new Page;
            $layoutPage->setData([
                'layout' => null,
                'data' => json_decode($pageLayout->data, true)
            ]);
            $layoutRenderer = new PageRenderer($this->theme, $layoutPage, $this->forPageBuilder);
            $layoutBody = $layoutRenderer->renderBody();

            // replace the layout main container with the page body or body of a parent layout
            $layoutMainContainerBlock = new ThemeBlock($this->theme, 'layout-main-container');
            $layoutMainContainerBlockViewFile = $layoutMainContainerBlock->getViewFile();
            $layoutMainContainerString = file_get_contents($layoutMainContainerBlockViewFile);
            $body = str_replace($layoutMainContainerString, $renderedParentBody, $layoutBody);

            // render layouts in which this layout or page body is contained
            $layoutPath = $this->theme->getFolder() . '/layouts/' . $pageLayout->layout . '/view.php';
            $layoutPage->setData(['layout' => $pageLayout->layout]);
            list($layoutPath, $body) = $this->renderLayouts($layoutPage, $layoutPath, $body);
        }

        // eventually return the base layout (a layout folder of the current theme) of the inner most page layout, and the final page body that combines all layouts
        return [$layoutPath ?? $parentLayoutPath, $body ?? $renderedParentBody];
    }
}

Next, I replaced the PageRenderer class by specifying a class replacement in the phpagebuiler config file.

'class_replacements' => [
    PHPageBuilder\Modules\GrapesJS\PageRenderer::class => Falco\Website\Libraries\PHPageBuilder\PageRenderer::class
],

from laravel-pagebuilder.

Dontorpedo avatar Dontorpedo commented on June 8, 2024

nice, thank you for the code!

what i meant is, i cant edit the text inside the block which has a background image.

i found out its not possible to put a block inside a block or did i miss something?

i created some "general" blocks like column, text, button and so on and tried to put the text or button block inside the colulmn, but thats not possible :(

from laravel-pagebuilder.

HansSchouten avatar HansSchouten commented on June 8, 2024

In my screenshot I have a text-editable block with a background image, so it should be a problem with your specific block html structure. I just used a block with a view.html which contains a <p> tag with some example text.

You cannot just drop blocks everywhere, but you can create a blocks container in which it is possible to drop blocks. You create a blocks container by following these steps.

from laravel-pagebuilder.

HansSchouten avatar HansSchouten commented on June 8, 2024

I reproduced the problem with li tags being removed and I just committed a fix.

from laravel-pagebuilder.

billiemead avatar billiemead commented on June 8, 2024

@HansSchouten

I am trying to integrate the layouts table as you detailed above.

I was wondering if you could give an example of what to use inside of PageLayoutRepository and the master layout file view.php? Also, where does the helper method findOneByField come from as Laravel 6 is giving me a hard time with it?

Cheers,
Billie

from laravel-pagebuilder.

HansSchouten avatar HansSchouten commented on June 8, 2024

You are correct, I see that method is part of the boilerplate I am working with, the findOneByField does this:

    public function findOneByField($field, $value = null, $columns = ['*'])
    {
        $model = $this->findByField($field, $value, $columns = ['*']);
        return $model->first();
    }

So just a findByField with a first.

PageLayoutRepository is a simple class I use that allows an abstraction for CRUD on page layouts (with some customization for my use cases). In standard Laravel a PageLayout class extending the base eloquent Model class would also work just fine.

This is a simplified version of my current master layout:

<!DOCTYPE html>
<html lang="<?= phpb_current_language() ?>">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title><?= e($page->getTitle()) ?></title>
    <meta name="description" content="<?= e($page->getMetaDescription()) ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <meta name="csrf-token" content="<?= e(csrf_token()) ?>">

    <link rel="stylesheet" href="<?= themeAssetVersion('css/app.css') ?>">
</head>
<body>

<?= $body ?>

<script src="<?= themeAssetVersion('js/app.js') ?>"></script>
<!-- Run block scripts -->
<script type="text/javascript">
    document.querySelectorAll("script").forEach(function(scriptTag) {
        scriptTag.dispatchEvent(new Event('run-script'));
    });
</script>
<?php
foreach ($page->get('custom-scripts-urls') ?? [] as $scriptUrl):
    echo '<script src="' . e($scriptUrl) . '"></script>';
endforeach;
?>
</body>
</html>

themeAssetVersion is a simple helper method I use to bust outdated cached css/js files:

    /**
     * Return the theme asset path with a version GET parameter based on the latest file change.
     *
     * @param $assetPath
     * @return string
     */
    function themeAssetVersion($assetPath)
    {
        $theme = config('pagebuilder.theme.active_theme');
        $themeFolder = config('pagebuilder.theme.folder') . '/' . $theme;
        $fullAssetPath = $themeFolder . '/public/' . $assetPath;

        if (realpath($fullAssetPath)) {
            $modifiedTime = filemtime($fullAssetPath);
            return url(phpb_theme_asset($assetPath) . '?v=' . $modifiedTime);
        }
        return url(phpb_theme_asset($assetPath));
    }

Ignoring this method and using phpb_theme_asset intead would also work just fine.

from laravel-pagebuilder.

billiemead avatar billiemead commented on June 8, 2024

@HansSchouten
Thank you so much. I will work on this straight away and can't wait to see how it works. Cheers Hans!

from laravel-pagebuilder.

Zeeshan-1313 avatar Zeeshan-1313 commented on June 8, 2024

@HansSchouten can i please update CKeditor
becouse this dont have option for listi

  • builts poitns etc

  • from laravel-pagebuilder.

    Related Issues (20)

    Recommend Projects

    • React photo React

      A declarative, efficient, and flexible JavaScript library for building user interfaces.

    • Vue.js photo Vue.js

      🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

    • Typescript photo Typescript

      TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

    • TensorFlow photo TensorFlow

      An Open Source Machine Learning Framework for Everyone

    • Django photo Django

      The Web framework for perfectionists with deadlines.

    • D3 photo D3

      Bring data to life with SVG, Canvas and HTML. 📊📈🎉

    Recommend Topics

    • javascript

      JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

    • web

      Some thing interesting about web. New door for the world.

    • server

      A server is a program made to process requests and deliver data to clients.

    • Machine learning

      Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

    • Game

      Some thing interesting about game, make everyone happy.

    Recommend Org

    • Facebook photo Facebook

      We are working to build community through open source technology. NB: members must have two-factor auth.

    • Microsoft photo Microsoft

      Open source projects and samples from Microsoft.

    • Google photo Google

      Google ❤️ Open Source for everyone.

    • D3 photo D3

      Data-Driven Documents codes.