Bedrock is a modern WordPress stack that helps you get started with the best development tools and project structure.

Last update: Aug 12, 2022

Bedrock

MIT License Packagist Build Status Follow Roots

A modern WordPress stack
Built with ❤️

Official Website | Documentation | Change Log

Supporting

Bedrock is an open source project and completely free to use.

However, the amount of effort needed to maintain and develop new features and products within the Roots ecosystem is not sustainable without proper financial backing. If you have the capability, please consider donating using the links below:

Donate via Patreon Donate via PayPal

Overview

Bedrock is a modern WordPress stack that helps you get started with the best development tools and project structure.

Much of the philosophy behind Bedrock is inspired by the Twelve-Factor App methodology including the WordPress specific version.

Features

  • Better folder structure
  • Dependency management with Composer
  • Easy WordPress configuration with environment specific files
  • Environment variables with Dotenv
  • Autoloader for mu-plugins (use regular plugins as mu-plugins)
  • Enhanced security (separated web root and secure passwords with wp-password-bcrypt)

Requirements

Installation

  1. Create a new project:
    $ composer create-project roots/bedrock
  2. Update environment variables in the .env file. Wrap values that may contain non-alphanumeric characters with quotes, or they may be incorrectly parsed.
  • Database variables
    • DB_NAME - Database name
    • DB_USER - Database user
    • DB_PASSWORD - Database password
    • DB_HOST - Database host
    • Optionally, you can define DATABASE_URL for using a DSN instead of using the variables above (e.g. mysql://user:[email protected]:3306/db_name)
  • WP_ENV - Set to environment (development, staging, production)
  • WP_HOME - Full URL to WordPress home (https://example.com)
  • WP_SITEURL - Full URL to WordPress including subdirectory (https://example.com/wp)
  • AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY, NONCE_KEY, AUTH_SALT, SECURE_AUTH_SALT, LOGGED_IN_SALT, NONCE_SALT
  1. Add theme(s) in web/app/themes/ as you would for a normal WordPress site
  2. Set the document root on your webserver to Bedrock's web folder: /path/to/site/web/
  3. Access WordPress admin at https://example.com/wp/wp-admin/

Documentation

Bedrock documentation is available at https://roots.io/docs/bedrock/master/installation/.

Contributing

Contributions are welcome from everyone. We have contributing guidelines to help you get started.

Bedrock sponsors

Help support our open-source development efforts by becoming a patron.

Kinsta KM Digital Carrot C21 Redwood Realty WordPress.com Motto

Community

Keep track of development and community news.

GitHub

https://github.com/roots/bedrock
Comments
  • 1. Multisite support

    There's a few features of Bedrock that might make some Multisite setups a problem:

    • WP installed in subdirectory
    • Custom content folder

    Looking at some issues regarding this, it seems like MS support is still a bit of a mess. Related issues:

    • https://core.trac.wordpress.org/ticket/27287
    • https://core.trac.wordpress.org/ticket/23221
    • https://core.trac.wordpress.org/ticket/26969

    Here's a potential mu-plugin we may want to consider adding in Bedrock by default: https://gist.github.com/danielbachhuber/9379135

    /cc @ddebernardy I'm hoping you can speak to/summarize some of the issues you've ran into and potential solutions.

    Reviewed by swalkinshaw at 2014-04-10 19:05
  • 2. Language support

    There is a problem with language support (again). In this setup seting WPLANG to something does not do the trick because WP does not expect language directory in wp/wp-content but in app. If I wanted to work, I must move directory manually after composer install and before wordpress installation. Is there a way to tell composer to do this. For some reason themes works from wp/wp-content but language not.

    Reviewed by lautreamont3 at 2014-01-19 17:42
  • 3. .htaccess rewrite for the /web subdirectory

    Hi,

    The current Bedrock setup is not ideal for shared hosting environments or hosting environments with a control panel like Direct Admin. Changing the vhost to point to the /web directory is not always possible, allowed or the best option. Maybe it's an idea to ship a .htaccess file with Bedrock with some rewrites like suggested here: https://discourse.roots.io/t/ftp-use-and-point-domain-to-web-folder-w-htaccess/1556 to make Bedrock more "compatible". But with some extra security like:

    RewriteRule .env - [F]
    

    OR

    Order Deny,Allow
    deny from all
    
    <Files web/*>
        allow from all
    </Files>
    

    Maybe we can debate here for the best .htaccess setup?

    Reviewed by royduin at 2015-05-21 11:24
  • 4. General caching questions/discussion

    I know there were recently two applicable discussions: https://github.com/roots/bedrock/issues/38 and https://github.com/roots/bedrock-ansible/issues/34 ... but after reading them I am still left with some questions.

    It seems like the "recommended" way is to use Batcache + Memcached. Okay, great... but is Batcache still supported? It had no update in >7 months and the version on WordPress.org has not been updated for 2 years. Even if it is still maintained and works, it looks like you still need to have advanced-cache.php in the wp-content/ (or app/) directory. But since this is configuration, we should not be linking it via shared? So how do I manage it for deployment?

    On top of that, I mostly run single sites on single servers. Or maybe a couple vhosts on a server. Memcached is not really for this situation and Batcache even recommends using WP Super Cache in that case. I like WP Super Cache and am familiar with it but am running into the same issue with advanced-cache.php and the cache/ directory it creates. I don't mind blowing up the cache on deploy, and I suppose I could also link cache/ to shared/ as is done with uploads/... but I'm still not sure if that is "right" and am still left with advanced-cache.php sitting in app/. On top of that, Batcache instructions on github are less than clear... i.e. what the hell is Ryan's Memcached Backend 2.0, what does it do and why do I need it? I know that is a Batcache thing and not Bedrock, but no one seems to be home over there anyway.

    I am only just dipping my toes into Bedrock to see if it will work for our organization and so far I love it, but I am little surprised that more focus has not been put on the issue of caching since it is pretty vital to any WP site that generates even moderate traffic. I just want to try and get some input on the "best practices" approach because if I need to start deviating too far from the norm than there is really no purpose for me to continue with Bedrock.

    Reviewed by alexciarlillo at 2015-03-24 17:33
  • 5. Truly disable all updates via WP admin UI

    Based on this article about completely disabling automatic and/or UI-driven updates in WP (which is what we want in Bedrock AFAIK) and on my own experiments:

    DISALLOW_FILE_MODS implicitly includes AUTOMATIC_UPDATER_DISABLED and DISALLOW_FILE_EDIT, plus:

    • It hides the update notifications in the admin bar.
    • It hides the "Updates" sub-menu in the "Dashboard" admin menu.
    • It hides the "Update Available" messages in "Appearance -> Themes" and "Plugins -> Installed Plugins".

    I verified in the WP source that DISALLOW_FILE_MODS actually includes AUTOMATIC_UPDATER_DISABLED and DISALLOW_FILE_EDIT, and it is confirmed respectively here and here.

    Reviewed by fabschurt at 2014-12-09 00:52
  • 6. W3 Total Cache and /app/plugins/

    The first plugin often installed in many Wordpress setups is W3 Total Cache.

    This plugin creates app/cache/ and app/w3tc-config/ directories outside of the app/plugins/ directory in addition to three other files used by the plugin: advanced-cache.php, db.php, and object-cache.php.

    Perhaps adding plugin-specific ignores to Bedrock is a bit much, but maybe a line about this is the readme would be a good idea?

    From README.md:

    plugins, and mu-plugins are Git ignored by default since Composer manages them

    As of now, it seems to suggest that all plugins will be placed into the /app/plugins/ directory and be contained there, kept in check via Composer without any additional configuration of Bedrock's files.

    Reviewed by benjibee at 2014-02-06 10:23
  • 7. URL issues on multisite

    I have recently set up my first multisite with Bedrock, and I have encountered several issues where the URLs are not correct. After some investigation, I figured that the issues are a result of a problem in WordPress Core - in some places it does not honor the site URL setting. This is no problem with a regular WP install, but when WordPress is installed in a subdirectory as it is in Bedrock, the site URL is different from the home URL.

    The most significant problem is that some areas in the network admin will direct me to /wp-admin instead of /wp/wp-admin, for example when you're on the My Sites section and click on "Edit Site".

    To be clear, this is not a Bedrock bug, but I think it would be great if Bedrock provided a fix for it, so that other people do not run into this problem. While there are ways to workaround this with nginx / htaccess rewrites, I'd prefer to actually fix it from the code site. As of now, I have fixed these issues on my site, so I'll create a pull-request with my approach.

    Btw I also created a ticket on Core Trac, the first responses told me that WP doesn't officially support this - so not sure whether there will be a Core fix soon.

    Reviewed by felixarntz at 2016-04-14 12:42
  • 8. Can't seem to deploy with capistrano3... but all responses are successful.

    $ cap production deploy
     INFO [e9cd1232] Running /usr/bin/env mkdir -p /tmp/my_app/ on my_app.com
     INFO [e9cd1232] Finished in 0.484 seconds with exit status 0 (successful).
     INFO Uploading /tmp/my_app/git-ssh.sh 100.0%
     INFO [e91dcfcd] Running /usr/bin/env chmod +x /tmp/my_app/git-ssh.sh on my_app.com
     INFO [e91dcfcd] Finished in 0.063 seconds with exit status 0 (successful).
    

    This all looks good, but it doesn't create the directories or anything.

    Reviewed by jfrux at 2014-02-10 22:29
  • 9. New Bedrock Configuration Model

    • [x] tag roots/wp-config 1.0.0 before merge

    Problem

    The current Bedrock configuration system does not strictly adhere to one of the most important Roots core values:

    All environments should match production as close as possible.

    Stated another way and scoped specifically for Bedrock:

    Environment configuration values should default to production values and only deviate if absolutely necessary.

    This is not how bedrock currently works. the current bedrock configuration process described by the docs in general works like so:

    oldconfig

    Which seems fine at first. However, upon further examination it falls apart.

    The docs describe this intended usage:

    The environment configs are required before the main application config so anything in an environment config takes precedence over application.

    Note: You can't re-define constants in PHP. So if you have a base setting in application.php and want to override it in production.php for example, you have a few options:

    • Remove the base option and be sure to define it in every environment it's needed
    • Only define the constant in application.php if it isn't already defined.

    At best the config process:

    1. is not DRY
    2. does not fail safe in situations of an unexpected WP_ENV value.
    3. will silently reject configuration values if a user is not clear on how define()ing constants in php works
    4. is not consistent with our environment parity recommendations

    Not DRY

    If you want all environments to match production you would have to copy paste the contents of environments/production.php to everywhere except environments/development.php. Obvious DRY violations aside, this is error prone. environments/staging.php can easily get out of sync with environments/production.php and congratulations your staging environment no longer reflects production or vice versa.

    Does Not Fail Safe

    You could perhaps require_once __dir__ . '/production.php'; in every file except development.php. However now the second Bedrock encounters an unexpected WP_ENV variable (staging-experimental, productoin, or undefined to name a few): Bedrock will fail open and stuff like WP_DEBUG_DISPLAY will default to true (!!!). No web framework should behave this way when undefined values make their way into the system.

    Silent Configuration Rejections

    In ruby

    irb(main):001:0> WP_DEBUG_DISPLAY = true
    => true
    irb(main):002:0> WP_DEBUG_DISPLAY = false
    (irb):2: warning: already initialized constant WP_DEBUG_DISPLAY
    (irb):1: warning: previous definition of WP_DEBUG_DISPLAY was here
    => false
    

    Clearly I am trying to do something bad and the logs will reflect this.

    In PHP

    php > define('WP_DEBUG_DISPLAY', true);
    php > define('WP_DEBUG_DISPLAY', false);
    php > var_dump(WP_DEBUG_DISPLAY);
    bool(true)
    

    Yikes.

    Not Consistent With Roots Recommendations

    If we recommend:

    All environments should match production as close as possible.

    Then why does a user have to take explicit action to make this happen for every environment they define? Why doesn't it just default to this behavior? In the current model production configuration is "opt-in" instead of "opt-out". This is perpendicular to what we recommend.

    Solution

    "Production" configuration should be specified in its entirety in config/application.php and files in config/environments/*.php should only be used to override production behavior. For instance in development.php you would want to show error messages and define debug flags and stuff.

    To do this we should

    1. Collect all the configuration values in application.php as key value pairs in a map
    2. Collect all the configuration values in the desired config/environments/WP_ENV.php file and merge them with the key value pairs collected in application.php
    3. After all configuration values are collected we should apply them to the environment via define()

    At every point in every step above we need to protect the users from redefining constants.

    Implementation

    NOTE: Before your eyes glaze over looking at crazy UML diagrams: go read the code. What we are doing here is very simple and takes less than 100 lines of code.

    Lines of Code (LOC)                              127
    Comment Lines of Code (CLOC)                      56 (44.09%)
    Non-Comment Lines of Code (NCLOC)                 71 (55.91%)
    

    The reason I am going so overboard with explaining the implementation is because I need a second pair of eyes to sign off on the UX I am proposing here. I want to validation on if throwing these exceptions in these places makes sense etc. Also in writing this explanation I have already fixed a couple edgecases.

    I have defined these classes:

    bedrock-classes

    Who's usage looks like:

    bedrock-classes-usage

    To produce:

    newconfig

    Exceptions

    I throw a ConstantAlreadyDefinedException when a user attempts to enter a situation described in the "Problem" section where PHP would silently reject the configuration value.

    I throw a UndefinedConfigKeyException when a user attempts to fetch a value with Config::get(k) that doesn't exist in Config::$configMap. I do this because the control flow is nice and return null is not working because null is a viable configuration value. We don't use Config::get(k) anywhere but it is a part of the API because I can see users needing it.

    Backwards Compatibility

    All of this Config class madness is opt-in. Nothing stops a user from just going back to using define(). Config::define() is just an alternative API that behaves in a safe and sane way with regards to overriding environment configurations.

    Conclusion

    I am out of time for today so can't elaborate much further. Interested to discuss this with you guys!

    Reviewed by austinpray at 2018-08-05 20:41
  • 10. Better webroot structure (web/)

    Bedrock currently exposes a lot of files to the webroot that shouldn't be there. The README provides some web server configs to block access to these files, but it's still not a proper solution.

    This PR moves what's required into a web/ directory including the vendor'd WP source, and the app source itself. Now an Apache/Nginx site should be pointed to /path/to/site/web/ instead of just /path/to/site/

    The name web was chosen since it reflects that its the webroot. public is a very common name in frameworks like Symfony, Rails, Laravel etc, but it doesn't directly map to our use case since that's always for static file serving like images, scripts, css etc.

    See #10 for more discussion.

    Reviewed by swalkinshaw at 2014-01-21 17:49
  • 11. oscarotero/env v2.1.0 Class 'Env' not found

    Description

    I have recently updated composer and got the oscarotero/env v2.1.0 package. Since then I keep getting this error:

    Fatal error: Uncaught Error: Class 'Env' not found in /myproject/config/application.php:6

    Steps to reproduce

    1. Update composer to v2.1.0 on package oscarotero/env
    2. Check your local repository

    Expected behavior: [What you expect to happen]

    Expected to run site normally.

    Actual behavior: [What actually happens]

    Throws error Fatal error: Uncaught Error: Class 'Env' not found in /myproject/config/application.php:6

    Reproduces how often: [What percentage of the time does it reproduce?]

    100%

    Versions

    oscarotero/env v2.1.0

    Additional information

    This is the content of the referenced file, where Env::init() corresponds to line 6:

    <?php
    
    $root_dir = dirname(__DIR__);
    $webroot_dir = $root_dir . '/public';
    
    Env::init();
    
    // Use Dotenv to set required environment variables and load .env file in root
    $dotenv = new Dotenv\Dotenv($root_dir);
    if (file_exists($root_dir . '/.env')) {
        $dotenv->load();
        try {
          $dotenv->required('DATABASE_URL')->notEmpty();
        } catch (Exception $e) {
          $dotenv->required(['DB_NAME', 'DB_USER', 'DB_PASSWORD', 'WP_HOME', 'WP_SITEURL']);
        }
    }
    

    It seems as if the package were not loaded since the Env Class doesn't load. Ideas?

    Reviewed by albertonieto at 2020-11-16 14:37
  • 12. Require project autoloader in wp-cli.yml

    If you're using the global WP-CLI, it won't include the project's Composer autoloader until WordPress itself loads and Bedrock's own code to include the autoloader happens. This means that if you require third-party WP-CLI commands in a project and attempt to run them via a global copy of WP-CLI, those commands will not load before WordPress, even if they should (via @when before_wp_load).

    Use case:

    • Have WP-CLI available globally via their install instructions
    • Create a Bedrock project
    • composer require aaemnnosttv/wp-cli-dotenv-command
    • Run wp help
    • See dotenv under available commands
    • Run wp dotenv init --template=.env.example --with-salts (this command is configured to be available before_wp_load)

    Expected behavior: Create .env file from template

    Actual behavior: Error because database could not be reached

    Requiring the local autoloader as part of WP-CLI's configuration makes commands available when they're supposed to be available, regardless of which instance of WP-CLI you're using.

    Reviewed by ethanclevenger91 at 2022-04-28 02:10
  • 13. Add Docker

    Work for add a local dev docker with container :

    • Maildev for catch mail on port 8080
    • PhpAdmin on port 8081
    • Nginx on port 80
    • PHP 8.0 & Xdebug 3
    • Mysql

    For starting :

    • cp .env.example .env
    • change WP_HOME='http://example.com' to WP_HOME='http://localhost' in .env
    • docker-compose up

    This docker configuration is not ready for production, only use for dev

    Reviewed by SalvadorCardona at 2022-02-02 15:21
  • 14. Infer `WP_ENVIRONMENT_TYPE` based on `WP_ENV`

    Currently, there is a mismatch between WP_ENV and WP_ENVIRONMENT_TYPE as described in #538. As opposed to PR #543, this does not try to keep WP_ENV and WP_ENVIRONMENT_TYPE in sync but rather infer the values of the latter from the former, as suggested in https://github.com/roots/bedrock/pull/543#issuecomment-877742762.

    This way for example dev, trunk, dev-joe all map to WP_ENVIRONMENT_TYPE=develpoment and staging, stage-us and stage-eu to WP_ENVIRONMENT_TYPE=staging.

    In my opinion, this is more backward-compatible than setting WP_ENV based on defined WP_ENVIRONMENT_TYPE because some people can unexpectedly get their configuration switched from staging to production for example when they set WP_ENVIRONMENT_TYPE=production.

    Reviewed by calind at 2022-01-29 23:32
  • 15. Fixes #474 - Don't leak env values into $_SERVER

    Updates to using a custom repository for Dotenv instead of the default which includes ServerConstAdapter.

    The new custom repository only includes EnvConstAdapter.

    The $_SERVER superglobal often gets dumped into logs or into monitoring services so it's better for security to avoid populating it with secrets contained in .env.

    Note: this could be a breaking change for some users, but we at least need to ensure it's not breaking in the normal case.

    Reviewed by swalkinshaw at 2021-05-29 03:29
  • 16. Remove post install .env copy

    .env.example is just an example and doesn't contain useful defaults. Copying this file can be confusing since it needs to be edited regardless. By not copying this file, we'll surface errors of missing config values sooner since they'll be no default values.

    This is an alternative to https://github.com/roots/bedrock/pull/587 and https://github.com/roots/bedrock/pull/586

    TODO if merged: updated roots.io docs

    Reviewed by swalkinshaw at 2021-05-28 03:13
Security, performance, marketing, and design tools — Jetpack is made by WordPress experts to make WP sites safer and faster, and help you grow your traffic.

Jetpack Monorepo This is the Jetpack Monorepo. It contains source code for the Jetpack plugin, the Jetpack composer packages, and other things. How to

Aug 7, 2022
Basic Bedrock Theme for Concrete CMS

Basic Bedrock Theme Package for Concrete CMS v9 Basic Bedrock Theme Package for Concrete CMS v9 Concrete CMS Bedrock Documentation Description Persona

Jun 13, 2022
GetSimple CMS - a flatfile CMS that works fast and efficient and has the best UI around, it is written in PHP

GetSimple CMS is a flatfile CMS that works fast and efficient and has the best UI around, it is written in PHP.

Jul 24, 2022
A module allowing you to write your Processwire template using MJML and get a converted HTML output using MJML API.
A module allowing you to write your Processwire template using MJML and get a converted HTML output using MJML API.

PageMjmlToHtml A module allowing you to write your Processwire template using MJML and get a converted HTML output using MJML API. This is considered

May 2, 2022
Best logging support into Nette Framework (@nette)
Best logging support into Nette Framework (@nette)

Website ?? contributte.org | Contact ????‍?? f3l1x.io | Twitter ?? @contributte Usage To install the latest version of contributte/monolog use Compose

Jan 29, 2022
This is the 2nd generation of a Two-Stack CMS package for Neos.

Decoupled Content Store based on Redis This is the 2nd generation of a Two-Stack CMS package for Neos. This Package is currently work-in-progress and

Apr 14, 2022
An advanced yet user-friendly content management system, based on the full stack Symfony framework combined with a whole host of community bundles
An advanced yet user-friendly content management system, based on the full stack Symfony framework combined with a whole host of community bundles

An advanced yet user-friendly content management system, based on the full stack Symfony framework combined with a whole host of community bundles. It provides a full featured, multi-language CMS system with an innovative page and form assembling process, versioning, workflow, translation and media managers and much more.

Jul 30, 2022
True Multisite, Modern, Crazy Fast, Ridiculously Easy and Amazingly Powerful Flat-File CMS powered by PHP, Markdown, Twig, and Symfony

True Multisite, Modern, Crazy Fast, Ridiculously Easy and Amazingly Powerful Flat-File CMS powered by PHP, Markdown, Twig, and Symfony

Aug 1, 2022
Modern, Crazy Fast, Ridiculously Easy and Amazingly Powerful Flat-File CMS

Grav Grav is a Fast, Simple, and Flexible, file-based Web-platform. There is Zero installation required. Just extract the ZIP archive, and you are alr

Aug 13, 2022
Modern CMS with shop features based on fullstack symfony and sylius components

The enhavo CMS is a open source PHP project on top of the fullstack Symfony framework and uses awesome Sylius components to serve a very flexible soft

Jun 16, 2022
Azuriom is a modern, reliable, fast and secure game CMS.
Azuriom is a modern, reliable, fast and secure game CMS.

Azuriom Azuriom is the next generation game CMS, it's free and open-source, and is a modern, reliable, fast and secure alternative to existing CMS so

Aug 8, 2022
Bolt CMS is an open source, adaptable platform for building and running modern websites.

Bolt CMS is an open source, adaptable platform for building and running modern websites. Built on PHP, Symfony and more. Read the site for more info.

Aug 8, 2022
Monstra is a modern and lightweight Content Management System.
Monstra is a modern and lightweight Content Management System.

Monstra is a modern and lightweight Content Management System.

Aug 4, 2022
🚀Bolt CMS is an open source, adaptable platform for building and running modern websites

??Bolt CMS is an open source, adaptable platform for building and running modern websites

Jun 13, 2022
Azuriom - a modern, reliable, fast and secure game CMS.
Azuriom - a modern, reliable, fast and secure game CMS.

Azuriom is the next generation game CMS, it's free and open-source, and is a modern, reliable, fast and secure alternative to existing CMS so you can have the best web experience possible.

May 5, 2022
Luminosity - A modern style blogging platform
Luminosity - A modern style blogging platform

Luminosity The Complete Modern Blogging Platform This branch is currently hosted. Refer to Local Branch to setup locally Features Features: Read Artic

Jun 3, 2022
Twill is an open source CMS toolkit for Laravel that helps developers rapidly create a custom admin console that is intuitive, powerful and flexible. /// Chat with us and others on Spectrum: https://spectrum.chat/twill
Twill is an open source CMS toolkit for Laravel that helps developers rapidly create a custom admin console that is intuitive, powerful and flexible. /// Chat with us and others on Spectrum: https://spectrum.chat/twill

About Twill Twill is an open source Laravel package that helps developers rapidly create a custom CMS that is beautiful, powerful, and flexible. By st

Aug 6, 2022
(Hard) Fork of WordPress Plugin Boilerplate, actively taking PRs and actively maintained. Following WordPress Coding Standards. With more features than the original.

Better WordPress Plugin Boilerplate This is a Hard Fork of the original WordPress Plugin Boilerplate. The Better WordPress Plugin Boilerplate actively

Aug 7, 2022