Skip to content

Commit 95668d4

Browse files
authored
Merge pull request #24 from justcoded/feature/view-extends
Feature/view extends
2 parents 9c2889b + fdfb391 commit 95668d4

File tree

8 files changed

+186
-48
lines changed

8 files changed

+186
-48
lines changed

framework/Objects/Post_Type.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
* https://codex.wordpress.org/Function_Reference/register_post_type
1212
*/
1313
abstract class Post_Type {
14+
use Singleton;
15+
1416
/**
1517
* Post_Type ID. Used to store it in DB and identify by post_type key
1618
* SHOULD BE OVERWRITTEN IN CHILD CLASS
@@ -231,7 +233,7 @@ abstract class Post_Type {
231233
*
232234
* @throws \Exception Missing $ID property.
233235
*/
234-
public function __construct() {
236+
protected function __construct() {
235237
if ( empty( $this::$ID ) ) {
236238
throw new \Exception( 'Post Type "' . get_class( $this ) . '" init failed: missing $ID property' );
237239
}

framework/Objects/Singleton.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
namespace JustCoded\WP\Framework\Objects;
4+
5+
/**
6+
* Class Singleton
7+
* Singleton design pattern base class
8+
*/
9+
trait Singleton {
10+
/**
11+
* Refers to a single instance of this class.
12+
*
13+
* @var self
14+
*/
15+
protected static $instance = null;
16+
17+
/**
18+
* Returns the *Singleton* current class.
19+
*
20+
* @return Singleton A single instance of this class.
21+
*/
22+
public static function instance() {
23+
static $instance = null;
24+
25+
return $instance ?: $instance = new static();
26+
}
27+
28+
/**
29+
* Protected constructor to prevent creating a new instance of the
30+
* *Singleton* via the `new` operator from outside of this class.
31+
*/
32+
protected function __construct() {
33+
}
34+
35+
/**
36+
* Private clone method to prevent cloning of the instance of the
37+
* *Singleton* instance.
38+
*
39+
* @return void
40+
*/
41+
final private function __clone() {
42+
}
43+
44+
/**
45+
* Private unserialize method to prevent unserializing of the *Singleton*
46+
* instance.
47+
*
48+
* @return void
49+
*/
50+
final private function __wakeup() {
51+
}
52+
53+
}

framework/Objects/Taxonomy.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
* https://codex.wordpress.org/Function_Reference/register_taxonomy
1212
*/
1313
abstract class Taxonomy {
14+
use Singleton;
15+
1416
/**
1517
* Taxonomy ID. Used to store it in DB and identify by taxonomy key
1618
* SHOULD BE OVERWRITTEN IN CHILD CLASS
@@ -150,7 +152,7 @@ abstract class Taxonomy {
150152
*
151153
* @throws \Exception Taxonomy $ID property not defined.
152154
*/
153-
public function __construct() {
155+
protected function __construct() {
154156
if ( empty( $this::$ID ) ) {
155157
throw new \Exception( 'Taxonomy "' . get_class( $this ) . '" init failed: missing $ID property' );
156158
}

framework/Theme.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ abstract class Theme {
116116
public function __construct() {
117117
$this->register_post_types();
118118
$this->register_taxonomies();
119-
new Template_Hierarchy();
119+
$this->init_views_templates();
120120

121121
/**
122122
* Pretty standard theme hooks
@@ -188,6 +188,14 @@ public function remove_assets_query_string( $src ) {
188188
return $src;
189189
}
190190

191+
/**
192+
* Init new Template Hierarchy based on "views" folder and load Views engine.
193+
*/
194+
public function init_views_templates() {
195+
Template_Hierarchy::instance();
196+
View::instance();
197+
}
198+
191199
/**
192200
* Called right away after constructor. You can define/call additional actions here
193201
*/

framework/Web/Template_Hierarchy.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22

33
namespace JustCoded\WP\Framework\Web;
44

5+
use JustCoded\WP\Framework\Objects\Singleton;
56
use JustCoded\WP\Framework\Web\View;
6-
use JustCoded\WP\Framework\Web\Views_Rule;
77

88
/**
99
* Class Template_Hierarchy
1010
* Hook get_*_template() functions to add "views" folder everywhere
1111
*/
1212
class Template_Hierarchy {
13+
use Singleton;
14+
1315
/**
1416
* Standard template types available for rewrite.
1517
*
@@ -49,17 +51,17 @@ class Template_Hierarchy {
4951

5052
/**
5153
* Template_Hierarchy constructor.
52-
* set wordpress template system hooks
54+
* set WordPress template system hooks
5355
*/
54-
public function __construct() {
56+
protected function __construct() {
57+
// patch page/custom post type templates.
58+
add_action( 'init', array( $this, 'init_theme_page_template_hooks' ), 1000 );
59+
5560
// set filter for all query template types.
5661
foreach ( $this->template_types as $type ) {
5762
add_filter( "{$type}_template_hierarchy", array( $this, "{$type}_template_hierarchy" ) );
5863
}
5964

60-
// patch page/custom post type templates.
61-
add_action( 'init', array( $this, 'init_theme_page_template_hooks' ), 1000 );
62-
6365
// add woocommerce support.
6466
add_filter( 'woocommerce_template_path', array( $this, 'woocommerce_template_path' ) );
6567

framework/Web/View.php

Lines changed: 107 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,150 @@
11
<?php
22
namespace JustCoded\WP\Framework\Web;
33

4+
use JustCoded\WP\Framework\Objects\Singleton;
5+
46
/**
57
* Views base class.
68
* Used for layouts and render partials
79
*/
810
class View {
11+
use Singleton;
12+
13+
/**
14+
* Layouts call chain.
15+
*
16+
* @var array
17+
*/
18+
private $extends = array();
19+
920
/**
10-
* Current layout name
21+
* Theme template path to be loaded.
1122
*
1223
* @var string
1324
*/
14-
private static $_layout;
25+
public $template;
1526

1627
/**
17-
* Layouts call chain
28+
* View constructor.
1829
*
19-
* @var array
30+
* Executed immediately before WordPress includes the predetermined template file
31+
* Override WordPress's default template behavior.
2032
*/
21-
private static $_processing = array();
33+
protected function __construct() {
34+
add_filter( 'template_include', array( $this, 'init_template' ), 999999 );
35+
}
2236

2337
/**
24-
* Start recording the content to be passed to the layout template
38+
* Implement template wrappers. For this we need to remember real template to be loaded.
39+
* Then we return the object itself to be able to manipulate the loading process.
2540
*
26-
* @param string $layout Layout name to be rendered after views render.
41+
* @param string $template Template to be included inside theme.
42+
*
43+
* @return $this
2744
*/
28-
public static function layout_open( $layout = 'main' ) {
29-
// WordPress compatibility to still process usual headers.
30-
do_action( 'get_header', null );
45+
public function init_template( $template ) {
46+
$this->template = $template;
3147

32-
// check that we have required template.
33-
$template = static::locate( 'layouts/' . $layout, true );
48+
return $this;
49+
}
3450

35-
// memorize the template.
36-
static::$_layout = $layout;
37-
array_push( static::$_processing, $template );
51+
/**
52+
* Convert object to string magic method.
53+
* We replaced string with object inside `template_include` hook, so to support next include statement we need
54+
* to add magic method, which make object to string conversion.
55+
*
56+
* Here we will just return theme index.php file, which will be the entry point of our views engine.
57+
*
58+
* @return string
59+
*/
60+
public function __toString() {
61+
return locate_template( array( 'index.php' ) );
62+
}
3863

39-
// start buffer.
40-
ob_start();
41-
ob_implicit_flush( false );
64+
/**
65+
* Start loading theme template.
66+
*/
67+
public function include_template() {
68+
// add alias.
69+
$template = $this->template;
70+
71+
include $this->template;
72+
73+
$this->wrap();
4274
}
4375

4476
/**
45-
* Stop recording content part and final render of the layout
77+
* Wrap content with another view or layout
4678
*
47-
* @throws \Exception No layout_open were called before close.
79+
* @return bool
4880
*/
49-
public static function layout_close() {
50-
if ( empty( static::$_processing ) ) {
51-
throw new \Exception( 'Unexpected Views::layout_close() method call. Check that you have layout_open() call and not close layout before.' );
81+
public function wrap() {
82+
if ( empty( $this->extends ) ) {
83+
return false;
5284
}
5385

54-
// get content.
55-
$content = ob_get_clean();
86+
while( ob_get_contents() && $template = array_pop( $this->extends ) ) {
87+
$content = ob_get_contents();
88+
89+
// clean view file buffer.
90+
ob_clean();
5691

57-
// reset query to protect header from unclosed query in the content.
58-
wp_reset_postdata();
92+
// reset query to protect header from unclosed query in the content.
93+
wp_reset_postdata();
94+
95+
// render under the existing context.
96+
include $template;
97+
}
98+
}
5999

60-
// render under the existing context.
61-
include array_pop( static::$_processing );
100+
/**
101+
* Registers parent template.
102+
* Parent template will be rendered just after current template execution.
103+
*
104+
* To use current template generated html use `$content` variable inside the parent view
105+
*
106+
* @param string $layout View name to register.
107+
*
108+
* @return bool
109+
* @throws \Exception If no parent view template found.
110+
*/
111+
public function extends( $layout = 'layouts/main' ) {
112+
if ( false === $layout ) {
113+
return false;
114+
}
115+
116+
// WordPress compatibility to still process usual headers.
117+
if ( empty( $this->extends ) ) {
118+
do_action( 'get_header', null );
119+
}
120+
121+
// check that we have required template.
122+
$template = $this->locate( $layout, true );
123+
124+
// memorize the template.
125+
array_push( $this->extends, $template );
126+
127+
// start buffer.
128+
ob_start();
129+
return true;
62130
}
63131

64132
/**
65133
* WordPress compatibility option instead of get_sidebar, to run a sidebar hook
66134
*
67135
* @param string|null $name custom sidebar name.
68136
*/
69-
public static function sidebar_begin( $name = null ) {
137+
public function sidebar_begin( $name = null ) {
70138
// WordPress compatibility.
71139
do_action( 'get_footer', $name );
72140
}
73141

74142
/**
75143
* WordPress compatibility option intead of get_sidebar
76144
*
77-
* @param string|name $name custom footer name.
145+
* @param string|null $name custom footer name.
78146
*/
79-
public static function footer_begin( $name = null ) {
147+
public function footer_begin( $name = null ) {
80148
// WordPress compatibility.
81149
do_action( 'get_footer', $name );
82150
}
@@ -88,19 +156,20 @@ public static function footer_begin( $name = null ) {
88156
* @param array $params params to be passed to the view.
89157
* @param boolean $__required print message if views not found.
90158
*
91-
* @return bool|void
159+
* @return bool
92160
*/
93-
public static function render( $view, $params = array(), $__required = true ) {
94-
$__views_path = static::locate( $view, $__required );
95-
if ( empty( $__views_path ) ) {
161+
public function render( $view, $params = array(), $__required = true ) {
162+
$template = $this->locate( $view, $__required );
163+
if ( empty( $template ) ) {
96164
return false;
97165
}
98166

99167
if ( ! empty( $params ) ) {
100168
extract( $params );
101169
}
102170

103-
include $__views_path;
171+
include $template;
172+
return true;
104173
}
105174

106175
/**
@@ -114,7 +183,7 @@ public static function render( $view, $params = array(), $__required = true ) {
114183
*
115184
* @throws \Exception Required and not found.
116185
*/
117-
public static function locate( $view, $required = false ) {
186+
public function locate( $view, $required = false ) {
118187
$view_file = "views/$view.php";
119188
$template = locate_template( $view_file );
120189
if ( $required && ( empty( $template ) || ! is_file( $template ) ) ) {

readme.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ To upgrade remove the old plugin folder. After than follow the installation step
9191

9292
== Changelog ==
9393

94+
= Version 2.1.0 - 15 December 2017 =
95+
* New: Updated View component and layouts wrapping rendering. Replaced layout_open()/layout_close() methods with extends() method.
9496
= Version 2.0.1 - 27 November 2017 =
9597
* New: Removed theme hooks to patch WordPress-generated .htaccess (moved to starter package)
9698
= Version 2.0 - 21 November 2017 =

wordpress-theme-framework.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
Plugin Name: WordPress Theme Framework
55
Description: Lightweight theme framework base with Model-View concept for developers who want to better organize their own custom themes.
66
Tags: mvc theme, theme boilerplate, oop theme, mini framework
7-
Version: 2.0.1
7+
Version: 2.1.0
88
Author: JustCoded / Alex Prokopenko
99
Author URI: http://justcoded.com/
1010
License: GPL3

0 commit comments

Comments
 (0)