1. Don't Sh** in the Pool How your code can ruin WordPress for others
2. Chris is a member of the iThemes.com team and is the lead developer of iThemes Builder. He stinks at writing his own bios and really dislikes writing in the third-person, so he'll just list some random things. Chris has 10 years of professional web development experience with three years spent with WordPress development. While he works with themes, he can't design an attractive site to save his life, so he focuses his efforts on coding, nitpicking on off-by-one-pixel issues, and working on new concepts. Chris thinks himself to be a nice guy, but he's really kind of a jerk. Who Am I?
3.
4. Very simple and valid looking solutions can quickly create compatibility problems with other plugins, with themes, and with WordPress itself.
5. People then talk about these amazing solutions that they've come up with to solve their problems.
8. This presentation is a focus on the “worst practices” in WordPress development. A study in how not to do certain things, why they are an issue, and how to avoid the problem. What Is This, Really?
22. We'll start with a very popular practice, using wp_deregister_script to replace a WordPress core script with a newer/older/modified script. wp_deregister_script('jquery'); wp_register_script('jquery', 'http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js'); wp_enqueue_script('jquery'); Changing Core Scripts: The Example
23.
24. Changing the script can quickly cause solutions that rely on a specific version of a script to break.
25. Replacing a script is shifting the development difficulty from yourself to everyone else.
26. In other words, it is a prime example of selfish development.
27.
28. Learn to make your code adapt to different script versions rather than requiring every other developer to adapt their code to suit your needs.
30. Directly Printing Scripts/Styles: The Example Have you written this before? echo '<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>'; If so, you're doing it wrong.
31. Directly Printing Scripts/Styles: The Problem In many ways, this problem is similar to the one where built-in scripts are modified. Imagine that someone used the enqueues system to properly enqueue a script that you then directly added to the page output. Now, the script is loaded twice, potentially with different versions and features. This quickly leads to compatibility conflicts.
34. A good reference for what hooks to use for script and style enqueues can be found at http://bit.ly/vYw3SY
35. Bad Menu Slugs for Dashboard Menus: The Example add_menu_page('Name', 'Name', 8, __FILE__, 'callback'); add_submenu_page(__FILE__, 'Name', 'Name', 1, basename(__FILE__), 'callback'); Notice the use of __FILE__ in these examples.
36. Bad Menu Slugs for Dashboard Menus: The Problem The argument that used __FILE__ in the previous examples is the $menu_slug argument. This is the name that is used for the “ page= ” argument to load the menu page. I believe that this practice started from a very old set of example code that was copied and pasted an untold number of times.
37. Bad Menu Slugs for Dashboard Menus: The Problem While this may not seem like a big issue, and the code that does this works just fine, it can easily create issues. If the menu slug ends up set to “ admin.php ” based on the name of the file with the function call, then other menus added by plugins will have their pages broken with a message that simply says: “ You do not have sufficient permissions to access this page.”
42. Not Prefixing Functions, Classes, and Vars: The Example Going straight to a code example, consider the following: function load_settings() { global $settings; $settings = get_option( 'my-settings' ); } Notice how every name used, the function name, the global variable name, and the option name are each very generic and could easily apply to any project.
43. Not Prefixing Functions, Classes, and Vars: The Problem The issue with using generic names for functions, classes, global variables, and names such as names for options, menu slugs, action/filter hooks, and scripts to be enqueued is that they can quickly collide with names used by another developer if they also use generic names. If two plugins use the same function or class name, PHP crashes and most people will see a blank white screen with no idea of how to fix it. If two plugins use the same variable, then very unusual problems can occur with seemingly-random results.
44. Not Prefixing Functions, Classes, and Vars: The Solution The solution is simple, always, always, always prefix anything your plugin exposes to the rest of the WordPress ecosystem.
45. Not Prefixing Functions, Classes, and Vars: The Solution For functions, actions, filters, and other items that “do” things, I use the following pattern: [author initials]-[project initials]-[verb]-[noun] Such as: caj-rfp-load-options caj-dsn-filter-rotary-girders caj-aep-enqueue-scripts
46. Not Prefixing Functions, Classes, and Vars: The Solution For variables, option names, classes, and other items that “represent” something, I use the following pattern: [author initials]-[project initials]-[noun] Such as: caj-tirn-settings CAJ_SEF_Author_Widget caj-uwriq-features
47. Enqueueing Scripts Everywhere: The Example function caj_epp_add_menu() { add_theme_page( 'Name', 'Name', 'manage_options', 'caj-epp-edit-settings', 'caj_epp_show_settings_page' ); } add_action( 'admin_menu', 'caj_epp_add_menu' ); function caj_epp_add_scripts() { wp_enqueue_script( 'jquery' ); wp_enqueue_script( 'media-upload' ); } add_action( 'admin_print_scripts', 'caj_epp_add_scripts' );
48. Enqueueing Scripts Everywhere: The Problem The code example above enqueues the jquery and media-upload scripts on every admin page. While this may seem harmless, it can easily cause problems. If you enqueue your own custom scripts on every admin page, you can now cause conflicts with other plugin's scripts on those plugin's pages... on pages that don't even involve your plugin.
49. Enqueueing Scripts Everywhere: The Problem This issue isn't just limited to custom scripts. If you enqueue styles in places where they aren't supposed to be enqueued, you can break the styling of the output of other plugins, other themes, or WordPress itself. In addition, some WordPress-provided scripts can cause problems for other projects. A good example is the media-upload script, which changes how all Thickboxes behave.
50. Enqueueing Scripts Everywhere: The Solution Since most scripts and styles that projects add to the Dashboard are meant to only be added to the pages specific to that project, you can simply use a page-specific action to ensure that the scripts and styles are only added to those pages. The key is to save the “hook suffix” returned by the function used to add the Dashboard menu entry. This is then used as part of the admin_print_styles-$hook_suffix or admin_print_scripts-$hook_suffix action hooks.
52. Not Using WP_DEBUG : The Example <?php $caj_epp_settings = get_option( 'caj-epp-settings', array() ); ?> <p>Hello <?php echo $caj_epp_settings['name'] ?></p>
53. Not Using WP_DEBUG : The Problem Unless you run with WP_DEBUG enabled on your site, you will never see a problem, but for other developers that happen to run your code and do use WP_DEBUG , they will see the following until the “ name ” index of the array is set: Notice: Undefined index: setting in /home/user/public_html/wp-content/plugins/example-project-plugin/public.php on line 5 And this is with just one instance of this issue. Imagine if your code had dozens of issues like this.
54. Not Using WP_DEBUG : The Solution Add the following to the wp-config.php file of every site you develop on: define( 'WP_DEBUG', true ); Make sure that you watch for your code to produce warnings, and fix them when you find them. If you have an existing project, erase all of its saved data (delete the option, clear the tables, etc) and check again to confirm that no warnings are produced.
55. Not Using WP_DEBUG : The Solution Create a function to have set defaults that returns the data. function caj_epp_get_settings() { $defaults = array( 'name' => 'User', ); return get_option( 'caj-epp-settings', $defaults ); } Use this function to get the settings. <?php $caj_epp_settings = caj_epp_get_settings(); ?> <p>Hello <?php echo $caj_epp_settings['name']; ?></p>
56. Using Example Code Without Modifying It: The Example Rather than directly picking on anyone, I will simply suggest that the examples used throughout this presentation typify the type of solutions you can find in books, on blogs, in help documents, on support forums, and just about anywhere else. In fact, most of these worst practices come from people simply copying and pasting code that they found elsewhere, leading to duplicate functions, spreading bad practices, and other conflict-causing problems.
57. Using Example Code Without Modifying It: The Problem When you take someone else's code, you also take all of its problems. In addition, you easily run the risk of having duplicate function, action, etc names. Just think about it. If you found that tutorial helpful, someone else is likely to have thought the same thing and is just as likely to have copied and pasted the same example code.
58. Using Example Code Without Modifying It: The Solution When you take code from examples, avoid the problems talked about in the rest of the presentation. Make sure that you prefix functions, global variables, etc. Check that the code doesn't dump any warnings by using WP_DEBUG . Make sure that it doesn't change core scripts/styles or add them directly to the page.
59. Using Example Code Without Modifying It: The Solution In short, if you take someone else's code, make sure that you actually test it and make it your own. After all, now that you've rolled it into your code, it is now yours and you are responsible for it.
60. Concluding Thoughts As a developer, you need to remember that your code doesn't just affect you. Your code affects every user that puts your code on their site, every visitor to those sites, every plugin or theme that runs on those sites, every developer behind each of those themes and plugins, and even WordPress itself. It sounds like a huge burden, but in reality it is your responsibility as a developer. Your goal should not be just making something work; you should also want it to work well.
61. Concluding Thoughts My hope is that I shifted some of your thoughts on development, to make you think of how you have a responsibility to those that use your code and to other developers.