mirror of
https://github.com/getgrav/grav.git
synced 2026-07-08 12:21:53 +02:00
Merge branch 'feature/blueprint-extend' into develop
Conflicts: system/blueprints/config/site.yaml system/blueprints/config/system.yaml
This commit is contained in:
76
system/blueprints/pages/blog.yaml
Normal file
76
system/blueprints/pages/blog.yaml
Normal file
@@ -0,0 +1,76 @@
|
||||
title: Blog
|
||||
@extends:
|
||||
type: default
|
||||
context: blueprints://pages
|
||||
|
||||
child_type: item
|
||||
|
||||
|
||||
title: Default
|
||||
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
form:
|
||||
fields:
|
||||
tabs:
|
||||
type: tabs
|
||||
active: 1
|
||||
|
||||
fields:
|
||||
advanced:
|
||||
fields:
|
||||
overrides:
|
||||
fields:
|
||||
header.child_type:
|
||||
default: item
|
||||
blog:
|
||||
type: tab
|
||||
title: Blog List
|
||||
|
||||
fields:
|
||||
header.content.items:
|
||||
type: select
|
||||
label: Items
|
||||
default: @self.children
|
||||
options:
|
||||
@self.children: Children
|
||||
|
||||
header.content.limit:
|
||||
type: text
|
||||
label: Max Item Count
|
||||
default: 5
|
||||
validate:
|
||||
required: true
|
||||
type: int
|
||||
min: 1
|
||||
|
||||
header.content.order.by:
|
||||
type: select
|
||||
label: Order By
|
||||
default: date
|
||||
options:
|
||||
folder: Folder
|
||||
title: Title
|
||||
date: Date
|
||||
default: Default
|
||||
|
||||
header.content.order.dir:
|
||||
type: select
|
||||
label: Order
|
||||
default: desc
|
||||
options:
|
||||
asc: Ascending
|
||||
desc: Descending
|
||||
|
||||
header.content.pagination:
|
||||
type: toggle
|
||||
label: Pagination
|
||||
highlight: 1
|
||||
default: 1
|
||||
options:
|
||||
1: Enabled
|
||||
0: Disabled
|
||||
186
system/blueprints/pages/default.yaml
Normal file
186
system/blueprints/pages/default.yaml
Normal file
@@ -0,0 +1,186 @@
|
||||
title: Default
|
||||
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
form:
|
||||
fields:
|
||||
type:
|
||||
type: hidden
|
||||
label: Page Type
|
||||
default: default
|
||||
|
||||
tabs:
|
||||
type: tabs
|
||||
active: 1
|
||||
|
||||
fields:
|
||||
content:
|
||||
type: tab
|
||||
title: Content
|
||||
|
||||
fields:
|
||||
header.title:
|
||||
type: text
|
||||
label: Title
|
||||
validate:
|
||||
required: true
|
||||
|
||||
header.process:
|
||||
type: checkboxes
|
||||
label: Process
|
||||
toggleable: true
|
||||
@config-default: system.pages.process
|
||||
default:
|
||||
markdown: true
|
||||
twig: false
|
||||
options:
|
||||
markdown: Markdown
|
||||
twig: Twig
|
||||
use: keys
|
||||
|
||||
content:
|
||||
type: markdown
|
||||
label: Content
|
||||
validate:
|
||||
type: textarea
|
||||
|
||||
uploads:
|
||||
type: uploads
|
||||
label: Page Media
|
||||
|
||||
meta:
|
||||
type: tab
|
||||
title: Meta
|
||||
|
||||
fields:
|
||||
header.description:
|
||||
type: textarea
|
||||
label: Description
|
||||
validate:
|
||||
max: 120
|
||||
|
||||
header.keywords:
|
||||
type: text
|
||||
label: Keywords
|
||||
validate:
|
||||
max: 120
|
||||
|
||||
header.robots:
|
||||
type: checkboxes
|
||||
label: Robots
|
||||
options:
|
||||
noindex: No index
|
||||
nofollow: No follow
|
||||
use: keys
|
||||
|
||||
taxonomies:
|
||||
type: section
|
||||
title: Taxonomies
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
header.taxonomy:
|
||||
type: taxonomy
|
||||
label: Taxonomy
|
||||
validate:
|
||||
type: array
|
||||
|
||||
advanced:
|
||||
type: tab
|
||||
title: Advanced
|
||||
|
||||
fields:
|
||||
columns:
|
||||
type: columns
|
||||
fields:
|
||||
column1:
|
||||
type: column
|
||||
fields:
|
||||
folder:
|
||||
type: text
|
||||
label: Folder Name
|
||||
validate:
|
||||
type: slug
|
||||
|
||||
route:
|
||||
type: select
|
||||
label: Parent
|
||||
classes: fancy
|
||||
@data-options: '\Grav\Common\Page\Pages::parents'
|
||||
@data-default: '\Grav\Plugin\admin::route'
|
||||
options:
|
||||
'/': '- Root -'
|
||||
|
||||
type:
|
||||
type: select
|
||||
classes: fancy
|
||||
label: Display Template
|
||||
default: default
|
||||
@data-options: '\Grav\Common\Page\Pages::types'
|
||||
|
||||
column2:
|
||||
type: column
|
||||
|
||||
fields:
|
||||
order:
|
||||
type: order
|
||||
label: Ordering
|
||||
sitemap:
|
||||
|
||||
overrides:
|
||||
type: section
|
||||
title: Overrides
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
|
||||
header.menu:
|
||||
type: text
|
||||
label: Menu
|
||||
|
||||
header.slug:
|
||||
type: text
|
||||
label: Alias
|
||||
validate:
|
||||
rule: slug
|
||||
|
||||
header.cache_enable:
|
||||
type: toggle
|
||||
label: Caching
|
||||
highlight: 1
|
||||
options:
|
||||
'': Global
|
||||
1: Enabled
|
||||
0: Disabled
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
header.routable:
|
||||
type: toggle
|
||||
label: Access by URL
|
||||
highlight: 1
|
||||
default: ''
|
||||
options:
|
||||
'': Global
|
||||
1: Enabled
|
||||
0: Disabled
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
header.child_type:
|
||||
type: select
|
||||
label: Default Child Type
|
||||
default: default
|
||||
@data-options: '\Grav\Common\Page\Pages::types'
|
||||
|
||||
header.order_by:
|
||||
type: hidden
|
||||
|
||||
header.order_manual:
|
||||
type: hidden
|
||||
validate:
|
||||
type: commalist
|
||||
83
system/blueprints/pages/item.yaml
Normal file
83
system/blueprints/pages/item.yaml
Normal file
@@ -0,0 +1,83 @@
|
||||
title: Item
|
||||
@extends:
|
||||
type: default
|
||||
context: blueprints://pages
|
||||
|
||||
form:
|
||||
fields:
|
||||
tabs:
|
||||
|
||||
fields:
|
||||
blog:
|
||||
type: tab
|
||||
title: Blog Item
|
||||
|
||||
|
||||
fields:
|
||||
publishing:
|
||||
type: section
|
||||
title: Publishing
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
header.date:
|
||||
type: datetime
|
||||
label: Date
|
||||
|
||||
header.publish_date:
|
||||
type: datetime
|
||||
label: Publish post on this date
|
||||
|
||||
header.unpublish_date:
|
||||
type: datetime
|
||||
label: Unpublish post on this date
|
||||
|
||||
header.published:
|
||||
type: toggle
|
||||
label: Published
|
||||
highlight: 1
|
||||
default: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
|
||||
summary:
|
||||
type: section
|
||||
title: Summary
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
|
||||
header.summary.enabled:
|
||||
type: toggle
|
||||
label: Summary
|
||||
highlight: 1
|
||||
default: 1
|
||||
options:
|
||||
1: Enabled
|
||||
0: Disabled
|
||||
|
||||
header.summary.format:
|
||||
type: select
|
||||
label: Format
|
||||
classes: fancy
|
||||
default: short
|
||||
options:
|
||||
'short': 'Use the first occurence of delimter or size'
|
||||
'long': 'Summary delimiter will be ignored'
|
||||
|
||||
header.summary.size:
|
||||
type: text
|
||||
label: Size
|
||||
classes: large
|
||||
default: 300
|
||||
validate:
|
||||
type: int
|
||||
min: 1
|
||||
|
||||
header.summary.delimiter:
|
||||
type: text
|
||||
label: Summary delimiter
|
||||
classes: large
|
||||
default: ===
|
||||
placeholder: ===
|
||||
46
system/blueprints/pages/modular.yaml
Normal file
46
system/blueprints/pages/modular.yaml
Normal file
@@ -0,0 +1,46 @@
|
||||
title: Modular
|
||||
@extends:
|
||||
type: default
|
||||
context: blueprints://pages
|
||||
|
||||
form:
|
||||
fields:
|
||||
tabs:
|
||||
type: tabs
|
||||
active: 1
|
||||
|
||||
fields:
|
||||
content:
|
||||
fields:
|
||||
|
||||
header.content.items:
|
||||
type: select
|
||||
label: Items
|
||||
default: @self.modular
|
||||
options:
|
||||
@self.modular: Children
|
||||
|
||||
header.content.order.by:
|
||||
type: select
|
||||
label: Order By
|
||||
default: date
|
||||
options:
|
||||
folder: Folder
|
||||
title: Title
|
||||
date: Date
|
||||
default: Default
|
||||
|
||||
header.content.order.dir:
|
||||
type: select
|
||||
label: Order
|
||||
default: desc
|
||||
options:
|
||||
asc: Ascending
|
||||
desc: Descending
|
||||
|
||||
header.process:
|
||||
type: ignore
|
||||
content:
|
||||
type: ignore
|
||||
uploads:
|
||||
type: ignore
|
||||
@@ -1,42 +0,0 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
title:
|
||||
type: text
|
||||
label: Title
|
||||
validate:
|
||||
required: true
|
||||
|
||||
folder:
|
||||
type: text
|
||||
label: Folder
|
||||
validate:
|
||||
type: slug
|
||||
required: true
|
||||
|
||||
route:
|
||||
type: select
|
||||
label: Parent
|
||||
classes: fancy
|
||||
@data-options: '\Grav\Common\Page\Pages::parents'
|
||||
@data-default: '\Grav\Plugin\admin::route'
|
||||
options:
|
||||
'/': '- Root -'
|
||||
validate:
|
||||
required: true
|
||||
|
||||
type:
|
||||
type: select
|
||||
classes: fancy
|
||||
label: Display Template
|
||||
default: default
|
||||
@data-options: '\Grav\Common\Page\Pages::types'
|
||||
validate:
|
||||
required: true
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\GravTrait;
|
||||
use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
|
||||
/**
|
||||
@@ -11,7 +12,7 @@ use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
*/
|
||||
class Blueprint
|
||||
{
|
||||
use Export, DataMutatorTrait;
|
||||
use Export, DataMutatorTrait, GravTrait;
|
||||
|
||||
public $name;
|
||||
|
||||
@@ -117,7 +118,17 @@ class Blueprint
|
||||
{
|
||||
// Initialize data
|
||||
$this->fields();
|
||||
return $this->extraArray($data, $this->nested, $prefix);
|
||||
$rules = $this->nested;
|
||||
|
||||
// Drill down to prefix level
|
||||
if (!empty($prefix)) {
|
||||
$parts = explode('.', trim($prefix, '.'));
|
||||
foreach ($parts as $part) {
|
||||
$rules = isset($rules[$part]) ? $rules[$part] : [];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->extraArray($data, $rules, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -286,7 +297,7 @@ class Blueprint
|
||||
// Item has been defined in blueprints.
|
||||
} elseif (is_array($field) && is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
$array += $this->ExtraArray($field, $val, $prefix);
|
||||
$array += $this->ExtraArray($field, $val, $prefix . $key . '.');
|
||||
} else {
|
||||
// Undefined/extra item.
|
||||
$array[$prefix.$key] = $field;
|
||||
@@ -313,11 +324,11 @@ class Blueprint
|
||||
$field['name'] = $prefix . $key;
|
||||
$field += $params;
|
||||
|
||||
if (isset($field['fields'])) {
|
||||
if (isset($field['fields']) && $field['type'] !== 'list') {
|
||||
// Recursively get all the nested fields.
|
||||
$newParams = array_intersect_key($this->filter, $field);
|
||||
$this->parseFormFields($field['fields'], $newParams, $prefix, $current[$key]['fields']);
|
||||
} else {
|
||||
} else if ($field['type'] !== 'ignore') {
|
||||
// Add rule.
|
||||
$this->rules[$prefix . $key] = &$field;
|
||||
$this->addProperty($prefix . $key);
|
||||
@@ -362,10 +373,20 @@ class Blueprint
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elseif (substr($name, 0, 8) == '@config-') {
|
||||
$property = substr($name, 8);
|
||||
$default = isset($field[$property]) ? $field[$property] : null;
|
||||
$config = self::getGrav()['config']->get($value, $default);
|
||||
|
||||
if (!is_null($config)) {
|
||||
$field[$property] = $config;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize predefined validation rule.
|
||||
if (isset($field['validate']['rule'])) {
|
||||
if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') {
|
||||
$field['validate'] += $this->getRule($field['validate']['rule']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\GravTrait;
|
||||
|
||||
/**
|
||||
* Blueprints class keeps track on blueprint instances.
|
||||
@@ -11,6 +12,8 @@ use Grav\Common\File\CompiledYamlFile;
|
||||
*/
|
||||
class Blueprints
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
protected $search;
|
||||
protected $types;
|
||||
protected $instances = array();
|
||||
@@ -55,8 +58,20 @@ class Blueprints
|
||||
if (isset($blueprints['@extends'])) {
|
||||
// Extend blueprint by other blueprints.
|
||||
$extends = (array) $blueprints['@extends'];
|
||||
foreach ($extends as $extendType) {
|
||||
$blueprint->extend($this->get($extendType));
|
||||
|
||||
if (is_string(key($extends))) {
|
||||
$extends = [ $extends ];
|
||||
}
|
||||
|
||||
foreach ($extends as $extendConfig) {
|
||||
$extendType = !is_string($extendConfig) ? empty($extendConfig['type']) ? false : $extendConfig['type'] : $extendConfig;
|
||||
|
||||
if (!$extendType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$context = is_string($extendConfig) || empty($extendConfig['context']) ? $this : new self(self::getGrav()['locator']->findResource($extendConfig['context']));
|
||||
$blueprint->extend($context->get($extendType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -503,6 +503,30 @@ class Validation
|
||||
return $values;
|
||||
}
|
||||
|
||||
public static function typeList($value, array $params, array $field)
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($field['fields'])) {
|
||||
foreach ($value as $key => $item) {
|
||||
foreach ($field['fields'] as $subKey => $subField) {
|
||||
$subKey = trim($subKey, '.');
|
||||
$subValue = isset($item[$subKey]) ? $item[$subKey] : null;
|
||||
self::validate($subValue, $subField);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static function filterList($value, array $params, array $field)
|
||||
{
|
||||
return (array) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom input: ignore (will not validate)
|
||||
*
|
||||
@@ -516,6 +540,11 @@ class Validation
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function filterIgnore($value, array $params, array $field)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
// HTML5 attributes (min, max and range are handled inside the types)
|
||||
|
||||
public static function validateRequired($value, $params)
|
||||
|
||||
@@ -539,7 +539,7 @@ class Page
|
||||
return preg_replace($regex, '', $this->folder);
|
||||
}
|
||||
if ($name == 'type') {
|
||||
return basename($this->name(), '.md');
|
||||
return $this->template();
|
||||
}
|
||||
if ($name == 'media') {
|
||||
return $this->media()->all();
|
||||
@@ -725,7 +725,7 @@ class Page
|
||||
public function extra()
|
||||
{
|
||||
$blueprints = $this->blueprints();
|
||||
return $blueprints->extra($this->toArray(), 'header.');
|
||||
return $blueprints->extra($this->toArray()['header'], 'header.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -404,8 +404,8 @@ class Pages
|
||||
{
|
||||
if (!self::$types) {
|
||||
self::$types = new Types();
|
||||
self::$types->scanBlueprints('theme://blueprints/');
|
||||
self::$types->scanTemplates('theme://templates/');
|
||||
file_exists('theme://blueprints/') && self::$types->scanBlueprints('theme://blueprints/');
|
||||
file_exists('theme://templates/') && self::$types->scanTemplates('theme://templates/');
|
||||
|
||||
$event = new Event();
|
||||
$event->types = self::$types;
|
||||
|
||||
@@ -13,27 +13,24 @@ class Types implements \ArrayAccess, \Iterator, \Countable
|
||||
use ArrayAccess, Constructor, Iterator, Countable, Export;
|
||||
|
||||
protected $items;
|
||||
protected $systemBlueprints;
|
||||
|
||||
public function register($type, $blueprint = null)
|
||||
{
|
||||
if (!$blueprint && $this->systemBlueprints && isset($this->systemBlueprints[$type])) {
|
||||
$useBlueprint = $this->systemBlueprints[$type];
|
||||
} else {
|
||||
$useBlueprint = $blueprint;
|
||||
}
|
||||
|
||||
if ($blueprint || empty($this->items[$type])) {
|
||||
$this->items[$type] = $blueprint;
|
||||
$this->items[$type] = $useBlueprint;
|
||||
}
|
||||
}
|
||||
|
||||
public function scanBlueprints($path)
|
||||
{
|
||||
$options = [
|
||||
'compare' => 'Filename',
|
||||
'pattern' => '|\.yaml$|',
|
||||
'filters' => [
|
||||
'key' => '|\.yaml$|'
|
||||
],
|
||||
'key' => 'SubPathName',
|
||||
'value' => 'PathName',
|
||||
];
|
||||
|
||||
$this->items = Folder::all($path, $options) + $this->items;
|
||||
$this->items = $this->findBlueprints($path) + $this->items;
|
||||
}
|
||||
|
||||
public function scanTemplates($path)
|
||||
@@ -48,6 +45,10 @@ class Types implements \ArrayAccess, \Iterator, \Countable
|
||||
'recursive' => false
|
||||
];
|
||||
|
||||
if (!$this->systemBlueprints) {
|
||||
$this->systemBlueprints = $this->findBlueprints('blueprints://pages');
|
||||
}
|
||||
|
||||
foreach (Folder::all($path, $options) as $type) {
|
||||
$this->register($type);
|
||||
}
|
||||
@@ -78,9 +79,24 @@ class Types implements \ArrayAccess, \Iterator, \Countable
|
||||
if (strpos($name, 'modular/') !== 0) {
|
||||
continue;
|
||||
}
|
||||
$list[basename($name)] = trim(ucfirst(strtr(basename($name), '_', ' ')));
|
||||
$list[$name] = trim(ucfirst(strtr(basename($name), '_', ' ')));
|
||||
}
|
||||
ksort($list);
|
||||
return $list;
|
||||
}
|
||||
|
||||
private function findBlueprints($path)
|
||||
{
|
||||
$options = [
|
||||
'compare' => 'Filename',
|
||||
'pattern' => '|\.yaml$|',
|
||||
'filters' => [
|
||||
'key' => '|\.yaml$|'
|
||||
],
|
||||
'key' => 'SubPathName',
|
||||
'value' => 'PathName',
|
||||
];
|
||||
|
||||
return Folder::all($path, $options);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user