WordPress

dobrý sluha, zlý pán

👉🏾 Ján Bočínec 👈🏾

width:400px

Why people LOVE WordPress?

  • Plugins and Themes
  • SEO friendly
  • Easy to manage
  • Easy to maintain
  • Safe and secure
  • You don't have to be a developer

Open-source and free

Why people HATE WordPress?

  • Plugins & Themes
  • SEO
  • Software updates
  • Hard to maintain
  • Security
  • Messy, bloated code with no structure

"WordPress is one of the most expensive CMS platforms out there!"

Is WordPress future-proof?

height:500px

WordPress API

  • Unhelpful names: get_children (get what children?)...
  • What are all these sanitize_* and esc_* functions...
  • Unnecessary functions: absint...
  • Who would use this? wp_hash...
  • Would you ever use wpdb class in you own app?

PHP 4

PHP 5

PHP 7

PHP today

PHP tomorrow

"The codebase is stuck in 2003 and probably will be forever."

bad practices

and

global variables

No standards...

height:500px

How others do it?

  • Symfony
  • Laravel
  • Nette
  • Drupal

Everybody needs some quidance

  • How to build plugins?
  • How to build themes?
  • What is the best structure for my custom project?
  • Why is my code always such a mess?

Not just HOW but mostly WHY

Better performance

More secure

Overall compatibility

More readable code

Testability

New features

Don't have to make it but enable it!

Use modern PHP practices

  • Namespaces
  • Autoloading
  • Closures (anonymous functions)
  • Type hints (and return type declarations) 😁
  • Exception-based error handling 😁

What else can PHP do?

  • Traits
  • Generators
  • Group aliasing
  • Late static binding
  • libsodium and modern security

NAME\SPACES

What can it do

  • Trademark your code
  • Simpler naming of everything
  • Better code segregation
  • Easier to use with other people's code

Before

class Webikon_PlatobneBrany_Payment_Gateway extends PaymentFramework {

	public function pay( $order ) {
		...
	}

}

After

namespace Webikon\PlatobneBrany;

class Payment_Gateway extends PaymentFramework {

	public function pay( \WC_Order $order ): ?Payment {
		...
	}

}

Why use namespaces?

  • Prevent naming collisions
  • Code readability
  • Better code organization
  • Aliasing (helping with legacy code)

Before

class New_Controller extends Legacy_Controller_Class {

	public function __construct ( Collection $collection ) {
		...
	}
}
class_alias( 'Legacy_Controller_Class', 'Standard_Controller' );


class New_Controller extends Standard_Controller {

	public function __construct ( Collection $collection ) {
		...
	}
}

Autoloading

  • Convert class names into file names
  • Load classes whe they are needed

Type hints

  • Helps catch avoidable mistakes
  • Defines what is expected and accepted
  • Multiple types not supported

In practice

// Core
function wp_insert_post( array $postarr, bool $wp_error = false ) {}


function back_to_future( string $old, string $new, \Bang $object ) {}


public static function instance(): ?Collection {
	return new Collection();
}

Traits

Before

class WordPress extends Code {
	public $people;

	public function set_people( array $people ) {
		$this->people = $people;
	}

	public function __constructor( array $people ) {
		$this->set_people( $people );
	}
}

Using same parts of code...

class WordCamp extends Community {
	public $people;
	
	public function set_people( array $people ) {
		$this->people = $people;
	}

	public function __constructor( array $people ) {
		$this->set_people( $people );
	}
}

After

trait People {
	public $people:

	public function set_people( array $people ) {
		$this->people = $people;
	}	
}

class WordPress extends Code {
	use People;

	public function __constructor( array $people ) {
		$this->set_people( $people );
	}
}

class WordCamp extends Community {
	use People;

	public function __constructor( array $people ) {
		$this->set_people( $people );
	}
}

web DEV

vs.

web HACK

Extra layer above WordPress

Automatic updates

are just the illusion.

Dependencies management

  • Automatic dependencies management
  • Easy updates for packages
  • Effective autoloading
  • Full version control

Composer

{
    "repositories":[
        {
            "type":"composer",
            "url":"https://wpackagist.org"
        }
    ],
    "require": {
        "aws/aws-sdk-php":"*",
        "wpackagist-plugin/wordpress-seo":">=7.0.2",
    }
}
{
    "require": {
    	"php": ">=7.2.0",
    	"nothingworks/blade-svg": "v0.3.1",
		"woocommerce/woocommerce": "3.6.5",
        "wpackagist-theme/hueman":"*"
        ...
    },
    "require-dev": {
    	"phpro/grumphp": "0.15.2",
    	"phpunit/phpunit": "^7.0",
    	"squizlabs/php_codesniffer": "3.4.2",
        "wp-cli/wp-cli-bundle": "2.3"
        ...
    }
}

Useful packages

https://github.com/mattstauffer/Torch

// Create new writer instance with dependencies
$log = new Illuminate\Log\Logger(
	new Monolog\Logger('Custom Logger')
	);

// Setup log file location
$log->pushHandler(
	new Monolog\Handler\StreamHandler('./logs/app.log')
	);

// Actual log(s)
$log->info('Logging an info message');

$log->error('Logging an error message');

$log->notice('Logging a notice message');

https://symfony.com/doc/current/components/index.html

use Symfony\Component\Yaml\Yaml;

$value = Yaml::parseFile('/path/to/file.yaml');

npm

{
  "devDependencies": {
    "browser-sync": "^2.26.7",
    "laravel-mix": "^4.1.2",
    "sass": "^1.17.3",
    ...
  },
  "dependencies": {
    "bootstrap": "4.3.1",
    "choices.js": "^6.0.3",
    "jquery": "^3.4.0",
    "popper.js": "^1.14.6",
    ...
  }
}

Event-driven architecture

Famous hooks

Model-View-Controller architecture

  • Faster development process.
  • Easy for multiple developers to collaborate and work together.
  • Easier to update the application.
  • Easier to debug as we have multiple levels properly written in the application.

Ideal for large application

  • Multiple views
  • Model returns the data without the need of formatting
  • The modification never affects the entire model

Disadvantages of MVC architecture

  • Harder to understand MVC architecture.
  • Must have strict rules on methods.

Routing

Route::get()
    ->url( '/custom' )
    ->query( function ( $query_vars ) {
        return [
            // WP_Query query vars go here ...
        ];
    } )
    ->middleware( ['user.can:manage_options', 'minify'] )
    ->handle( 'CustomController@custom' );

Templating Twig/Blade/PHP

View::addComposer( 'templates/about-us', function( $view ) {
    $view->with( ['hello' => 'world'] );
} );

Blade template

<html>
    <head>
        <title>Site Name - @yield('title')</title>
    </head>
    <body>
        @section('sidebar')
            This is the master sidebar.
        @show

        <div class="container">
            @yield('content')
        </div>
    </body>
</html>

Themosis

  • Bedrock (+ Sage)
  • WP Emerge
  • MWP Application Framework

Models

Corcel

https://github.com/corcel/corcel

// Get 3 posts with custom post type (store) and show its address
$stores = Post::type('store')->status('publish')->take(3)->get();
// Find a published post which matches both meta_key and meta_value.
$post = Post::published()->hasMeta('username', 'Janko')->first();
// only all categories and posts connected with it
$cat = Taxonomy::where('taxonomy', 'category')->with('posts')->get();

And others

But...

there're reasons not to use
WordPress

...