Category

WordPress

WP CLI add custom command WordPress

How to add a custom WP CLI command in WordPress

By | WordPress | No Comments

What is WP CLI?

WP-CLI is the official command-line interface for WordPress. It helps developers automate tasks, and increase their productivity. It opens up a whole array of opportunities once you’ve started using it.

It comes with a whole bunch of useful commands like cache clearing, cron, media management, user management, and many other useful commands.

But if you’re building a custom website, chances are you’re going to need to write your own custom WP CLI command.

Adding a custom WP CLI command

Let’s add a simple WP CLI command, and the break it down. Add this to your functions.php file:

/**
* Updates a post's title.
*
* @param array $args
* @param array $assoc_args
*
* Usage: `wp jb-update-post-title --id=123 --title="New post title"`
*/
function jb_update_post_title( $args = array(), $assoc_args = array() ) {
	// Get arguments
	$arguments = wp_parse_args( $assoc_args, array(
		'id'    => 0,
		'title' => '',
	) );

	// Check if arguments are alright
	if ( $arguments['id'] > 0 && ! empty( $arguments['title'] ) ) {

		// Arguments are okay, update the post
		$post = array(
			'ID'         => $arguments['id'],
			'post_title' => $arguments['title'],
		);
		wp_update_post( $post );

		// Show success message
		WP_CLI::success( 'Updated post title successfully.' );

	} else {

		// Arguments not okay, show an error.
		WP_CLI::error( 'Invalid arguments.' );

	}
}
if ( defined( 'WP_CLI' ) && WP_CLI ) {
	WP_CLI::add_command( 'jb-update-post-title', 'jb_update_post_title' );
}

Let’s break the code down:

  • We first check if the constant WP_CLI is defined. If this line isn’t added, it will throw an error when you access your site normally. This is because the constant WP_CLI is only added when WP CLI is running. So when WordPress encounters this constant in your functions.php file when you access it from your browser, this constant will not be defined – throwing the error
  • WP_CLI::add_command( 'jb-update-post-title', 'jb_update_post_title' ); adds a new command jb-update-post-title which uses the function jb_update_post_title
  • The function passes two parameters $args and $args_assoc . The second parameter picks up anything that has two dashes, ie: --like-this . The first parameter picks up anything that does not have the two dashes. We’ve used the second parameter in the example above
  • We’re parsing the arguments and setting default values, if they were missing. We then check if the values the user entered are correct
  • If the values are correct, we update the post and show a success message via WP_CLI::success
  • If the values are incorrect, we show an error message via WP_CLI::error

Notes:

  1. Once we use WP_CLI::success or WP_CLI::error, we do not need to add a specific return statement in the function, because the function will terminate immediately
  2. If you’re using parameters without the two dashes, the $args variable will be a normal array. So the first value would be in $args[0], the second would be in $args[1] and so on

Usage

  1. Open up your terminal and navigate to your WordPress root folder (the one with wp-config.php in it)
  2. Make sure you’ve got WP CLI installed. You can do this by running wp --version . If it’s installed correctly, it should give you the version. If it’s not, you can install it by following these instructions
  3. Now just enter wp jb-update-post-title --id=123 --title="New post title" with the post ID and the title, and it should update the post with the new title!

Now that you know how to add a custom WP CLI command, you can use it to suit your need!

Happy coding! 🙂

WordPress Admin: How to Fix the “Fatal Error: Allowed Memory Size…” Error

By | WordPress | 11 Comments

The Problem

If you’ve been working on a complex WordPress site with a lot of custom fields, perhaps with the Advanced Custom Fields (ACF) plugin – chances are you’ve come across this error when you try to access your post type in the WordPress admin:

"Fatal error: Allowed memory size of xxx bytes exhausted (tried to allocate 64 bytes) in /xxx/wp-includes/wp-db.php on line xxx"

The Cause

The cause of this problem is that WordPress tries to preload the posts’ meta saved in the postmeta table for all the posts which are currently being displayed in the admin.

This helps improve performance for smaller sites or sites which don’t use a lot of custom post meta / fields. But this is disastrous for sites which heavily rely on custom fields.

The Solution

Fortunately, WordPress provides a hook which lets us control this. Just add this into your functions.php file and watch your troubles go away!

/**
 * Disable Posts' meta from being preloaded
 * This fixes memory problems in the WordPress Admin
 */
function jb_pre_get_posts( WP_Query $wp_query ) {
	if ( in_array( $wp_query->get( 'post_type' ), array( 'my_post_type_1', 'my_post_type_2' ) ) ) {
		$wp_query->set( 'update_post_meta_cache', false );
	}
}

// Only do this for admin
if ( is_admin() ) {
	add_action( 'pre_get_posts', 'jb_pre_get_posts' );
}

Explanation

This is what the code above does:

  1. It checks if it is the WordPress admin – If you want this to also happen on the front-end, you can go ahead and remove that condition
  2. It hooks on to the WordPress pre_get_posts action
  3. We only do this for certain post types. If you want this to happen for all post types, you can go ahead and remove that condition
  4. We set the update_post_meta_cache property to false, which forces WordPress to not load the post meta – which is what saves us all that memory!

Hope this was helpful! 🙂

WordPress Dynamically generate image sizes on the fly

WordPress: How to create image sizes dynamically on the fly

By | Web Development, WordPress | No Comments

WordPress is awesome. But like any system, it’s not great at everything. One of those things is media image size management, where it just doesn’t work well.

The Problems:

WordPress uses something called “Thumbnail Image Sizes” to maintain different versions of your images in different image sizes. You define these image sizes under Settings -> Media and some custom ones in your theme, as needed.

When you upload an image in your WordPress admin, WordPress automatically generates the thumbnails as soon as the image is uploaded. This causes the following issues:

  1. The image sizes are created forever when you upload an image. In your development process, if you realize that you want to change an image size after thousands of images have been uploaded, the default way is to upload all those images all over again. Fortunately, there are plugins which automatically regenerate thumbnails, but it’s still a hassle.
  2. If you have 20 custom image sizes (maybe 2x, 3x for responsive images), and upload an image in the WordPress admin, it creates 20 thumbnail versions based on the sizes you defined in add_image_size(), even though you might only need one. That means 19 thumbnails in this example would go for a waste. Imagine if you have thousands of images where 19 image thumbnails are created as a waste! This increases the size of the media library unnecessarily.

 

Solutions:

The solution for changing image sizes as mentioned above, would be to use a plugin to automatically regenerate thumbnails either individually or for all your images. The Regenerate Thumbnails plugin does a great job of this. But this has to be manually done, and isn’t the optimal solution.

Unfortunately, there is no solution for the fact that there will be additional unnecessary images created with the add_image_size() method.

 

Using the Fly Dynamic Image Resizer:

I was so frustrated with this problem, that I decided to build my own plugin. Introducing: Fly Dynamic Image Resizer for WordPress! If you want to contribute to this plugin, you can do so on Github.

How this plugin works:

  • You can define image sizes in your theme, or just directly add the image sizes in your code
  • When a user visits a page for the first time and comes across a dynamic image, the dynamic image thumbnail is created and stored under /wp-content/uploads/fly-images/{image_id}/{image_size}
  • When users visit the page the next time onwards, they are served the newly created image
  • If you want to delete all the cached / stored image sizes, you can do so under Tools -> Fly Images
  • If you want to delete only a single image’s cached / stored image sizes, you can do so in the media library

Defining dynamic image sizes in your theme

You can add as many image sizes in your theme’s functions.php file like so:

if ( function_exists( 'fly_add_image_size' ) ) {
    fly_add_image_size( 'home_page_square', 500, 500, true );
    fly_add_image_size( 'home_page_square_2x', 1000, 1000, true );
}

Explanation of parameters:

  1. The first is the name of the size
  2. The width
  3. The height
  4. Whether you want to crop this image from the center

Method 1: Using pre-defined image sizes

If you’ve defined image sizes using the method above, you get an image like so:

fly_get_attachment_image( $attachment_id, 'your_image_size' );

So, using the example of image sizes declared above, your code would look like:

echo fly_get_attachment_image( get_post_thumbnail_id(), 'home_page_square' );

This would return a HTML image string. If you want the image as an array, you can use:

$image = fly_get_attachment_image_src( get_post_thumbnail_id(), 'home_page_square' );

Method 2: Using explicit image sizes

If you don’t want to declare any image sizes, and just want a dynamically generated image size, you can directly enter the image dimensions in the code like so:

fly_get_attachment_image( $attachment_id, array( $width, $height ), $crop );

So, if you want to get an image size of your own dimensions, your code would look like:

echo fly_get_attachment_image( get_post_thumbnail_id(), array( 500, 500 ), true );

This would return a HTML image string. If you want the image as an array, you can use:

$image = fly_get_attachment_image_src( get_post_thumbnail_id(), array( 500, 500 ), true );

Using custom image attributes

The image HTML that this plugin returns uses the attributes like “alt” from the media library. If you want to use your own, you can do it like so:

echo fly_get_attachment_image( get_post_thumbnail_id(), 'home_page_square', null, array( 'alt' => 'My custom alt value!' ) );

 

I hope this helps you in building your theme optimally 🙂

WordPress dynamically change user capabilities

By | Web Development, WordPress | No Comments

I was looking for an easy way to dynamically add or remove capabilities for users based on either their IDs or roles, but I couldn’t find any elegant solution. That is until I found a beautiful filter:

https://codex.wordpress.org/Plugin_API/Filter_Reference/user_has_cap

It’s so simple, and you can just add this to your functions.php file, or use it in your own plugin:

/**
 * User Capabilities
 * 
 * @see https://codex.wordpress.org/Plugin_API/Filter_Reference/user_has_cap
 */
function jb_user_capabilities( $allcaps, $cap, $args ) {
	// Get current user ID
	$user_id = get_current_user_id();

	// Get current user
	$current_user = get_user_by( 'id', $user_id );

	// Remove capabilities
	if ( in_array( 'administrator', $current_user->roles ) ) {
		$allcaps['activate_plugins'] = false;
		$allcaps['update_core'] = false;
		$allcaps['update_plugins'] = false;
		$allcaps['update_themes'] = false;
		$allcaps['switch_themes'] = false;
		$allcaps['edit_themes'] = false;
		$allcaps['install_plugins'] = false;
		$allcaps['install_themes'] = false;
		$allcaps['delete_themes'] = false;
		$allcaps['delete_plugins'] = false;
		$allcaps['edit_plugins'] = false;
		$allcaps['edit_themes'] = false;
		$allcaps['edit_files'] = false;
		$allcaps['edit_users'] = false;
		$allcaps['create_users'] = false;
		$allcaps['delete_users'] = false;
		$allcaps['list_users'] = false;
	}
	
	return $allcaps;
}
add_filter( 'user_has_cap', 'jb_user_capabilities', 10, 3 );

You can see a list of all roles and capabilities here:
https://codex.wordpress.org/Roles_and_Capabilities

Setting capabilities to “true” enables them, and setting them to “false” disables them. Simple! The above function could be useful when you want to give access to your SEO team, for example. Since this adds or removes capabilities, it is the best way to securely hide menu items in the WP Admin side.

Hope this helps, happy coding! 🙂

Make Polylang WordPress plugin copy the content from the original post

Make Polylang WordPress plugin copy the content from the original post

By | WordPress | 48 Comments

If you’re like me, you love Polylang!

I’ve used WPML in the past, and Polylang makes it look like an oversized overpowering slowpoke. What I hate the most about WPML is the fact that it is not “fully compatible” with Advanced Custom Fields, which is stupid to put it politely.

There is one problem with Polylang, however. Which is the fact that it does not copy the title and content when you create a new translation. I don’t fully agree with the reasoning behind this. There should at least be an option to copy the content from the original post to the translation.

But don’t worry, the fix is easy! Just add this in your theme’s functions.php file and the problem is fixed:

// Make sure Polylang copies the content when creating a translation
function jb_editor_content( $content ) {
    // Polylang sets the 'from_post' parameter
    if ( isset( $_GET['from_post'] ) ) {
        $my_post = get_post( $_GET['from_post'] );
        if ( $my_post )
            return $my_post->post_content;
    }

    return $content;
}
add_filter( 'default_content', 'jb_editor_content' );

Similarly, if you want to copy the title as well, use the following code:

// Make sure Polylang copies the title when creating a translation
function jb_editor_title( $title ) {
    // Polylang sets the 'from_post' parameter
    if ( isset( $_GET['from_post'] ) ) {
        $my_post = get_post( $_GET['from_post'] );
        if ( $my_post )
            return $my_post->post_title;
    }

    return $title;
}
add_filter( 'default_title', 'jb_editor_title' );
How to get the second level navigation only from WordPress wp_nav_menu()

How to get the second level navigation only from WordPress wp_nav_menu()

By | Web Development, WordPress | 6 Comments

We’ve all been there. There’s a perfectly good menu in the admin under Appearance -> Menus which has the whole site laid out perfectly.

Now we start coding the templates and realize that we only need sub-menu items of a particular page, of a particular level from that menu. There are two ways to do this out of the box:

  1. Create a separate menu for each requirement
  2. Create a custom Walker Class which allows you to only choose only the sub-menu from the main menu

For obvious reasons, the first option is not the best way to do it. The second option solves the problem quite well. But you can’t keep writing a walker class for every project, and not every developer – particularly new developers – is familiar with how this works.

This should be something that comes out of the box, which it does on other platforms like Joomla. When you delve into the code of WordPress and see the function responsible for this ( /wp-includes/nav-menu-template.php :: wp_nav_menu() ), you quickly realize that this function was written without any foresight for extendability.

I have solved this problem of extending this function by writing a plugin!
https://wordpress.org/plugins/wp-nav-menu-extended/

It extends the native wp_nav_menu function so you don’t need to add any special functions to the code. It just adds a few options that I felt were missing. Here are the options:

level : (integer) (required for this plugin to work) The level of the navigation menu to show. If no child_of parameter is passed, it shows all the items of this level

child_of : (string|integer) (optional) Either the title or menu item ID of the parent in the menu whose direct children are to be shown

This is how easy it is to use:

$defaults = array(
    'theme_location' => 'main_menu',
    'level' => 2,
    'child_of' => 'About Us'
);

wp_nav_menu( $defaults );

So, the child_of option can either be the title of the parent’s menu item, or the menu item ID of the parent, so that you don’t have to hardcore the title in the code. Here is one easy way to find the menu item ID:

Hover your mouse on top of the menu item that you want, and look for the item ID in the status bar. In this case it is 466.

I hope this makes it easy for you to build your site! I’ll be open to adding more features to this plugin, so feel free to write in any feature requests in the comments.

Happy coding!

How to add custom styles in the Wordpress TinyMCE editor without a plugin

How to add custom styles in the WordPress TinyMCE editor without a plugin

By | Web Development, WordPress | 2 Comments

I’m sure you’ve run into this issue so many times if you’ve made themes whose complexity ranges from medium to tearing-your-hair-out-and-wishing-the-designer-has-diarrhea: The admin needs to be able to add a custom style to one of the elements from the WordPress editor. Sounds simple enough, and it is.

But before you go styling away, always keep this to a minimum. Although WordPress and other publishing platforms are used as Content Management Systems, the meaning of that phrase seems to be misunderstood. “Content” management is exactly that: managing content. This means the layout and styles are supposed to be kept separate from the content. But there are cases where this cannot be avoided, and those are exactly the cases for which this post was created.

As always, this is done in three easy steps:

Step 1: Edit your functions.php

If you don’t have a functions.php files in your theme, create one, and add the following code:

// Add a "styleselect" drop down menu to the editor
add_filter( 'mce_buttons_2', 'my_awesome_buttons' );
function my_awesome_buttons( $buttons ) {
    array_unshift( $buttons, 'styleselect' );
    return $buttons;
}

// Initialize our buttons
add_filter( 'tiny_mce_before_init', 'init_my_awsome_buttons' );
function init_my_awsome_buttons( $settings ) {

    $style_formats = array(
        array(
        	'title' => 'Super Div',
        	'block' => 'div',
        	'classes' => 'super-div',
        	'wrapper' => true // --- * Notice how this is a wrapper * ---
        ),
    	array(
    		'title' => 'Awesome Button Link',
    		'selector' => 'a', // --- * This means it will only work with A's * ---
    		'classes' => 'awesome-button-link'
    	)
    );

    $settings['style_formats'] = json_encode( $style_formats );

    return $settings;
}

// Add style sheet for the custom styles to the TinyMCE Editor in the Admin
function awesome_tinymce_css( $blah ) {
	$blah .= ',' . get_bloginfo('stylesheet_directory') . '/awesome.css';
	return $blah;
}
// We now tell WordPress to load our style sheet inside its editor!
add_filter( 'mce_css', 'awesome_tinymce_css' );

Step 2: awesome.css

Create an “awesome.css” and put it in your theme’s directory. We will use this files to make our awesome styles appear in the TinyMCE editor.

.super-div {
	border:1px dotted #CCC;
	padding:5px;
}
.awesome-button-link {
	display:inline-block;
	padding:5px;
	background-color:#F90;
	color:#FFF;
}

Step 3: Be awesome

Now add a new Post or Page in your WordPress admin and you can try out your newly created styles like so:

  • Add a Super Div by selecting it from the “Styles” dropdown
  • Type some text and make it a link. Remember, according to our code the Awesome Button Link only works with an ‘A’ tag
  • Once you’ve made a link, select it and apply the “Awesome Button Link” style to it
  • Impress your client!

Here’s an example of how our code works: