WordPress – crap code

I’ve just been digging through query.php trying to fix a WordPress problem.

And the code I see is staggeringly bad. Yet this is core code.

e.g. take a look at get_posts(), pages upon pages of if statements. Utterly unreadable and there is no way to figure out how a change might cascade down the code.

I ran the code through a debugger. After staggering through the hundreds of lines of if statements I found WordPress was calling the function a 2nd time. So, not only is it incredibly long and incomprehensible. It gets called multiple times.

 

Mac as a Development platform

I sometimes feel as if I spend half my time making fixes caused by Apple upgrades.

This morning I found my previously hand-crafted php.ini had been removed.

So, each time Apple does an upgrade I have to go back in and update php.ini with various customizations (like max post size, etc).

This also happened to Apache. Apple did an upgrade and I lost my virtualhosts.

And other things change too – like I now have to use mysql.server start rather than using mysqld. I can understand that things need to change but why not provide a graphic tool and just change things under the hood.

Now I try restarting MySQL and I get:

So clearly another update has happened that I’ll need to fix.

My experience on Linux has always been much smoother. I’m starting to wonder if I should try using it again as a development platform.

How does WordPress load templates?

The short answer:

– go see https://codex.wordpress.org/Template_Hierarchy

However, here’s a worked-out example.

I have a page called News with the slug “news”.  Here’s how WordPress loads the necessary page:

1. Apache runs your root /index.php file

2. This require’s

3. wp-blog-header then:

require_once’s wp-load.php

runs wp() and

require_once’s template-loader.php

4. template-loader.php does a few checks and then runs a huge if, elseif:

Lovely!

It turns out that the example given sets $template to ‘wp-content/themes/<theme name>/page-news.php’.

How does it do that? Well, if we search for the function get_page_templates() it turns out there are 3 occurrences in the WordPress code (in wp-admin/includes/theme.php and in various wp-includes files – class-wp-theme.php, template.php).

So, which one is it using?

The answer:

wp-includes/template.php which returns the value here:

Where is get_page_template_slug() defined?

In wp-includes/post-template.php. This works out the post using the post_id.

Then it works out the template using get_post_meta() (which is defined in post.php).

get_post_meta simply returns the result of another function get_metadata which is defined in meta.php.

The full code:

In meta.php > get_metadata it checks $meta_key. It cycles through a bunch of values in $meta_cache until it gets to $meta_key = ‘_wp_mf_page_template’.

The code:

cycles through the $meta_cache values just to decide the template! I had 343 values!

I literally gave up here as, whilst I spotted a $meta_key = “_wp_page_template” it continued to cycle through the $meta_cache values. Without wasting more time on this I can only assume it found the value here.

 

 

 

 

This is what’s wrong with programming

In addition to built-in coding assistance, PhpStorm provides code style check through integration with the PHP Code Sniffer tool, which validates your code for consistence with a coding standard of your choice. You can appoint one of the predefined coding standards or use your own previously defined coding standard with the root directory outside the default PHP Code Sniffer’s Standards directory. Moreover, you can share your custom coding style with your team fellows.

To use PHP Code Sniffer right from PhpStorm instead of from a command line, you need to register it in PhpStorm and configure it as a PhpStorm code inspection. Once installed and enabled in PhpStorm, the tool is available in any opened PHP file, so no steps are required from your side to launch it. The on-the-fly code check is activated upon every update in the file thus making it extremely easy to get rid of problems reported by PHP Code Sniffer.

Errors and warnings reported by PHP Code Sniffer on-the-fly are displayed as pop-up messages. When the tool is run in the batch mode, the errors and warnings are displayed in the Inspection tool window. Anyway, each message has the phpcs prefix to distinguish it from PhpStorm internal inspections.

On this page:

Prerequisites

  1. The PEAR package manager is installed on your machine.
  2. PHP Code Sniffer is installed on your machine. To check it, switch to the directory with thepear.bat file and run the following command: phpcs –versionIf the tool is available, you will get a message in the following format: PHP_CodeSniffer version <version> (stable) by Squiz Pty Ltd. (http://www.squiz.net)
  3. To have code checked against your own custom coding standard, create it. Store the rules and the ruleset.xml file that points to them in the coding standard root directory.

To register PHP Code Sniffer in PhpStorm
  1. Open the project settings, and click Code Sniffer under the PHP node.
  2. In the PHP Code Sniffer path text box, specify the location of the Code Sniffer executablephpcs.bat. Type the path manually or click the Browse button browseButton.png and select the path in the dialog box, that opens.To check that the specified path to phpcs.bat ensures interaction between PhpStorm and Code Sniffer, that is, the tool can be launched from PhpStorm and PhpStorm will receive problem reports from it, click the Validate button. This validation is equal to running the phpcs –versioncommand. If validation passes successfully, PhpStorm displays the information on the detected Code Sniffer version.

To specify advanced PHP Code Sniffer options

PhpStorm provides the ability to specify advanced PHP Code Sniffer options and thus fine tune the PHP Code Sniffer process behavior depending on the configuration of your computer and the rule sets used.

  1. Open the project settings, and click Code Sniffer under the PHP node.
  2. In the Maximum number of messages per file text box, set the upper limit for the total number of messages to be reported for a file. All the messages above this limit will be rejected and PhpStorm will display the following warning right in the code:
  3. In the Tool process timeout text box, specify how long you want PhpStorm to wait for a result from PHP Code Sniffer, whereupon the process is killed to prevent excessive CPU and memory usage.

To configure PHP Code Sniffer as a PhpStorm inspection
  1. Open the project settings, and click Inspections.
  2. On the Inspections page that opens, select the PHP Code Sniffer validation check box under the PHP node.
  3. On the right-hand pane of the page, configure the PHP Code Sniffer tool using the controls in theOptions area:
    1. From the Severity drop-down list, choose the severity degree for the Code Sniffer inspection. The selected value determines how serious the detected discrepancies will be treated by PhpStorm and presented in the inspection results.
    2. In the Coding standard drop-down list, appoint the coding style to check your code against. The list contains all the coding standards installed inside the main PHP_CodeSniffer directory structure.Use one of the predefined coding standards or choose Custom to appoint your own standard.
    3. Optionally, select the Ignore warnings check box to have only errors reported and suppress reporting warnings. This option is equal to the -n command line argument.

To appoint a custom coding style to use

You can have code checked against your own previously defined coding standard with the root directory outside the default PHP Code Sniffer’s Standards directory. This root directory should contain the rules themselves and the ruleset.xml file that points to them.

  1. Open the project settings, click Inspections. The Inspections page opens. Select the PHP Code Sniffer validation check box under the PHP node.
  2. From the Coding standard drop-down list, choose Custom.
  3. Click the Browse button browseButton.png.
  4. In the Custom Coding Standard dialog box that opens, specify the path to the root directory of your own coding standard in the Root directory. Type the path manually or click the Browse buttonbrowseButton.png and choose the relevant folder in the dialog that opens.

    Note

    The selected root directory should contain the ruleset.xml file that points to the rules.

To share a custom coding style with the team
  1. Put the root directory of your coding standard under the project root.
  2. Configure Code Sniffer as a PhpStorm inspection.
  3. Appoint your coding standard.
  4. At the top of the Inspections page, select the Share Profile check box.
  5. On the Version Control page of the Settings dialog box, put the root directory of your coding standard under version control.

To run Code Sniffer in the batch mode
  1. To run the inspection, choose Code | Inspect code on the main menu. Specify the inspection scope and profile.
  2. View the inspection results in the Inspection tool window. Errors and warnings reported by PHP Code Sniffer have the phpcs prefix to distinguish them from PhpStorm internal inspections.

Excluding files from inspection

When waiting for Code Sniffer response exceeds the limit specified in the Tool process timeoutfield on Code Sniffer page, PhpStorm suggests adding the file to the ignore list. This list is shown on the Code Sniffer page in the Ignored files area. For each file, PhpStorm displays its name and location.

  • To delete a file from the list and have Code Sniffer process it again, select the file and click theRemove file button delete.png.
  • To remove all the files from the list, click the Clean the list button close.png.

Mac: GPU Panic

I’ve recently had a few issues where the Mac has crashed with a “GPU Panic”.

Turns out it might be something to do with Google’s Chrome browser which uses some GPU acceleration for HTML5 updates. 

More here:

http://betanews.com/2012/06/29/google-comes-clean-yes-your-kernel-panic-is-chromes-fault/ 

and here:

http://forums.macrumors.com/showthread.php?t=1597599

For the moment I’m going to uninstall Chrome and see what happens.

Also experienced an annoying logout problem which also happens to be related to the GPU and GPU switching. If you’re using multiple GPUs then you can use gfxCardStatus to fix the Mac to 1 GPU.

http://forums.macrumors.com/showthread.php?p=13322234#post13322234

Rails: Phusion Passenger

Passenger is an application server for Ruby (Rack) and Python (WSGI) apps.

Some notes on installing it:

https://www.phusionpassenger.com/download

Ignore the docs that suggest:

$ sudo gem install passenger

$ sudo passenger-install-apache2-module

Instead use:

gem install passenger

passenger-install-apache2-module

Then paste the LoadModule code it spits out at the end into your Apache conf file.

Test whether Passenger has installed by running:

curl -sI localhost | grep ^Server

and check for the “Phusion_Passenger” signature. E.g. 

Server: Apache/2.2.22 (Unix) DAV/2 PHP/5.3.15 with Suhosin-Patch Phusion_Passenger/4.0.5 mod_ssl/2.2.22 OpenSSL/0.9.8x

If you need to uninstall Passenger using sudo then:

$ sudo gem uninstall passenger

And a discussion on whether to use rvmsudo or not here:

https://groups.google.com/forum/#!topic/rubyversionmanager/9dnmAsTiHR4

In short, https://www.phusionpassenger.com/download

suggests using sudo but the rvm page suggests not:

https://rvm.io/integration/passenger

Note:

If you get a warning doing the passenger install apache2 module like this:

rvmsudo rvm get stable && rvm reload && rvmsudo rvm repair all

Warning: can not check /etc/sudoers for secure_path, falling back to call via /usr/bin/env, this breaks rules from /etc/sudoers. Run:

    export rvmsudo_secure_path=1

Then run:

    export rvmsudo_secure_path=1

and:

rvmsudo rvm get stable && rvm reload && rvmsudo rvm repair all

(remember to run rvm requirements afterwards)

On the Mac the Apache conf and restart commands go like this:

[~]$ sudo vim /etc/apache2/httpd.conf

[~]$ sudo apachectl restart

See also:

https://developer.apple.com/library/mac/#featuredarticles/PhusionRails/_index.html

and this very useful guide:

http://jasoncodes.com/posts/mac-os-rails-server

Rails: Phusion Passenger

Passenger is an application server for Ruby (Rack) and Python (WSGI) apps.

Some notes on installing it:

https://www.phusionpassenger.com/download

Ignore the docs that suggest:

$ sudo gem install passenger

$ sudo passenger-install-apache2-module

Instead use:

gem install passenger

should be sufficient and rvm.io suggests just running:

passenger-install-apache2-module

See also:

http://stackoverflow.com/questions/17245105/passenger-module-fails-to-install

and

http://stackoverflow.com/questions/17248660/installing-passenger-use-sudo-rvmsudo-or-nothing

Then, paste the LoadModule code it spits out at the end into your Apache conf file.

Test whether Passenger has installed by running:

curl -sI localhost | grep ^Server

and check for the “Phusion_Passenger” signature. E.g. 

Server: Apache/2.2.22 (Unix) DAV/2 PHP/5.3.15 with Suhosin-Patch Phusion_Passenger/4.0.5 mod_ssl/2.2.22 OpenSSL/0.9.8x

If you need to uninstall Passenger using sudo then:

$ sudo gem uninstall passenger

And a discussion on whether to use rvmsudo or not here:

https://groups.google.com/forum/#!topic/rubyversionmanager/9dnmAsTiHR4

In short, https://www.phusionpassenger.com/download

suggests using sudo but the rvm page suggests not:

https://rvm.io/integration/passenger

Note:

If you get a warning doing the passenger install apache2 module like this:

rvmsudo rvm get stable && rvm reload && rvmsudo rvm repair all

Warning: can not check /etc/sudoers for secure_path, falling back to call via /usr/bin/env, this breaks rules from /etc/sudoers. Run:

    export rvmsudo_secure_path=1

Then run:

    export rvmsudo_secure_path=1

and:

rvmsudo rvm get stable && rvm reload && rvmsudo rvm repair all

(remember to run rvm requirements afterwards)

On the Mac the Apache conf and restart commands go like this:

[~]$ sudo vim /etc/apache2/httpd.conf

[~]$ sudo apachectl restart

See also:

https://developer.apple.com/library/mac/#featuredarticles/PhusionRails/_index.html

Ruby: dynamic methods

This takes some getting your head around if you’ve been using statically referenced methods such as in Java or PHP.

Take this class which we’ll save as a file ‘methods.rb’:

class Person

attr_reader :name

def initialize(name)

@name = name

end

def inspect 

“This person’s name is #{@name}”

end

def a_method

puts “I’m a method”

end

end

Now go into irb, load it up and instantiate a new object, e.g.:

load ‘methods.rb’

p = Person.new(“Rafa”)

p.a_method

outputs:

I’m a method

 => nil 

Let’s try a (currently) non-existent method:

p.b_method

which outputs:

defined method `b_method’ for This person’s name is Rafa:Person

from (irb):4

Now here’s the dynamic bit. We can add a new method to the file, save it, load it via irb and those methods are now available to our already-‘compiled’ class. E.g. save this:

class Person

attr_reader :name

def initialize(name)

@name = name

end

def inspect 

“This person’s name is #{@name}”

end

def a_method

puts “I’m a method”

end

def b_method

puts “I’m another method”

end

end

Enter irb, load it and then run this new method:

load ‘methods.rb’

p = Person.new(“Rafa”)

p.b_method

which outputs:

I’m another method

 => nil 

Note: we didn’t create a new object here. We simply loaded the new class into our environment and our existing object dynamically picks up the new method. 

This is just a simple example of how Ruby allows you to add methods in dynamically. Very neat.

Why hasn’t Facebook ditched PHP

The reason?

Incumbent inertia (there is so much code and there are so many engineers familiar with the code that it would be suicide to change) and the engineers have worked around many of its flaws by patches and internal discipline.

However, preferred strategy is to write new components in a de-couple manner using a better language of choice (C++, python, Erlang, Java, etc).

So, the overall codebase is slowly evolving away from depending heavily on PHP.

More here:

http://www.zdnet.com/blog/facebook/why-facebook-hasnt-ditched-php/9536

and here:

http://www.quora.com/Facebook-Engineering/Why-hasn-t-Facebook-migrated-away-from-PHP