Website

Overview

Lamotivo Website Manager is a Laravel package that offers a front-end part of the project and it may be used along with Lamotivo Admin Panel.

Main features:

  • Handling the website with a layout, navigation helpers, SEO tools, forms, widgets.
  • Editing site pages through Eloquent models.
  • Exporting site to an XML sitemap and RSS feeds.
  • Handling site settings.
  • Full customization.
  • Integration with Lamotivo Assets, Lamotivo Themes, Lamotivo Uploads.

Requirements

Lamotivo Website Manager works with Laravel 5.4+ or Laravel 6.

Installation

Require the package:

composer require lamotivo/website

Publish some configuration and migration files:

php artisan vendor:publish --provider="Lamotivo\Themes\ThemeServiceProvider" --tag=config
php artisan vendor:publish --provider="Lamotivo\Assets\AssetServiceProvider" --tag=config
php artisan vendor:publish --provider="Lamotivo\Uploads\UploadServiceProvider" --tag=config
php artisan vendor:publish --provider="Lamotivo\Uploads\UploadServiceProvider" --tag=migrations
php artisan vendor:publish --provider="Lamotivo\Website\SiteServiceProvider" --tag=config
php artisan vendor:publish --provider="Lamotivo\Website\SiteServiceProvider" --tag=website-migrations

Add to the end of your routes/web.php file:


// your routes

Website::routes();

Add to your App\Providers\AppServiceProvider file:

use Website;

public function boot()
{
    Website::boot();
}

Configuration

The default configuration file is config/website.php, each option is well documented.

Basic Layout

Lamotivo Website utilizes Lamotivo Themes as a core front-end interface.

Lamotivo Website ships the website:: Blade's namespaced views.

The default layout is website::layout.app. All pages should extend it:

@extends('website::layouts.app')

@section('content')
    <h1>Page Header</h1>
    <p>Page content goes here...</p>
@endsection

Themes

When you create a theme, typically you should override the Websites's website::partials.header, website::partials.content and website::partials.footer views by placing them in the views/vendor/website/partials directory of your theme.

Pages

Lamotivo Website supports 2 page drivers: file and eloquent.

Page provider list is configured at the website.providers configuration option. Each provider describes some options:

  • driver - supported values are file and eloquent
  • path - a directory where page files are stored, e.g. resource_path('pages')
  • model - a Eloquent model as a source of pages, e.g. Lamotivo\Website\Content\Page::class
  • prefix - a URL prefix
  • cache_time - this value is used to cache page slugs for routing

The website.default_provider option sets a default page provider. It is mostly important, if you use pages without a special URL prefix.

File Page Driver

This driver uses static files as a source of pages.

By default configuration static pages are placed in the resources/pages directory. You may change this, as you wish.

The file format is Markdown.

Eloquent Page Driver

This driver uses an Eloquent model as a source of pages.

Your website may have multiple menus. Each menu is a class that extends the Lamotivo\Website\Navigation\Menu class.

Defining Menu

To generate a menu use the make:menu Artisan command:

php artisan make:menu MainMenu

The freshly create Website menu will have the App\Menu namespace and will be placed in the app/Menu directory.

To populate menu items you should use the __constuct method with calling the menu's add method:

public function __construct()
{
    $this->add(['url' => '/', 'anchor' => 'Home']);
}

You may define a submenu, as well:

$this->add([
    'url' => '/about',
    'anchor' => 'About us',
    'items' => [
        ['url' => '/about/company', 'anchor' => 'Our Company'],
        ['url' => '/about/jobs', 'anchor' => 'Jobs'],
    ],
]);

Registering Menu

Once you have created a menu, you are ready to attach it to the Website configuration, you may use this menu in the menus configuration of your website.php configuration file:

'menus' => [
    'main' => App\Menu\MainMenu::class,
],

Alternatively, you may register a menu in your code:

Website::menu()->register('main', \App\Menu\MainMenu::class)

Rendering Menu

At your Blade views you may use the @website_menu helper to render your menu. This helper accepts a menu name as the first argument. If no argument is passed, the website.default_menu menu will be used.

Breadcrumbs are an important part of almost every website. These navigation aids don't just tell people wgere they are on your website, but they alsow help search engines work out how your site is structured.

To populate your breadcrumb navigation with link items you should use the Breadcrumb Manager:

Website::breadcrumb()->link(url('/'), 'Home')
    ->link(route('products'), 'Products')
    ->link(route('product', $product), $product->name);

Rendering Breadcrumbs

At your views you may use the @website_breadcrumb Blade helper to render your breadcrumb navigation.

SEO and Meta Tags

Website offers a Meta Manager that allows you to handle any meta tags on your website page.

To fill SEO meta tags you may use the fill Meta Manager method and pass an Eloquent model as the first argument.

Website::meta()->fill($page);

The Eloquent model should use the Lamotivo\Website\Seo\SeoMetaTrait trait.

Also, you may assign meta tags using the Website::meta('key', 'value') construction. The valid keys are:

  • title - a value for the title tag
  • description - a value for the meta description tag
  • robots - a value for the meta robots tag
  • keywords - a value for the meta keywords tag
  • ogUrl - a value for the OpenGraph url, if omitted, the current url is used
  • ogSiteName - a value for the OpenGraph url
  • ogType - a value for the OpenGraph url
  • ogTitle - a value for the OpenGraph title, if omitted, the title value is used
  • ogDescription - a value for the OpenGraph description, if omitted, the description value is used
  • ogLocale - a value for the OpenGraph locale
  • ogImage - a value for the OpenGraph image
  • ogImageType - a value for the OpenGraph image type
  • ogImageWidth - a value for the OpenGraph image width
  • ogImageHeight - a value for the OpenGraph image height
  • ogImageSecureUrl - a value for the OpenGraph image secure URL
  • twitterCard - a value for the Twitter card
  • twitterSite - a value for the Twitter site
  • twitterCreator - a value for the Twitter creator
  • twitterTitle - a value for the Twitter title, if omitted, the title value is used
  • twitterDescription - a value for the Twitter description, if omitted, the description value is used
  • twitterImage - a value for the Twitter image

Of course, you are free to add any other meta tag, if needed:

Website::meta()->meta($tagName, $tagValue);

Meta Manager allows you to handle link and script tags, too:

Website::meta()->link('icon', '/favicon.png')
    ->attributes([
        'sizes' => '16x16',
        'type' => 'image/png',
    ]);

Website::meta()->link('stylesheet', '/some.css');

Website::meta()->link('alternate', '/rss.xml');

Website::meta()->script('<script src="/some.js" async></script>');

Some common links have shortcuts:

  • Website::meta()->ampLink($prefix, $url)
  • Website::meta()->icon($href, array $attributes)
  • Website::meta()->shortcutIcon($href, array $attributes = [])
  • Website::meta()->alternate($href, array $attributes = [])
  • Website::meta()->stylesheet($href, array $attributes = [])
  • Website::meta()->next($href, array $attributes = [])
  • Website::meta()->prev($href, array $attributes = [])
  • Website::meta()->search($href, array $attributes = [])
  • Website::meta()->prefetch($href, array $attributes = [])
  • Website::meta()->dnsPrefetch($href, array $attributes = [])
  • Website::meta()->preload($href, array $attributes = [])
  • Website::meta()->preconnect($href, array $attributes = [])
  • Website::meta()->manifest($href, array $attributes = [])
  • Website::meta()->canonical($href)

Meta Configuration

You may setup default meta values at the website.meta configuration option.

Forms

Form Manager handles forms on your website.

Forms are stored in the app/Forms directory.

Form classes must extend the Lamotivo\Website\Forms\Form class.

Registering Form

Once you have created a form, you are ready to attach it to the Website configuration, you may use this form in the forms configuration of your website.php configuration file:

'forms' => [
    'order' => App\Forms\OrderForm::class,
],

Alternatively, you may register a form in your code:

Website::form()->register('order', \App\Forms\OrderForm::class)

Rendering Form

At your views you may use the @website_form('order') Blade helper to render your form. This helper accepts a form name as the first argument.

Using old dynamic Blade helpers, such as like @form_order, is deprecated by now.

Widgets

Widget Manager handles widgets on your website.

Widgets are stored in the app/Widgets directory.

Widget classes must extend the Lamotivo\Website\Widgets\Widget class.

Registering Widget

Once you have created a widget, you are ready to attach it to the Website configuration, you may use this form in the widgets configuration of your website.php configuration file:

'widgets' => [
    'socials' => App\Widgets\SocialSharing::class,
],

Alternatively, you may register a widget in your code:

Website::form()->register('socials', \App\Widgets\SocialSharing::class)

Rendering Widget

At your Blade views you may use the @website_widget('socials') helper to render your widget. This helper accepts a widget name as the first argument.

Using old dynamic Blade helpers, such as like @widget_socials, is deprecated by now.

Javascript Repositories

Repository Manager handles javascript repositories on your website.

Repositories are stored in the app/Supplements directory.

Repository classes must extend the Lamotivo\Website\Supplement\Repository class.

<?php

namespace App\Supplements;

use Illuminate\Http\Request;
use Lamotivo\Website\Supplement\Repository;

use App\Order;
use App\Product;

class ShopRepository extends Repository
{
    /**
     * The repository name.
     *
     * @var string
     */
    protected static $name = 'shop';

    /**
     * Autoload the repository.
     *
     * @var boolean
     */
    protected $autoload = true;

    /**
     * Get a configuration of the repository.
     *
     * @return array
     */
    public function getConfig()
    {
        return [
            // `interval` define an auto reload data
            'interval' => 0, // seconds

            // `actions` is an array of available actions, defined in this repository as public methods
            'actions' => [
                'get_info',
                'buy',
            ],
        ];
    }

    /**
     * Get additional info on products.
     *
     * @return array
     */
    public function get_info(Request $request)
    {
        return [
            'info' => Product::find($request->product_id),
        ];
    }

    /**
     * Buy a product.
     *
     * @return array
     */
    public function buy(Request $request)
    {
        $order = Order::create([
            'product_id' => $request->product_id,
        ]);

        return [
            // `redirect_url` is used to make a redirect to another location
            'redirect_url' => route('order', $order->id),
        ];
    }

    /**
     * Boot repository data.
     *
     * @return void
     */
    protected function boot()
    {
        $this->products = Product::select('id', 'name', 'price')->paginate();
    }

}

Registering Repository

Once you have created a repository, you are ready to attach it to the Website configuration, you may use this form in the repositories configuration of your website.php configuration file:

'repositories' => [
    'shop' => App\Supplements\Shop::class,
],

Alternatively, you may register a repository in your code:

Website::form()->register('shop', \App\Supplements\Shop::class)

Rendering Repository

All your registered repositories are rendered automatically on HTML document.

Using Repository

In your Javascript application controller, you may use the $rep dependency as in an example below:

websiteApp.controller('ShopController', [
  '$scope',
  '$rep',
  function($scope, $rep) {
    $scope.shop = $rep.shop;

    $scope.reload = function()
    {
        $rep.shop.reload();
    }

    $scope.nextPage = function()
    {
        var page = $rep.shop.products.current_page;

        if (page && $rep.shop.products.last_page > page)
        {
            page++;
            $rep.shop.reload(null, {page: page});
        }
    }

    $scope.loadNext = function()
    {
        $rep.shop.appendNext('products');
    }

    $scope.buy = function(product)
    {
        $rep.shop.buy({ product_id: product.id });
    }

    $scope.getInfo = function(product)
    {
        $rep.shop.get_info({ product_id: product.id });
    }
  }
]);

The controller view:

<div class="products">
    <div class="product-item" 
         ng-repeat="product in shop.products.data">
        <div class="product-name" 
             ng-bind="product.name"></div>
        <div class="product-price" 
             ng-bind="product.price"></div>
        <button class="product-buy-button" 
                ng-click="buy(product)" 
                ng-disabled="shop.buy__is_loading">Buy</button>
        <button class="product-info-button" 
                ng-click="getInfo(product)"
                ng-disabled="shop.get_info__is_loading">Info</button>
    </div>

    <div class="product-info" 
         ng-if="shop.info" 
         ng-bind="shop.info.description"></div>

    <div class="product-buttons">
        <button class="product-more-button" 
                ng-click="loadNext()" 
                ng-disabled="shop.next__is_loading">Load more</button>
        <button class="product-next-button" 
                ng-click="nextPage()" 
                ng-disabled="shop.reload__is_loading">Next Page</button>
    </div>
</div>

Feed Exports

Export Manager handles your RSS feed exports. Of course, you are not limited to generate only RSS feeds, you may generate any desired exports with this manager.

Defining Export

To create an feed definition use the make:export Artisan command:

php artisan make:export Rss

Export definitions are stored in the app/Export directory. You may populate link items at the seed method.

Registering Export

Once you have created an export, you are ready to attach it to the Website configuration, you may use this form in the export.feeds configuration of your website.php configuration file:

'export' => [
    'path' => 'export',
    'feeds' => [
        'rss' => App\Export\Rss::class,
    ]
],

By default, all generated feeds are stored in the public/export directory, as of the website.export.path option.

You still need to provide a link to an RSS feed using Meta Manager:

Website::meta()->alternate(url('export/rss.xml'));

Or just configure it at the website.meta.links option value.

Dumping Export

To start the feed generation, you should run the dump:export Artisan command:

php artisan dump:export

This command will dump all your feeds to the public/export directory.

If you wish to process only one feed, you may pass the feed name to the command:

php artisan dump:export --feed=rss

Sitemaps

Sitemap Manager handles your XML sitemaps.

Defining Sitemap

To create a sitemap definition use the make:sitemap Artisan command:

php artisan make:sitemap CatalogSitemap

Sitemap definitions are stored in the app/Sitemap directory. You may populate link items at the seed method.

Registering Sitemap

Once you have created a sitemap, you are ready to attach it to the Website configuration, you may use this form in the sitemap.maps configuration of your website.php configuration file:

'sitemap' => [
    'path' => 'sitemaps',
    'limit' => 50000,
    'maps' => [
        'catalog' => App\Sitemap\CatalogSitemap::class,
    ]
],

By default, all generated sitemaps are stored in the public/sitemaps directory, as of the website.sitemap.path option.

However, you still need to add a link to a sitemap to the robots.txt file.

Dumping Sitemap

To start the sitemap generation, you should run the dump:sitemap Artisan command:

php artisan dump:sitemap

This command will dump all your sitemaps to the public/sitemaps directory.

If you wish to process only one sitemap, you may pass the sitemap name to the command:

php artisan dump:export --map=catalog

Trackers

Trackers are used to easily integrate some third-party services on your website. It may be a Google Analytics code or a Jivosite chat.

Lamotivo Website ships with a variety of tracker drivers:

  • google - Google Analytics
  • gtm - Google Tag Manager
  • yandex - Yandex.Metrika
  • mailru - Mail.ru counter
  • facebook - Facebook pixel
  • vkontakte - Vkontakte retargetting
  • jivosite - Jivosite chat

To add a service, you need to define a tracker in the website.trackers configuration array.

    'trackers' => [
        'yandex' => [
            'driver' => 'yandex',
            'code' => '... ID ...',
        ],
        'google' => [
            'driver' => 'google',
            'code' => '... ID ...',
        ],
        'gtm' => [
            'driver' => 'gtm',
            'code' => '... ID ...',
        ],
    ],

All defined trackers are rendered in your HTML automatically.

Also you are free to create your own tracker driver.

Settings

As an addition to powerfull Laravel configuration, Lamotivo Website offers online editable dynamic settings to your application.

Settings are stored in an Eloquent model, defined at the website.settings.model configuration value. By default it is set to the Lamotivo\Website\Settings\Setting class.

Settings are merged with your application configuration, when calling Website::boot(). So you can use dynamic settings via the config() helper, as well.

If you use a Lamotivo admin panel to manage your website, you may create a Lamotivo component based on the provided Configurator component.

<?php

namespace App\Lm\Components;

use Illuminate\Http\Request;
use Anyspin\Lamotivo\Fields\Text;
use Lamotivo\Website\Lm\Components\Configurator;

class WebsiteSettings extends Configurator
{
    protected static $menu_label = 'Website Settings';
    protected static $base_url = 'website-settings';

    public function settings()
    {
        return [
            Text::make('website.company.name', 'Company Name'),
            Text::make('website.company.email', 'Company E-mail'),
        ];
    }
}

Once you have created a component, you should add it to the Lamotivo menu:

lm()->menu()->component(App\Lm\Components\WebsiteSettings::class);