Library for working with SEO parameters of models
You add 2 fields to you model:
seo_url
VARCHAR: it is unique model name, example:http://example.com/post/<seo_url>
.seo_meta
TEXT: it is serialized array:['title' => 'Post title', 'desc' => 'Post description', 'keys' => 'Post title, other keywords...']
.
This behavior help you with:
- Generate
seo_url
from model title considering your unique-conditions. - Internationalization for
seo_meta
. - Get model view url by simple call
$model->viewUrl
. (return relative url/post/my-first
and even/cat1/cat2/awesome-post
is possible). - Output model seo fields(internationalized) to html:
<title>
,<meta name="description">
and<meta name="keywords">
- Form fields for
seo_url
and allseo_meta
and internationalizations fields if needed. - You can(must) configure
seo_meta
fields generator, for example: keywords is:<postTitle>, key1, key2, <postTags>, ...
.
Examples of generated seo_url
for some cases:
http://example.com/first-category/awesome-post
- post1, cat1,seo_url
isawesome-post
http://example.com/other-category/awesome-post
- post2, cat2,seo_url
isawesome-post
also possiblehttp://example.com/first-category/awesome-post_
- post3, cat1,seo_url
isawesome-post_
(add underscore at end if name in post category already used)
Run
composer require "demi/seo" "~1.0"
Each view should have access to demi\seo\SeoViewBehavior
methods.
So configure /frontend/config/main.php
:
return [
'components' => [
'view' => [
'as seo' => [
'class' => 'demi\seo\SeoViewBehavior',
// options by default:
'titleTemplate' => '{title} - {appName}',
'descriptionTemplate' => '{description}',
'keywordsTemplate' => '{keywords}',
]
],
],
];
In model file add seo model behavior:
<?php
public function behaviors()
{
return [
'seo' => [
'class' => 'demi\seo\SeoModelBehavior',
'seoConfig' => [
'urlField' => 'seo_url',
'metaField' => 'seo_meta',
// attribute name or anonymous function
'urlProduceField' => 'title',
// attribute name or anonymous function
'titleProduceFunc' => 'title',
// attribute name or anonymous function
'descriptionProduceFunc' => 'short_desc',
// attribute name or anonymous function
'keysProduceFunc' => static function (self $model) {
return $model->title . ', tag1, tag2';
},
// when user can manage model seo-fields (anonymous function possible)
'clientChange' => Yii::$app->has('user') && Yii::$app->user->can(User::ROLE_ADMIN),
// param for Url::to(<viewRoute>)
'viewRoute' => '/post/view',
// param for Url::to(<viewRoute>, ['title' => $model->seo_url])
'linkTitleParamName' => 'title',
// only anon-function returns array of additional link params with values
'additionalLinkParams' => static function (self $model) {
// Url::to(<viewRoute>, ['title' => $model->seo_url, 'category' => $model->category->seo_url])
return ['category' => $model->category->seo_url];
},
// if you model have some unique condition
'uniqueUrlFilter' => function (\yii\db\ActiveQuery $query) {
$query->andWhere(['category_id' => $this->category_id]);
},
// if array - seo_meta will have possible to internationalization
'languages' => 'en',
// Optional. All controller actions will added to stop-list for seo_url value.
// For example: if you create model with seo_url = 'delete' you can't open model by url '/post/delete',
// if this option enabled, then seo_url will be 'delete_' and url: '/post/delete_'
'controllerClassName' => '\frontend\controllers\PostController',
// @see [\demi\seo\SeoModelBehavior] for more properties
],
],
];
}
PHPdoc for model:
/**
* @property-read array $seoData
* @method array getSeoData($lang = null) Metadata for this model
* @method \demi\seo\SeoModelBehavior getSeoBehavior()
* @property-read array $viewUrl
* @method array getViewUrl() URL to material view page
* @property-read array $absoluteViewUrl
* @method array getAbsoluteViewUrl() Absolute URL to material view page
*/
Change /frontend/views/layouts/main.php
:
<?php
/* @var $this \yii\web\View|\demi\seo\SeoViewBehavior */
?>
<head>
<!-- Replace default <title> tag -->
<title><?= Html::encode($this->title) ?></title>
<!-- by this line: -->
<?php $this->renderMetaTags(); ?>
...
</head>
In "view.php" file for model:
// set SEO:meta data for current page
$this->setSeoData($model->getSeoBehavior());
// Helper: set <link> tag for "no index" (and optional "no follow") for current page
$this->noIndex($and_no_follow_bool);
or in controller:
Yii::$app->view->setSeoData($model->getSeoBehavior());
Yii::$app->view->noIndex($and_no_follow_bool);
Simple url rules example in '/frontend/config/main.php':
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
'post/<action:(index|create|update|delete)>' => 'post/<action>',
'post/<title:[-\w]+>' => 'post/view',
],
],
and change /frontend/controllers/PostController.php
:
public function actionView($title)
{
$model = Post::find()->where(['seo_url' => $title])->one();
if (!$model) {
throw new NotFoundHttpException('Post not found');
}
return $this->render('view', [
'model' => $model,
]);
}
// And in actionCreate() and actionUpdate() change
return $this->redirect(['view', 'id' => $model->id]);
// to
return $this->redirect($model->viewUrl);
Get link to model view page. Based on behavior config values: viewRoute
and additionalLinkParams
// return url to material view page: '/post/super-post'
$url = $model->getViewUrl();
$url = $model->viewUrl;
// return absolute url to material view page: 'http://example.com/post/super-post'
$abs_url = $model->getAbsoluteViewUrl();
$abs_url = $model->absoluteViewUrl;
// Behind scene (for understanding):
return Url::to([$viewRoute, ['title' => $model->$titleField] + $additionalLinkParams]], $isAbsolute);
Render SEO:url and SEO:meta fields in the "/frontend/views/post/_form.php" file:
<?php
/* @var $model common\models\Post|demi\seo\SeoModelBehavior */
?>
...
<?php $model->renderFormSeoFields($ActiveForm_or_void); ?>