Upgrade to Pro — share decks privately, control downloads, hide ads and more …

WordPress as a 12 Factor Application

Michael Heap
November 17, 2016

WordPress as a 12 Factor Application

Powering over 25% of the web, WordPress is one of the most used projects in existence. WordPress strives to make life easy for their end users first, but what if I told you that with less than an hour’s work you could make it a joy to work with for developers? By following the Twelve Factor App methodology we can deploy WordPress in a way that makes it easy to develop, easy to update and easy to maintain. Come and watch as we take a standard WordPress install and bring it into the future.

Michael Heap

November 17, 2016
Tweet

More Decks by Michael Heap

Other Decks in Technology

Transcript

  1. @mheap at #phpworld
    WordPress as a
    12 Factor App

    View Slide

  2. @mheap
    @mheap

    View Slide

  3. @mheap
    Chris AKA @tweetingsherry

    View Slide

  4. @mheap
    What is a
    12 Factor Application?

    View Slide

  5. @mheap
    WordPress as a
    12 Factor Application

    View Slide

  6. @mheap
    What is a
    12 Factor Application?

    View Slide

  7. @mheap
    The Twelve-Factor App
    https://12factor.net/

    View Slide

  8. @mheap
    Codebase
    One codebase tracked in revision
    control, many deploys

    View Slide

  9. @mheap
    Dependencies
    Explicitly declare and isolate
    dependencies

    View Slide

  10. @mheap
    Config
    Store config in the environment

    View Slide

  11. @mheap
    Backing Services
    Treat backing services as
    attached resources

    View Slide

  12. @mheap
    Build, Release, Run
    Strictly separate build and run
    stages

    View Slide

  13. @mheap
    Processes
    Execute the app as one or more
    stateless processes

    View Slide

  14. @mheap
    Port Binding
    Export services via port binding

    View Slide

  15. @mheap
    Concurrency
    Scale out via the process model

    View Slide

  16. @mheap
    Disposability
    Maximize robustness with fast
    startup and graceful shutdown

    View Slide

  17. @mheap
    Dev/Prod Parity
    Keep development, staging, and
    production as similar as possible

    View Slide

  18. @mheap
    Logs
    Treat logs as event streams

    View Slide

  19. @mheap
    Admin Processes
    Run admin/management tasks as
    one-off processes

    View Slide

  20. @mheap
    1. Codebase
    2. Dependencies
    3. Config
    4. Backing Services
    5. Build, Release, Run
    6. Processes
    7. Port Binding
    8. Concurrency
    9. Disposability
    10. Dev/Prod Parity
    11. Logs
    12. Admin Processes
    The Twelve-Factor App

    View Slide

  21. @mheap
    Why is the
    Codebase
    important?
    1 /12

    View Slide

  22. @mheap
    Add to version control
    $ git init
    $ git add .
    $ git commit -m "Initial Commit"

    View Slide

  23. @mheap
    One codebase
    Development
    Staging
    Production

    View Slide

  24. @mheap
    No web based updates
    Update locally
    Commit to version control
    Build and deploy

    View Slide

  25. @mheap
    Disable Automatic Updates
    define('AUTOMATIC_UPDATER_DISABLED', true);
    wp-config.php

    View Slide

  26. @mheap
    Disable Online Editor
    define('DISALLOW_FILE_EDIT', true);
    wp-config.php

    View Slide

  27. @mheap
    Change file ownership
    $ chown : -R *
    $ chown www-data:www-data wp-content/uploads
    wp-config.php

    View Slide

  28. @mheap

    View Slide

  29. @mheap
    Why are
    Dependencies
    important?
    2 /12

    View Slide

  30. @mheap
    commit 599d45019f92f6cc191e39014674caeeedcd87b0
    Author: Scott Taylor
    Date: Sat Aug 27 03:49:28 2016 +0000
    Bootstrap: add `composer.lock` and `src/wp-vendor` files. Nothing is using this code yet, just going
    through the motions. Ignore the files in `src/wp-vendor/composer` that will explode in PHP 5.2.
    See #36335.
    Built from https://develop.svn.wordpress.org/trunk@38394
    git-svn-id: http://core.svn.wordpress.org/trunk@38335 1a063a9b-81f0-0310-95a4-ce76da25c4cd
    WordPress’ composer.json :)
    wp-config.php

    View Slide

  31. @mheap
    commit f1631f4e03303945c5c47682a36c184542cf094b
    Author: Scott Taylor
    Date: Wed Aug 31 20:36:30 2016 +0000
    Bootstrap: goodnight sweet prince.
    See #36335.
    Built from https://develop.svn.wordpress.org/trunk@38480
    git-svn-id: http://core.svn.wordpress.org/trunk@38421 1a063a9b-81f0-0310-95a4-ce76da25c4cd
    WordPress’ composer.json :(
    wp-config.php

    View Slide

  32. @mheap
    @mheap

    View Slide

  33. @mheap
    Do it yourself!

    View Slide

  34. @mheap
    {
    "packages": {
    "mheap/wordpress": {
    "v4.6.1": {
    "name": "mheap/wordpress",
    "dist" : {
    "url" : "http://wordpress.org/wordpress-4.6.1.zip",
    "type": "zip"
    },
    "source" : {
    "url" : "https://github.com/WordPress/WordPress",
    "type" : "git",
    "reference": "4.6.1"
    },
    "type": "package",
    "version": "4.6.1"
    }
    }
    }
    }

    View Slide

  35. @mheap
    {
    "config": {
    "secure-http": false
    },
    "repositories" : [
    {
    "type" : "composer",
    "url" : "http://example.com"
    }
    ],
    "require" : {
    "mheap/wordpress" : ">=4.6"
    }
    }

    View Slide

  36. @mheap
    .
    ├── composer.json
    ├── composer.lock
    └── vendor
    ├── autoload.php
    ├── composer
    │ ├── ClassLoader.php
    │ ├── LICENSE
    │ ├── autoload_classmap.php
    │ ├── autoload_namespaces.php
    │ ├── autoload_psr4.php
    │ ├── autoload_real.php
    │ ├── autoload_static.php
    │ └── installed.json
    └── mheap
    └── wordpress
    ├──
    └── wp-content.php

    View Slide

  37. @mheap
    Do it yourself!
    (Take Two)

    View Slide

  38. @mheap
    https://getcomposer.org/doc/articles/custom-installers.md

    View Slide

  39. @mheap
    {
    "packages": {
    "mheap/wordpress": {
    "v4.6.1": {
    "name": "mheap/wordpress",
    "dist" : {
    "url" : "http://wordpress.org/wordpress-4.6.1.zip",
    "type": "zip"
    },
    "source" : {
    "url" : "https://github.com/WordPress/WordPress",
    "type" : "git",
    "reference": "4.6.1"
    },
    "type": "wordpress-core",
    "version": "4.6.1",
    "require": {
    "johnpbloch/wordpress-core-installer": "~0.1"
    }
    }
    }
    }
    }

    View Slide

  40. @mheap
    .
    ├── composer.json
    ├── composer.lock
    ├── vendor
    │ ├── autoload.php
    │ ├── composer
    │ └── johnpbloch
    └── wordpress
    ├──
    └── wp-config.php

    View Slide

  41. @mheap
    Do it yourself!
    (Take Three, the real way)

    View Slide

  42. @mheap
    {
    "require": {
    "johnpbloch/wordpress": ">=4.6"
    }
    }

    View Slide

  43. @mheap
    .
    ├── composer.json
    ├── composer.lock
    ├── vendor
    │ ├── autoload.php
    │ ├── composer
    │ └── johnpbloch
    └── wordpress
    ├──
    └── wp-config.php

    View Slide

  44. @mheap
    http://example.com/wordpress
    @mheap

    View Slide

  45. @mheap
    Remove /wordpress/
    mv wordpress/index.php .
    mv wordpress/wp-content.php .

    View Slide

  46. @mheap
    .
    ├── composer.json
    ├── composer.lock
    ├── index.php
    ├── vendor
    ├── wordpress
    └── wp-config.php

    View Slide

  47. @mheap
    Edit wp-config.php
    /* That's all, stop editing! Happy blogging. */
    /** Absolute path to the WordPress directory. */
    if ( !defined('ABSPATH') )
    define('ABSPATH', dirname(__FILE__) . '/');
    /** Sets up WordPress vars and included files. */
    require_once(ABSPATH . 'wp-settings.php');

    View Slide

  48. @mheap
    Edit wp-config.php
    /* That's all, stop editing! Happy blogging. */
    /** Absolute path to the WordPress directory. */
    if ( !defined('ABSPATH') )
    define('ABSPATH', dirname(__FILE__) . '/wordpress');
    /** Sets up WordPress vars and included files. */
    require_once(ABSPATH . 'wp-settings.php');

    View Slide

  49. @mheap
    Edit index.php
    define('WP_USE_THEMES', true);
    /** Loads the WordPress Environment and Template */
    require( dirname( __FILE__ ) . '/wp-blog-header.php' );

    View Slide

  50. @mheap
    Edit index.php
    define('WP_USE_THEMES', true);
    /** Loads the WordPress Environment and Template */
    require( dirname( __FILE__ ) . '/wordpress/wp-blog-
    header.php' );

    View Slide

  51. @mheap
    UPDATE wp_options
    SET option_value='http://example.com'
    WHERE option_name='home';

    View Slide

  52. @mheap
    Control wp-content
    mv wordpress/wp-content .

    View Slide

  53. @mheap
    Edit wp-config.php
    /** Absolute path to the WordPress directory. */
    if ( !defined('ABSPATH') )
    define('ABSPATH', dirname(__FILE__) . '/wordpress');
    define('WP_HOME', 'http://example.com');
    define('CONTENT_DIR', '/wp-content');
    define('WP_CONTENT_DIR', __DIR__ . CONTENT_DIR);
    define('WP_CONTENT_URL', WP_HOME . CONTENT_DIR);
    /** Sets up WordPress vars and included files. */
    require_once(ABSPATH . 'wp-settings.php');

    View Slide

  54. @mheap
    Create .gitignore
    vendor
    wordpress

    View Slide

  55. @mheap
    Do we have to commit:
    Plugins?
    Themes?

    View Slide

  56. @mheap
    @mheap

    View Slide

  57. @mheap
    {
    "repositories":[
    {
    "type":"composer",
    "url":"https://wpackagist.org"
    }
    ],
    "require": {
    "johnpbloch/wordpress": ">=4.6"
    }
    }

    View Slide

  58. @mheap
    {
    "repositories":[
    {
    "type":"composer",
    "url":"https://wpackagist.org"
    }
    ],
    "require": {
    "johnpbloch/wordpress": ">=4.6",
    "wpackagist-plugin/captcha":">=3.9",
    "wpackagist-theme/hueman":"*"
    }
    }

    View Slide

  59. @mheap
    Edit .gitignore
    vendor
    wordpress
    wp-content

    View Slide

  60. @mheap
    │ ├── customize.php
    │ ├── edit-comments.php
    │ ├── edit-form-advanced.php
    │ ├── edit-form-comment.php
    │ ├── edit-link-form.php
    │ ├── edit-tag-form.php
    │ ├── edit-tags.php
    │ ├── edit.php
    │ ├── export.php
    │ ├── freedoms.php
    │ ├── images
    │ │ ├── align-center-2x.png
    │ │ ├── align-center.png
    │ │ ├── align-left-2x.png
    │ │ ├── align-left.png
    │ │ ├── align-none-2x.png
    │ │ ├── align-none.png
    │ │ ├── align-right-2x.png
    │ │ ├── align-right.png
    │ │ ├── arrows-2x.png
    │ │ ├── arrows.png
    │ │ ├── browser-rtl.png
    │ │ ├── browser.png
    │ │ ├── bubble_bg-2x.gif
    │ │ ├── bubble_bg.gif
    │ │ ├── comment-grey-bubble-2x.png
    │ │ ├── comment-grey-bubble.png
    │ │ ├── date-button-2x.gif
    │ │ ├── date-button.gif
    │ │ ├── generic.png
    │ │ ├── icons32-2x.png
    │ │ ├── icons32-vs-2x.png
    │ │ ├── icons32-vs.png
    │ │ ├── icons32.png
    │ │ ├── imgedit-icons-2x.png
    │ │ ├── imgedit-icons.png
    │ │ ├── list-2x.png
    │ │ ├── list.png
    │ │ ├── loading.gif
    │ │ ├── marker.png
    │ │ ├── mask.png
    │ │ ├── media-button-2x.png
    │ │ ├── media-button-image.gif
    │ │ ├── media-button-music.gif
    │ │ ├── media-button-other.gif
    │ │ ├── media-button-video.gif
    │ │ ├── media-button.png
    │ │ ├── menu-2x.png
    │ │ ├── menu-vs-2x.png
    │ │ ├── menu-vs.png
    │ │ ├── menu.png
    │ │ ├── no.png
    │ │ ├── post-formats-vs.png
    │ │ ├── post-formats.png
    │ │ ├── post-formats32-vs.png
    │ │ ├── post-formats32.png
    │ │ ├── resize-2x.gif
    │ │ ├── resize-rtl-2x.gif
    │ │ ├── resize-rtl.gif
    │ │ ├── resize.gif
    │ │ ├── se.png
    │ │ ├── sort-2x.gif
    │ │ ├── sort.gif
    │ │ ├── spinner-2x.gif
    │ │ ├── spinner.gif
    │ │ ├── stars-2x.png
    │ │ ├── stars.png
    │ │ ├── w-logo-blue.png
    │ │ ├── w-logo-white.png
    │ │ ├── wheel.png
    │ │ ├── wordpress-logo-white.svg
    │ │ ├── wordpress-logo.png
    │ │ ├── wordpress-logo.svg
    │ │ ├── wpspin_light-2x.gif
    │ │ ├── wpspin_light.gif
    │ │ ├── xit-2x.gif
    │ │ ├── xit.gif
    │ │ └── yes.png
    │ ├── import.php
    │ ├── includes
    │ │ ├── admin-filters.php
    │ │ ├── admin.php
    │ │ ├── ajax-actions.php
    │ │ ├── bookmark.php
    │ │ ├── class-automatic-upgrader-skin.php
    │ │ ├── class-bulk-plugin-upgrader-skin.php
    │ │ ├── class-bulk-theme-upgrader-skin.php
    │ │ ├── class-bulk-upgrader-skin.php
    │ │ ├── class-core-upgrader.php
    │ │ ├── class-file-upload-upgrader.php
    │ │ ├── class-ftp-pure.php
    │ │ ├── class-ftp-sockets.php
    │ │ ├── class-ftp.php
    │ │ ├── class-language-pack-upgrader-skin.php
    │ │ ├── class-language-pack-upgrader.php
    │ │ ├── class-pclzip.php
    │ │ ├── class-plugin-installer-skin.php
    │ │ ├── class-plugin-upgrader-skin.php
    │ │ ├── class-plugin-upgrader.php
    │ │ ├── class-theme-installer-skin.php
    │ │ ├── class-theme-upgrader-skin.php
    │ │ ├── class-theme-upgrader.php
    │ │ ├── class-walker-category-checklist.php
    │ │ ├── class-walker-nav-menu-checklist.php
    │ │ ├── class-walker-nav-menu-edit.php
    │ │ ├── class-wp-ajax-upgrader-skin.php
    │ │ ├── class-wp-automatic-updater.php
    │ │ ├── class-wp-comments-list-table.php
    │ │ ├── class-wp-filesystem-base.php
    │ │ ├── class-wp-filesystem-direct.php
    │ │ ├── class-wp-filesystem-ftpext.php
    │ │ ├── class-wp-filesystem-ftpsockets.php
    │ │ ├── class-wp-filesystem-ssh2.php
    │ │ ├── class-wp-importer.php
    │ │ ├── class-wp-internal-pointers.php
    │ │ ├── class-wp-links-list-table.php
    │ │ ├── class-wp-list-table-compat.php
    │ │ ├── class-wp-list-table.php
    │ │ ├── class-wp-media-list-table.php
    │ │ ├── class-wp-ms-sites-list-table.php
    │ │ ├── class-wp-ms-themes-list-table.php
    │ │ ├── class-wp-ms-users-list-table.php
    │ │ ├── class-wp-plugin-install-list-table.php
    │ │ ├── class-wp-plugins-list-table.php
    │ │ ├── class-wp-post-comments-list-table.php
    │ │ ├── class-wp-posts-list-table.php
    │ │ ├── class-wp-press-this.php
    │ │ ├── class-wp-screen.php
    │ │ ├── class-wp-site-icon.php
    │ │ ├── class-wp-terms-list-table.php
    │ │ ├── class-wp-theme-install-list-table.php
    │ │ ├── class-wp-themes-list-table.php
    │ │ ├── class-wp-upgrader-skin.php
    │ │ ├── class-wp-upgrader.php
    │ │ ├── class-wp-users-list-table.php
    │ │ ├── comment.php
    │ │ ├── continents-cities.php
    │ │ ├── credits.php
    │ │ ├── dashboard.php
    │ │ ├── deprecated.php
    │ │ ├── edit-tag-messages.php
    │ │ ├── export.php
    │ │ ├── file.php
    │ │ ├── image-edit.php
    │ │ ├── image.php
    │ │ ├── import.php
    │ │ ├── list-table.php
    │ │ ├── media.php
    │ │ ├── menu.php
    │ │ ├── meta-boxes.php
    │ │ ├── misc.php
    │ │ ├── ms-admin-filters.php
    │ │ ├── ms-deprecated.php
    │ │ ├── ms.php
    .
    ├── composer.json
    ├── composer.lock
    ├── index.php
    └── wp-config.php
    (1762 files)

    View Slide

  61. @mheap

    View Slide

  62. @mheap
    Why is
    Config
    important?
    3 /12

    View Slide

  63. @mheap
    wp-config.php
    Committed to git
    Hard to change between environments

    View Slide

  64. @mheap
    if ($_SERVER['REMOTE_ADDR'] == '82.123.234.12') {
    define('DB_USER', 'prod_wp');
    } else if ($_SERVER['REMOTE_ADDR'] == '127.0.0.1') {
    define('DB_USER', 'root');
    }

    View Slide

  65. @mheap
    if ($_SERVER['REMOTE_ADDR'] == '82.123.234.12') {
    include 'wp-config-staging.php';
    } else if ($_SERVER['REMOTE_ADDR'] == '127.0.0.1') {
    include 'wp-config-dev.php';
    }

    View Slide

  66. @mheap
    composer.json
    {
    "repositories":[
    {
    "type":"composer",
    "url":"https://wpackagist.org"
    }
    ],
    "require": {
    "johnpbloch/wordpress": ">=4.6",
    "wpackagist-plugin/captcha":">=3.9",
    "wpackagist-theme/hueman":"*",
    "vlucas/phpdotenv": "^2.4"
    }
    }

    View Slide

  67. @mheap
    wp-config.php
    require_once __DIR__.'/vendor/autoload.php';
    $dotenv = new Dotenv\Dotenv(__DIR__);
    $dotenv->load();
    /**
    * The base configuration for WordPress
    *

    View Slide

  68. @mheap
    wp-config.php
    /** The name of the database for WordPress */
    define('DB_NAME', getenv('DB_NAME'));
    /** MySQL database username */
    define('DB_USER', getenv('DB_USER'));
    /** MySQL database password */
    define('DB_PASSWORD', getenv('DB_PASSWORD'));
    /** MySQL hostname */
    define('DB_HOST', getenv('DB_HOST'));

    View Slide

  69. @mheap
    .env
    DB_NAME=wptest
    DB_USER=user
    DB_PASSWORD=secret
    DB_HOST=localhost

    View Slide

  70. @mheap
    Shameless Plug

    View Slide

  71. @mheap

    View Slide

  72. @mheap
    Why are
    Backing Services
    important?
    4 /12

    View Slide

  73. @mheap
    Attached Resources
    Local or remote
    Your application doesn’t care

    View Slide

  74. @mheap
    Config Driven
    Zero code changes
    Scale up/down at will

    View Slide

  75. @mheap
    Misbehaving Hardware
    Attach / detach at will
    No need to redeploy, config only

    View Slide

  76. @mheap

    View Slide

  77. @mheap
    Why is
    Build, Release, Run
    important?
    5 /12

    View Slide

  78. @mheap
    Build
    $ composer install
    $ zip -r app.zip *

    View Slide

  79. @mheap
    Release
    $ scp app.zip remote-host:~
    $ ssh remote-host
    $ unzip app.zip
    $ cd /var/www
    $ mv ~/app releases/20161201
    $ ln -s releases/20161201 live_new
    $ mv -Tf live_new live

    View Slide

  80. @mheap
    Release
    $ sudo yum upgrade my-app

    View Slide

  81. @mheap
    Run
    PHP does this for free
    (Maybe restart php-fpm)

    View Slide

  82. @mheap

    View Slide

  83. @mheap
    Why are
    Processes
    important?
    6 /12

    View Slide

  84. @mheap
    Shared Resources
    Memory
    Disk

    View Slide

  85. @mheap
    @mheap

    View Slide

  86. @mheap

    View Slide

  87. @mheap
    Why is
    Port Binding
    important?
    7 /12

    View Slide

  88. @mheap
    PHP-FPM
    Binds it’s own port
    Doesn’t talk HTTP

    View Slide

  89. @mheap
    $ php -S localhost:8000
    Built in server

    View Slide

  90. @mheap
    ReactPHP
    Async PHP event loop

    View Slide

  91. @mheap

    View Slide

  92. @mheap
    Why is
    Concurrency
    important?
    8 /12

    View Slide

  93. @mheap
    Scale out via processes
    Web process
    Worker process
    Admin process

    View Slide

  94. @mheap
    PHP-FPM Daemonises
    12 Factor app should not write PID file
    Instead, rely on process manager

    View Slide

  95. @mheap

    View Slide

  96. @mheap
    Why is
    Disposability
    important?
    9 /12

    View Slide

  97. @mheap
    Elastic Scaling

    View Slide

  98. @mheap
    Rapid Deployment

    View Slide

  99. @mheap
    Config Changes

    View Slide

  100. @mheap
    Fast Startup Time

    View Slide

  101. @mheap

    View Slide

  102. @mheap
    Why is
    Dev / Prod parity
    important?
    10/12

    View Slide

  103. @mheap
    Reducing the gap
    Make the time gap small
    Make the personnel gap small
    Make the tools gap small

    View Slide

  104. @mheap
    Releases
    Time: Hours
    People: Code Authors
    Tools: Identical

    View Slide

  105. @mheap

    View Slide

  106. @mheap
    Why are
    Logs
    important?
    11/12

    View Slide

  107. @mheap
    Logs are streams
    Write to STDOUT
    Managed by process manager

    View Slide

  108. @mheap
    Spotting patterns
    Finding specific events in the past.
    Large-scale graphing of trends
    Triggering alerts

    View Slide

  109. @mheap

    View Slide

  110. @mheap
    Why are
    Admin processes
    important?
    12/12

    View Slide

  111. @mheap
    update_links.php
    Updates all posts to switch links from
    http://example.com to https://
    example.com

    View Slide

  112. @mheap
    Ship with app code
    Deployed in the same package
    Code reviews and tests

    View Slide

  113. @mheap

    View Slide

  114. @mheap
    The Twelve-Factor App
    https://12factor.net/

    View Slide

  115. @mheap
    Bonus!

    View Slide

  116. @mheap
    wp-cli
    Comments
    Menus
    Posts
    Users

    View Slide

  117. @mheap
    composer.json Explorer
    http://composer.json.jolicode.com/

    View Slide

  118. https://joind.in/
    18722
    @mheap at #phpworld
    Michael Heap
    @mheap
    [email protected]

    View Slide