11<?php
22namespace 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 */
810class 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 ) ) ) {
0 commit comments