138

You can make the 'slug' for the submenu page equal that of the top level page, and they'll point to the same place: add_action('admin_menu', 'my_menu_pages'); function my_menu_pages(){ add_menu_page('My Page Title', 'My Menu Title', 'manage_options', 'my-menu', 'my_menu_output' ); add_submenu_page('my-menu', 'Submenu Page Title', 'Whatever You Want',...


95

Okay, I've had two big projects where I've been in control of the server enough to namespace and rely on autoloading. First up. Autoloading is awesome. Not worrying about requires is a relatively good thing. Here's a loader I've been using on a few projects. Checks to make sure the class is in the current namespace first, then bails if not. From there it'...


82

Arriving here exactly 2 years after the original question was asked, there are a few things I want to point out. (Don't ask me to point out a lot of things, ever). Proper hook To instantiate a plugin class, the proper hook should be used. There isn't a general rule for which it is, because it depends on what the class does. Using a very early hook like "...


77

I would start with this question: Is the functionality related to presentation of content, or with generation/management of content, or of the site, or of the user identity? If the functionality is not related specifically to presentation of content, then it is squarely within Plugin Territory. This list is long: Modifying core WP filters (wp_head content, ...


70

To add our button to the TinyMCE editor we need to do several things: Add our button to the toolbar Register a TinyMCE plugin Create that TinyMCE plug-in which tells TinyMCE what to do when our button is clicked. Steps #1 and #2 In these steps we register our TinyMCE plug-in which will live inside a javascript file at 'path/to/shortcode.js' (see ...


63

Good question, there are a number of approaches and it depends on what you want to achieve. I often do; add_action( 'plugins_loaded', array( 'someClassy', 'init' )); class someClassy { public static function init() { $class = __CLASS__; new $class; } public function __construct() { //construct what you see fit here....


62

When you visit a frontend page, WordPress will query the database and if your page does not exist in the database, that query is not needed and is just a waste of resources. Luckily, WordPress offers a way to handle frontend requests in a custom way. That is done thanks to the 'do_parse_request' filter. Returning false on that hook, you will be able to ...


55

In backend there is global ajaxurl variable defined by WordPress itself. This variable is not created by WP in frontend. It means that if you want to use AJAX calls in frontend, then you have to define such variable by yourself. Good way to do this is to use wp_localize_script. Let's assume your AJAX calls are in my-ajax-script.js file, then add ...


53

An easy test where the code is best placed: write the code into the functions.php switch theme do you miss the functionality, is the blog not proper working or fragments of the old theme (e.g. shortcodes) are left? yes: put it into a plugin no: leave it in functions.php Examples: Write a shortcode. After switching the theme, the plain shortcodes are left ...


43

to use ajaxurl directly, in your plugin file add this: add_action('wp_head', 'myplugin_ajaxurl'); function myplugin_ajaxurl() { echo '<script type="text/javascript"> var ajaxurl = "' . admin_url('admin-ajax.php') . '"; </script>'; } you can then use the ajaxurl for ajax request.


41

1. Write with localization in mind Don't use echo or print() to produce text output, instead use the WordPress functions __() and _e(): /** Not localization friendly */ echo "Welcome to my plugin"; // OR print("Welcome to my plugin"); /** Localization friendly */ _e('Welcome to my plugin', 'my-plugin'); // OR $my_text = __('Welcome to my plugin', 'my-...


41

Thanks for the answers guys. Though both answers set me on the right path, none worked out of the box. So I'm sharing my solutions below. Method 1 - Using register_activation_hook: Create the Parent Plugin in plugins/parent-plugin/parent-plugin.php: <?php /* Plugin Name: Parent Plugin Description: Demo plugin with a dependent child plugin. Version: 1.0....


38

Short answer: your name attribute values must use the schema option_name[array_key]. So, when you use … <input name="option_name[key1]"> <input name="option_name[key2]"> … you get an array as option value in your validation function: array ( 'key1' => 'some value', 'key2' => 'some other value' ) PHP does that for you, this is ...


35

Whenever you find a piece of code without clear installation instructions it is probably a plugin. The example you gave is a good one, because that is the most common case: add_action('template_redirect', 'remove_404_redirect', 1); function remove_404_redirect() { // do something } To use such a snippet, put it into a plugin: Create a new file, name it ...


35

There are many themes and plugins using jQuery as loaded by WP core. Every time jQuery is updated, there is a risk of older themes and plugins breaking (because lots of them are still used but no longer updated). That's why you also see jquery-migrate.js in your source code. It's a script that catches old functions used by plugins/themes and makes sure that ...


34

The default response from admin-ajax.php is, die( '0' ); ...by adding your own wp_die() or exit() or die() after returning your desired content prevents the default response from admin-ajax.php being returned as well. It also generally means that your ajax call has succeeded. Ultimately, to answer your question, it's meant to work this way. What you ...


32

As the error says you need an instance of the class to use $this. There are at least three possibilities: Make everything static class My_Plugin { private static $var = 'foo'; static function foo() { return self::$var; // never echo or print in a shortcode! } } add_shortcode( 'baztag', array( 'My_Plugin', 'foo' ) ); But that’s not ...


32

The reason this doesn't work is because there is a redirection happening after the save_post action. One way you can acheive want you want is by implementing a quick work around using query vars. Here is a sample class to demonstrate: class My_Awesome_Plugin { public function __construct(){ add_action( 'save_post', array( $this, 'save_post' ) ); ...


31

Use get_posts() and the parameter name which is the slug: $page = get_posts( array( 'name' => 'your-slug' ) ); if ( $page ) { echo $page[0]->post_content; } Be aware that the post type in get_posts() defaults to 'post'. If you want a page use … $page = get_posts( array( 'name' => 'your-slug', 'post_type' => 'page' ...


31

Your code seems correct, but it will load the script only in admin area beacuse you are enqueuing the script in admin_enqueue_scripts action. To load the script in frontend, use wp_enqueue_scripts action (which is not the same that wp_enqueue_script() function): function Zumper_widget_enqueue_script() { wp_enqueue_script( 'my_custom_script', ...


28

AFAIK, there's no official/standard framework, and there will be as many plugin development styles as there are shades of white in north pole. I'd say WordPress Coding Standards is a blueprint for a good style. You'll find lots of good examples and excellent coders here in WPSE. A nice starting point: questions/tagged/plugin-development. Highlighting: ...


28

When in doubt, look at the source code. Digging in to get_option(), you'll see (abbreviated): $value = wp_cache_get( $option, 'options' ); if ( false === $value ) { $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) ); // Has to be get_row instead of get_var because ...


27

Use the Core API, not only its CSS Normally you just use an instance of the WP_List_Table class. Guides: More about it in the Codex here. Here's also a guide from WP Engineer - too much to copy it over. And another guide on Smashing Magazine online. Benefits? YES! You can add pagination, search boxes, actions and whatever magic you can imagine (and are ...


26

The API you offer in a plugin or a theme depends on the logic of that specific code. There is probably no guide that applies to all situations. I am a contributor for multiple plugins with APIs, and what I have learned so far is: Do not offer an API until you really know how people use your code. Release the first two or three versions without any API. ...


26

Because you're using a namespace in this class, you need to add a \ in front of the WP_Query call to tell PHP that it's in the global namespace and not the namespace of this class. Try this: $query = new \WP_Query($args);


24

Do not point the URL to admin.php, use admin-post.php instead: '<a href="' . admin_url( 'admin-post.php?action=print.csv' ) . '">' In your plugin register a callback for that action: add_action( 'admin_post_print.csv', 'print_csv' ); function print_csv() { if ( ! current_user_can( 'manage_options' ) ) return; header('Content-Type: ...


24

The following small plugin creates a custom button inside line 1 of the WordPress TinyMCE Version 4, tested in WP Version 3.9-beta2. The plugin has var_dump included to understand the values. It's also possible to add the button to other lines of the visual editor, only a other hook, like for line 2: mce_buttons_2. Result Plugin, PHP side - tinymce4-test....


24

It is mandatory, though it is not enforced. Consider the scenario when two Wordpress site has been setup in the same database. One with prefix wp_ and another with wp2_. If you install your plugin in both of the sites with the prefix, your created tables will be wp_liveshoutbox for first site and wp2_liveshoutbox for the second site. But if you omit the ...


23

It's not outdated Moving to 2.x or 3.x is too early, people still use IE8 which is only supported on 1.x


22

First of all, WordPress registers jQuery UI via wp_default_scripts(). Dependencies are already set, so you only need to enqueue the script you really need (and not the core). Since you're not changing version number or anything, it is ok to only use the handle. // no need to enqueue -core, because dependancies are set wp_enqueue_script( 'jquery-ui-widget' ); ...


Only top voted, non community-wiki answers of a minimum length are eligible