Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yii2 add to head() and endBody()

Tags:

yii2

In developing a site that can have multiple front-end themes, I am looking for a way to allow users on the back-end to manually inject code into the head and body. Two use cases are as follows:

Case 1 - Styles

  1. In the back-end, the user selects a theme.
  2. User likes the theme but would like to make links a different color.
  3. Rather than copy and modify the theme, user can set custom code to execute at end of <head> tag.

Case 2 - Scripts

  1. User wants to add custom JavaScript to end of document but requires an additional JavaScript library as well.
  2. Rather than copy and modify the theme, user can set custom code to execute at and of <body> tag.

I understand that both of these specific cases could be accomplished (in part) with the use of registerCss and registerJs but those automatically wrap whatever is passed to them in <style> or <script> tags. I am hoping there is a way to just directly inject whatever is indicated directly into the head() or endBody() methods. The reason behind this is that I do not wish to limit what the user can inject (perhaps a script tag is needed in the head).

Currently, I am just storing the code-to-be-added in params then manually including them in each theme as follows:

<?php $this->endBody() ?>
<?= $this->params['theme_include_body_end'] ?>

This is undesirable as it can easily be forgotten when creating the theme. I would like to find a way to append my param value to the endBody() call automatically so whenever endBody() is called, my code is included (same for the head() call).

like image 996
justinvoelker Avatar asked Oct 11 '25 18:10

justinvoelker


2 Answers

You can use own View component that overrides methods renderHeadHtml() and renderBodyEndHtml(). In these methods can be injected necessary code as you need:

namespace common/components;

class View extends \yii\web\View {

    /**
     * @var string Content that should be injected to end of `<head>` tag
     */
    public $injectToHead    = '';

    /**
     * @var string Content that should be injected to end of `<body>` tag
     */
    public $injectToBodyEnd = '';

    /**
     * @inheritdoc
     */
    protected function renderHeadHtml()
    {
        return parent::renderHeadHtml() . $this->injectToHead;
    }

    /**
     * @inheritdoc
     */
    protected function renderBodyEndHtml($ajaxMode)
    {
        return parent::renderBodyEndHtml(ajaxMode) . $this->injectToBodyEnd;
    }

}

In config file:

// ...
'components' => [
    // ...
    'view' => [
        'class' => '\common\components\View',
    ]
]

Somewhere in controller code:

\Yii::$app->view->injectToHead = '...';
\Yii::$app->view->injectToBodyEnd = '...';
like image 184
IStranger Avatar answered Oct 14 '25 09:10

IStranger


Yii2 already provide this functionality in View Class by using Block Widget

you need 2 simple steps:

1- (in required View file): in any given view

<?php $this->beginBlock('block1'); ?>

...content of block1...

<?php $this->endBlock(); ?>

...

<?php $this->beginBlock('block3'); ?>

...content of block3...

<?php $this->endBlock(); ?>

2- (in layout): define block name and its place in the layout page

...

<?php if (isset($this->blocks['block1'])): ?>
    <?= $this->blocks['block1'] ?>
<?php else: ?>
    ... default content for block1 ...
<?php endif; ?>

...

<?php if (isset($this->blocks['block2'])): ?>
    <?= $this->blocks['block2'] ?>
<?php else: ?>
    ... default content for block2 ...
<?php endif; ?>

...

<?php if (isset($this->blocks['block3'])): ?>
    <?= $this->blocks['block3'] ?>
<?php else: ?>
    ... default content for block3 ...
<?php endif; ?>
...

Referance: Yii2 Guide

http://www.yiiframework.com/doc-2.0/guide-structure-views.html#using-blocks

I hope this will help someone. Thank you.

like image 43
Muaid Avatar answered Oct 14 '25 09:10

Muaid