Limit TinyMCE text colors

function my_mce_settings( $settings ) {
 
  //limit TinyMCE text colors to have only predifined custom colors available
  $custom_colors = '"43a9cf", "Blue", "dfa10d", "Orange", "be7bd2", "Purple"';    
  $settings['textcolor_map'] = '['.$custom_colors.']';
 
  return $settings;
}
add_filter('tiny_mce_before_init', 'my_mce_settings');

WordPress Development Tools and Resources

This list may grow or change with time.

GitHub updater
Plugin to enable automatic updates to your GitHub or Bitbucket hosted WordPress plugins and themes.
https://github.com/afragen/github-updater

Developer
Plugin that will help you optimize your development environment by making sure that you have all the essential tools and plugins installed.
https://wordpress.org/plugins/developer/

Theme Check
Test your theme for all the latest WordPress standards and practices
https://wordpress.org/plugins/theme-check/

Log Deprecated Notices
This plugin logs the usage of deprecated files, functions, and function arguments. Identifies where the deprecated functionality is being used and it will offer an alternative if it’s available. It also logs incorrect function usage.
https://wordpress.org/plugins/log-deprecated-notices/

Monster Widget
Provides a quick and easy method of adding all core widgets to a sidebar for testing purposes
https://wordpress.org/plugins/monster-widget/

Debug Bar
Plugin that adds a debug menu to the admin bar that shows helpful debugging information.
https://wordpress.org/plugins/debug-bar/

List Code Validation Tools
http://codex.wordpress.org/Validating_a_Website#HTML_-_Validation

Theme Framework: Hybrid Core
This is not a parent Theme. It’s a framework to build your own themes.
https://github.com/justintadlock/hybrid-core

WP Test
Import dummy content to test. The content has many different styles, lists, floating images… so you can see how you all the elements are displaying in your theme.
http://wptest.io/

Load scripts only when needed in the WordPress admin

Lets say we are creating a plugin witch needs to load a javascript file on it’s settings page, we would only want to load the file on that specific page and not in every other admin page.

To do so, we can declare a global variable while creating the settings page so we can know exactly when we need to load our js file.

1. Create the settings page for the plugin.

 
function my_settings_page (){
 
     global $my_settings_page;
 
     $my_settings_page = add_options_page( __('My Settings', 'my-domain'), 
                                           __('Settings', 'my-domain'), 
	 			           'manage_options', 
                                           'my-page-slug', 
	 				   'my-callback'
	 				 );
}
 
add_action( 'admin_menu', 'my_settings_page');

2. Make the call checking the global variable $my_settings_page;

 
function my_admin_script( $hook ) {
 
    global $my_settings_page;
 
    if( $hook != $my_settings_page ) return;
 
    wp_enqueue_script( 'my-admin-script', MY_PLUGIN_URL . 'js/my-script.js');
}
 
add_action( 'admin_enqueue_scripts', 'my_admin_script' );
 
/*
To call the script in other WordPress pages, for example the edit page of a post: 
 
if( $hook != 'edit.php' ) return;
 
Other pages:
- Dashboard: index.php
- Media library: upload.php
- Comments: edit-comments.php
- Edit a comment: comment.php
- Appearance: themes.php
- Widgets: widgets.php
- Menus: nav-menus.php
- Plugins: plugins.php
- Users: users.php
- General Settings: options-general.php
*/

More information:
http://codex.wordpress.org/Plugin_API/Action_Reference/admin_enqueue_scripts

How to add dynamic values into Contact Form 7 inputs

Contact Form 7 is a great plugin to add forms to your site, but these forms contain static inputs and sometimes we require to add inputs with dynamic values like a post ID or PHP variables like GET and POST.

This is very easy to do with the plugin Contact Form 7 Dynamic Text Extension.

This plugin adds two additional tag types to the Contact Form 7 plugin, these two types are Dynamic Text field and Dynamic Hidden field, the dynamic value for a scpecif input is generated throught a shortcode.

The plugin has it’s own shortcodes integrated, but you can create your own.

Let me put a very simple example:

Lets say you want to add a hidden input in your form which value should be the current post ID.
If you create your own shortcode it would look like this:

function cf7_add_post_id(){
 
    global $post;
    return $post->ID;
}
 
add_shortcode('CF7_ADD_POST_ID', 'cf7_add_post_id');

And the dynamic field in your form setup would look like this:

[dynamictext my-filed-name "CF7_ADD_POST_ID"]

The other way would be to use the plugin’s shortcodes.
In this case we want to have the current post ID so you would only have to add your dynamic field in the form setup like this:

[dynamictext my-filed-name "CF7_get_post_var key='ID'"]

The plugin has shortcodes for GET, POST, blog info, post info, current URL, custom fields, current user info, referrer URL.
You have all the details in the plugin’s page on wordpress.org

WP Import All, import any kind of data to your WordPress database

wp-all-importWp All Import is a great plugin to import any kind of data into your WordPress site.

You can import XML, CSV/Excel, JSON, SQL and in any kind of structure for posts, pages or custom post types.
With a simple and very easy to use drag and drop system to indicate what information is for what data base field.

It will import your images and also can autodetect the custom fields for the postmeta table.
They have an advanced version that supports Advanced Custom Fields and WooCommerce products.

The free version is very limited, it won’t work for the images or custom fields, wich I think you probably need in almost 100% of the cases. So if you are not a developer this plugin is worth the price.

I will tell you an example of when this plugin can be usefull. Imagine you run (or you have a client that runs) a portal of classified ads, a property portal or something similar, and you constantly have to import files with data from other external websites where each one sends you the data in a different structure and format. This plugin is great for that as you can also save the settings for each import as a template, so you only need to set up the import once and then load the template each time you need to import new data sent by the same source.

Check out the video on their wordpress.org page

Note: I used it in a site that manages classified ads, the user is able to create an ad, after that he receives a notification by email confirming the ad has been created. When I did the import of 1000 ads asigned to an author, the server tried to send 1000 email notifications. So be sure to turn off email notifications on this case scenario.

How to load template files in a plugin

Template files are usually used in themes and child themes, but you can also load template files from a plugin.

It’s not to difficult to create your own template loader, but you can also find the Gamajo_Template_Loader on GitHub by Gary Jones.

To use this class:

1. Create a file in your plugin and copy the Gamajo_Template_Loader class into it.
2. Create a new class that extends the Gamajo_Template_Loader. Find an example here
3. Override the class properties for your plugin, these are:
$filter_prefix, $theme_template_directory, $plugin_directory.

You can also find a full plugin example by Pippin Williamson from pippinsplugins.com using the Gamajo_Template_Loader

Add meta box to a custom post type

Before adding a metabox to a custom post type we need to create the custom post type.
Check this post where you can find a full class to create your custom post type.

So following on this example our custom post type is cpt_examples.

In the __construct function of our custom post type class add the following:

1
2
add_action( 'add_meta_boxes', array( $this, 'add_meta_box') );
add_action( 'save_post',      array( $this, 'save_meta_box_data' ) );

And then create the functions in the class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
 * add_meta_box
 */
public function add_meta_box(){
 
	add_meta_box( 'cpt_examples_meta', 'CPT Examples Extra Info', array( $this, 'display_meta_form' ), 'cpt_examples', 'advanced', 'high' );
}
 
/**
 * display_meta_form	
 */
 
public function display_meta_form( $post ) {
 
	wp_nonce_field( 'cptexamples_meta_box', 'cptexamples_meta_box_nonce' );
 
	$my_first_field  = get_post_meta( $post->ID, 'cpt_first_meta_field', true );
	$my_second_field = get_post_meta( $post->ID, 'cpt_second_meta_field', true );
 
		echo '<div class="wrap">';
		echo '<label for="cpt_first_meta_field">' . _e( 'First Meta Field', 'cpt_domain' ) . '</label> <br/>';
		echo '<input class="text" type="text" id="cpt_first_meta_field" name="cpt_first_meta_field" value="' . esc_attr( $my_first_field ) . '"   />';
		echo '</div>';
 
		echo '<div class="wrap">';
		echo '<label for="cpt_second_meta_field">' . _e( 'Second Meta Field', 'cpt_domain' ) . '</label>  <br/>';
		echo '<input class="text" type="text" id="cpt_second_meta_field" name="cpt_second_meta_field" value="' . esc_attr( $my_second_field ) . '"   />';
		echo '</div>';
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
 * save_meta_box_data
 * function called on save_post hook to sanitize and save the data
 */
 
public function save_meta_box_data( $post_id ){
 
  // Check if nonce is set.
    if ( ! isset( $_POST['cptexamples_meta_box_nonce'] ) ) {
	  return;
    }
 
  // Verify that the nonce is valid.
    if ( ! wp_verify_nonce( $_POST['cptexamples_meta_box_nonce'], 'cptexamples_meta_box' ) ) {
	   return;
    }
 
  // If autosave, don't do anything
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
	  return;
    }
 
  // Check the user's permissions.
    if ( isset( $_POST['post_type'] ) && $_POST['post_type'] == 'cpt_examples' ) {
            if ( ! current_user_can( 'edit_page', $post_id ) ) {
		     return;
	    }
 
    } else {
            if ( ! current_user_can( 'edit_post', $post_id ) ) {
		     return;
	    }
    }
 
   // Save the information into the database
       if ( isset( $_POST['cpt_first_meta_field'] ) ) {
 
             $my_first_meta_field = sanitize_text_field( $_POST['cpt_first_meta_field'] );
	     update_post_meta( $post_id, 'cpt_first_meta_field', $my_first_meta_field );
	}
 
       if ( isset( $_POST['cpt_second_meta_field'] ) ) {
 
             $my_second_meta_field = sanitize_text_field( $_POST['cpt_second_meta_field'] );
	     update_post_meta( $post_id, 'cpt_second_meta_field', $my_second_meta_field );
	}
 
 
}

Also view this snippet to add the meta box just after the title.

Create custom post type from a plugin

The Class file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
<?php 
/** 
 * @package    WPtips
 * @subpackage Custom Post Type Example
 * @author     Lucy Tomás
 * @since      1.0
 */
 
// Exit if accessed directly
if ( !defined( 'ABSPATH' ) ) exit;
 
 
if( !class_exists( 'CPT_Example' )){
 
class CPT_Example {
 
	/**
	 * constructor
	 * @since 1.0
	 */
 
	public function __construct() {
 
		add_action( 'init', 		     array( $this, 'register_posttype'));
		add_filter( 'post_updated_messages', array( $this, 'custom_post_type_messages'));
		add_action( 'admin_head',            array( $this, 'custom_post_type_help' ) );
		add_filter( 'template_include',      array( $this, 'post_type_template'));
 
	}	
 
	/**
	 * register_posttype
	 * @since 1.0
	 */
 
	public function register_posttype() {
 
		$labels = array(
					'name'               => __('CPT Examples', 'cpt_domain'),
					'singular_name'      => __('CPT Example', 'cpt_domain'),
					'menu_name'          => __('CPT Examples', 'cpt_domain'),
					'name_admin_bar'     => __('CPT Example', 'cpt_domain'),
					'add_new'            => __('Add new', 'cpt_domain'),
					'add_new_item'       => __('Add new CPT Example', 'cpt_domain'),
					'new_item'           => __('New CPT Example', 'cpt_domain'),
					'edit_item'          => __('Edit CPT Example', 'cpt_domain'),
					'view_item'          => __('View CPT Examples', 'cpt_domain'),
					'all_items'          => __('All CPT Examples', 'cpt_domain'),
					'search_items'       => __('Search CPT Examples', 'cpt_domain'),
					'parent_item_colon'  => __('CPT Example parent', 'cpt_domain'),
					'not_found'          => __('No CPT Example found', 'cpt_domain'),
					'not_found_in_trash' => __('No CPT Example in trash', 'cpt_domain')
		);
 
 
		$slug = get_theme_mod( 'ctp_example_permalink' );
  		$slug = ( empty( $slug ) ) ? 'cpt-example' : $slug;
 
 
 		$args = array( 
			'public'        => true, 
			'labels'        => $labels,
			'description'   => __('CPT Examples', 'cpt_domain'),
			'menu_icon'     => 'dashicons-groups',
			'menu_position' => 5,
			'has_archive' 	=> true,
			'supports'      => array( 'title', 'editor', 'thumbnail'),
			'rewrite'     	=> array( 'slug' => $slug )
 
		);
 
		register_post_type( 'cpt_examples', $args );
 
	}
 
	/**
	 * custom_post_type_messages
	 * @since 1.0
	 */
 
	public function custom_post_type_messages( $messages ) {
 
		$post = get_post();
 
			$messages['cpt_examples'] = array(
				0  => '',
				1  => __('CTP Example updated', 'cpt_domain'),
				2  => __('Custom field updated', 'cpt_domain'),
				3  => __('Custom field deleted', 'cpt_domain'),
				4  => __('CTP Example updated', 'cpt_domain'),
				5  => isset( $_GET['revision'] ) ? sprintf( __('CTP Example restored to revision', 'cpt_domain') . ' %s',wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
				6  => __('CTP Example published', 'cpt_domain'),
				7  => __('CTP Example saved', 'cpt_domain'),
				8  => __('CTP Example sent', 'cpt_domain'),
				9  => sprintf(
					__('CTP Example programed for', 'cpt_domain') . ': <strong>%1$s</strong>.',
					date_i18n( 'M j, Y @ G:i', strtotime( $post->post_date ) )
				),
				10 => __('Draft CTP Example updated', 'cpt_domain')
			);
 
 
		return $messages;
 
	}
 
	/**
	 * custom_post_type_help
	 * @since 1.0
	 */
 
	public function custom_post_type_help() {
 
 
		$screen = get_current_screen();
 
		if ( $screen->post_type != 'cpt_examples' ) {
			return;
		}
 
		$basics = array(
			'id'      => 'cpt_examples_basics',
			'title'   => 'Basic help CPT Examples',
			'content' => '<p>From this section you can view a list of CPT Examples.</p>
                                      <p>Click on one of them to Edit or click on Add New to create a new one.</p>'
		);
 
		$formatting = array(
			'id'      => 'cpt_examples_formating',
			'title'   => 'Creation of a CPT Example',
			'content' => '<p>Fill in the form with title and text .</p>'
 
		);
 
		$screen->add_help_tab( $basics );
		$screen->add_help_tab( $formatting );
 
 	}
 
	/**
	 * post_type_template
	 * @since 1.0
	 */
 
	function post_type_template( $original_template ) {
 
 
		  if ( is_post_type_archive('cpt_examples') ) {
 
		    load_template( plugin_dir_path( __FILE__ ) . 'templates/cpt_examples.php');
 
		  } else {
 
		    return $original_template;
		  }
 
	}
 
}// class
 
}

You can see on this other post how to add Meta Boxes with extra form fields for this custom post type class.

Remove WooCommerce email notifications

Useful snippet by Mike Jolley found on Github with a list of the notification hooks in WooCommerce.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
add_action( 'woocommerce_email', 'unhook_those_pesky_emails' );
 
function unhook_those_pesky_emails( $email_class ) {
 
		/**
		 * Hooks for sending emails during store events
		 **/
		remove_action( 'woocommerce_low_stock_notification', array( $email_class, 'low_stock' ) );
		remove_action( 'woocommerce_no_stock_notification', array( $email_class, 'no_stock' ) );
		remove_action( 'woocommerce_product_on_backorder_notification', array( $email_class, 'backorder' ) );
 
		// New order emails
		remove_action( 'woocommerce_order_status_pending_to_processing_notification', array( $email_class-&gt;emails['WC_Email_New_Order'], 'trigger' ) );
		remove_action( 'woocommerce_order_status_pending_to_completed_notification', array( $email_class-&gt;emails['WC_Email_New_Order'], 'trigger' ) );
		remove_action( 'woocommerce_order_status_pending_to_on-hold_notification', array( $email_class-&gt;emails['WC_Email_New_Order'], 'trigger' ) );
		remove_action( 'woocommerce_order_status_failed_to_processing_notification', array( $email_class-&gt;emails['WC_Email_New_Order'], 'trigger' ) );
		remove_action( 'woocommerce_order_status_failed_to_completed_notification', array( $email_class-&gt;emails['WC_Email_New_Order'], 'trigger' ) );
		remove_action( 'woocommerce_order_status_failed_to_on-hold_notification', array( $email_class-&gt;emails['WC_Email_New_Order'], 'trigger' ) );
 
		// Processing order emails
		remove_action( 'woocommerce_order_status_pending_to_processing_notification', array( $email_class-&gt;emails['WC_Email_Customer_Processing_Order'], 'trigger' ) );
		remove_action( 'woocommerce_order_status_pending_to_on-hold_notification', array( $email_class-&gt;emails['WC_Email_Customer_Processing_Order'], 'trigger' ) );
 
		// Completed order emails
		remove_action( 'woocommerce_order_status_completed_notification', array( $email_class-&gt;emails['WC_Email_Customer_Completed_Order'], 'trigger' ) );
 
		// Note emails
		remove_action( 'woocommerce_new_customer_note_notification', array( $email_class-&gt;emails['WC_Email_Customer_Note'], 'trigger' ) );
}

How to get the post slug

basename( get_permalink($id) );

If you have access to the data through the global variable $post you can simply use $post->post_name;

1
2
3
4
5
6
7
8
9
10
11
12
function get_slug( $id = NULL ) {
 
   if( $id != NULL ) {
     return basename( get_permalink($id) );
   }
 
   global $post;
   if( empty($post) ) return;
 
   return $post->post_name;
 
}

In other cases maybe you don’t have the $id and you are trying to get the $post var to early like in an init hook, in this case you can try using url_to_postid to retrieve the ID and then get the slug.

So the full function would be:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function get_slug( $id = NULL ) {
 
  if( $id == NULL ){
 
    global $post;
 
   if( !empty( $post )) {
        $id = $post->ID;
    } else {
        $id = url_to_postid( "http://".$_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
    }
 
  } // if $id NULL
 
  return basename( get_permalink($id) );
}