Things developers tend to do wrong with WordPress. Based on amazing presentations from many great WordPress developers across the world.
Slides mostly in English, presentation was in Hebrew at WordCamp Jerusalem (September 2011).
הערות והפניות בבלוג בכתובת http://wp.me/pD4bk-Jn
11. WP_DEBUG 1/2
define('WP_DEBUG', true);
• Include notices
• Bypasses some error suppression (ie
WPDB )
• Triggers notices for deprecated functions
ex: PHP Notice: get_links is deprecated since version
2.1! Use get_bookmarks() instead. in /Users/
yoavfarhi/Sites/trunk/wp-includes/functions.php on
line 3409
Monday, September 12, 11
12. WP_DEBUG 2/2
Don’t display
define('WP_DEBUG_DISPLAY', false);
Output to wp-content/debug.log
define('WP_DEBUG_LOG', true);
Monday, September 12, 11
25. $last_posts = (array)$wpdb->get_results("
SELECT post_date, ID, post_title, name,
{$table_prefix}terms.term_id
FROM {$table_prefix}posts, {$table_prefix}
term_relationships, {$table_prefix}terms, {$table_prefix}
postmeta, {$table_prefix}term_taxonomy
WHERE {$table_prefix}posts.ID = {$table_prefix}
term_relationships.object_id
AND {$table_prefix}term_taxonomy.term_taxonomy_id =
{$table_prefix}term_relationships.term_taxonomy_id
AND {$table_prefix}terms.term_id = {$table_prefix}
term_taxonomy.term_id
AND {$table_prefix}posts.ID = {$table_prefix}
postmeta.post_id
AND {$table_prefix}postmeta.meta_key = '_mini_post'
AND {$table_prefix}postmeta.meta_value = 0
AND post_status = 'publish'
AND {$table_prefix}terms.term_id != 25
AND {$table_prefix}terms.term_id != 24
AND {$table_prefix}term_taxonomy.taxonomy =
'category' ");
Monday, September 12, 11
26. $last_posts = (array)$wpdb->get_results("
SELECT post_date, ID, post_title, name,
{$table_prefix}terms.term_id
FROM {$table_prefix}posts, {$table_prefix}
term_relationships, {$table_prefix}terms, {$table_prefix}
postmeta, {$table_prefix}term_taxonomy
WHERE {$table_prefix}posts.ID = {$table_prefix}
term_relationships.object_id
NG!
AND {$table_prefix}term_taxonomy.term_taxonomy_id =
O
R
{$table_prefix}term_relationships.term_taxonomy_id
W
AND {$table_prefix}terms.term_id = {$table_prefix}
term_taxonomy.term_id
AND {$table_prefix}posts.ID = {$table_prefix}
postmeta.post_id
AND {$table_prefix}postmeta.meta_key = '_mini_post'
AND {$table_prefix}postmeta.meta_value = 0
AND post_status = 'publish'
AND {$table_prefix}terms.term_id != 25
AND {$table_prefix}terms.term_id != 24
AND {$table_prefix}term_taxonomy.taxonomy =
'category' ");
Monday, September 12, 11
29. This is so much better because:
Monday, September 12, 11
30. This is so much better because:
• It is easier to read, easier to change
Monday, September 12, 11
31. This is so much better because:
• It is easier to read, easier to change
• It is more secure
Monday, September 12, 11
32. This is so much better because:
• It is easier to read, easier to change
• It is more secure
• It Uses WP object caching and so faster
Monday, September 12, 11
33. This is so much better because:
• It is easier to read, easier to change
• It is more secure
• It Uses WP object caching and so faster
• It is platform indifferent
Monday, September 12, 11
34. This is so much better because:
• It is easier to read, easier to change
• It is more secure
• It Uses WP object caching and so faster
• It is platform indifferent
• It is future proof
Monday, September 12, 11
35. This is so much better because:
• It is easier to read, easier to change
• It is more secure
• It Uses WP object caching and so faster
• It is platform indifferent
• It is future proof
• It is bound to be improved
Monday, September 12, 11
38. Javascript
<script type='text/javascript' src='http://thisismysite.com/wp-content/
themes/mytheme/js/newsletter.js'></script>
Monday, September 12, 11
39. Javascript
<script type='text/javascript' src='http://thisismysite.com/wp-content/
ng!
themes/mytheme/js/newsletter.js'></script>
W ro
Monday, September 12, 11
40. Javascript
<script type='text/javascript' src='http://thisismysite.com/wp-content/
ng!
themes/mytheme/js/newsletter.js'></script>
W ro
function mytheme_load_script() {
wp_enqueue_script( 'newsletter', 'http://thisismysite.com/wp-content/
themes/mytheme/js/newsletter.js', array( 'jquery' ), '0.1' );
}
add_action( 'wp_enqueue_scripts', 'mytheme_load_script');
Monday, September 12, 11
41. Javascript
<script type='text/javascript' src='http://thisismysite.com/wp-content/
ng!
themes/mytheme/js/newsletter.js'></script>
W ro
function mytheme_load_script() {
wp_enqueue_script( 'newsletter', 'http://thisismysite.com/wp-content/
themes/mytheme/js/newsletter.js', array( 'jquery' ), '0.1' );
}
at i f ...
add_action( 'wp_enqueue_scripts', 'mytheme_load_script');
but wh
O k,
Monday, September 12, 11
42. Javascript
<script type='text/javascript' src='http://thisismysite.com/wp-content/
ng!
themes/mytheme/js/newsletter.js'></script>
W ro
Monday, September 12, 11
44. Use wp_enqueue_* because:
• DRY - don’t repeat yourself
• You can set dependencies
• And manage versions
• And easily move to the footer
• And control where it loads (admin/page/...)
Monday, September 12, 11
46. Never assume a file location
• There’s a function for that:
Monday, September 12, 11
47. Never assume a file location
• There’s a function for that:
site_url()
Monday, September 12, 11
48. Never assume a file location
• There’s a function for that:
site_url()
plugins_url()
Monday, September 12, 11
49. Never assume a file location
• There’s a function for that:
site_url()
plugins_url()
content_url()
Monday, September 12, 11
50. Never assume a file location
• There’s a function for that:
site_url()
plugins_url()
content_url()
get_theme_directory() *
Monday, September 12, 11
51. Never assume a file location
• There’s a function for that:
site_url()
plugins_url()
content_url()
get_theme_directory() *
get_theme_directory_uri() *
Monday, September 12, 11
52. Never assume a file location
• There’s a function for that:
site_url()
plugins_url()
content_url()
get_theme_directory() *
get_theme_directory_uri() *
includes_url()
Monday, September 12, 11
53. Never assume a file location
• There’s a function for that:
site_url()
plugins_url()
content_url()
get_theme_directory() *
get_theme_directory_uri() *
includes_url()
admin_url()
Monday, September 12, 11
69. Never trust user input
1. XSS
<h1>Search results for: <?php echo $_GET['s']; ?></h1>
http://mysite.com/?s=</h1><script>alert('This Javascript can do anything!');</script>
Monday, September 12, 11
70. Never trust user input
1. XSS
Wro ng!
<h1>Search results for: <?php echo $_GET['s']; ?></h1>
http://mysite.com/?s=</h1><script>alert('This Javascript can do anything!');</script>
Monday, September 12, 11
71. Never trust user input
1. XSS
Wro ng!
<h1>Search results for: <?php echo $_GET['s']; ?></h1>
http://mysite.com/?s=</h1><script>alert('This Javascript can do anything!');</script>
get_search_query()
Solution:
Escape late, escape EVERYTHING
<h1>Search results for: <?php echo esc_attr( $_GET['s'] ) ; ?></h1>
Monday, September 12, 11
73. Never trust user input
2.SQL Injection
$wpdb->query(
" UPDATE $wpdb->posts
SET post_title = ". $POST['title'] ."
WHERE ID = 1"
);
Monday, September 12, 11
74. Never trust user input
2.SQL Injection
$wpdb->query(
ro ng!
" UPDATE $wpdb->posts
W
SET post_title = ". $POST['title'] ."
WHERE ID = 1"
);
Monday, September 12, 11
75. Never trust user input
2.SQL Injection
$wpdb->query(
ro ng!
" UPDATE $wpdb->posts
W
SET post_title = ". $POST['title'] ."
WHERE ID = 1"
);
Solution:
• Use APIS ( $wpdb->update, $wpdb->prepare )
• Validate data ( whitelist > blacklist )
Monday, September 12, 11
77. Never trust user input
3.CSRF
Authorization VS Intention
Monday, September 12, 11
78. Never trust user input
3.CSRF
Authorization VS Intention
Solution:
Use nonces, not just current_user_can()
wp_create_nonce(), wp_verify_nonce(), check_admin_referer()
Monday, September 12, 11