diff --git a/composer.json b/composer.json index 833dd322a..b97e6c745 100755 --- a/composer.json +++ b/composer.json @@ -89,7 +89,8 @@ "Webkul\\Sales\\": "packages/Webkul/Sales/src", "Webkul\\Tax\\": "packages/Webkul/Tax/src", "Webkul\\API\\": "packages/Webkul/API", - "Webkul\\Discount\\": "packages/Webkul/Discount/src" + "Webkul\\Discount\\": "packages/Webkul/Discount/src", + "Webkul\\CMS\\": "packages/Webkul/CMS/src" } }, "autoload-dev": { diff --git a/config/app.php b/config/app.php index 5b7dd6c55..14eec2d67 100755 --- a/config/app.php +++ b/config/app.php @@ -244,7 +244,8 @@ return [ Webkul\Sales\Providers\SalesServiceProvider::class, Webkul\Tax\Providers\TaxServiceProvider::class, Webkul\API\Providers\APIServiceProvider::class, - Webkul\Discount\Providers\DiscountServiceProvider::class + Webkul\Discount\Providers\DiscountServiceProvider::class, + Webkul\CMS\Providers\CMSServiceProvider::class ], /* diff --git a/config/cms.php b/config/cms.php new file mode 100644 index 000000000..25058db0c --- /dev/null +++ b/config/cms.php @@ -0,0 +1,5 @@ + 'admin.cart-rule.index', 'sort' => 1, 'icon-class' => '', - ] + ], // , [ // 'key' => 'promotions.catalog-rule', // 'name' => 'admin::app.promotion.catalog-rule', @@ -196,4 +196,17 @@ return [ // 'sort' => 1, // 'icon-class' => '', // ] + [ + 'key' => 'cms', + 'name' => 'admin::app.layouts.cms', + 'route' => 'admin.cms.index', + 'sort' => 6, + 'icon-class' => 'promotion-icon', + ], [ + 'key' => 'cms.pages', + 'name' => 'admin::app.cms.pages.pages', + 'route' => 'admin.cms.index', + 'sort' => 1, + 'icon-class' => '', + ] ]; \ No newline at end of file diff --git a/packages/Webkul/Admin/src/DataGrids/CMSPageDataGrid.php b/packages/Webkul/Admin/src/DataGrids/CMSPageDataGrid.php new file mode 100644 index 000000000..0731332e1 --- /dev/null +++ b/packages/Webkul/Admin/src/DataGrids/CMSPageDataGrid.php @@ -0,0 +1,79 @@ + @prashant-webkul + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class CMSPageDataGrid extends DataGrid +{ + protected $index = 'id'; //the column that needs to be treated as index column + + protected $sortOrder = 'desc'; //asc or desc + + public function prepareQueryBuilder() + { + $queryBuilder = DB::table('cms_pages')->select('id', 'url_key', 'layout'); + + $this->setQueryBuilder($queryBuilder); + } + + public function addColumns() + { + $this->addColumn([ + 'index' => 'id', + 'label' => trans('admin::app.datagrid.id'), + 'type' => 'number', + 'searchable' => false, + 'sortable' => true, + 'filterable' => true + ]); + + $this->addColumn([ + 'index' => 'url_key', + 'label' => trans('admin::app.datagrid.url-key'), + 'type' => 'string', + 'searchable' => true, + 'sortable' => true, + 'filterable' => true + ]); + + $this->addColumn([ + 'index' => 'layout', + 'label' => trans('admin::app.datagrid.layout'), + 'type' => 'string', + 'searchable' => true, + 'sortable' => true, + 'filterable' => true, + 'wrapper' => function($row) { + foreach(config('cms') as $key => $value) { + if ($row->layout == $value) { + return $key; + } + } + } + ]); + } + + public function prepareActions() { + $this->addAction([ + 'type' => 'Edit', + 'method' => 'GET', // use GET request only for redirect purposes + 'route' => 'admin.cms.edit', + 'icon' => 'icon pencil-lg-icon' + ]); + + $this->addAction([ + 'type' => 'Delete', + 'method' => 'POST', // use GET request only for redirect purposes + 'route' => 'admin.cms.delete', + 'icon' => 'icon trash-icon' + ]); + } +} \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Http/routes.php b/packages/Webkul/Admin/src/Http/routes.php index d25d7f5de..2b9103a2d 100755 --- a/packages/Webkul/Admin/src/Http/routes.php +++ b/packages/Webkul/Admin/src/Http/routes.php @@ -677,6 +677,34 @@ Route::group(['middleware' => ['web']], function () { Route::post('cart-rules/delete/{id}', 'Webkul\Discount\Http\Controllers\CartRuleController@destroy')->name('admin.cart-rule.delete'); }); + + Route::prefix('cms')->group(function () { + Route::get('/', 'Webkul\CMS\Http\Controllers\Admin\PageController@index')->defaults('_config', [ + 'view' => 'admin::cms.index' + ])->name('admin.cms.index'); + + Route::get('preview', 'Webkul\CMS\Http\Controllers\Admin\PageController@preview')->name('admin.cms.preview'); + + Route::get('create', 'Webkul\CMS\Http\Controllers\Admin\PageController@create')->defaults('_config', [ + 'view' => 'admin::cms.create' + ])->name('admin.cms.create'); + + Route::post('create', 'Webkul\CMS\Http\Controllers\Admin\PageController@store')->defaults('_config', [ + 'redirect' => 'admin.cms.index' + ])->name('admin.cms.store'); + + Route::get('update/{id}', 'Webkul\CMS\Http\Controllers\Admin\PageController@edit')->defaults('_config', [ + 'view' => 'admin::cms.edit' + ])->name('admin.cms.edit'); + + Route::post('update/{id}', 'Webkul\CMS\Http\Controllers\Admin\PageController@update')->defaults('_config', [ + 'redirect' => 'admin.cms.index' + ])->name('admin.cms.update'); + + Route::post('/delete/{id}', 'Webkul\CMS\Http\Controllers\Admin\PageController@delete')->defaults('_config', [ + 'redirect' => 'admin.cms.index' + ])->name('admin.cms.delete'); + }); }); }); }); \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Resources/lang/en/app.php b/packages/Webkul/Admin/src/Resources/lang/en/app.php index 52e393e68..204af48fc 100755 --- a/packages/Webkul/Admin/src/Resources/lang/en/app.php +++ b/packages/Webkul/Admin/src/Resources/lang/en/app.php @@ -41,7 +41,8 @@ return [ 'tax-categories' => 'Tax Categories', 'tax-rates' => 'Tax Rates', 'promotion' => 'Promotions', - 'discount' => 'Discount' + 'discount' => 'Discount', + 'cms' => 'CMS' ], 'acl' => [ @@ -126,6 +127,8 @@ return [ 'email' => 'Email', 'group' => 'Group', 'title' => 'Title', + 'layout' => 'Layout', + 'url-key' => 'URL Key', 'comment' => 'Comment', 'product-name' => 'Product', 'currency-name' => 'Currency Name', @@ -971,6 +974,31 @@ return [ 'illegal-format' => 'Error! This type of format is either not supported or its illegal format' ], + 'cms' => [ + 'pages' => [ + 'pages' => 'Page', + 'title' => 'pages', + 'add-title' => 'Add Page', + 'content' => 'Content', + 'url-key' => 'URL Key', + 'create-btn-title' => 'Add Page', + 'edit-title' => 'Edit Page', + 'edit-btn-title' => 'Edit Page', + 'create-success' => 'Page created successfully', + 'create-failure' => 'Page cannot be created', + 'update-success' => 'Page updated successfully', + 'update-failure' => 'Page cannot be updated', + 'page-title' => 'Page Title', + 'layout' => 'Layout', + 'meta_keywords' => 'Meta Keywords', + 'meta_description' => 'Meta Description', + 'meta_title' => 'Meta Title', + 'delete-success' => 'CMS page deleted successfully', + 'delete-failure' => 'CMS page cannot be deleted', + 'preview' => 'Preview' + ] + ], + 'response' => [ 'being-used' => 'This resource :name is getting used in :source', 'cannot-delete-default' => 'Cannot delete the default channel', diff --git a/packages/Webkul/Admin/src/Resources/views/cms/create.blade.php b/packages/Webkul/Admin/src/Resources/views/cms/create.blade.php new file mode 100644 index 000000000..0907cc9e3 --- /dev/null +++ b/packages/Webkul/Admin/src/Resources/views/cms/create.blade.php @@ -0,0 +1,146 @@ +@extends('admin::layouts.content') + +@section('page_title') + {{ __('admin::app.cms.pages.add-title') }} +@stop + +@section('content') +
+
+ + + +
+ +
+ @csrf() + +
+ + + + + @{{ errors.first('url_key') }} +
+ +
+ + + @foreach(config('cms') as $key => $value) + + + + + {{ $key }} + + @endforeach + + @{{ errors.first('layout') }} +
+ +
+ + + + + @{{ errors.first('content') }} +
+ +
+ + + + + @{{ errors.first('page_title') }} +
+ +
+ + + + + @{{ errors.first('meta_title') }} +
+ +
+ + + + + @{{ errors.first('meta_keywords') }} +
+ +
+ + + + + @{{ errors.first('meta_description') }} +
+
+
+
+
+@stop + +@push('scripts') + + + +@endpush \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Resources/views/cms/edit.blade.php b/packages/Webkul/Admin/src/Resources/views/cms/edit.blade.php new file mode 100644 index 000000000..ce217762d --- /dev/null +++ b/packages/Webkul/Admin/src/Resources/views/cms/edit.blade.php @@ -0,0 +1,169 @@ +@extends('admin::layouts.content') + +@section('page_title') + {{ __('admin::app.cms.pages.edit-title') }} +@stop + +@section('content') +
+
+ + + +
+ +
+ @csrf() + +
+ + + + + @{{ errors.first('url_key') }} +
+ +
+ + + @foreach(config('cms') as $key => $value) + + layout == $value) checked @endif> + + + {{ $key }} + + @endforeach + + @{{ errors.first('layout') }} +
+ + @php + $content = json_decode($page->content); + @endphp +
+ + + + + @{{ errors.first('content') }} +
+ +
+ + + + + @{{ errors.first('page_title') }} +
+ +
+ + + + + @{{ errors.first('meta_title') }} +
+ +
+ + + + + @{{ errors.first('meta_keywords') }} +
+ +
+ + + + + @{{ errors.first('meta_description') }} +
+
+
+
+
+@stop + +@push('scripts') + + + +@endpush \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Resources/views/cms/index.blade.php b/packages/Webkul/Admin/src/Resources/views/cms/index.blade.php new file mode 100644 index 000000000..484c69c5a --- /dev/null +++ b/packages/Webkul/Admin/src/Resources/views/cms/index.blade.php @@ -0,0 +1,47 @@ +@extends('admin::layouts.content') + +@section('page_title') + {{ __('admin::app.cms.pages.title') }} +@stop + +@section('content') + +
+ + +
+ @inject('customerGrid', 'Webkul\Admin\DataGrids\CMSPageDataGrid') + + {!! $customerGrid->render() !!} +
+
+ + +

{{ __('admin::app.export.download') }}

+
+ +
+
+ +@stop + +@push('scripts') + @include('admin::export.export', ['gridName' => $customerGrid]) +@endpush + diff --git a/packages/Webkul/CMS/composer.json b/packages/Webkul/CMS/composer.json new file mode 100644 index 000000000..9ecd07c1c --- /dev/null +++ b/packages/Webkul/CMS/composer.json @@ -0,0 +1,27 @@ +{ + "name": "bagisto/laravel-cms", + "license": "MIT", + "authors": [ + { + "name": "Prashant Singh", + "email": "prashant.singh852@webkul.com" + } + ], + "require": { + "konekt/concord": "^1.2" + }, + "autoload": { + "psr-4": { + "Webkul\\CMS\\": "src/" + } + }, + "extra": { + "laravel": { + "providers": [ + "Webkul\\CMS\\Providers\\CMSServiceProvider" + ], + "aliases": {} + } + }, + "minimum-stability": "dev" +} diff --git a/packages/Webkul/CMS/src/Config/cms-config.php b/packages/Webkul/CMS/src/Config/cms-config.php new file mode 100644 index 000000000..abc9ee252 --- /dev/null +++ b/packages/Webkul/CMS/src/Config/cms-config.php @@ -0,0 +1,7 @@ + 'shop::cms.onecol', + 'two-column' => 'shop::cms.twocol', + 'three-column' => 'shop::cms.threecol' +]; \ No newline at end of file diff --git a/packages/Webkul/CMS/src/Contracts/CMS.php b/packages/Webkul/CMS/src/Contracts/CMS.php new file mode 100644 index 000000000..2d920f51d --- /dev/null +++ b/packages/Webkul/CMS/src/Contracts/CMS.php @@ -0,0 +1,7 @@ +increments('id'); + $table->json('content')->nullable(); + $table->string('url_key'); + $table->string('layout')->nullable(); + $table->integer('channel_id')->unsigned(); + $table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade'); + $table->integer('locale_id')->unsigned(); + $table->foreign('locale_id')->references('id')->on('locales')->onDelete('cascade'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('cms_pages'); + } +} diff --git a/packages/Webkul/CMS/src/Http/Controllers/Admin/PageController.php b/packages/Webkul/CMS/src/Http/Controllers/Admin/PageController.php new file mode 100644 index 000000000..73633115f --- /dev/null +++ b/packages/Webkul/CMS/src/Http/Controllers/Admin/PageController.php @@ -0,0 +1,234 @@ + @prashant-webkul + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ + class PageController extends Controller +{ + /** + * To hold the request variables from route file + */ + protected $_config; + + /** + * To hold the channel reposotry instance + */ + protected $channel; + + /** + * To hold the locale reposotry instance + */ + protected $locale; + + /** + * To hold the CMSRepository instance + */ + protected $cms; + + public function __construct(Channel $channel, Locale $locale, CMS $cms) + { + /** + * Channel repository instance + */ + $this->channel = $channel; + + /** + * Locale repository instance + */ + $this->locale = $locale; + + /** + * CMS repository instance + */ + $this->cms = $cms; + + $this->_config = request('_config'); + } + + /** + * Loads the index page showing the static pages resources + */ + public function index() + { + return view($this->_config['view']); + } + + /** + * To create a new CMS page + * + * @return view + */ + public function create() + { + return view($this->_config['view']); + } + + /** + * To store a new CMS page in storage + * + * @return view + */ + public function store() + { + $this->validate(request(), [ + 'channel' => 'required|string', + 'locale' => 'required|string', + 'url_key' => 'required|unique:cms_pages,url_key', + 'layout' => 'required|string', + 'content' => 'required|string', + 'page_title' => 'required|string', + 'meta_title' => 'required|string', + 'meta_description' => 'string', + 'meta_keywords' => 'required|string' + ]); + + $data = request()->all(); + + $content = $data['content']; + $pageTitle = $data['page_title']; + + unset($data['content']); + unset($data['page_title']); + + $data['content']['html'] = $content; + $data['content']['page_title'] = $pageTitle; + $data['content']['meta_keywords'] = $data['meta_keywords']; + $data['content']['meta_title'] = $data['meta_title']; + $data['content']['meta_description'] = $data['meta_description']; + + $data['content'] = json_encode($data['content']); + + $result = $this->cms->create($data); + + if ($result) { + session()->flash('success', trans('admin::app.cms.pages.create-success')); + } else { + session()->flash('success', trans('admin::app.cms.pages.create-failure')); + } + + return redirect()->route($this->_config['redirect']); + } + + /** + * To edit a previously created CMS page + * + * @return view + */ + public function edit($id) + { + $page = $this->cms->findOrFail($id); + + return view($this->_config['view'])->with('page', $page); + } + + /** + * To update the previously created CMS page in storage + * + * @return view + */ + public function update($id) + { + $page = $this->cms->findOrFail($id); + + $this->validate(request(), [ + 'channel' => 'required|string', + 'locale' => 'required|string', + 'url_key' => 'required|unique:cms_pages,url_key,'.$id, + 'layout' => 'required|string', + 'content' => 'required|string', + 'page_title' => 'required|string', + 'meta_title' => 'required|string', + 'meta_description' => 'string', + 'meta_keywords' => 'required|string' + ]); + + $data = request()->all(); + + $content = $data['content']; + $pageTitle = $data['page_title']; + + unset($data['content']); + unset($data['page_title']); + + $data['content']['html'] = $content; + $data['content']['page_title'] = $pageTitle; + $data['content']['meta_keywords'] = $data['meta_keywords']; + $data['content']['meta_title'] = $data['meta_title']; + $data['content']['meta_description'] = $data['meta_description']; + + $data['content'] = json_encode($data['content']); + + $result = $this->cms->update($data, $id); + + if ($result) { + session()->flash('success', trans('admin::app.cms.pages.update-success')); + } else { + session()->flash('success', trans('admin::app.cms.pages.update-failure')); + } + + return redirect()->route($this->_config['redirect']); + } + + /** + * To preview the content of the currently creating page or previously creating page + * + * @return mixed + */ + public function preview() + { + $page = request()->all(); + + if (isset($page['layout'])) { + return view($page['layout'])->with('data', $page); + } else { + abort(404); + } + + } + + /** + * To delete the previously create CMS page + * + * @return json + */ + public function delete($id) + { + $page = $this->cms->findOrFail($id); + + if ($page->delete()) { + session()->flash('success', trans('admin::app.cms.delete-success')); + + return response()->json(['message' => true], 200); + } else { + session()->flash('success', trans('admin::app.cms.delete-failure')); + + return response()->json(['message' => false], 200); + } + } + + /** + * To extract the page content and load it in the respective view file\ + * + * @return view + */ + public function presenter($slug) + { + $page = $this->cms->findOneWhere([ + 'url_key' => $slug + ]); + + $layout = $page->layout; + + return view($layout)->with('data', $page); + } +} \ No newline at end of file diff --git a/packages/Webkul/CMS/src/Http/Controllers/Controller.php b/packages/Webkul/CMS/src/Http/Controllers/Controller.php new file mode 100644 index 000000000..971cb744c --- /dev/null +++ b/packages/Webkul/CMS/src/Http/Controllers/Controller.php @@ -0,0 +1,12 @@ +loadTranslationsFrom(__DIR__ . '/../Resources/lang', 'cms'); + + $this->loadMigrationsFrom(__DIR__ . '/../Database/Migrations'); + } + + /** + * Register services. + * + * @return void + */ + public function register() + { + $this->registerConfig(); + } + + /** + * To register the configuration with application's configuration + */ + protected function registerConfig() + { + $this->mergeConfigFrom( + dirname(__DIR__) . '/Config/cms-config.php', 'cms' + ); + } +} \ No newline at end of file diff --git a/packages/Webkul/CMS/src/Providers/ModuleServiceProvider.php b/packages/Webkul/CMS/src/Providers/ModuleServiceProvider.php new file mode 100644 index 000000000..d95c1b094 --- /dev/null +++ b/packages/Webkul/CMS/src/Providers/ModuleServiceProvider.php @@ -0,0 +1,12 @@ + @prashant-webkul + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ + +class CMSRepository extends Repository +{ + /** + * To hold the channel reposotry instance + */ + protected $channel; + + /** + * To hold the locale reposotry instance + */ + protected $locale; + + public function __construct(Channel $channel, Locale $locale, App $app) + { + $this->channel = $channel; + + $this->locale = $locale; + + parent::__construct($app); + } + /** + * Specify Model class name + * + * @return mixed + */ + function model() + { + return 'Webkul\CMS\Contracts\CMS'; + } + + public function create(array $data) + { + $channel = $this->channel->findOneByField('code', $data['channel']); + + $locale = $this->locale->findOneByField('code', $data['locale']); + + $data['channel_id'] = $channel->id; + $data['locale_id'] = $locale->id; + + $result = $this->model->create($data); + + if ($result) { + return true; + } else { + return false; + } + } +} \ No newline at end of file diff --git a/packages/Webkul/Shop/src/Http/routes.php b/packages/Webkul/Shop/src/Http/routes.php index c575f8a60..e97625a00 100755 --- a/packages/Webkul/Shop/src/Http/routes.php +++ b/packages/Webkul/Shop/src/Http/routes.php @@ -287,5 +287,11 @@ Route::group(['middleware' => ['web', 'locale', 'theme', 'currency']], function }); //customer routes end here + Route::get('pages/{slug}', 'Webkul\CMS\Http\Controllers\Admin\PageController@presenter')->name('shop.cms.page'); + + Route::view('onecol', 'shop::cms.onecol'); + Route::view('twocol', 'shop::cms.twocol'); + Route::view('threecol', 'shop::cms.threecol'); + Route::fallback('Webkul\Shop\Http\Controllers\HomeController@notFound'); }); diff --git a/packages/Webkul/Shop/src/Resources/assets/sass/_variables.scss b/packages/Webkul/Shop/src/Resources/assets/sass/_variables.scss index bee1647c6..29d95c0ec 100755 --- a/packages/Webkul/Shop/src/Resources/assets/sass/_variables.scss +++ b/packages/Webkul/Shop/src/Resources/assets/sass/_variables.scss @@ -1,4 +1,5 @@ @import url("https://fonts.googleapis.com/css?family=Montserrat:400,500"); + //shop variables $brand-color: #0031F0; $background-color: #F2F2F2; diff --git a/packages/Webkul/Shop/src/Resources/assets/sass/app.scss b/packages/Webkul/Shop/src/Resources/assets/sass/app.scss index 519579bda..a0805f3f0 100755 --- a/packages/Webkul/Shop/src/Resources/assets/sass/app.scss +++ b/packages/Webkul/Shop/src/Resources/assets/sass/app.scss @@ -4078,3 +4078,31 @@ section.review { } } } + +// Static content pages layout +.static-container { + display: block; + width: 100%; + padding: 10px; + margin-left: auto; + margin-right: auto; + + &.one-column { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + } + + &.two-column { + display: grid; + grid-template-columns: 48% 48%; + grid-column-gap: 4%; + } + + &.three-column { + display: grid; + grid-template-columns: 30% 30% 30%; + grid-column-gap: 4%; + } +} \ No newline at end of file diff --git a/packages/Webkul/Shop/src/Resources/views/cms/onecol.blade.php b/packages/Webkul/Shop/src/Resources/views/cms/onecol.blade.php new file mode 100644 index 000000000..85aceb255 --- /dev/null +++ b/packages/Webkul/Shop/src/Resources/views/cms/onecol.blade.php @@ -0,0 +1,9 @@ +@extends('shop::layouts.master') + +@section('content-wrapper') +
+

One Column Layout

+ + {{ $data['content'] }} +
+@endsection \ No newline at end of file diff --git a/packages/Webkul/Shop/src/Resources/views/cms/threecol.blade.php b/packages/Webkul/Shop/src/Resources/views/cms/threecol.blade.php new file mode 100644 index 000000000..63fd2820d --- /dev/null +++ b/packages/Webkul/Shop/src/Resources/views/cms/threecol.blade.php @@ -0,0 +1,11 @@ +@extends('shop::layouts.master') + +@section('content-wrapper') +
+

First Column

+ +

Second Column

+ +

Third Column

+
+@endsection \ No newline at end of file diff --git a/packages/Webkul/Shop/src/Resources/views/cms/twocol.blade.php b/packages/Webkul/Shop/src/Resources/views/cms/twocol.blade.php new file mode 100644 index 000000000..eb7f5389d --- /dev/null +++ b/packages/Webkul/Shop/src/Resources/views/cms/twocol.blade.php @@ -0,0 +1,9 @@ +@extends('shop::layouts.master') + +@section('content-wrapper') +
+

First Column

+ +

Second Column

+
+@endsection \ No newline at end of file