WP Emerge 0.15.0: What’s new and what’s next

by Atanas Angelov | Jun 3rd, 2019 | Releases

The release of 0.15.0 is a major stepping stone towards a stable 1.0.0 release. As such, it includes a number of minor breaking changes aimed at extensibility and consistency across the board.

Framework (GitHub)

What’s New

  • Defining routes and route groups has been completely rewritten (docs).

  • You can now define Web, Admin and AJAX routes each with their own global middleware.

  • Automatic namespace prefixes have been added for Controllers, View Composers and Middleware.
    This allows you to define controllers like this:


    which will be automatically prefixed like this:


    Note: you can still use fully qualified class names – the prefix is only added if the class does not exist.

  • Route namespace prefixes can be adjusted on a per-group or per-route basis.
    For example this:

    Route::setNamespace( '\\App\\Controllers\\Dashboard\\')->group( function () {
      Route::get()->url( '/dashboard/profile' )->handle( 'Profile@view' );
    } );

    will result in this:

  • Added a new Route::view() shortcut to directly rendering a view in response to a request.

    Route::get()->url( '/' )->view( 'index.php' );
  • Middlewares now use string aliases that you need to register in your configuration (docs).

    // Configuration:
    'middleware' => [
      'foo' => FooMiddleware::class,
    // Routes:
    Route::middleware( 'foo' )->...
  • Added ability to pass basic parameters to middleware (docs).

    Route::middleware( 'user.can:manage_options' )->...
  • Arbitrary middleware groups can now be created and assigned as middleware to routes by utilizing the new aliases functionality. You can even reference groups within groups (docs).

    // Configuration:
    'middleware_groups' => [
      'privileged' => [
    // Routes:
    Route::middleware( 'privileged' )->...
  • Middleware ordering has been simplified and made consistent in cases where priority has not been specified (docs).

  • Middleware classes are now instantiated through the container allowing for dependency injection.

  • Introduced several new built-in middlewares to deal with authentication and authorization: user.logged_in, user.logged_out and user.can (docs).

  • Introduced WPEmerge\run() which allows you to run a full middleware + controller pipeline and get a response object independently from defined routes.
    Running this:

    $response = \WPEmerge\run( \WPEmerge\Requests\Request::fromGlobals(), ['user.logged_in'], function ( $request, $foo ) {
      return 'Hello ' . $foo;
    }, ['World'] );

    will result in a PSR-7 response object be it a redirect response if the user is not logged in due to the middleware supplied or a 200 OK response with a body of ‘Hello World’.
    If you want to output the response as usual you can use \WPEmerge\Facades\Response::respond( $response );

  • Added support for multiple views directories for all view engines.
    You can now specify a single path or an array of paths.

  • Fixed a race condition in Blade and Twig which caused global variables to not be available if registered too early.

  • The URL condition now has full regular expression support through a new parameter (docs).

    Route::get()->url( '/year/{year}', ['year' => '/^\d+$/'] )->...
  • Added @method annotations for every facade class for improved IDE support.

  • Various codebase-covering improvements targeting consistency and simplicity.

  • Various improvements to the documentation including a new CONTRIBUTING.md file in the repository.

Breaking Changes

  • Routes now must be defined in a separate file and then referenced in the configuration (docs):

    // Configuration:
    'routes' => [
      'web'   => 'routes/web.php',
      'admin' => 'routes/admin.php',
      'ajax'  => 'routes/ajax.php',

    All groups are optional so you do not need to create an admin routes file if you have no admin routes.

  • Fixed PHP layout hierarchy being executed in the incorrect order (inside-out instead of outside-in).

  • Direct \WPEmerge\Requests\Request references have been replaced with a new \WPEmerge\Requests\RequestInterface interface.

  • app_response() is now \WPEmerge\response().

  • app_output is now \WPEmerge\output().

  • app_json is now \WPEmerge\json().

  • app_redirect is now \WPEmerge\redirect().

  • app_view is now \WPEmerge\view().

  • app_error is now \WPEmerge\error().

  • app_partial is now \WPEmerge\render().

  • app_layout_content is now \WPEmerge\layout_content().

  • ->add() is now ->middleware()

  • Routes are no longer declared using Router::. See here for more information.

  • Router::handleAll() is now Route::all().

  • The ability to specify a regular expresson inline for a URL condition parameter has been removed. Use the new separate URL condition parameter instead (docs).

  • The RouteCondition facade has been removed.

  • ServiceProviderInterface::boot() is now ServiceProviderInterface::bootstrap().

  • WPEmerge::boot() is now WPEmerge::bootstrap().

  • Framework facade is now WPEmerge.


  • WPEmerge::facade() is now WPEmerge::alias().

  • MiddlewareInterface has been removed and is no longer required for middleware.

  • Blade and Twig extensions will now proxy .php view rendering to the default view engine by default.

  • An exception will no longer be thrown if manifest.json is missing.

Starter Theme (GitHub)

  • Added a new yarn release command which builds and zips up your theme to be ready for distribution (docs).
  • Added suport for WordPress 5.2 features such as wp_body_open and login_headertext.
  • Removed app/framework.php in favor of separate app/routes/*.php and /app/views.php files.
  • Added a new app/helpers/admin.php file.
  • Updated WPCS to 2.0.
  • Added a version number in composer.json for easy referencing.
  • Automatically install and build all assets on install for easier setup process.
  • Added @hook annotations to files that are loaded during a hook.
  • Added an .htaccess file which blocks direct access to “source” directories.
  • Implemented common browserslist for Babel and Autoprefixer.
  • Added development port option to config.json (props @mickaelperrin).
  • Simplified editor.scss by utilizing SASS map loops.
  • Added missing ABSPATH check to certain files.
  • Updated Blade templates for consistency.
  • Updated all WP Emerge usage to match latest release.

What’s Next

While nothing is set in store, here what WP Emerge is aiming at next, in no particular order:

Plugin Support

While having all that functionality in a theme has its benefits it is not “the WordPress way”. Plugin support will enable users to include WP Emerge into their plugins in a pain-free way.

Starter Plugin

A starter plugin would be a great addition to Plugin Support to enable developers to hit the ground running.

Progressive CSS

There is nothing stopping users from implementing their own solution to this but I believe this is an interesting opportunity for WP Emerge to step in and provide some boilerplate-free tooling.

Theme Styles

The starter theme comes with zero theme styles so users don’t have to delete or override styling to implement their design. Having an optional theme styles package on the other hand should help developers get acquainted with the WP Emerge workflow.

Long Term: Migrations

If you’ve used Laravel or Symfony you probably miss the database migration tools that they provide (e.g. update, rollback and seed). Doing the same in WordPress is by no means straightforward which is why I’m thinking about creating a WordPress-specific migrations library which can tightly integrate with WP Emerge.

Excited about WP Emerge’s new features? Let me know by posting a comment and joining me in the WP Emerge Gitter Lobby for a chat!

Comments are closed.