SlideShare a Scribd company logo
1 of 68
Download to read offline
Supercharging WordPress
Development in 2018
by Adam Tomat, Rareloop
LUMBERJACK
@adamtomat
The Digital Product Studio
Projects
vs
Products
– Liz Keogh
“You’re not really ‘done’ until the software
has been retired and is no longer used at all”
Make your website easier to change
I ❤ PHP
I ❤ WordPress
Lumberjack
What are the problems with
WordPress?
$the_query = new WP_Query([
'posts_per_page' => 5,
'tag' => 'club'
]);
if ($the_query->have_posts()) : ?>
<h4>Recent Articles</h4>
<ul>
<?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
<li class="article">
<h3><?php the_title(); ?></h3>
<?php the_excerpt(10); ?>
<a href="<?php the_permalink(); ?>">Read more</a>
</li>
<?php endwhile; ?>
</ul>
<?php endif; ?>
t
Mix of concerns:
Presentation logic &
Database queries
"
This file has multiple
reasons to change
index.php
$the_query = new WP_Query([
'posts_per_page' => 5,
'tag' => 'club'
]);
if ($the_query->have_posts()) : ?>
<h4>Recent Articles</h4>
<ul>
<?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
<li class="article">
<h3><?php the_title(); ?></h3>
<?php the_excerpt(10); ?>
<a href="<?php the_permalink(); ?>">Read more</a>
</li>
<?php endwhile; ?>
</ul>
<?php endif; ?>
t
Procedural
"
Procedural code is often
not DRY or reusable.



It’s difficult to change.
Hard to read.
index.php
Timber!
<?php
$context = Timber::get_context();
$context['posts'] = Timber::get_posts([
'posts_per_page' => 5,
'tag' => 'club'
]);
Timber::render('index.twig', $context);
{% if posts is not empty %}
<h4>Recent Articles</h4>
<ul>
{% for post in posts %}
<li class="article">
<h3>{{ $post->title }}</h3>
{{ $post->preview }}
<a href="{{ $post->link }}">Read the full story</a>
</li>
{% endfor %}
</ul>
{% endif %}
index.twig
index.php
What are the problems with
Timber controllers?
<?php
$context = Timber::get_context();
$context['posts'] = Timber::get_posts([
'posts_per_page' => 5,
'tag' => 'club'
]);
Timber::render('index.twig', $context);
index.php
t
Procedural
"
Procedural code is often
not DRY or reusable.



It’s difficult to change.
Hard to read.
index.php
class IndexController
{
}
public function handle()
{
$context = Timber::get_context();
$context['posts'] = Timber::get_posts([
'posts_per_page' => 5,
'tag' => 'club'
]);
}
extends BaseController
return new TimberResponse('index.twig', $context);return Timber::render('index.twig', $context);
index.php
class IndexController extends BaseController
{
public function handle()
{
$context = Timber::get_context();
$context['posts'] = $this->getPosts();
return new TimberResponse('index.twig', $context);
}
private function getPosts()
{
return Timber::get_posts([
'posts_per_page' => 5,
'tag' => 'club'
]);
}
}
Benefits
• Write Object Orientated code rather than Procedural code
• Can use inheritance to extend a base class for common functionality
• Can encapsulate more complex routines in private functions
• Make use of PSR-7 compliant Response objects
Config
What are the problems with

wp-config?
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'wordpress');
/** MySQL database username */
define('DB_USER', 'root');
/** MySQL database password */
define('DB_PASSWORD', ‘letmein');
/** MySQL hostname */
define('DB_HOST', 'localhost');
/** Database Charset to use in creating database tables. */
define('DB_CHARSET', 'utf8');
/** The Database Collate type. Don't change this if in doubt. */
define('DB_COLLATE', '');
wp-config.php
DB_NAME=wordpress
DB_USER=root
DB_PASSWORD=letmein
# Optional variables
# DB_HOST=localhost
# DB_PREFIX=wp_
WP_ENV=development
WP_HOME=http://example.com
WP_SITEURL=${WP_HOME}/wp
GOOGLE_MAPS_API_KEY=KJjn32s32dN2
.env
$apiKey = getenv('GOOGLE_MAPS_API_KEY');
Some PHP file
What is Bedrock?
Traditional WordPress
Theme
WordPressTimber
Yoast
ACF
Theme
Bedrock
Bedrock
WordPress v4.5.*
Timber
v1.1.*
Yoast
v5.2.3
ACF
v5.6.1.2
How does Lumberjack fit
into this?
Lumberjack Starter Theme
Lumberjack + Bedrock = ❤
Bedrock
WordPress v4.5.*
Timber
v1.1.*
Yoast
v5.2.3
ACF
v5.6.1.2
Lumberjack Core v3.0.*
DB_NAME=wordpress
DB_USER=root
DB_PASSWORD=letmein
# Optional variables
# DB_HOST=localhost
# DB_PREFIX=wp_
WP_ENV=development
WP_HOME=http://example.com
WP_SITEURL=${WP_HOME}/wp
GOOGLE_MAPS_API_KEY=KJjn32s32dN2
.env
$apiKey = getenv('GOOGLE_MAPS_API_KEY');
Some PHP file
t
You can’t change config
settings
Your code shouldn’t
actually care about
dotenv
Your code just wants to say:
“Hey config, can I get the ‘google maps api key’ please?”
Some PHP file
$apiKey = Config::get('app.google_maps_api_key');
config/app.php
return [
'google_maps_api_key' => getenv('GOOGLE_MAPS_API_KEY', 'dummy-api-key'),
];
return [
'logs' => [
'enabled' => true,
'location' => '/tmp',
],
];
config/app.php
Some PHP file
$location = Config::get('app.logs.location'); // => '/tmp'
Lumberjack Config
• Post Type Registration
• Image sizes
• Error logging
• Menu locations
• Load paths of Twig files for Timber
• Basic theme support (e.g. enable Featured Image support)
Querying Posts
$args = [
'post_type' => 'product',
'posts_per_page' => 10,
'orderby' => 'title',
'order' => 'ASC',
'meta_query' => [
'relation' => 'AND',
[
'key' => 'available_from_date',
'value' => [$from_date, $to_date],
'compare' => 'BETWEEN',
'type' => 'DATE',
],
[
'key' => 'available_to_date',
'value' => [$from_date, $to_date],
'compare' => 'BETWEEN',
'type' => 'DATE',
],
]
];
$query = new WP_Query($args);
$posts = $query->get_posts();
use TimberPost;
$post = new Post(1);
$collection = Timber::get_posts($wpQueryArray);
Timber Post Object
use RareloopLumberjackPost;
use AppPostTypesProduct;
$post = new Post(1);
$collection = Post::query($wpQueryArray);
$product = new Product(1);
$collection = Product::query($wpQueryArray);
Lumberjack Post Object
class Product extends Post
{
public function getPhotos() : array
{
// Do database query to get the assigned photos
}
}
Encapsulate Business Logic
$product = new Product(123);
$photos = $product->getPhotos();
class Product extends Post
{
}
Register Custom Post Types
// config/posttypes.php
return [
'register' => [
AppPostTypesProduct::class,
],
];
protected static function getPostTypeConfig()
{
return [
'labels' => [
'name' => __('Products'),
'singular_name' => __('Product'),
],
'public' => true,
'has_archive' => false,
];
}
public static function getPostType()
{
return 'product';
}
Making queries more readable
Advanced Queries
$productType = new ProductType;
$products = Product::whereStatus('publish')
->whereMeta('type', '"' . $productType->id . '"', 'LIKE')
->limit(10)
->orderBy('title', 'asc')
->get();
Using the Query Builder directly
$products = QueryBuilder::wherePostType([
Product::getPostType(),
GiftSet::getPostType(),
])
->whereStatus('publish')
->limit(10)
->orderBy(‘title', 'asc')
->get();
Extending the Query Builder
$announcements = Announcement::whereStatus('publish')
->whereAddedSince('10 days ago')
->whereSearchTerm('Lorem Ipsum')
->orderBy('date', 'desc')
->paginate();
Custom Requests
Router::get('hello/world', function () {
return HtmlResponse('<h1>Hello World!</h1>');
});
Simple Routes
use RareloopLumberjackFacadesRouter;
use ZendDiactorosResponseHtmlResponse;
Router::get('hello/{name}', function ($name) {
return HtmlResponse('<h1>Hello ' . $name . '!</h1>');
});
echo Router::url('hello.world', ['name' => 'adam']);
->name('hello.world');
Params & Named Routes
Router::get('hello/world', 'AppControllersHelloController@show');
Controller Definitions
AJAX endpoint that returns JSON
class ArticleCommentController
{
}
Router::post('articles/{id}/comments', 'AppHttpControllersArticleCommentController@store');
public function store($id, ServerRequest $request) {
}
$content = json_decode($request->getBody(), true);
$user = wp_get_current_user();
wp_new_comment([
'comment_post_ID' => (int) $articleId,
'comment_author' => $user->ID,
'comment_content' => data_get($content, 'comment'),
]);
return new JsonResponse([
'data' => [
'content' => $content['comment'],
'author' => $user->display_name,
]
], 201);
Router benefits
• Extend WordPress site with custom URL endpoints
• Access to all REST based verbs
• Can add Groups, for collecting similar resources together
Responses
Baked-in Responses
$response = new TimberResponse(‘templates/home.twig’, $context);
// From https://github.com/zendframework/zend-diactoros
$response = new TextResponse('Hello world!');
$response = new HtmlResponse($htmlContent);
$response = new XmlResponse($xml);
$response = new JsonResponse($data);
$response = new EmptyResponse(); // Basic 204 response:
$response = new RedirectResponse('/user/login');
CONTENT SITE BESPOKE SYSTEM
Project Spectrum
“Don’t use what you
don’t understand.”
Everything I’ve shown
you is optional
• PSR11 Dependency Injection
Container (using PHP-DI)
• Facades
• Exception Handling (PSR3)
• Validation (currently an external
package)
• View Models
More power at your fingertips ✨
• Service Providers
• Hatchet (CLI)
• Global helper functions (e.g.
config(‘app.environment’); )
• Debug bar & Dump server
• ‘Responsable’ objects (from Laravel) -
in, but currently undocumented
• Sessions (coming soon)
• Example theme (currently in development)
• Automated Testing
• Unit tests with PHPUnit
• Integration tests with Laravel Dusk
On the radar 📡
namespace TestsBrowser;
use ChadanukDuskWordpressTestsTestCase;
class ExampleTest extends TestCase
{
/* @test */
public function can_see_home_page_title()
{
$postFactory = new WP_UnitTest_Factory_For_Post();
$postId = $postFactory->create_object([
'post_title' => 'Home page title',
'post_type' => 'page',
'post_name' => 'home'
]);
$this->browse(function ($browser) {
$browser->visit(‘/')
->assertSee('Home page title');
});
}
}
Get Involved
Take Lumberjack for a spin
• Evaluate the product mindset for you (and your team?)
• WordPress is awesome, we can make it even more awesome!
• Challenge and push your stack forward
• Write code which is easier to change
• Lumberjack is basically Laravel in WordPress
• Use only what you need to in Lumberjack
In summary…
docs.lumberjack.rareloop.com slack.lumberjack.rareloop.com
Documentation Join Slack
We’re always hiring 😊

More Related Content

What's hot

Getting Creative with WordPress Queries
Getting Creative with WordPress QueriesGetting Creative with WordPress Queries
Getting Creative with WordPress QueriesDrewAPicture
 
Doctrine 2
Doctrine 2Doctrine 2
Doctrine 2zfconfua
 
Developing applications for performance
Developing applications for performanceDeveloping applications for performance
Developing applications for performanceLeon Fayer
 
Php 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the GoodPhp 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the GoodJeremy Kendall
 
CoffeeScript - A Rubyist's Love Affair
CoffeeScript - A Rubyist's Love AffairCoffeeScript - A Rubyist's Love Affair
CoffeeScript - A Rubyist's Love AffairMark
 
Leveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPLeveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPJeremy Kendall
 
The effective use of Django ORM
The effective use of Django ORMThe effective use of Django ORM
The effective use of Django ORMYaroslav Muravskyi
 
PHP performance 101: so you need to use a database
PHP performance 101: so you need to use a databasePHP performance 101: so you need to use a database
PHP performance 101: so you need to use a databaseLeon Fayer
 
Let's write secure drupal code! - Drupal Camp Pannonia 2019
Let's write secure drupal code! - Drupal Camp Pannonia 2019Let's write secure drupal code! - Drupal Camp Pannonia 2019
Let's write secure drupal code! - Drupal Camp Pannonia 2019Balázs Tatár
 
Corinna Status 2022.pptx
Corinna Status 2022.pptxCorinna Status 2022.pptx
Corinna Status 2022.pptxCurtis Poe
 
Leveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPLeveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPJeremy Kendall
 
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway ichikaway
 
Let's write secure Drupal code! - Drupal Camp Poland 2019
Let's write secure Drupal code! - Drupal Camp Poland 2019Let's write secure Drupal code! - Drupal Camp Poland 2019
Let's write secure Drupal code! - Drupal Camp Poland 2019Balázs Tatár
 
Let's write secure Drupal code! DUG Belgium - 08/08/2019
Let's write secure Drupal code! DUG Belgium - 08/08/2019Let's write secure Drupal code! DUG Belgium - 08/08/2019
Let's write secure Drupal code! DUG Belgium - 08/08/2019Balázs Tatár
 
How to make a WordPress theme
How to make a WordPress themeHow to make a WordPress theme
How to make a WordPress themeHardeep Asrani
 

What's hot (20)

Getting Creative with WordPress Queries
Getting Creative with WordPress QueriesGetting Creative with WordPress Queries
Getting Creative with WordPress Queries
 
Perl object ?
Perl object ?Perl object ?
Perl object ?
 
Wp query
Wp queryWp query
Wp query
 
Doctrine 2
Doctrine 2Doctrine 2
Doctrine 2
 
Hooks WCSD12
Hooks WCSD12Hooks WCSD12
Hooks WCSD12
 
WCLV13 JavaScript
WCLV13 JavaScriptWCLV13 JavaScript
WCLV13 JavaScript
 
Developing applications for performance
Developing applications for performanceDeveloping applications for performance
Developing applications for performance
 
Php 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the GoodPhp 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the Good
 
CoffeeScript - A Rubyist's Love Affair
CoffeeScript - A Rubyist's Love AffairCoffeeScript - A Rubyist's Love Affair
CoffeeScript - A Rubyist's Love Affair
 
Leveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPLeveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHP
 
The effective use of Django ORM
The effective use of Django ORMThe effective use of Django ORM
The effective use of Django ORM
 
PHP performance 101: so you need to use a database
PHP performance 101: so you need to use a databasePHP performance 101: so you need to use a database
PHP performance 101: so you need to use a database
 
Let's write secure drupal code! - Drupal Camp Pannonia 2019
Let's write secure drupal code! - Drupal Camp Pannonia 2019Let's write secure drupal code! - Drupal Camp Pannonia 2019
Let's write secure drupal code! - Drupal Camp Pannonia 2019
 
Corinna Status 2022.pptx
Corinna Status 2022.pptxCorinna Status 2022.pptx
Corinna Status 2022.pptx
 
Leveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPLeveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHP
 
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
 
Let's write secure Drupal code! - Drupal Camp Poland 2019
Let's write secure Drupal code! - Drupal Camp Poland 2019Let's write secure Drupal code! - Drupal Camp Poland 2019
Let's write secure Drupal code! - Drupal Camp Poland 2019
 
Assetic (OSCON)
Assetic (OSCON)Assetic (OSCON)
Assetic (OSCON)
 
Let's write secure Drupal code! DUG Belgium - 08/08/2019
Let's write secure Drupal code! DUG Belgium - 08/08/2019Let's write secure Drupal code! DUG Belgium - 08/08/2019
Let's write secure Drupal code! DUG Belgium - 08/08/2019
 
How to make a WordPress theme
How to make a WordPress themeHow to make a WordPress theme
How to make a WordPress theme
 

Similar to [WLDN] Supercharging word press development in 2018

[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress DevelopmentAdam Tomat
 
Drupal vs WordPress
Drupal vs WordPressDrupal vs WordPress
Drupal vs WordPressWalter Ebert
 
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)Mike Schinkel
 
Supercharging WordPress Development in 2018
Supercharging WordPress Development in 2018Supercharging WordPress Development in 2018
Supercharging WordPress Development in 2018Adam Tomat
 
Becoming a better WordPress Developer
Becoming a better WordPress DeveloperBecoming a better WordPress Developer
Becoming a better WordPress DeveloperJoey Kudish
 
What's new in the Drupal 7 API?
What's new in the Drupal 7 API?What's new in the Drupal 7 API?
What's new in the Drupal 7 API?Alexandru Badiu
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxMichelangelo van Dam
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11Michelangelo van Dam
 
Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?Yevhen Kotelnytskyi
 
Childthemes ottawa-word camp-1919
Childthemes ottawa-word camp-1919Childthemes ottawa-word camp-1919
Childthemes ottawa-word camp-1919Paul Bearne
 
The Way to Theme Enlightenment
The Way to Theme EnlightenmentThe Way to Theme Enlightenment
The Way to Theme EnlightenmentAmanda Giles
 
WordPress as an application framework
WordPress as an application frameworkWordPress as an application framework
WordPress as an application frameworkDustin Filippini
 
The Query the Whole Query and Nothing but the Query
The Query the Whole Query and Nothing but the QueryThe Query the Whole Query and Nothing but the Query
The Query the Whole Query and Nothing but the QueryChris Olbekson
 
Can WordPress really do that? A case study of vierderduer.no
Can WordPress really do that? A case study of vierderduer.noCan WordPress really do that? A case study of vierderduer.no
Can WordPress really do that? A case study of vierderduer.noMorten Rand-Hendriksen
 
WordPress Café: Using WordPress as a Framework
WordPress Café: Using WordPress as a FrameworkWordPress Café: Using WordPress as a Framework
WordPress Café: Using WordPress as a FrameworkExove
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Shinya Ohyanagi
 
Gail villanueva add muscle to your wordpress site
Gail villanueva   add muscle to your wordpress siteGail villanueva   add muscle to your wordpress site
Gail villanueva add muscle to your wordpress sitereferences
 

Similar to [WLDN] Supercharging word press development in 2018 (20)

[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Drupal vs WordPress
Drupal vs WordPressDrupal vs WordPress
Drupal vs WordPress
 
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)
 
Supercharging WordPress Development in 2018
Supercharging WordPress Development in 2018Supercharging WordPress Development in 2018
Supercharging WordPress Development in 2018
 
Becoming a better WordPress Developer
Becoming a better WordPress DeveloperBecoming a better WordPress Developer
Becoming a better WordPress Developer
 
Separation of concerns - DPC12
Separation of concerns - DPC12Separation of concerns - DPC12
Separation of concerns - DPC12
 
QA for PHP projects
QA for PHP projectsQA for PHP projects
QA for PHP projects
 
What's new in the Drupal 7 API?
What's new in the Drupal 7 API?What's new in the Drupal 7 API?
What's new in the Drupal 7 API?
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 
Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?
 
Childthemes ottawa-word camp-1919
Childthemes ottawa-word camp-1919Childthemes ottawa-word camp-1919
Childthemes ottawa-word camp-1919
 
The Way to Theme Enlightenment
The Way to Theme EnlightenmentThe Way to Theme Enlightenment
The Way to Theme Enlightenment
 
WordPress as an application framework
WordPress as an application frameworkWordPress as an application framework
WordPress as an application framework
 
The Query the Whole Query and Nothing but the Query
The Query the Whole Query and Nothing but the QueryThe Query the Whole Query and Nothing but the Query
The Query the Whole Query and Nothing but the Query
 
Can WordPress really do that? A case study of vierderduer.no
Can WordPress really do that? A case study of vierderduer.noCan WordPress really do that? A case study of vierderduer.no
Can WordPress really do that? A case study of vierderduer.no
 
WordPress Café: Using WordPress as a Framework
WordPress Café: Using WordPress as a FrameworkWordPress Café: Using WordPress as a Framework
WordPress Café: Using WordPress as a Framework
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2
 
Gail villanueva add muscle to your wordpress site
Gail villanueva   add muscle to your wordpress siteGail villanueva   add muscle to your wordpress site
Gail villanueva add muscle to your wordpress site
 

Recently uploaded

Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfStefano Stabellini
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceBrainSell Technologies
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtimeandrehoraa
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 

Recently uploaded (20)

Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdf
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. Salesforce
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 
2.pdf Ejercicios de programación competitiva
2.pdf Ejercicios de programación competitiva2.pdf Ejercicios de programación competitiva
2.pdf Ejercicios de programación competitiva
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtime
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 

[WLDN] Supercharging word press development in 2018

  • 1. Supercharging WordPress Development in 2018 by Adam Tomat, Rareloop LUMBERJACK @adamtomat
  • 4. – Liz Keogh “You’re not really ‘done’ until the software has been retired and is no longer used at all”
  • 5. Make your website easier to change
  • 6. I ❤ PHP I ❤ WordPress
  • 7.
  • 8.
  • 9.
  • 11. What are the problems with WordPress?
  • 12. $the_query = new WP_Query([ 'posts_per_page' => 5, 'tag' => 'club' ]); if ($the_query->have_posts()) : ?> <h4>Recent Articles</h4> <ul> <?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?> <li class="article"> <h3><?php the_title(); ?></h3> <?php the_excerpt(10); ?> <a href="<?php the_permalink(); ?>">Read more</a> </li> <?php endwhile; ?> </ul> <?php endif; ?> t Mix of concerns: Presentation logic & Database queries " This file has multiple reasons to change index.php
  • 13. $the_query = new WP_Query([ 'posts_per_page' => 5, 'tag' => 'club' ]); if ($the_query->have_posts()) : ?> <h4>Recent Articles</h4> <ul> <?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?> <li class="article"> <h3><?php the_title(); ?></h3> <?php the_excerpt(10); ?> <a href="<?php the_permalink(); ?>">Read more</a> </li> <?php endwhile; ?> </ul> <?php endif; ?> t Procedural " Procedural code is often not DRY or reusable.
 
 It’s difficult to change. Hard to read. index.php
  • 15. <?php $context = Timber::get_context(); $context['posts'] = Timber::get_posts([ 'posts_per_page' => 5, 'tag' => 'club' ]); Timber::render('index.twig', $context); {% if posts is not empty %} <h4>Recent Articles</h4> <ul> {% for post in posts %} <li class="article"> <h3>{{ $post->title }}</h3> {{ $post->preview }} <a href="{{ $post->link }}">Read the full story</a> </li> {% endfor %} </ul> {% endif %} index.twig index.php
  • 16. What are the problems with Timber controllers?
  • 17. <?php $context = Timber::get_context(); $context['posts'] = Timber::get_posts([ 'posts_per_page' => 5, 'tag' => 'club' ]); Timber::render('index.twig', $context); index.php t Procedural " Procedural code is often not DRY or reusable.
 
 It’s difficult to change. Hard to read.
  • 18. index.php class IndexController { } public function handle() { $context = Timber::get_context(); $context['posts'] = Timber::get_posts([ 'posts_per_page' => 5, 'tag' => 'club' ]); } extends BaseController return new TimberResponse('index.twig', $context);return Timber::render('index.twig', $context);
  • 19. index.php class IndexController extends BaseController { public function handle() { $context = Timber::get_context(); $context['posts'] = $this->getPosts(); return new TimberResponse('index.twig', $context); } private function getPosts() { return Timber::get_posts([ 'posts_per_page' => 5, 'tag' => 'club' ]); } }
  • 20. Benefits • Write Object Orientated code rather than Procedural code • Can use inheritance to extend a base class for common functionality • Can encapsulate more complex routines in private functions • Make use of PSR-7 compliant Response objects
  • 22. What are the problems with
 wp-config?
  • 23. // ** MySQL settings - You can get this info from your web host ** // /** The name of the database for WordPress */ define('DB_NAME', 'wordpress'); /** MySQL database username */ define('DB_USER', 'root'); /** MySQL database password */ define('DB_PASSWORD', ‘letmein'); /** MySQL hostname */ define('DB_HOST', 'localhost'); /** Database Charset to use in creating database tables. */ define('DB_CHARSET', 'utf8'); /** The Database Collate type. Don't change this if in doubt. */ define('DB_COLLATE', ''); wp-config.php
  • 24. DB_NAME=wordpress DB_USER=root DB_PASSWORD=letmein # Optional variables # DB_HOST=localhost # DB_PREFIX=wp_ WP_ENV=development WP_HOME=http://example.com WP_SITEURL=${WP_HOME}/wp GOOGLE_MAPS_API_KEY=KJjn32s32dN2 .env $apiKey = getenv('GOOGLE_MAPS_API_KEY'); Some PHP file
  • 28. How does Lumberjack fit into this?
  • 29. Lumberjack Starter Theme Lumberjack + Bedrock = ❤ Bedrock WordPress v4.5.* Timber v1.1.* Yoast v5.2.3 ACF v5.6.1.2 Lumberjack Core v3.0.*
  • 30. DB_NAME=wordpress DB_USER=root DB_PASSWORD=letmein # Optional variables # DB_HOST=localhost # DB_PREFIX=wp_ WP_ENV=development WP_HOME=http://example.com WP_SITEURL=${WP_HOME}/wp GOOGLE_MAPS_API_KEY=KJjn32s32dN2 .env $apiKey = getenv('GOOGLE_MAPS_API_KEY'); Some PHP file t You can’t change config settings Your code shouldn’t actually care about dotenv
  • 31. Your code just wants to say: “Hey config, can I get the ‘google maps api key’ please?”
  • 32. Some PHP file $apiKey = Config::get('app.google_maps_api_key'); config/app.php return [ 'google_maps_api_key' => getenv('GOOGLE_MAPS_API_KEY', 'dummy-api-key'), ];
  • 33. return [ 'logs' => [ 'enabled' => true, 'location' => '/tmp', ], ]; config/app.php Some PHP file $location = Config::get('app.logs.location'); // => '/tmp'
  • 34. Lumberjack Config • Post Type Registration • Image sizes • Error logging • Menu locations • Load paths of Twig files for Timber • Basic theme support (e.g. enable Featured Image support)
  • 36. $args = [ 'post_type' => 'product', 'posts_per_page' => 10, 'orderby' => 'title', 'order' => 'ASC', 'meta_query' => [ 'relation' => 'AND', [ 'key' => 'available_from_date', 'value' => [$from_date, $to_date], 'compare' => 'BETWEEN', 'type' => 'DATE', ], [ 'key' => 'available_to_date', 'value' => [$from_date, $to_date], 'compare' => 'BETWEEN', 'type' => 'DATE', ], ] ]; $query = new WP_Query($args); $posts = $query->get_posts();
  • 37. use TimberPost; $post = new Post(1); $collection = Timber::get_posts($wpQueryArray); Timber Post Object
  • 38. use RareloopLumberjackPost; use AppPostTypesProduct; $post = new Post(1); $collection = Post::query($wpQueryArray); $product = new Product(1); $collection = Product::query($wpQueryArray); Lumberjack Post Object
  • 39. class Product extends Post { public function getPhotos() : array { // Do database query to get the assigned photos } } Encapsulate Business Logic $product = new Product(123); $photos = $product->getPhotos();
  • 40. class Product extends Post { } Register Custom Post Types // config/posttypes.php return [ 'register' => [ AppPostTypesProduct::class, ], ]; protected static function getPostTypeConfig() { return [ 'labels' => [ 'name' => __('Products'), 'singular_name' => __('Product'), ], 'public' => true, 'has_archive' => false, ]; } public static function getPostType() { return 'product'; }
  • 42. Advanced Queries $productType = new ProductType; $products = Product::whereStatus('publish') ->whereMeta('type', '"' . $productType->id . '"', 'LIKE') ->limit(10) ->orderBy('title', 'asc') ->get();
  • 43. Using the Query Builder directly $products = QueryBuilder::wherePostType([ Product::getPostType(), GiftSet::getPostType(), ]) ->whereStatus('publish') ->limit(10) ->orderBy(‘title', 'asc') ->get();
  • 44. Extending the Query Builder $announcements = Announcement::whereStatus('publish') ->whereAddedSince('10 days ago') ->whereSearchTerm('Lorem Ipsum') ->orderBy('date', 'desc') ->paginate();
  • 46. Router::get('hello/world', function () { return HtmlResponse('<h1>Hello World!</h1>'); }); Simple Routes use RareloopLumberjackFacadesRouter; use ZendDiactorosResponseHtmlResponse;
  • 47. Router::get('hello/{name}', function ($name) { return HtmlResponse('<h1>Hello ' . $name . '!</h1>'); }); echo Router::url('hello.world', ['name' => 'adam']); ->name('hello.world'); Params & Named Routes
  • 49. AJAX endpoint that returns JSON class ArticleCommentController { } Router::post('articles/{id}/comments', 'AppHttpControllersArticleCommentController@store'); public function store($id, ServerRequest $request) { } $content = json_decode($request->getBody(), true); $user = wp_get_current_user(); wp_new_comment([ 'comment_post_ID' => (int) $articleId, 'comment_author' => $user->ID, 'comment_content' => data_get($content, 'comment'), ]); return new JsonResponse([ 'data' => [ 'content' => $content['comment'], 'author' => $user->display_name, ] ], 201);
  • 50. Router benefits • Extend WordPress site with custom URL endpoints • Access to all REST based verbs • Can add Groups, for collecting similar resources together
  • 52. Baked-in Responses $response = new TimberResponse(‘templates/home.twig’, $context); // From https://github.com/zendframework/zend-diactoros $response = new TextResponse('Hello world!'); $response = new HtmlResponse($htmlContent); $response = new XmlResponse($xml); $response = new JsonResponse($data); $response = new EmptyResponse(); // Basic 204 response: $response = new RedirectResponse('/user/login');
  • 53.
  • 54. CONTENT SITE BESPOKE SYSTEM Project Spectrum
  • 55.
  • 56. “Don’t use what you don’t understand.”
  • 58. • PSR11 Dependency Injection Container (using PHP-DI) • Facades • Exception Handling (PSR3) • Validation (currently an external package) • View Models More power at your fingertips ✨ • Service Providers • Hatchet (CLI) • Global helper functions (e.g. config(‘app.environment’); ) • Debug bar & Dump server • ‘Responsable’ objects (from Laravel) - in, but currently undocumented
  • 59. • Sessions (coming soon) • Example theme (currently in development) • Automated Testing • Unit tests with PHPUnit • Integration tests with Laravel Dusk On the radar 📡
  • 60. namespace TestsBrowser; use ChadanukDuskWordpressTestsTestCase; class ExampleTest extends TestCase { /* @test */ public function can_see_home_page_title() { $postFactory = new WP_UnitTest_Factory_For_Post(); $postId = $postFactory->create_object([ 'post_title' => 'Home page title', 'post_type' => 'page', 'post_name' => 'home' ]); $this->browse(function ($browser) { $browser->visit(‘/') ->assertSee('Home page title'); }); } }
  • 61.
  • 62.
  • 63.
  • 66. • Evaluate the product mindset for you (and your team?) • WordPress is awesome, we can make it even more awesome! • Challenge and push your stack forward • Write code which is easier to change • Lumberjack is basically Laravel in WordPress • Use only what you need to in Lumberjack In summary…
  • 67.