WordCamp Jerusalem - Doing it Wrong

  • 3,660 views
Uploaded on

Things developers tend to do wrong with WordPress. Based on amazing presentations from many great WordPress developers across the world. …

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

More in: Technology , Education
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
3,660
On Slideshare
0
From Embeds
0
Number of Embeds
3

Actions

Shares
Downloads
5
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. You’re doing it wrong! ‫עשר טעויות נפוצות בפיתוח לוורדפרס‬Monday, September 12, 11
  • 2. You’re doing it wrong! ‫עשר תשע טעויות נפוצות בפיתוח לוורדפרס‬Monday, September 12, 11
  • 3. Monday, September 12, 11
  • 4. Monday, September 12, 11
  • 5. ‫ בחברת‬VIP ‫מפתח‬ Automattic ‫ מפקח בין‬VIP-‫צוות ה‬ WordPress ‫השאר על קוד‬ ‫שיוצר מעל‬ ‫ל-000,000,000,1 דפים‬ ‫נצפים בחודש‬ http://yoavfarhi.com @yoavfMonday, September 12, 11
  • 6. Monday, September 12, 11
  • 7. Monday, September 12, 11
  • 8. /me activates WP_DEBUG...Monday, September 12, 11
  • 9. Monday, September 12, 11
  • 10. (wsod) 1. WP_DEBUGMonday, September 12, 11
  • 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 3409Monday, 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
  • 13. 2. Function NamingMonday, September 12, 11
  • 14. Imagine... Plugin 1 Theme / Plugin 2 function custom_script() { function custom_script() { //... //... } }Monday, September 12, 11
  • 15. Imagine... Plugin 1 Theme / Plugin 2 function custom_script() { function custom_script() { //... //... } } Fatal ErrorMonday, September 12, 11
  • 16. Imagine... Plugin 1 Theme / Plugin 2 function custom_script() { function custom_script() { //... //... } } Angry ClientMonday, September 12, 11
  • 17. Imagine... Plugin 1 Theme / Plugin 2 function custom_script() { function custom_script() { //... //... } } Call From ClientMonday, September 12, 11
  • 18. Imagine... Plugin 1 Theme / Plugin 2 function custom_script() { function custom_script() { //... //... } } Time / MoneyMonday, September 12, 11
  • 19. Imagine... Plugin 1 Theme / Plugin 2 function custom_script() { function custom_script() { //... //... } } We don’t want that!Monday, September 12, 11
  • 20. Imagine... Plugin 1 Theme / Plugin 2 function custom_script() { function custom_script() { //... //... } } Solution: PrefixMonday, September 12, 11
  • 21. Prefix! Plugin 1 Theme / Plugin 2 function plugin1_custom_script() { function themename_custom_script() { //... //... } }Monday, September 12, 11
  • 22. Prefix! Plugin 1 Theme / Plugin 2 function plugin1_custom_script() { function themename_custom_script() { //... //... } } Happy!Monday, September 12, 11
  • 23. Or: Use a Class class my_plugin { function custom_script() { //... } function whatever() { //... } } new my_plugin;Monday, September 12, 11
  • 24. AND {$table_prefix}erms.term_id =$table_prefix}erm_taxonomy.term_taxonomy_donomy.term_id Queries 3. Direct SQL AND {$table_prefix}osts.ID = {$table_prefix}ostmetata.post_id AND {$table_prefix}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
  • 27. $args = array( post_type => post, post_status => publish, tax_query => array( array( taxonomy => category, terms => array( 25, 24), field => id, operator => NOT IN, ) ), meta_query => array( array( key => _mini_post, value => 0, ) ) ); $last_posts = new WP_Query( $args );Monday, September 12, 11
  • 28. $args = array( post_type => post, post_status => publish, tax_query => array( array( taxonomy => category, terms => array( 25, 24), field => id, operator => NOT IN, ) ), meta_query => array( array( key => _mini_post, value => 0, ) ) ); $last_posts = new WP_Query( $args );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 changeMonday, September 12, 11
  • 31. This is so much better because: • It is easier to read, easier to change • It is more secureMonday, 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 fasterMonday, 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 indifferentMonday, 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 proofMonday, 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 improvedMonday, September 12, 11
  • 36. 4. Loading JS/CSS/etcMonday, September 12, 11
  • 37. JavascriptMonday, 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 roMonday, 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 roMonday, September 12, 11
  • 43. 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, get_template_directory_uri() . /js/newsletter.js, array( jquery ), 0.1 ); } ht! add_action( wp_enqueue_scripts, mytheme_load_script); RigMonday, 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
  • 45. Never assume a file locationMonday, 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
  • 54. 5. Fetching remote contentMonday, September 12, 11
  • 55. What’s your transport? file_get_contents() ? CURL ? fsockopen() ? stream_socket_client() ?Monday, September 12, 11
  • 56. What’s your transport? ! file_get_contents() ? W RO NG CURL ? fsockopen() ? stream_socket_client() ?Monday, September 12, 11
  • 57. The WP_Http class Helper functions //Simple Get $resp = wp_remote_get( http://example.com/ ); //Simple Post $args = array( body => some data, user-agent => your plugin ); $resp = wp_remote_post( http://example.com, $args );Monday, September 12, 11
  • 58. The WP_Http class Supports • Cookies • Headers • Authentication • Timeouts • Etc... * Add your own cachingMonday, September 12, 11
  • 59. 6. Doing AjaxMonday, September 12, 11
  • 60. Doing AjaxMonday, September 12, 11
  • 61. Doing Ajax front-end: <script> var ajaxurl = <?php echo plugins_url( ajax.php, __FILE__ ); ?> $(#button).click(function(){ $.post(ajaxurl, function(data) { $(.result).html(data); }); }); </script>Monday, September 12, 11
  • 62. Doing Ajax front-end: <script> var ajaxurl = <?php echo plugins_url( ajax.php, __FILE__ ); ?> $(#button).click(function(){ $.post(ajaxurl, function(data) { $(.result).html(data); }); }); </script>ajax.php: <?php require_once(../../../wp-load.php); //...Monday, September 12, 11
  • 63. Doing Ajax front-end: <script> var ajaxurl = <?php echo plugins_url( ajax.php, __FILE__ ); ?> $(#button).click(function(){ $.post(ajaxurl, function(data) { $(.result).html(data); NG! }); }); RO </script>ajax.php: <?php W require_once(../../../wp-load.php); //...Monday, September 12, 11
  • 64. Doing AjaxMonday, September 12, 11
  • 65. Doing Ajax front-end: <script> var ajaxurl = <?php echo admin_url( admin-ajax.php); ?> $(#button).click(function(){ var data = { action: my_action, }; $.post(ajaxurl, function(data) { $(.result).html(data); }); }); </script>Monday, September 12, 11
  • 66. Doing Ajax front-end: <script> var ajaxurl = <?php echo admin_url( admin-ajax.php); ?> $(#button).click(function(){ var data = { action: my_action, }; $.post(ajaxurl, function(data) { $(.result).html(data); }); }); </script>php: add_action(wp_ajax_my_action, plugin_action_callback); add_action(wp_ajax_nopriv_my_action, plugin_action_callback); function plugin_action_callback() { // do whatever echo $whatever; die(); }Monday, September 12, 11
  • 67. 7. Security? What ‘bout it? http://xkcd.com/327/Monday, September 12, 11
  • 68. Never trust user inputMonday, 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
  • 72. Never trust user inputMonday, 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
  • 76. Never trust user inputMonday, September 12, 11
  • 77. Never trust user input 3.CSRF Authorization VS IntentionMonday, 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
  • 79. 8. Trunk?Monday, September 12, 11
  • 80. Mac / Linux $ mkdir blog $ cd blog $ svn co http://core.svn.wordpress.org/trunk/ .Monday, September 12, 11
  • 81. Windows / Tortoise SVNMonday, September 12, 11
  • 82. Running on Trunk No, not for productionMonday, September 12, 11
  • 83. 9. Not ContributingMonday, September 12, 11
  • 84. ContributingMonday, September 12, 11
  • 85. Contributing • Core patches/testing/documentationMonday, September 12, 11
  • 86. Contributing • Core patches/testing/documentation • Release plugins and themesMonday, September 12, 11
  • 87. Contributing • Core patches/testing/documentation • Release plugins and themes • Translations and i18nMonday, September 12, 11
  • 88. Contributing • Core patches/testing/documentation • Release plugins and themes • Translations and i18n • Forums supportMonday, September 12, 11
  • 89. Contributing • Core patches/testing/documentation • Release plugins and themes • Translations and i18n • Forums support • Tip! (or Buy)Monday, September 12, 11
  • 90. Questions ?Monday, September 12, 11