Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
126 | 127 | Skip » 128 | 129 |├── .gitignore ├── .nojekyll ├── 404.html ├── CNAME ├── README.md ├── _404.md ├── _images ├── apple-touch-icon.png ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── favicon.png ├── safari-pinned-tab.svg ├── wpemerge-logo-bar.png ├── wpemerge-logo.png ├── wpemerge-plugin-logo-bar.png ├── wpemerge-theme-logo-bar.png └── wpemerge.png ├── _media └── style.css ├── _sidebar.md ├── framework ├── 0-to-100-setup.md ├── _sidebar.md ├── configuration.md ├── extending │ └── overview.md ├── overview.md ├── quickstart.md ├── routing │ ├── conditions.md │ ├── controllers.md │ ├── defining-routes.md │ ├── error-handling.md │ ├── groups.md │ ├── handlers.md │ ├── methods.md │ ├── middleware.md │ └── request-lifecycle.md ├── tools │ ├── app-shortcuts.md │ ├── csrf-protection.md │ ├── flash.md │ ├── oldinput.md │ └── service-providers.md └── views │ ├── global-context.md │ ├── layouts.md │ ├── overview.md │ └── view-composers.md ├── index.html └── starter ├── _sidebar.md ├── assets ├── gutenberg.md ├── overview.md └── sprites.md ├── cli └── overview.md ├── configuration.md ├── plugin ├── overview.md ├── quickstart.md └── what-goes-where.md ├── publishing.md ├── scripts.md ├── theme ├── overview.md ├── quickstart.md └── what-goes-where.md └── utilities ├── assets.md ├── avatar.md ├── config.md ├── image.md └── sidebar.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Build modules 2 | /node_modules/ 3 | 4 | # Composer packages 5 | /vendor/ 6 | 7 | # NPM lockfile as it causes more problems than it solves 8 | package-lock.json 9 | 10 | # Common 11 | .DS_Store 12 | .DS_Store? 13 | ._* 14 | .Spotlight-V100 15 | .Trashes 16 | ehthumbs.db 17 | Thumbs.db 18 | .idea 19 | -------------------------------------------------------------------------------- /.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/htmlburger/wpemerge-docs/6a7109e1dd9e7a331d51dba50d4d48c93423561e/.nojekyll -------------------------------------------------------------------------------- /404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
126 | 127 | Skip » 128 | 129 |Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
270 | 271 | Skip » 272 | ``` 273 | 274 | We reduced PHP logic duplication, but this doesn't solve the use case where we want to have that variable available in a view partial, for example. For this we can use the `\App::render( $view, $context = [] )` function which works very similarly to `get_template_part()` but as you can see it has an optional argument which allows you to pass context variables as well: 275 | ```php 276 | $skip_url] ); ?> 277 | ``` 278 | 279 | ## FAQ 280 | 281 | ##### What if we wish to have a partial that is reused throughout the site but it needs a certain variable? Do we have to add that logic to every controller which loads a view which includes that partial? 282 | 283 | Thankfully, no! This is where view composers come into play - check out the [View Composers](/framework/views/view-composers) article to see how they can solve this problem and more. 284 | 285 | ##### What if we wanted to show the CTA on a page other than the homepage - do we have to hardcode that page's URL in the route definition? 286 | 287 | We can but we don't have to. We can take advantage of WP Emerge's dynamic [Route Conditions](/framework/routing/conditions). As an example, this is what our route definition will look like if we wish to show the CTA on any page that uses a custom template called `template-cta-enabled-page.php`: 288 | ```php 289 | \App::route()->get() 290 | ->where( 'post_template', 'template-cta-enabled-page.php' ) 291 | ->handle( 'HomeController@index' ); 292 | ``` 293 | -------------------------------------------------------------------------------- /framework/_sidebar.md: -------------------------------------------------------------------------------- 1 | * Framework 2 | 3 | * [Overview](/framework/overview) 4 | * [Quickstart](/framework/quickstart) 5 | * [Configuration](/framework/configuration) 6 | * [0 to 100 Setup](/framework/0-to-100-setup) 7 | 8 | * Routing 9 | 10 | * [Request Lifecycle](/framework/routing/request-lifecycle) 11 | * [Defining Routes](/framework/routing/defining-routes) 12 | * [Methods](/framework/routing/methods) 13 | * [Conditions](/framework/routing/conditions) 14 | * [Groups](/framework/routing/groups) 15 | * [Handlers](/framework/routing/handlers) 16 | * [Controllers](/framework/routing/controllers) 17 | * [Middleware](/framework/routing/middleware) 18 | * [Error Handling](/framework/routing/error-handling) 19 | 20 | * Views 21 | 22 | * [Overview](/framework/views/overview) 23 | * [Layouts](/framework/views/layouts) 24 | * [Global Context](/framework/views/global-context) 25 | * [View Composers](/framework/views/view-composers) 26 | 27 | * Tools 28 | 29 | * [\App shortcuts](/framework/tools/app-shortcuts) 30 | * [Service Providers](/framework/tools/service-providers) 31 | * [Flash](/framework/tools/flash) 32 | * [OldInput](/framework/tools/oldinput) 33 | * [CSRF Protection](/framework/tools/csrf-protection) 34 | 35 | * Extending 36 | 37 | * [Overview](/framework/extending/overview) 38 | -------------------------------------------------------------------------------- /framework/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | When booting WP Emerge you can specify a number of configuration options: 4 | ```php 5 | \App::make()->bootstrap( [ 6 | /** 7 | * Default class namespace prefix. 8 | * Automatically prepended to all controllers and view composers for convenience. 9 | */ 10 | 'namespace' => 'App\\', 11 | 12 | /** 13 | * Array of service providers you wish to enable. 14 | */ 15 | 'providers' => [ 16 | // Examples: 17 | MyServiceProviders::class, 18 | // Blade example for htmlburger/wpemerge-blade: 19 | WPEmergeBlade\View\ServiceProvider::class, 20 | ], 21 | 22 | /** 23 | * Array of route group definitions and default attributes. 24 | * All of these are optional so if we are not using 25 | * a certain group of routes we can skip it. 26 | * If we are not using routing at all we can skip 27 | * the entire 'routes' option. 28 | */ 29 | 'routes' => [ 30 | 'web' => [ 31 | 'definitions' => get_template_directory() . '/routes/web.php', 32 | 'attributes' => [], 33 | ], 34 | 'admin' => [ 35 | 'definitions' => get_template_directory() . '/routes/admin.php', 36 | 'attributes' => [], 37 | ], 38 | 'ajax' => [ 39 | 'definitions' => get_template_directory() . '/routes/ajax.php', 40 | 'attributes' => [], 41 | ], 42 | ], 43 | 44 | /** 45 | * Register middleware class aliases. 46 | * Use fully qualified middleware class names. 47 | * 48 | * Internal aliases that you should avoid overriding: 49 | * - 'flash' 50 | * - 'old_input' 51 | * - 'csrf' 52 | * - 'user.logged_in' 53 | * - 'user.logged_out' 54 | * - 'user.can' 55 | */ 56 | 'middleware' => [ 57 | // Examples: 58 | 'mymiddleware' => \App\Middleware\MyMiddleware::class, 59 | ], 60 | 61 | /** 62 | * Register middleware groups. 63 | * Use fully qualified middleware class names or registered aliases. 64 | * There are a couple built-in groups that you may override: 65 | * - 'web' - Automatically applied to web routes. 66 | * - 'admin' - Automatically applied to admin routes. 67 | * - 'ajax' - Automatically applied to ajax routes. 68 | * - 'global' - Automatically applied to all of the above. 69 | * - 'wpemerge' - Internal group applied the same way 'global' is. 70 | * 71 | * Warning: The 'wpemerge' group contains some internal WP Emerge 72 | * middleware which you should avoid overriding. 73 | */ 74 | 'middleware_groups' => [ 75 | 'global' => [], 76 | 'web' => [ 77 | // Examples: 78 | 'mymiddleware', 79 | ], 80 | 'ajax' => [], 81 | 'admin' => [], 82 | ], 83 | 84 | /** 85 | * Optionally specify middleware execution order. 86 | * Use fully qualified middleware class names. 87 | * Middlewares not in this list will execute after all middlewares in 88 | * it in the order they were assigned. 89 | */ 90 | 'middleware_priority' => [ 91 | // Examples: 92 | \App\Middleware\MyMiddlewareThatShouldRunFirst::class, 93 | \App\Middleware\MyMiddlewareThatShouldRunSecond::class, 94 | ], 95 | 96 | /** 97 | * Custom directories to search for views. 98 | * Use absolute paths or leave blank to disable. 99 | * View engines other than the default PhpViewEngine 100 | * will default to this value as well but may have 101 | * their own setting as well. 102 | */ 103 | 'views' => [get_stylesheet_directory(), get_template_directory()], 104 | 105 | /** 106 | * View Composers settings. 107 | */ 108 | 'view_composers' => [ 109 | // Default namespace. 110 | 'namespace' => 'App\\ViewComposers\\', 111 | ], 112 | 113 | /** 114 | * Cache settings. 115 | */ 116 | 'cache' => [ 117 | // Absolute path to custom default cache directory. 118 | // Extensions like Blade and Twig will use this value for their views cache 119 | // unless one has been specified for them. 120 | // Defaults to ROOT_DIR/wp-content/uploads/wpemerge/cache. 121 | 'path' =>'/some/cache/directory/', 122 | ], 123 | 124 | /** 125 | * Debug settings. 126 | */ 127 | 'debug' => [ 128 | // Enable debug mode. Defaults to the value of WP_DEBUG. 129 | 'enable' => true, 130 | // Enable the use of filp/whoops for an enhanced error interface. Defaults to true. 131 | 'pretty_errors' => true, 132 | ], 133 | ] ) 134 | ``` 135 | -------------------------------------------------------------------------------- /framework/extending/overview.md: -------------------------------------------------------------------------------- 1 | # Extending 2 | 3 | WP Emerge uses a service container for all of its dependencies which means that you can easily replace or add dependencies. 4 | For a real-world example, we will be adding our own custom routing condition. 5 | 6 | ## Scenario 7 | 8 | - Our site has events with a post type of `event`. 9 | - Events have an `event_date` post meta which holds the date the event is scheduled for. The date format stored is 10 | `Y-m-d` e.g. 2018-12-31. 11 | - Our goal is to match all past events and display a custom page. 12 | 13 | ## Implementation 14 | 15 | 1. First, we will define our custom condition class: 16 | ```php 17 | use WPEmerge\Requests\RequestInterface; 18 | use WPEmerge\Routing\Conditions\ConditionInterface; 19 | 20 | class PastEvent implements ConditionInterface { 21 | public function isSatisfied( RequestInterface $request ) { 22 | // Makre sure we are on a singular event page. 23 | if ( is_singular( 'event' ) ) { 24 | // Get the event date. 25 | $event_date = get_post_meta( get_the_ID(), 'event_date', true ); 26 | // Get today's date in the same format. 27 | $today = date( 'Y-m-d' ); 28 | 29 | // The Y-m-d format is very easy to compare. 30 | if ( $today > $event_date ) { 31 | // Our condition is satisfied - we must return true. 32 | return true; 33 | } 34 | } 35 | 36 | // In all other cases return false. 37 | return false; 38 | } 39 | 40 | public function getArguments( RequestInterface $request ) { 41 | // We can return an array of arguments we wish to pass on to the 42 | // route handler for convenience. 43 | // We do not really need to pass anything so we return an empty 44 | // array but we could pass the event date, for example. 45 | return []; 46 | } 47 | } 48 | ``` 49 | 50 | 2. Next, we will define a service provider class which will register our new condition: 51 | ```php 52 | use WPEmerge\ServiceProviders\ServiceProviderInterface; 53 | 54 | class PastEventConditionServiceProvider implements ServiceProviderInterface { 55 | public function register( $container ) { 56 | // Conditions are registered by appending them to the 57 | // array of condition types which is registered with 58 | // the WPEMERGE_ROUTING_CONDITION_TYPES_KEY key 59 | // in the container. 60 | $condition_name = 'past_event'; 61 | $condition_class = PastEvent::class; 62 | 63 | $container[ WPEMERGE_ROUTING_CONDITION_TYPES_KEY ] = array_merge( 64 | $container[ WPEMERGE_ROUTING_CONDITION_TYPES_KEY ], 65 | [ 66 | $condition_name => $condition_class, 67 | ] 68 | ); 69 | } 70 | 71 | public function bootstrap( $container ) { 72 | // We have nothing to bootstrap. 73 | } 74 | } 75 | ``` 76 | 77 | 3. Finally, we pass our brand new service provider while booting WP Emerge: 78 | ```php 79 | \App::make()->bootstrap( [ 80 | 'providers' => [ 81 | // ... other providers go here 82 | PastEventConditionServiceProvider::class, 83 | // ... or here 84 | ], 85 | // ... other options go here 86 | ] ); 87 | ``` 88 | 89 | We can now use our custom route condition like so: 90 | ```php 91 | \App::route()->get() 92 | ->where( 'past_event' ) 93 | ->handle( function( $request ) { 94 | return 'This event has already passed :('; 95 | } ); 96 | ``` 97 | -------------------------------------------------------------------------------- /framework/overview.md: -------------------------------------------------------------------------------- 1 | #' . $error . '
'; 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /framework/tools/oldinput.md: -------------------------------------------------------------------------------- 1 | # OldInput 2 | 3 | OldInput is a built-in global middleware which allows you to recall POST request input from the previous request ( this will be familiar if you've used [Laravel's old()](https://laravel.com/docs/5.4/requests#old-input) ). 4 | 5 | Since OldInput internally uses Flash, you have to ensure a session is available for it: 6 | ```php 7 | add_action( 'init', function() { 8 | session_start(); 9 | } ); 10 | ``` 11 | 12 | ## Usage 13 | 14 | A typical use case is to fill in field values after an error has occurred with the user's form submission: 15 | ```php 16 | // inside your form view 17 | 18 | ``` 19 | 20 | To reduce verbosity you can define your own simple `old()` function like this: 21 | 22 | ```php 23 | function old() { 24 | return call_user_func_array( [\App::oldInput(), 'get'], func_get_args() ); 25 | } 26 | ``` 27 | -------------------------------------------------------------------------------- /framework/tools/service-providers.md: -------------------------------------------------------------------------------- 1 | # Service Providers 2 | 3 | A service provider is a class that registers and bootstraps services into the WP Emerge service container. 4 | 5 | WP Emerge itself uses service providers to register and bootstrap most of its functionality, for example: 6 | - `\WPEmerge\Flash\FlashServiceProvider` 7 | - `\WPEmerge\Routing\RoutingServiceProvider` 8 | 9 | The external Twig and Blade view implementations also use service providers to add their respective view engines: 10 | - https://github.com/htmlburger/wpemerge-twig - `\WPEmergeTwig\View\ServiceProvider` 11 | - https://github.com/htmlburger/wpemerge-blade - `\WPEmergeBlade\View\ServiceProvider` 12 | 13 | Here's how to register a service provider with WP Emerge: 14 | ```php 15 | \App::make()->bootstrap( [ 16 | 'providers' => [ 17 | SomeServiceProvider::class, 18 | SomeOtherServiceProvider::class, 19 | // ... 20 | ], 21 | // ... other boot options here 22 | ] ); 23 | ``` 24 | 25 | Take a look at the [Extending](/framework/extending/overview) section for a real-world usage example. 26 | -------------------------------------------------------------------------------- /framework/views/global-context.md: -------------------------------------------------------------------------------- 1 | # Global Context 2 | 3 | You can pass variables to all views and partials by adding them as globals using `\App::views()->addGlobal()` or `\App::views()->addGlobals()`. 4 | 5 | First, we need to create a service provider class: 6 | ```php 7 | addGlobal( 'foo', 'bar' ); 27 | 28 | // Add many variables. 29 | \App::views()->addGlobals( [ 30 | 'name' => get_bloginfo( 'name' ), 31 | 'url' => home_url( '/' ), 32 | ] ); 33 | } 34 | } 35 | ``` 36 | 37 | Second, we need to register that service provider in the configuration: 38 | ```php 39 | \App::make()->bootstrap( [ 40 | 'providers' => [ 41 | // ... 42 | \App\View\ViewGlobalContextServiceProvider::class, 43 | ], 44 | // ... 45 | ] ); 46 | ``` 47 | 48 | Then, we can use the registered globals in any view: 49 | ```php 50 | 51 | 52 | 53 | ``` 54 | -------------------------------------------------------------------------------- /framework/views/layouts.md: -------------------------------------------------------------------------------- 1 | # Layouts 2 | 3 | It is a common pattern in WordPress themes to see `get_header()` and `get_footer()` called in every template. In addition, these calls are often followed or preceded by related markup. 4 | In WP Emerge, all of this repetition can be avoided by utilizing layouts. 5 | 6 | !> The layout functionality described below only applies to the default PHP view engine. Other view 7 | engines such as Blade and Twig have their own layout implementation which should be used instead. 8 | 9 | ## Example 10 | 11 | Here's the main `theme/index.php` view of the WP Emerge Starter Theme: 12 | 13 | ```php 14 | ', '' ); 35 | } 36 | 37 | \App::layoutContent(); 38 | 39 | \App::render( 'sidebar' ); 40 | 41 | \App::render( 'footer' ); 42 | ``` 43 | 44 | Nothing unusual about this file except the call to `\App::layoutContent()` - this is what defines where the actual view content should be rendered. Essentially, any view can be used as a layout as long as it calls `\App::layoutContent()` to include the "child" view content. 45 | Also like any other view, layouts can declare their own `Layout` to achieve layout nesting and you can even use View Composers on layouts to pass context values. 46 | 47 | You no longer need to have the header/footer boilerplate in every view while retaining the flexibility of having different header/footer partials for different templates by declaring your desired layouts when needed. 48 | -------------------------------------------------------------------------------- /framework/views/overview.md: -------------------------------------------------------------------------------- 1 | # Views 2 | 3 | WP Emerge comes with a default view engine built-in - `\WPEmerge\View\PhpViewEngine`. 4 | This view engine uses `extract()` for the view context and then includes the view file. The resulting output is then passed as the rendered view string. 5 | Essentially, this engine loads views in the same way WordPress does, but with a couple extra features: 6 | 7 | 1. Context variable passing. 8 | 2. Ability to specify layouts for views. 9 | 10 | ## External view engines 11 | 12 | ### WP Emerge Blade 13 | 14 | Renders your views using Blade: https://github.com/htmlburger/wpemerge-blade 15 | 16 | ### WP Emerge Twig 17 | 18 | Renders your views using Twig: https://github.com/htmlburger/wpemerge-twig 19 | 20 | ## Other built-in view engines 21 | 22 | ### NameProxyViewEngine 23 | 24 | WP Emerge also comes with a small utility view engine which delegates view rendering to other engines depending on the view name suffix. 25 | The main use-case for it is to allow you to use multiple view engines so you can migrate to a new one on a view-by-view basis instead of forcing you to rewrite all of your views. 26 | 27 | Replacing the default view engine: 28 | ```php 29 | // Run this inside the register() method of a service provider. 30 | $container[ WPEMERGE_VIEW_ENGINE_KEY ] = function( $container ) { 31 | return new \WPEmerge\View\NameProxyViewEngine( 32 | $container[ WPEMERGE_APPLICATION_KEY ], 33 | [ 34 | // Format: view name suffix => service container key for alternative engine. 35 | 36 | // Use Twig for twig.php views. 37 | '.twig.php' => WPEMERGETWIG_VIEW_TWIG_VIEW_ENGINE_KEY, 38 | 39 | // Use Blade for .blade.php views. 40 | '.blade.php' => WPEMERGEBLADE_VIEW_BLADE_VIEW_ENGINE_KEY, 41 | 42 | // Use default PHP engine for .php views. 43 | '.php' => WPEMERGE_VIEW_PHP_VIEW_ENGINE_KEY, 44 | 45 | // Use Blade for all other cases as blade views can be referenced 46 | // in blade.format.as.well without an extension. 47 | ], 48 | WPEMERGEBLADE_VIEW_BLADE_VIEW_ENGINE_KEY 49 | ); 50 | }; 51 | ``` 52 | !> The example above assumes you have included both WP Emerge Twig and WP Emerge Blade composer packages. 53 | `WPEMERGETWIG_VIEW_TWIG_VIEW_ENGINE_KEY` and `WPEMERGEBLADE_VIEW_BLADE_VIEW_ENGINE_KEY` are not provided by default. 54 | 55 | ## Implementing other View Engines 56 | 57 | Implementing your own or a third-party engine is straightforward - there are only a couple requirements: 58 | 59 | 1. Your class must implement the `\WPEmerge\View\ViewEngineInterface` interface 60 | ```php 61 | use \WPEmerge\View\ViewEngineInterface; 62 | 63 | class MyCustomViewEngine implements ViewEngineInterface { 64 | // ... 65 | } 66 | ``` 67 | 68 | 2. You must use a service provider class to register your new view engine: 69 | ```php 70 | use \WPEmerge\ServiceProviders\ServiceProviderInterface; 71 | 72 | class MyCustomServiceProvider implements ServiceProviderInterface { 73 | public function register( $container ) { 74 | $container['my_custom_view_engine'] = function ( $c ) { 75 | return new MyCustomViewEngine(); 76 | }; 77 | } 78 | // ... 79 | } 80 | ``` 81 | 3. ... and to replace the built-in engine: 82 | ```php 83 | use \WPEmerge\ServiceProviders\ServiceProviderInterface; 84 | 85 | class MyCustomServiceProvider implements ServiceProviderInterface { 86 | public function register( $container ) { 87 | $container['my_custom_view_engine'] = function ( $c ) { 88 | return new MyCustomViewEngine(); 89 | }; 90 | 91 | $container[ WPEMERGE_VIEW_ENGINE_KEY ] = function ( $c ) { 92 | return $c['my_custom_view_engine']; 93 | }; 94 | } 95 | // ... 96 | } 97 | ``` 98 | 4. Finally, register your service provider with WP Emerge: 99 | ```php 100 | \App::make()->bootstrap( [ 101 | 'providers' => [ 102 | // ... other providers 103 | MyCustomServiceProvider::class, 104 | ], 105 | // ... other options 106 | ] ); 107 | ``` 108 | -------------------------------------------------------------------------------- /framework/views/view-composers.md: -------------------------------------------------------------------------------- 1 | # View Composers 2 | 3 | View composers prepare context for a view, partial, or layout whenever it is rendered. A view composer can be one of the following: 4 | - An anonymous function. 5 | - A reference in the `[ ClassName::class, 'METHOD_NAME' ]` format. 6 | - A reference in the `'CLASS_NAME@METHOD_NAME'` format. 7 | 8 | !> Default View Engine WARNING: Due to the nature of how `get_template_part()` works, you __MUST__ render partials using `\App::render()` instead of `get_template_part()` in order to support composition. 9 | 10 | !> If you wish to compose core partials (e.g. `header.php`, `footer.php`) that are rendered using a `get_*()` function call (e.g. `get_header()`) you will have to use `\App::render( 'name' )` (e.g. `\App::render( 'header' )`) instead. 11 | 12 | ?> If the specified class name does not exist, by default, `\App\ViewComposers\` is automatically prepended for convenience. 13 | 14 | ?> More information on how to use `\App::render()` is available at the end of this article. 15 | 16 | ## Example 17 | 18 | In this example we want to pass the latest posts to the `templates/partials/latest-news.php` partial. 19 | 20 | First, we need to create a service provider class: 21 | ```php 22 | addComposer( 'templates/partials/latest-news', function( $view ) { 41 | $view->with( [ 42 | 'news' => new WP_Query( [ 43 | 'posts_per_page' => 3, 44 | ] ), 45 | ] ); 46 | } ); 47 | } 48 | } 49 | ``` 50 | 51 | Then, we need to register that service provider in the configuration: 52 | ```php 53 | \App::make()->bootstrap( [ 54 | 'providers' => [ 55 | // ... 56 | \App\ViewComposers\ViewComposersServiceProvider::class, 57 | ], 58 | // ... 59 | ] ); 60 | ``` 61 | 62 | With this, whenever the `latest-news.php` partial is loaded, we will have the `$news` variable automatically available: 63 | ```php 64 | // Inside latest-news.php: 65 | have_posts() ) : $news->the_post() ?> 66 | ... 67 | 68 | 69 | ``` 70 | 71 | Here's the same example, but using a class: 72 | 73 | ```php 74 | with( [ 81 | 'news' => new WP_Query( [ 82 | 'posts_per_page' => 3, 83 | ] ), 84 | ] ); 85 | } 86 | } ); 87 | ``` 88 | And in our service provider we refer to the class instead of the anonymous function: 89 | ```php 90 | // ... 91 | public function bootstrap( $container ) { 92 | \App::views()->addComposer( 93 | 'templates/partials/latest-news', 94 | \App\ViewComposers\LatestNewsViewComposer::class 95 | ); 96 | } 97 | // ... 98 | ``` 99 | 100 | The expected method name by default is `compose` but you can use a custom one as well: 101 | ```php 102 | // ... 103 | public function bootstrap( $container ) { 104 | \App::views()->addComposer( 105 | 'templates/partials/latest-news', 106 | 'LatestNewsViewComposer@customMethodName' 107 | ); 108 | } 109 | // ... 110 | ``` 111 | 112 | By default, WP Emerge will instantiate your class directly. However, if your class is registered in the service container with its class name as the key, then the class will be resolved from the service container instead: 113 | 114 | ```php 115 | // Run this inside the register() method of a service provider. 116 | $container[ LatestNewsViewComposer::class ] = function( $container ) { 117 | // your custom instantiation code here, e.g.: 118 | return new LatestNewsViewComposer(); 119 | } 120 | ``` 121 | 122 | ## \App::render( $views, $context = [] ) 123 | 124 | Why you would use `\App::render()`: 125 | 126 | 1. You are using the default default view engine. You do not need it when using Blade or Twig, for example, as they have composition built-in. 127 | 2. Partials rendered using `include`, `require`, `get_template_part()` etc. __DO NOT__ support composition, `\App::render()` does. 128 | 3. `\App::render()` optionally provides context to the partial through the `$context` parameter. 129 | 130 | For example, instead of using 131 | ```php 132 | 133 | ``` 134 | you would use 135 | ```php 136 | 137 | ``` 138 | or instead of using 139 | ```php 140 | 141 | ``` 142 | you would use 143 | ```php 144 | 145 | ``` 146 | 147 | If you do not need composition or context for a given partial, feel free to use `get_template_part()` instead. 148 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |