WPExplorer https://www.wpexplorer.com/ Mon, 03 Feb 2025 20:07:56 +0000 en-US hourly 1 https://wordpress.org/?v=6.7.1 https://www.wpexplorer.com/wp-content/uploads/cropped-wpexplorer-wordpress-blog.jpg WPExplorer https://www.wpexplorer.com/ 32 32 The Complete Guide to Removing Elementor Upsells https://www.wpexplorer.com/complete-guide-to-removing-elementor-upsells/ https://www.wpexplorer.com/complete-guide-to-removing-elementor-upsells/#respond Thu, 16 Jan 2025 20:52:58 +0000 https://www.wpexplorer.com/?p=65419 Elementor is a powerful tool for building WordPress websites, but its dashboard can sometimes feel cluttered with upsell ads and prompts for premium features. In this guide, I’ll show you how to remove most Elementor upsells, allowing you to enjoy a cleaner, more focused interface. You can follow along the guide and add the code […]

The post The Complete Guide to Removing Elementor Upsells appeared first on WPExplorer.

]]>
Elementor is a powerful tool for building WordPress websites, but its dashboard can sometimes feel cluttered with upsell ads and prompts for premium features.

In this guide, I’ll show you how to remove most Elementor upsells, allowing you to enjoy a cleaner, more focused interface. You can follow along the guide and add the code to your custom theme or you can skip the guide and download the handy plugin on Github instead.

Before we dive in, it’s worth mentioning that the simplest way to remove Elementor upsells is by purchasing and installing Elementor Pro (affiliate link). This is what I recommend, however, not everyone needs the extra features, or may not be ready to commit to the ongoing cost.

This guide may be controversial, but here’s my perspective: while I fully understand the need to generate revenue, I believe that when you create a free GPL product, users should have the freedom to modify it as they see fit.

Again, I strongly recommend you purchase Elementor Pro to access tons of awesome features and support from the developers. Have a look at the Elementor Free vs Pro article on their site to see what you would be missing out on!

If you’re not ready to upgrade to the pro version and prefer sticking with the free one, keep reading to learn how to remove the upsells for a cleaner user interface.

TL;DR Skip to the final code & plugin

WPEX_Remove_Elementor_Upsells PHP Class

Let’s start by creating our PHP class which will hold all the code necessary to remove Elementor upsells. This will keep everything tidy and structured. At the top of the class, we’ll include a check to ensure that if you upgrade to Elementor Pro, nothing gets removed or affected.

Here is our starter class:

/**
 * Remove Elementor Upsells.
 */
class WPEX_Remove_Elementor_Upsells {

	/**
	 * Constructor.
	 */
	public function __construct() {
		if ( did_action( 'elementor/loaded' ) ) {
			$this->register_actions();
		} else {
			add_action( 'elementor/loaded', [ $this, 'register_actions' ] );
		}
	}

	/**
	 * Register our main class actions.
	 */
	public function register_actions(): void {
		if ( is_callable( 'Elementor\Utils::has_pro' ) && Elementor\Utils::has_pro() ) {
			return; // bail early if we are using Elementor Pro.
		}

		// We will do things here...
	}
	
}

new WPEX_Remove_Elementor_Upsells;

In the remainder of this tutorial, we’ll be adding new code within this class. It’s important to follow along closely, as skipping any section could cause you to miss essential code. Alternatively, you can skip ahead to the end and copy the complete final version of the class.

Elementor extra pages

Elementor registers various admin pages that don’t actually do anything besides display a landing page to upgrade to the pro version. We are going to first remove the following useless pages:

  • Submissions
  • Custom Fonts
  • Custom Icons
  • Custom Code
  • Add-ons (Bonus)

We’ll start out by updating our register_actions method to look like this:

/**
 * Register our main class actions.
 */
public function register_actions(): void {
	if ( is_callable( 'Elementor\Utils::has_pro' ) && Elementor\Utils::has_pro() ) {
		return; // bail early if we are using Elementor Pro.
	}

	add_action( 'elementor/admin/menu/after_register', [ $this, 'remove_admin_pages' ], PHP_INT_MAX, 2 );
}

Then we’ll add a new method named remove_admin_pages to the class which will look like this:

/**
 * Remove admin pages.
 */
public function remove_admin_pages( $menu_manager, $hooks ): void {
	$pages_to_remove = [];
	$subpages_to_remove = [];
	if ( is_callable( [ $menu_manager, 'get_all' ] ) ) {
		foreach ( (array) $menu_manager->get_all() as $item_slug => $item ) {
			if ( isset( $hooks[ $item_slug ] )
				&& is_object( $item )
				&& ( is_subclass_of( $item, 'Elementor\Modules\Promotions\AdminMenuItems\Base_Promotion_Item' )
					|| is_subclass_of( $item, 'Elementor\Modules\Promotions\AdminMenuItems\Base_Promotion_Template' )
				)
			) {
				$parent_slug = is_callable( [ $item, 'get_parent_slug' ] ) ? $item->get_parent_slug() : '';
				if ( ! empty( $parent_slug ) ) {
					$subpages_to_remove[] = [ $parent_slug, $item_slug ];
				} else {
					$pages_to_remove[] = $hooks[ $item_slug ];
				}
			}
		}
	}
	foreach ( $pages_to_remove as $menu_slug ) {
		remove_menu_page( $menu_slug );
	}
	foreach ( $subpages_to_remove as $subpage ) {
		remove_submenu_page( $subpage[0], $subpage[1] );
	}
}

This code hooks takes advantage of a handy hook in the Elementor plugin so we can dynamically get a list of promotional admin pages and remove them.

Remove the Add-ons Page

You may find the Add-ons panel useful as it’s a way to locate plugins compatible with Elementor that provide additional functionality. However, most of these are premium add-ons (aka ads) and if you aren’t buying Elementor Pro, you will likely not be buying anything from this page either.

To remove the add-ons page we’ll update the previous method to have an extra check like so:

/**
 * Remove admin pages.
 */
public function remove_admin_pages( $menu_manager, $hooks ): void {
	$pages_to_remove = [];
	$subpages_to_remove = [];
	if ( is_callable( [ $menu_manager, 'get_all' ] ) ) {
		foreach ( (array) $menu_manager->get_all() as $item_slug => $item ) {
			if ( isset( $hooks[ $item_slug ] )
				&& is_object( $item )
				&& ( is_subclass_of( $item, 'Elementor\Modules\Promotions\AdminMenuItems\Base_Promotion_Item' )
					|| is_subclass_of( $item, 'Elementor\Modules\Promotions\AdminMenuItems\Base_Promotion_Template' )
					|| 'elementor-apps' === $item_slug
				)
			) {
				$parent_slug = is_callable( [ $item, 'get_parent_slug' ] ) ? $item->get_parent_slug() : '';
				if ( ! empty( $parent_slug ) ) {
					$subpages_to_remove[] = [ $parent_slug, $item_slug ];
				} else {
					$pages_to_remove[] = $hooks[ $item_slug ];
				}
			}
		}
	}
	foreach ( $pages_to_remove as $menu_slug ) {
		remove_menu_page( $menu_slug );
	}
	foreach ( $subpages_to_remove as $subpage ) {
		remove_submenu_page( $subpage[0], $subpage[1] );
	}
}

All we did was add || 'elementor-apps' === $item_slug to the the if statement.

Elementor top bar admin add-ons link

If you removed the Add-ons page you’ll also want to remove the link in the Elementor top bar. Otherwise, if someone clicks on the link it will take them to a WordPress error page with the warning “Sorry, you are not allowed to access this page.”.

To keep things simple what we’ll do is add a little custom CSS in the WP admin that hides the link using the modern :has() selector.

Let’s add a new action to the register_actions method like such:

add_action( 'elementor/admin_top_bar/before_enqueue_scripts', [ $this, 'admin_top_bar_css' ] );

Then add the new add_css_to_elementor_admin method to the bottom of the class:

/**
 * Add inline CSS to modify the Elementor admin top bar.
 */
public function admin_top_bar_css(): void {
	wp_add_inline_style(
		'elementor-admin-top-bar',
		'.e-admin-top-bar__bar-button:has(.eicon-integration){display:none!important;}'
	);
}

This code leverages the fact that Elementor assigns specific font icons to each top bar link, allowing us to target the button directly based on its icon.

Tracking Referrals Violates the WordPress Plugin Guidelines

As of the time this article was published, Elementor is using cloaked links on their Add-ons page. So when you hover on a premium add-on “Let’s go” button you will see a target URL that looks something like this:

https://go.elementor.com/{product-slug}/

When you click and go to this link it may redirect you to a referral link. Which may be a violation of the following plugin guideline. As noted in this section:

Advertising within the WordPress dashboard should be avoided, as it is generally ineffective…Remember: tracking referrals via those ads is not permitted.

To be fair, Elementor does a decent job at disclosing how their Add-ons page works on their own site. But to be fully compliant with the WordPress guidelines (from my understanding) they should be linking to pages on their site, not adding cloaked links directly in the WP admin.

If you would also like to remove the Get Help link you can go back to our remove_admin_pages method and add the following at the bottom:

remove_submenu_page( 'elementor', 'go_knowledge_base_site' );

Remove the Sidebar Pink Upgrade Button

Elementor upgrade button

Next we’ll remove the pink upgrade button that displays in the admin sidebar under the Elementor parent menu item. This is technically an admin page (when visited it uses a redirection to go to their website) so it can also be removed using remove_submenu_page.

Add the following code inside (at the bottom) of the remove_admin_pages method.

remove_submenu_page( 'elementor', 'go_elementor_pro' );

The “Upgrade Now” link at the top of Elementor pages is the least intrusive upsell and, in my opinion, is done in a fairly classy way. While I personally think it’s perfectly acceptable, this guide is all about helping you remove as many upsells as possible, so I’ll show you how to get rid of it.

If you are following along and you decided to hide the add-ons page then you’ve already added the admin_top_bar_css method to your class. We’ll be updating this method to also hide the upgrade now button. If not, please scroll up and follow the steps in this section.

This is what your updated admin_top_bar_css method should look like:

public function admin_top_bar_css(): void {
	$target_icon_classes = [
		'.eicon-integration', // Add-ons
		'.eicon-upgrade-crown', // Upgrade now
	];
	wp_add_inline_style(
		'elementor-admin-top-bar',
		'.e-admin-top-bar__bar-button:has(' . implode( ',', $target_icon_classes ) . '){display:none!important;}'
	);
}

Remove the Theme Builder

As a free user you won’t have access to the Theme Builder. Which is awesome by the way, and fully supported in our Total theme. In my opinion, Theme Builder is the primary reason you should purchase the Pro version. It will allow you to truly create a custom website.

As you probably guessed, this is also a “dummy” admin page like the pink upgrade button we removed earlier. To remove we’ll go back to our remove_admin_pages method and add the following at the bottom:

if ( ! isset( $_GET['page'] ) || 'elementor-app' !== $_GET['page'] ) {
    remove_submenu_page( 'edit.php?post_type=elementor_library', 'elementor-app' );
}

We add an extra check for the the page query parameter, otherwise, the Kit Library will stop working.

Elementor theme builder admin bar link

Elementor also adds the Theme Builder link to the user admin bar when logged in and viewing the frontend of your site. Which, again, if you click the link you are taken to a useless page where you can’t do anything as a free user.

To remove this link we’ll first need to add a new action to our register_actions method:

add_filter( 'elementor/frontend/admin_bar/settings', [ $this, 'modify_admin_bar' ], PHP_INT_MAX );

Then we’ll add a new modify_admin_bar method to the bottom of our class:

/**
 * Modify the admin bar links.
 */
public function modify_admin_bar( $admin_bar_config ) {
	if ( isset( $admin_bar_config['elementor_edit_page']['children'] )
		&& is_array( $admin_bar_config['elementor_edit_page']['children'] )
	) {
		foreach ( $admin_bar_config['elementor_edit_page']['children'] as $k => $item ) {
			if ( isset( $item['id'] ) && 'elementor_app_site_editor' === $item['id'] ) {
				unset( $admin_bar_config['elementor_edit_page']['children'][ $k ] );
				break;
			}
		}
	}
	return $admin_bar_config;
}

Remove the Promo Widgets

Screenshot taken from the total theme Synergy demo.

Elementor also includes all the premium widgets in the widget selector, which I understand as a way to show users what they’re missing. However, it can be quite frustrating when searching for items, especially if you’re using an add-on plugin that registers widgets with similar names.

We’re not technically “removing” the widgets, so we won’t free up any memory. However, we can hide them using CSS to clean up and slim down the sidebar.

Let’s add a new action to our register_actions method:

add_action( 'elementor/editor/after_enqueue_styles', [ $this, 'editor_css' ] );

Then we’ll add the following method to the bottom of our class:

/**
 * Hide elements in the editor.
 */
public function editor_css(): void {
	wp_add_inline_style(
		'elementor-editor',
		'.elementor-element-wrapper.elementor-element--promotion,#elementor-panel-category-pro-elements,#elementor-panel-category-theme-elements,#elementor-panel-category-theme-elements-single,#elementor-panel-category-woocommerce-elements{display:none!important;}'
	);
}

Remove the Editor Sidebar Banner

In order to remove the banner from the sidebar in the Elementor widget we’ll use CSS as well. We’ll simply update the previous snippet to include a few more elements like such:

/**
 * Hide elements in the editor.
 */
public function editor_css(): void {
	wp_add_inline_style(
		'elementor-editor',
		'.elementor-element-wrapper.elementor-element--promotion,#elementor-panel-category-pro-elements,#elementor-panel-category-theme-elements,#elementor-panel-category-theme-elements-single,#elementor-panel-category-woocommerce-elements,#elementor-panel-get-pro-elements,#elementor-panel-get-pro-elements-sticky{display:none!important;}'
	);
}

Remove the Editor Notice Bar

Elementor bottom notice bar

When you first open the Elementor editor, you’ll notice a sticky notice bar at the bottom of the page. Because, of course, there can never be too many upsells, right? While you can click the “X” to close it, this won’t stop it from reappearing later (14 days later).

Let’s go back to our editor_css method and update it to include the e-notice-bar classname. Here is the updated method.

/**
 * Hide elements in the editor.
 */
public function editor_css(): void {
	wp_add_inline_style(
		'elementor-editor',
		'.e-notice-bar,.elementor-element-wrapper.elementor-element--promotion,#elementor-panel-category-pro-elements,#elementor-panel-category-theme-elements,#elementor-panel-category-theme-elements-single,#elementor-panel-category-woocommerce-elements,#elementor-panel-get-pro-elements,#elementor-panel-get-pro-elements-sticky{display:none!important;}'
	);
}

Remove Admin Dashboard Widget

I’m sure many of you, like me, don’t spend much time on the WordPress “Dashboard” page. However, this is the default page you’re redirected to when you log into WordPress. Elementor adds a custom widget to the dashboard that displays a feed from their blog—and of course, more upsell links!

Add the following to the register_actions method:

add_action( 'wp_dashboard_setup', [ $this, 'remove_dashboard_widget' ], PHP_INT_MAX );

Then add the following method to the bottom of the class:

/**
 * Remove dashboard widget.
 */
public function remove_dashboard_widget(): void {
	remove_meta_box( 'e-dashboard-overview', 'dashboard', 'normal' );
}

Final Code & Plugin

If you followed along you should now have a class that looks like this:


/**
 * Remove Elementor Upsells.
 */
class WPEX_Remove_Elementor_Upsells {

	/**
	 * Constructor.
	 */
	public function __construct() {
		if ( did_action( 'elementor/loaded' ) ) {
			$this->register_actions();
		} else {
			add_action( 'elementor/loaded', [ $this, 'register_actions' ] );
		}
	}

	/**
	 * Register our main class actions.
	 */
	public function register_actions(): void {
		if ( is_callable( 'Elementor\Utils::has_pro' ) && Elementor\Utils::has_pro() ) {
			return; // bail early if we are using Elementor Pro.
		}

		add_action( 'elementor/admin/menu/after_register', [ $this, 'remove_admin_pages' ], PHP_INT_MAX, 2 );
		add_action( 'elementor/admin_top_bar/before_enqueue_scripts', [ $this, 'admin_top_bar_css' ] );
		add_filter( 'elementor/frontend/admin_bar/settings', [ $this, 'modify_admin_bar' ], PHP_INT_MAX );
		add_action( 'elementor/editor/after_enqueue_styles', [ $this, 'editor_css' ] );
		add_action( 'wp_dashboard_setup', [ $this, 'remove_dashboard_widget' ], PHP_INT_MAX );
	}

	/**
	 * Remove admin pages.
	 */
	public function remove_admin_pages( $menu_manager, $hooks ): void {
		$pages_to_remove = [];
		$subpages_to_remove = [];
		if ( is_callable( [ $menu_manager, 'get_all' ] ) ) {
			foreach ( (array) $menu_manager->get_all() as $item_slug => $item ) {
				if ( isset( $hooks[ $item_slug ] )
					&& is_object( $item )
					&& ( is_subclass_of( $item, 'Elementor\Modules\Promotions\AdminMenuItems\Base_Promotion_Item' )
						|| is_subclass_of( $item, 'Elementor\Modules\Promotions\AdminMenuItems\Base_Promotion_Template' )
						|| 'elementor-apps' === $item_slug
					)
				) {
					$parent_slug = is_callable( [ $item, 'get_parent_slug' ] ) ? $item->get_parent_slug() : '';
					if ( ! empty( $parent_slug ) ) {
						$subpages_to_remove[] = [ $parent_slug, $item_slug ];
					} else {
						$pages_to_remove[] = $hooks[ $item_slug ];
					}
				}
			}
		}
		foreach ( $pages_to_remove as $menu_slug ) {
			remove_menu_page( $menu_slug );
		}
		foreach ( $subpages_to_remove as $subpage ) {
			remove_submenu_page( $subpage[0], $subpage[1] );
		}
		remove_submenu_page( 'elementor', 'go_knowledge_base_site' );
		remove_submenu_page( 'elementor', 'go_elementor_pro' );
		if ( ! isset( $_GET['page'] ) || 'elementor-app' !== $_GET['page'] ) {
			remove_submenu_page( 'edit.php?post_type=elementor_library', 'elementor-app' );
		}
	}

	/**
	 * Add inline CSS to modify the Elementor admin top bar.
	 */
	public function admin_top_bar_css(): void {
		$target_icon_classes = [
			'.eicon-integration', // Add-ons
			'.eicon-upgrade-crown', // Upgrade now
		];
		wp_add_inline_style(
			'elementor-admin-top-bar',
			'.e-admin-top-bar__bar-button:has(' . implode( ',', $target_icon_classes ) . '){display:none!important;}'
		);
	}

	/**
	 * Modify the admin bar links.
	 */
	public function modify_admin_bar( $admin_bar_config ) {
		if ( isset( $admin_bar_config['elementor_edit_page']['children'] )
			&& is_array( $admin_bar_config['elementor_edit_page']['children'] )
		) {
			foreach ( $admin_bar_config['elementor_edit_page']['children'] as $k => $item ) {
				if ( isset( $item['id'] ) && 'elementor_app_site_editor' === $item['id'] ) {
					unset( $admin_bar_config['elementor_edit_page']['children'][ $k ] );
					break;
				}
			}
		}
		return $admin_bar_config;
	}

	/**
	 * Hide elements in the editor.
	 */
	public function editor_css(): void {
		wp_add_inline_style(
			'elementor-editor',
			'.e-notice-bar,.elementor-element-wrapper.elementor-element--promotion,#elementor-panel-category-pro-elements,#elementor-panel-category-theme-elements,#elementor-panel-category-theme-elements-single,#elementor-panel-category-woocommerce-elements,#elementor-panel-get-pro-elements,#elementor-panel-get-pro-elements-sticky{display:none!important;}'
		);
	}

	/**
	 * Remove dashboard widget.
	 */
	public function remove_dashboard_widget(): void {
		remove_meta_box( 'e-dashboard-overview', 'dashboard', 'normal' );
	}

}

new WPEX_Remove_Elementor_Upsells;

You can copy and paste this code into your custom WordPress parent or child theme functions.php file or include it via it’s own file (recommended).

Alternatively, I added the code into a handy plugin that you can download from Github and install on your site. I won’t be uploading this plugin to the WordPress repository, so if it ever needs updating you will need to manually patch it.

Conclusion

If it’s within your budget, you should head over and purchase Elementor Pro (affiliate link). Even if you don’t need any of the premium features, if you use Elementor at all, it’s good to give back to the developers and help support the product.

Did I Miss Anything? Which Plugin is Next?

If there is a plugin you are using that bombards you with advertisements and promos, mention me @wpexplorer (on X/Twitter). If the plugin is popular enough I may consider writing as similar guide for that one next.

Or if I missed anything in Elementor let me know!

The post The Complete Guide to Removing Elementor Upsells appeared first on WPExplorer.

]]>
Stop WordPress from Creating Extra Cropped Image Sizes https://www.wpexplorer.com/stop-wordpress-from-creating-extra-cropped-image-sizes/ https://www.wpexplorer.com/stop-wordpress-from-creating-extra-cropped-image-sizes/#respond Tue, 07 Jan 2025 19:46:49 +0000 https://www.wpexplorer.com/?post_type=wpex_dev_tutorials&p=65409 Whenever you upload an image to your WordPress site through the media library, it automatically creates and stores multiple additional versions of that image. If your site doesn’t utilize these extra image sizes, they will consume valuable storage space and increase the size of your server backups. In this guide, I’ll walk you through the […]

The post Stop WordPress from Creating Extra Cropped Image Sizes appeared first on WPExplorer.

]]>
Whenever you upload an image to your WordPress site through the media library, it automatically creates and stores multiple additional versions of that image. If your site doesn’t utilize these extra image sizes, they will consume valuable storage space and increase the size of your server backups.

In this guide, I’ll walk you through the default image sizes, explain why they are generated, show you how to identify additional image sizes and provide you with the code snippet to prevent WordPress from creating unnecessary image sizes.

TL;DR Skip to the snippet or the plugin.

Default Image Sizes in WordPress

Here is a table of all the default image sizes in WordPress:

NameDefault SizeDescription
thumbnail150×150User defined thumbnail size.
medium300×300User defined medium size.
medium_large768×0For responsive and HDPI displays.
large1024×1024User defined large size.
1536×15361536×1536For retina/HDPI displays.
2048×20482048×2048For larger, high-resolution displays.
-scaled~2560When the original image uploaded is larger than the big image size threshold, WordPress creates this scaled version.
fullLargest possible size. Original or scaled image.

As you can see there are quite a lot!

This means that each time you upload an image to your WordPress site, it could generate and store up to 7 additional image versions on your server! And these are only the default sizes defined in core, it doesn’t include any extra sizes defined by your themes & plugins.

Image Sizes Created by Your WordPress Theme & Plugins

Most classic WordPress themes (non-block themes) don’t make use of the thumbnail, medium and large core sizes. They usually register their own image sizes that work best with the design and layout of the theme.

Plugins may also register new image sizes. This is common in plugins used to display posts or include custom post types. Prime examples would be directory, events, real estate, ecommerce, LMS, page builders, etc.

This means your site could be creating even more image sizes and really bloating up your server and backup files.

It’s a good idea to read the documentation for the theme and all plugins used on your site to ensure they are not creating unnecessary resized versions of your images. Most well coded themes and plugins will offer a setting to modify or disable any additional image sizes.

If you are using our Total theme be sure to check out the documentation regarding the Image Sizes Panel. If you are not, but you are a developer you may want to have a look at how I did things for inspiration.

Later in this guide I will provide you with an easy code-based solution for viewing all registered image sizes on your site.

Why are Extra Resized Images Created

Before explaining how to stop WordPress from generating alternative image sizes for your uploads, it’s important to understand why WordPress creates these extra sizes in the first place. Below is a list of the key reasons:

  • Faster Loading Times: Smaller images load faster.
  • Responsive Images: Provide alternative image sizes for different screen sizes.
  • Consistency: For keeping all your featured images the same size.
  • High-Resolution Displays: Provide alternative images for high-resolution and retina displays.
  • Featured Thumbnails: Provide alternative image sizes for use in different parts of the site or with theme/plugins specific elements.
  • Server Performance: As in the case with the -scaled image as noted in the table above.

WordPress Media Settings Admin Panel

When logged into your WordPress site if you go to Settings > Media you will find options to set three of the core WordPress image sizes (Thumbnail, Medium, Large).

Setting the width and height of all fields to 0 will prevent WordPress from creating those extra images. This is the first thing I do whenever I install WordPress and recommend it for most sites.

WordPress media settings page

However, this isn’t a full solution for preventing unwanted resized images from your site. Keep reading to find out more and see my code snippet for disabling all image sizes.

The Big Image Size Threshold in WordPress

In WordPress 5.3.0 they introduced what is known as the Big Image Size Threshold. This is the maximum width or height an image can be for which WordPress will generate additional image sizes when the image is uploaded. The default value is 2560.

If an image is uploaded to the media library that exceeds the threshold, WordPress will scale down the image and it will be used as the largest available size. WordPress will then generate all the additional image sizes defined on your site based on the scaled down version.

So, if you are uploading images that are larger than 2560 (width or height) WordPress will create extra images on your server. You may want to disable or adjust this accordingly.

Disable the Big Image Size Threshold

If you want to be able to upload large images to your site without WordPress scaling them down and creating an alternative version you can do so with the following code snippet:

// Disable the big image size threshold
add_filter( 'big_image_size_threshold', '__return_false' );

Caution: The big image threshold exists for a reason and I highly recommend NOT disabling it. Disabling this feature could cause performance issues on the server. If you know only smaller images are uploaded to the site than you can disable it, but it won’t matter anyway to leave it on.

Modify the Big Image Size Threshold

If your site needs to allow for larger images (for example a photography website) then you may want to modify the big image size threshold value. This way WordPress won’t scale down your images.

Here is an example of how you can change the value from 2560 to 5000:

// Modify the big image size threshold
add_filter( 'big_image_size_threshold', function( $threshold ) {
    return 5000;
} );

How to Check what Image Sizes are Defined on Your Site?

Unfortunately WordPress doesn’t have a native way of seeing a list of all the image sizes registered on your website. There are plugins you can use for this, but since I focus primarily on code based tutorials I will show you how you can use code to display a list of registered images on your site.

Quick & “Dirty” Method

If you copy and paste this code into your functions.php file then refresh your site you will see a list of the registered image sizes at the top of the live site. You can then copy and paste them into a text file for reference then remove the code.

// Display all defined image sizes at the top of the site inside a <pre> tag
add_action( 'wp_head', function() {
	echo '<pre>';
	foreach ( (array) wp_get_registered_image_subsizes() as $size => $dims ) {
		$width = $dims['width'] ?? 0;
		$height = $dims['height'] ?? 0;
		echo "{$size}: {$width}x{$height}\n";
	}
	echo '</pre>';
} );

Display Registered Image Sizes in the WP Admin

Having access to a list of registered image sizes in your WordPress admin panel is ideal. This way if you ever enable a new plugin or switch themes you can quickly check to see if new image sizes are being defined.

The following code snippet will display a table of all defined image sizes at the bottom of the Settings > Media panel:

// Add a table of image sizes to the Settings > Media admin page
add_action( 'admin_init', function() {
	add_settings_section(
		'dummy_registered_image_sizes_info',
		esc_html__( 'Registered Image Sizes', 'text_domain' ),
		function() {
			echo '<table class="wp-list-table widefat fixed striped">';
			echo '<thead><tr><th>' . esc_html__( 'Name', 'text_domain' ) . '</th><th>' . esc_html__( 'Dimensions', 'text_domain' ) . '</th></tr></thead>';
			foreach ( (array) wp_get_registered_image_subsizes() as $size => $dims ) {
				if ( ! in_array( $size, [ 'thumbnail', 'medium', 'large' ], true ) ) {
					$width = $dims['width'] ?? 0;
					$height = $dims['height'] ?? 0;
					echo "<tr><td><strong>{$size}</strong></td><td>{$width}x{$height}</td>";
				}
			}
			echo '</table>';
		},
		'media'
	);
}, PHP_INT_MAX );

Technically we are defining a new settings section with this code but we aren’t actually registering any settings. Instead we set the callback for our section to return a table that loops through and displays all registered image sizes.

Here is a screenshot of the end result:

WordPress media settings table of registered image sizes

This example is from the Total theme where the default theme registered image sizes are set to 9999×9999 which is very large so they wont ever crop by default.

Prevent WordPress from Creating Extra Image Sizes

There isn’t any option you can just check in the WordPress admin so in order to stop WordPress from creating cropped versions of your images you will need to use a little code. Luckily it can be done with a single line of code!

// Return false for calculated resized image dimensions
add_filter( 'image_resize_dimensions', '__return_false' );

To understand how this code works we’ll take a look at the core image_resize_dimensions() function. It’s quite long, so I won’t post it here, but you can click on the previous link if you want to see all the code associated with the function.

Basically, whenever WordPress is going to create a new image size it uses this function to return the calculated resize dimensions for the image, which it then passes to the WP_Image_Editor class. Hooking into the image_resize_dimensions filter and returning false will make the function exit early so no calculations are made and ultimately no extra image will be generated.

Optimized Code Snippet

The previous snippet will prevent WordPress from cropping any image when a new image size is requested. This will work regardless of when an image size is requested.

However, we can optimize our code by hooking into the intermediate_image_sizes_advanced filter which returns the array of image sizes automatically generated when uploading an image.

// Return an empty list of image sizes to generate on upload
add_filter( 'intermediate_image_sizes_advanced', '__return_empty_array' );

By returning an empty array for the filter we let WordPress know there shouldn’t be any extra images generated when uploading a new image to our site. Now, whenever you upload an image to your website only the original image will be added to the server.

Full Snippet:

Here are both snippets combined:

// Return false for calculated resized image dimensions
add_filter( 'image_resize_dimensions', '__return_false' );

// Return an empty list of image sizes to generate on upload
add_filter( 'intermediate_image_sizes_advanced', '__return_empty_array' );

Now, if you are hooking into intermediate_image_sizes_advanced you don’t necessarily have to also hook into image_resize_dimensions.

The reason for hooking into both filters is in case a theme or plugin is using it’s own “on-the-fly” cropping solution – which hopefully makes use of the image_resize_dimensions() function.

WP Disable All Image Sizes Plugin

I’ve also put the code snippet into a little plugin if you want to just download and install it instead. This plugin should never require any updates and the WordPress plugin review process is a nightmare so for now I’m just leaving it on Github.

WP Disable all Image Sizes Plugin Github Repository

The plugin will do 3 things:

  • Disable the big image size threshold.
  • Return false for the image_resize_dimensions filter.
  • Return an empty array for the intermediate_image_sizes_advanced filter.

What if Extra Image Sizes Are Still Created?

If you’ve added the code snippet to your site and find that image sizes are still being generated when you upload images, you will need to disable plugins and/or your theme to locate the culprit.

As mentioned previously, it’s possible there is a custom”on-the-fly” image cropping solution on your site that is not using core WP functionality and thus the core filters won’t affect it.

Exclude Specific Image Sizes from Being Created on Upload

Perhaps you don’t want to prevent all image sizes from being generated. It’s possible to modify the code to only exclude certain image sizes, like such:

// Exclude certain image sizes from being generated on upload
add_filter( 'intermediate_image_sizes_advanced', function( $sizes ) {
	$sizes_to_exclude = [
		'thumbnail',
		'medium',
		'large',
		'medium_large',
		'1536×1536',
		'2048×2048',
	];
	foreach ( $sizes_to_exclude as $size_to_exclude ) {
		unset( $sizes[ $size_to_exclude ] );
	}
    return $sizes;
} );

If you want to exclude only certain image sizes make sure you are NOT hooking into image_resize_dimensions and returning false.

And you probably noticed I included the thumbnail, medium and large image sizes in the snippet. This way, even if someone messes with the settings in the admin those image sizes will be excluded.

Tips for Reducing the Need for Resized Images

At the beginning of the article I gave some of the reasons as to why WordPress creates additional image sizes. With those in mind, if you are planning on disabling the extra image sizes here are some tips to ensure you don’t create extra “issues”.

  • Don’t Upload Massive Images: Make sure you are not uploading massive images to your site. If you don’t have control over this, make sure you don’t remove the big image threshold and be ok with the fact that your site will create scaled images when needed.
  • Upload Big “Enough” Images: It’s hard to say how big is big enough as it depends on the site and context in which the image is added. But, you will want your images to be large enough that they look good on high-resolution screens while being small enough (in kb) that it doesn’t slow down site loading.
  • Optimize Images Prior to Upload: There are many great image optimization plugins out there, but why bloat up your site and consume server resources if you can optimize your images prior to upload. I personally use tinypng.com and convert my images to webP format prior to upload.
  • Use Image Aspect Ratios: One of the main reasons image sizes are created is to keep a consistent look across your posts as all your featured images will be cropped to the same dimensions. Rather, you can use the CSS aspect-ratio property to target your images.

These are the main tips that come to my mind, let me know in the comments if you have some other good suggestions or concerns that should be addressed.

How to Remove Old Image Sizes from Your Server

Adding the code to prevent WordPress from creating extra image sizes will only take affect for newly uploaded images. If you are adding the code to an existing site there may be tons of old cropped images on the server you will want to clean up.

There are several methods you can use to delete old resized images and many blogs recommend using CLI (terminal) – however, WordPress stores image sizes in the attachment meta data so I don’t recommend that solution.

The easiest method I’ve found is using the Force Regenerate Thumbnails plugin. You can enable the plugin, run the process and then delete it from your site.

The plugin works by looping through every image attachment on the site, pulling it’s defined sizes from the meta data and deleting them all. After deleting the image sizes it runs the core wp_generate_attachment_metadata() function which will re-create the intermediate image sizes for the attachment. So, if you’ve disabled extra image sizes via the previous code no images will be generated.

I could provide you with a code snippet to delete old image sizes from your site, however, the process can be very resource intensive and is best done using AJAX. The Force Regenerate Thumbnails plugin will go through each image at a time and if there are any issues it will log and display them.

The plugin will also show you what images were deleted and generated which is really nice!

As always, before you install any new plugins or delete anything from your site you should make sure you have a full backup. I’ve used the plugin many times without issues, but it’s better safe than sorry.

Conclusion

Personally I think disabling all extra image sizes is best for most websites. It ensures your server space is not consumed by images (many which will never be used) and in turn keeps your backups significantly smaller.

There could be an argument also for SEO. I don’t know much about Google Image Search Optimization, but perhaps having many of the same image at different sizes could cause issues. If you are an SEO expert, please let me know in the comments if that’s the case!

Further reading:

You may also be interested in the following:

The post Stop WordPress from Creating Extra Cropped Image Sizes appeared first on WPExplorer.

]]>
Highlight Sponsored & Nofollow Links in Gutenberg https://www.wpexplorer.com/highlight-sponsored-nofollow-links-gutenberg/ https://www.wpexplorer.com/highlight-sponsored-nofollow-links-gutenberg/#respond Sun, 08 Sep 2024 06:50:16 +0000 https://www.wpexplorer.com/?post_type=wpex_dev_tutorials&p=65143 Recently I’ve been going through old articles and updating affiliate links to the text (affiliate link) next to any affiliate link for complete disclosure. I’ve also been switching links that previously used rel nofollow to sponsored. This is a long process as we have thousands of posts and I’m completely re-structuring how our theme and […]

The post Highlight Sponsored & Nofollow Links in Gutenberg appeared first on WPExplorer.

]]>
Recently I’ve been going through old articles and updating affiliate links to the text (affiliate link) next to any affiliate link for complete disclosure. I’ve also been switching links that previously used rel nofollow to sponsored.

This is a long process as we have thousands of posts and I’m completely re-structuring how our theme and plugin collections look. To make things easier I’ve added a little code to the site which will highlight sponsored and nofollow links so I quickly locate them.

I can’t be the only one that would benefit from highlighting sponsored/rel links so I figured I would post a little guide on how I did it. Being able to quickly glance at a post and see these links will allow you to judge if there are too many and if you should remove some. It will also let you see which links don’t have any rel attribute so you can decide if you should add one or not.

How to Add CSS to the WordPress Editor

In order to highlight links we’ll need to add some CSS to the WordPress editor. If you are working with a theme you can easily add custom CSS to the editor using a css file otherwise you can insert inline CSS with a hook.

Using an Editor CSS file:

Simply create a new style-editor.css file in your theme and add the following:

add_action( 'after_setup_theme', function() {
    add_theme_support( 'editor-styles' );
    add_editor_style( 'style-editor.css' );
} );

WordPress will then automatically load this file in both the classic and block editors.

Adding Inline CSS:

If you aren’t working with a theme you can still add CSS to the editor inline. For this you will hook into the enqueue_block_editor_assets hook

/**
 * Hooks into "enqueue_block_editor_assets" to add inline styles to the Gutenberg Editor.
 */
add_action( 'enqueue_block_editor_assets', function() {
	wp_register_style( 'wpexplorer-editor-styles', false );
	$css = 'YOUR CSS HERE';
	wp_add_inline_style( 'wpexplorer-editor-styles', $css );
	wp_enqueue_style( 'wpexplorer-editor-styles' );
} );

For the purpose of this guide I’m going to be using the second method. This is because I will place my code inside a plugin so I can easily enable/disable the functionality.

Highlighting links based on their rel attribute is very easy! We’ll simply use the CSS tilde attribute selector. If you are new to attribute selectors I recommend you check out w3schools. So here is an example of the CSS we can use:

a[rel~=sponsored], a[rel~=nofollow] {
    background: #FFFF00;
    color: #000;
}

This CSS will make any link that has a rel sponsored or nofollow attribute look like this.

Now, because we are working with the WordPress editor it’s a good idea to target the .editor-styles-wrapper classname.

Targeting the editor-styles-wrapper element isn’t required if you are using the editor-styles method and loading a css file via your child theme or if you are targeting the classic editor. But it doesn’t hurt to just add it.

Here is the updated CSS:

.editor-styles-wrapper a:is([rel~=sponsored],[rel~=nofollow]) {
    background: #FFFF00;
    color: #000;
}

If you are using an editor-style.css file simply add the code in there and save it. Otherwise you can use the following function to insert this code inline:

/**
 * Adds inline CSS to the block editor.
 */
add_action( 'enqueue_block_editor_assets', function() {
	wp_register_style( 'wpexplorer-editor-highlight-rel-sponsored-nofollow', false );
	wp_add_inline_style(
		'wpexplorer-editor-highlight-rel-sponsored-nofollow',
		'.editor-styles-wrapper a:is([rel~=sponsored],[rel~=nofollow]){background:#FFFF00;color: #000;}'
	);
	wp_enqueue_style( 'wpexplorer-editor-highlight-rel-sponsored-nofollow' );
} );

Result:

With this code added if you edit any post that has nofollow or sponsored links they will be highlighted so you can easily locate them. Here is a screenshot from our WordPress Hosting page which of course has affiliate links:

Now I can easily scan any post to locate nofollow and sponsored links! Of course you can use this concept for other things (not sure what that could be…let me know in the comments).

Download the Plugin

I created a little plugin that has the code from this guide if you want to just download and upload it to your site. You can head over and check out the plugin on Github.

The reason I don’t upload these mini plugins to the WordPress.org directory is because the review process over there is an absolute shit-show. It takes a month just to get your plugin reviewed. I don’t understand why with the amount of money WordPress makes, they can’t just hire more reviewers.

Let me know in the comments if you’ve found this plugin useful or have any questions!

The post Highlight Sponsored & Nofollow Links in Gutenberg appeared first on WPExplorer.

]]>
How to Add Custom Block Styles in WordPress https://www.wpexplorer.com/how-to-add-custom-block-styles-wordpress/ https://www.wpexplorer.com/how-to-add-custom-block-styles-wordpress/#comments Sat, 31 Aug 2024 22:17:02 +0000 https://www.wpexplorer.com/?post_type=wpex_dev_tutorials&p=64809 If you have a look at the Gutenberg “Button” block and click on the styles tab (half moon cookie) you will see that you can select from Fill or Outline for it’s style. What if you wanted to add more options? Or you wanted to add style options to other blocks? In this guide, I […]

The post How to Add Custom Block Styles in WordPress appeared first on WPExplorer.

]]>
If you have a look at the Gutenberg “Button” block and click on the styles tab (half moon cookie) you will see that you can select from Fill or Outline for it’s style. What if you wanted to add more options? Or you wanted to add style options to other blocks?

In this guide, I will show you how to register your own custom block styles.

What are Block Styles?

If you’ve come to this guide you probably already know what Block styles are. But just incase I will quickly explain. Actually it’s easier if I let WordPress explain for me. Below is an excerpt from the official Gutenberg documentation:

Block Styles allow alternative styles to be applied to existing blocks. They work by adding a className to the block’s wrapper. This className can be used to provide an alternative styling for the block if the block style is selected

WordPress.org

So, block styles are options that you can click on when editing a block. When doing so, it will inject a classname to the block. This classname can then be referenced via CSS.

Why Register Custom Block Styles?

Registering custom styles will allow you to have different designs for your blocks that you can use in different contexts. For example, if your website is white and you insert a white picture in a post it may not look great. You could register a “Bordered” style for the Image block that adds a gray border around the image that will make it pop.

Sure, you could just use the setting at Block > Advanced > Additional CSS class(es) to add custom classnames for your blocks. However, this requires remembering class names. And if you are working on a client site they will appreciate an easy way to apply custom designs to their blocks.

An added benefit is that when you register custom block styles you can set the inline CSS for the style, this way the CSS is automatically added in the editor and the frontend whenever the style is selected.

How to Register a New Block Style

For the purpose of this guide, I’m going to focus specifically on server-side registering of custom styles. In other words, using PHP instead of Javascript. For most users, this will be easier and faster. You can quickly dump code into a code snippet plugin to add custom block styles to the site.

So, to register a new block style with PHP you will use the appropriately named register_block_style function. This function takes to arguments: $block and $style_properties. So you would tell it what block you want to add your styles to and then an array of the style properties.

Here is an example of adding a new “Plain” style to the List block:

/**
 * Register custom block styles.
 *
 * @link https://www.wpexplorer.com/how-to-add-custom-block-styles-wordpress/
 */
function wpexplorer_register_block_styles() {
	register_block_style(
		'core/list',
		[
			'name'  => 'list-plain',
			'label' => 'Plain',
		]
	);
}
add_action( 'init', 'wpexplorer_register_block_styles' );

With this coded added to your site when you insert a new list block you should see a new option to select a “Plain” style like such:

Notice how in my example I am using ‘core/list’ as the block name I want to add my custom style option to and not just ‘list’. All the WordPress default block names are prefixed in such a way. If you aren’t sure what the correct name is for a block, have a look at the list of all WordPress core blocks.

Also, in my example I have used 2 properties (the required ones) for my custom style: name and label. The label is will be used as the text in the Gutenberg UI and the name will be used for the classname added to the block in the format is-style-{name}.

I will explain later on how you can apply custom CSS to your block styles. So keep on reading.

How to Register Multiple Block Styles

For each style you want to add you will need to use the register_block_style function. So for example if you want to add more styles to the List block you could do so like such:

/**
 * Register custom block styles.
 */
function wpexplorer_register_block_styles() {

	// Inside List
	register_block_style(
		'core/list',
		[
			'name'  => 'list-inside',
			'label' => 'Inside',
		]
	);

	// Square List
	register_block_style(
		'core/list',
		[
			'name'  => 'list-square',
			'label' => 'Square',
		]
	);

	// Checkmark list.
	register_block_style(
		'core/list',
		[
			'name'  => 'list-checkmark',
			'label' => 'Checkmark',
		]
	);

}
add_action( 'init', 'wpexplorer_register_block_styles' );

With this code added you would now see 3 extra styles added to the list block like such:

Writing Slimmer Code (DRY Code)

If you are registering a ton of styles on your site I would recommend creating an array of the styles you will register so you can loop through them. This way you aren’t having to add the register_block_style over and over. This will keep your code slim and DRY.

Here is an example using an array to register multiple block styles:

/**
 * Register custom block styles.
 */
function wpexplorer_register_block_styles() {
	$styles = [
		// List Styles
		'core/list' => [
			[
				'name'  => 'list-inside',
				'label' => 'Inside',
			],
			[
				'name'  => 'list-checkmark',
				'label' => 'Checkmark',
			]
		],
		// Button Styles
		'core/button' => [
			[
				'name'  => 'button-three-d',
				'label' => 'Three-D',
			]
		],
	];
	foreach ( $styles as $block => $block_styles ) {
        foreach ( $block_styles as $style_props ) {
		    register_block_style( $block, $style_props );
        }
	}

}
add_action( 'init', 'wpexplorer_register_block_styles' );

See how much nicer this is? I would encourage you to always think about writing code in a DRY way without repeating yourself.

Styling Your Block Styles with CSS

I’ve showed you how to register custom block styles that you can select in the Gutenberg editor. But, this won’t actually cause your block to look any different. For that, you will need to add CSS to your site to target your custom styles.

I mentioned previously when you select a block style WordPress will insert the classname format is-style-{name} into the block’s class attribute. So you can use this to target the element.

Let’s say you wanted to add a checkmark list style type to your site so you would register your style like such:

function wpexplorer_register_checkmark_list_style() {
	register_block_style(
		'core/list',
		[
			'name'  => 'list-checkmark',
			'label' => 'Checkmark',
		]
	);
}
add_action( 'init', 'wpexplorer_register_checkmark_list_style' );

Then you can add the following CSS to your site to apply a custom checkmark design for your list:

@counter-style checkmark {
  system: cyclic;
  symbols: "\2713";
  suffix: " ";
}

.wp-block-list.is-style-list-checkmark {
  list-style: checkmark;
}

If you added your CSS to your theme’s style.css file, the WP custom CSS customizer field or via a plugin then your list should be styled correctly on the frontend.

But, we are working with Gutenberg, so you should add your CSS when you register your block to ensure the styling is applied in the backend as well.

To register your CSS along with your style you can do so via 2 methods:

  • Custom Stylesheet: You can pass the “style_handle” property to your register_block_style function with the name of a registered stylesheet. WordPress will automatically load the CSS file when the block is added to the post content.
  • Inline CSS: You can pass the “inline_style” property with the CSS you want applied to your custom block style.

Here is an example showing both methods:

function wpexplorer_register_block_styles_with_css() {
	// Style that loads stylesheet.
	register_block_style(
		'core/list',
		[
			'name'         => 'list-example-one',
			'label'        => 'Example One',
			'style_handle' => 'list-example-one-style-handle'
		]
	);
	// Style that adds inline CSS.
	register_block_style(
		'core/list',
		[
			'name'         => 'list-example-two',
			'label'        => 'Example Two',
			'inline_style' => '.wp-block-list.is-style-list-example-two { list-style: square; }',
		]
	);

}
add_action( 'init', 'wpexplorer_register_block_styles_with_css' );

For most cases, I would recommend using the inline_style property. This will keep your site faster as it won’t need to load a 3rd party dependency. In most cases you should only have a few lines of CSS anyway.

With this knowledge we can go back to the checklist example and add the CSS inline as such:

function wpexplorer_register_checkmark_list_style() {
	register_block_style(
		'core/list',
		[
			'name'         => 'list-checkmark',
			'label'        => 'Checkmark',
			'inline_style' => '@counter-style checkmark {system: cyclic;symbols: "\2713";suffix: " ";}.wp-block-list.is-style-list-checkmark {list-style: checkmark;}'
		]
	);
}
add_action( 'init', 'wpexplorer_register_checkmark_list_style' );

Now if you were to try this checkmark list style out it should render beautifully in both the Gutenberg editor and on the live site. Here is a screenshot taken in the backend.

How to Set a Custom Style as the Default Style

This isn’t something I would necessarily recommend but if you wanted you could also set one of your custom styles as the default. To make your style the default, simply pass the is_default property to your array like such:

register_block_style(
	'core/list',
	[
		'name'       => 'list-new-default',
		'label'      => 'New Default',
		'is_default' => true, // ADD THIS.
	]
);

Now anytime you insert the targeted block (in this case List) your custom style will be used as the default style.

Important: When a custom style is set as the default it means that NO classname will be added to the block when it’s selected.

Bonus: How to Remove a Registered Block Style

Ok, you are now a pro at adding custom block styles. But what if you wanted to remove an existing style from a block? Luckily, WordPress has a helper function we can use for this as well.

To remove an existing block style use the unregister_block_style function. Here is an example showing how to remove the ‘list-checkmark’ style from the ‘core/list’ block:

function wpexplorer_unregister_checkmark_list_style() {
	unregister_block_style( 'core/list', 'list-checkmark' );
}
add_action( 'init', 'wpexplorer_unregister_checkmark_list_style' );

The unregister_block_style is useful primarily for removing styles from a block theme that’s registering custom ones server-side.

Important: Using the unregister_block_style function will ONLY remove blocks that were registered server-side via the register_block_style function. To remove styles added client-side you will need to use the Javascript Block API – keep reading to learn how!

Since you can’t remove core WordPress block styles using PHP I wanted to provide to show you how you can do so using JS. The following example will remove the “outline” style from the Button block:

/**
 * Remove the outline block style.
 */
function wpexplorer_remove_outline_block_style() {
	// Register a "dummy" script so we can add our JS inline.
	wp_register_script(
		'wpexplorer-unregister-block-styles',
		false,
		[ 'wp-blocks', 'wp-dom-ready', 'wp-edit-post' ],
	);

	// JS that removes the outline style from the button element.
	$script = "wp.domReady( () => {
		wp.blocks.unregisterBlockStyle( 'core/button', [ 'outline' ] );
	} );";

	// Load our JS.
	wp_enqueue_script( 'wpexplorer-unregister-block-styles' );
	wp_add_inline_script( 'wpexplorer-unregister-block-styles', $script );
}
add_action( 'admin_init', 'wpexplorer_remove_outline_block_style' );

Conclusion

Adding custom Gutenberg block styles is super easy and also very useful. Here at WPExplorer I register various block styles to elements such as lists, images and buttons. This allows me to display the elements differently based on the context.

Let me know if you’ve had any issues following my guide or if you have any feedback or questions. Simply drop me a comment below.

Further Reading

And now that I’ve got your attention you may be interested in the following related articles:

The post How to Add Custom Block Styles in WordPress appeared first on WPExplorer.

]]>
1
How to Include Custom Field Values in WordPress Search https://www.wpexplorer.com/how-to-include-custom-field-values-in-wordpress-search/ https://www.wpexplorer.com/how-to-include-custom-field-values-in-wordpress-search/#respond Mon, 26 Aug 2024 19:57:04 +0000 https://www.wpexplorer.com/?post_type=wpex_dev_tutorials&p=64787 By default WordPress search works by searching post content and titles. If you have an advanced website where data is store in custom fields, you may want to also search those values. In this guide I will provide you with the code needed to update WordPress so it can search custom fields. All without the […]

The post How to Include Custom Field Values in WordPress Search appeared first on WPExplorer.

]]>
By default WordPress search works by searching post content and titles. If you have an advanced website where data is store in custom fields, you may want to also search those values. In this guide I will provide you with the code needed to update WordPress so it can search custom fields. All without the need for a 3rd party plugin.

If you are not a developer or are scared to add custom code to your website we would recommend using a 3rd party plugin such as SearchWP or Relevanssi. Both of those plugins are completely free but they do offer premium upgrades.

Cautionary note: The code provided in this tutorial will make it so WordPress will use ALL custom field values in the search calculation. Depending on your site this could create a security concern or slow down your search queries.

Why Search Custom Fields

We wrote an article a while back on Why & How to Improve the Internal WordPress Site Search. The article goes over the reasons why you may want to improve the WordPress site search and which plugins are good for the job. So rather then re-iterating everything here, go check out that post.

That said, an example may be a website that has a post type for the organization’s staff members. For your staff members you will likely have custom fields to store data such as their job title, skills, education, etc. So, you may want to include these fields in the WordPress search calculation to make it easier to locate members.

But before modifying how the WordPress search works, take a second to think if you really need to. There are situations where modifying your search results won’t really provide the best user experience. It may be better to create an AJAX filter so users can select values from various fields to limit the posts by.

How to Search by Custom Fields without a Plugin

In order to allow custom field values to be included in WordPress search results we will need to hook into three different filters (one optional). We’ll filter the JOIN, WHERE and DISTINCT clauses for the search query. I’ll walk you through each filter and explain what it’s doing.

Step 1: Filter the JOIN Clause

We’ll start by modifying the JOIN clause via the posts_join filter.

/**
 * Adds the postmeta table to the search query.
 *
 * @link https://www.wpexplorer.com/how-to-include-custom-field-values-in-wordpress-search/
 */
function wpexplorer_search_posts_join( $join, $query ) {
	if ( $query->is_search() ) {
		global $wpdb;
		$join .= " LEFT JOIN {$wpdb->postmeta} ON {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id";
	}
	return $join;
}
add_filter( 'posts_join', 'wpexplorer_search_posts_join', 10, 2 );

By default, WordPress is set up to search only the “posts” table and since custom fields are stored inside their own “postsmeta” table we’ll need to include it in the Query. That’s what the previous snippet does.

Step: 2 Filter the WHERE Clause

Next we’ll filter the WHERE clause by hooking into posts_where hook.

/**
 * Adds meta values to the search query.
 *
 * @link https://www.wpexplorer.com/how-to-include-custom-field-values-in-wordpress-search/
 */
function wpexplorer_search_posts_where( $where, $query ) {
    if ( $query->is_search() ) {
		global $wpdb;
		$where = preg_replace(
			"/\(\s*{$wpdb->posts}.post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
			"({$wpdb->posts}.post_title LIKE $1) OR ({$wpdb->postmeta}.meta_value LIKE $1)",
			$where
		);
    }
    return $where;
}
add_filter( 'posts_where', 'wpexplorer_search_posts_where', 10, 2 );

The previous code tells the WordPress search query to look inside the meta_value columns. Again, this will include all custom fields. If you only want WordPress to search specific fields the code will be much more complex.

Step 3: Filter the DISTINC Clause (optional)

Last we’ll filter the posts_distinct hook.

/**
 * Prevent duplicate posts in search results.
 *
 * @link https://www.wpexplorer.com/how-to-include-custom-field-values-in-wordpress-search/
 */
function wpexplorer_search_posts_distinct( $where, $query ) {
	if ( $query->is_search() ) {
		return "DISTINCT";
	}
	return $where;
}
add_filter( 'posts_distinct', 'wpexplorer_search_posts_distinct', 10, 2 );

This last bit of code prevents duplicate search results if you have custom fields with the same values added to the same post in different fields. This isn’t generally an issue, but it’s worth mentioning in case. It doesn’t really hurt to add the code regardless (at least I don’t think so).

PHP Class & Plugin

To make it easier, I’ve compiled all 3 snippets above into a single class you can add to your site. Using a class will keep the code separate and neatly organized. You can add the code to your child theme functions.php file or a code snippet plugin.

I recommend adding the PHP class inside it’s own file in your child theme and loading it using require. This will keep your code nicely organized instead of having a massive functions.php.

/**
 * Allow searching by custom fields.
 *
 * @link https://www.wpexplorer.com/how-to-include-custom-field-values-in-wordpress-search/
 */
final class Search_By_Custom_Fields {

	/**
	 * Class constructor.
	 */
	public function __construct() {
		add_filter( 'posts_join', [ $this, 'filter_posts_join' ], 10, 2 );
		add_filter( 'posts_where', [ $this, 'filter_posts_where' ], 10, 2 );
		add_filter( 'posts_distinct', [ $this, 'filter_posts_distinct' ], 10, 2 );
	}

	/**
	 * Adds the postmeta table to the search query.
	 */
	public function filter_posts_join( $join, $query ) {
		if ( $query->is_search() ) {
			global $wpdb;
			$join .= " LEFT JOIN {$wpdb->postmeta} ON {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id";
		}
		return $join;
	}

	/**
	 * Adds meta values to the search query.
	 */
	public function filter_posts_where( $where, $query ) {
		if ( $query->is_search() ) {
			global $wpdb;
			$where = preg_replace(
				"/\(\s*{$wpdb->posts}.post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
				"({$wpdb->posts}.post_title LIKE $1) OR ({$wpdb->postmeta}.meta_value LIKE $1)",
				$where
			);
		}
		return $where;
	}

	/**
	 * Prevent duplicate posts in search results.
	 */
	public function filter_posts_distinct( $where, $query ) {
		if ( $query->is_search() ) {
			return "DISTINCT";
		}
		return $where;
	}

}
new Search_By_Custom_Fields();

Download the Plugin

I’ve also added the code above to Github so you can download it as a plugin. This plugin won’t be uploaded to the WordPress repository so it will never get updates. When you download it you can modify the folder name and plugin details to whatever you want.

I prefer creating mini plugins for code like this. By having the code inside a plugin it makes it easier to troubleshoot site issues since you can quickly disable snippets from your site. I actually have over 50 mini plugins on wpexplorer.com that accomplish various tasks.

Conclusion

As you can see including custom field values in the internal WordPress search is easy. I can definitely see some situations where it may be useful. Let me know if you have any issues or questions regarding the code.

Also, I would be curious to see some real world examples of websites using custom fields in their search results to improve user experience. Please share them in the comments!

Further Reading

While you’re here, you may want to read some related tutorials:

The post How to Include Custom Field Values in WordPress Search appeared first on WPExplorer.

]]>
How to Add Custom Columns to the WordPress Users Dashboard https://www.wpexplorer.com/how-to-add-custom-columns-to-the-wordpress-users-dashboard/ https://www.wpexplorer.com/how-to-add-custom-columns-to-the-wordpress-users-dashboard/#respond Sat, 24 Aug 2024 20:47:09 +0000 https://www.wpexplorer.com/?post_type=wpex_dev_tutorials&p=64781 I was recently doing some updates to a website that had hundreds of registered users. The updates required checking to see if a specific user meta field was empty or not. Rather then opening every single user and checking I decided to add a new column to the Users dashboard. This way I could skim […]

The post How to Add Custom Columns to the WordPress Users Dashboard appeared first on WPExplorer.

]]>
I was recently doing some updates to a website that had hundreds of registered users. The updates required checking to see if a specific user meta field was empty or not. Rather then opening every single user and checking I decided to add a new column to the Users dashboard. This way I could skim through the dashboard and quickly locate any user that required updating.

Adding custom/extra columns to the users dashboard can be very useful when managing sites with many users. Displaying data such as the user’s website, social links or even Yoast Seo open graph fields can make it easier to manage user data.

Keep on reading to find out how you can add custom user columns without any 3rd party plugins. The code is very simple and for my example I will be adding a new “website” column to the users screen like the screenshot below:

Adding New Columns to the Users Dashboard

To start, we’ll want to hook into the core WordPress manage_{$screen->id}_columns filter. This filter is used to register new columns to any admin screen. For our purposes we’ll specifically target the “users” screen.

Here is the code to add a new column to the users dashboard:

/**
 * Add new columns to the users dashboard.
 *
 * @link https://www.wpexplorer.com/how-to-add-custom-columns-to-the-wordpress-users-dashboard/
 */
function wpexplorer_add_new_users_columns( $columns ) {
	$new_columns = [
		'website' => esc_html__( 'Website', 'text_domain' ),
	];
	return array_merge( $columns, $new_columns );
}
add_filter( 'manage_users_columns' , 'wpexplorer_add_new_users_columns' );

For my purposes I needed to see if the user’s “website” field was empty or not so in that’s what this example will do. With this code added to your site, if you visit the users dashboard you should see a new “Website” column.

You can add more items to the $new_columns array for all the custom columns you need. The columns will be added to the “end” of the table. If you with sot display your custom columns before the core WP columns you can swap the variables in the array_merge() function.

Populate Your Custom User Dashboard Columns

Now that you know how to add new columns, the next step is to display data for the columns. For this, we are going to hook into the manage_users_custom_column filter. This filter can be used to modify the output for any user dashboard column. So we’ll need to specifically check for the columns we added.

Here is an example of how you would populate the custom “website” field from the previous snippet:

/**
 * Populate new users dashboard columns.
 *
 * @link https://www.wpexplorer.com/how-to-add-custom-columns-to-the-wordpress-users-dashboard/
 */
function wpexplorer_populate_custom_users_columns( $output, $column_name, $user_id ) {
	if ( 'website' === $column_name ) {
		$user_url = get_userdata( $user_id )->user_url ?? '';
		if ( $user_url ) {
			$output = '<a href="' . esc_url( $user_url ) . '">' . esc_html( esc_url( $user_url ) ) . '</a>';
		} else {
			$output = '-';
		}
	}
    return $output;
}
add_filter( 'manage_users_custom_column',  'wpexplorer_populate_custom_users_columns', 10, 3 );

With code added you should now be able to refresh your users dashboard and view their assigned website in the custom website column added previously.

In this example I’ve only checked for the website field, if you are adding multiple fields I would recommend using a switch statement like such:

function wpexplorer_populate_custom_users_columns( $output, $column_name, $user_id ) {
	$user_data = get_userdata( $user_id ); // store user data to use in all custom columns
	switch ( $column_name ) {
		case 'custom_column_1':
			$output = 'Column 1 output';
			break;
		case 'custom_column_2':
			$output = 'Column 2 output';
			break;
		case 'custom_column_3':
			$output = 'Column 3 output';
			break;
	}
    return $output;
}
add_filter( 'manage_users_custom_column',  'wpexplorer_populate_custom_users_columns', 10, 3 );

Conclusion

As you can see it’s very easy to add new columns to the users dashboard. If you have any issues or questions please let me know in the comments! Also, let me know what custom columns you are adding for your WordPress users. I don’t think many websites would ever need to extend the default users dashboard, so I’m curious to know what you are doing!

The post How to Add Custom Columns to the WordPress Users Dashboard appeared first on WPExplorer.

]]>
How to Add Custom Options to the PTU WordPress Plugin https://www.wpexplorer.com/post-types-unlimited-custom-options/ https://www.wpexplorer.com/post-types-unlimited-custom-options/#respond Fri, 23 Aug 2024 01:40:57 +0000 https://www.wpexplorer.com/?post_type=wpex_dev_tutorials&p=64663 The Post Types Unlimited plugin, also known as “PTU”, allows you to easily add custom post types and taxonomies to your WordPress site. I created this plugin because other plugins, such as the popular Custom Post Type UI plugin, are bloated & full of upsells. It is a great add-on for any site that requires […]

The post How to Add Custom Options to the PTU WordPress Plugin appeared first on WPExplorer.

]]>
The Post Types Unlimited plugin, also known as “PTU”, allows you to easily add custom post types and taxonomies to your WordPress site. I created this plugin because other plugins, such as the popular Custom Post Type UI plugin, are bloated & full of upsells. It is a great add-on for any site that requires custom types and/or taxonomies.

In this guide, I will show you how to add custom options to the post type and taxonomy registration screens. This way, you can provide built-in integration for your theme so anyone using it can have more control over their custom post types and taxonomies.

This guide is primarily focused around classic themes, since block themes have access to the site editor where the end user can fully customize their post types and taxonomies.

Why Add Custom Options to the Post Types Unlimited Plugin

As a theme developer you may be wondering why should you add custom options to the PTU plugin. We’ll, by adding options to the plugin you can make it easier for the end user to control the design of their custom post types and taxonomies. My Total Theme is a great example.

Here is a screenshot showing the “Single Post” settings added by the Total theme:

Total WordPress theme post types unlimited single post settings

This provides the user with the following useful fields:

  • Use Blank Template: Enable to usee a blank template for the single post type posts (aka no header/footer)
  • Dynamic Template: Select a template for the single post display.
  • Title: Modifies the default single post page header title text.
  • Title Style: Select the title style (can be used to hide the page header title).
  • Title Tag: Select the page header title HTML tag (h1,h2,h3,h4,h5,h6,div).
  • Layout: Select the layout for the single post type posts (no sidebar, left sidebar, right sidebar, full screen, etc).
  • Next/Previous: Enables the next and previous links at the bottom of the post before the footer (usually disabled when using a dynamic template as you can add the next/prev directly in the dynamic template).

There are actually a lot more settings if a dynamic template isn’t set, but most of the time users will be creating dynamic templates for their post types.

As you can see, when creating custom post types with Total, you will have a lot of control over how the single posts look. Generally, themes are coded so that custom post type archives and single posts always look the same. Total also includes settings for custom taxonomies.

This way, users don’t have to use hooks, filters or template parts to modify their custom post types and taxonomies. This makes it possible for non-developers to create more advanced websites.

How Post Types Unlimited Works

The Post Types Unlimited plugin works using core WordPress functionality. Custom post types and taxonomies are actually registered as post types themselves. And the settings when registering/editing a post type or taxonomy are done via a custom metabox.

Registered custom post types are saved in a custom post type named ptu and custom taxonomies are saved in a custom post type named ptu_tax.

When the page loads the plugin hooks into the init hook to query the ptu and ptu_tax post types, loop through and register them. The custom post types and taxonomies are stored in a class variable so they can be retrieved quickly later.

Retrieving a List of Post Types & Taxonomies

These are the two functions you can use to retrieve the custom post types and taxonomies:

  • \PTU\PostTypes::get_registered_items() – returns an array of post types, where the key is the post type name and the value is the ID of the ptu post type post.
  • \PTU\Taxonomies::get_registered_items() – returns an array of registered taxonomies, where the key is the taxonomy name and the value is the ID of the ptu_tax post type post.

If you need to check or loop through user created custom post types or taxonomies you can use those to public methods.

Retrieving a Post Type or Taxonomy Setting Value

I mentioned previously that the post type and taxonomy settings are done via a metabox, which means they are stored as custom fields. To get the value of any setting you would use the core get_post_meta() function like such:

// Get post type setting value.
get_post_meta( 'post_type_name', '_ptu_{option_id}', true );

// Get taxonomy setting value.
get_post_meta( 'taxonomy_name', '_ptu_{option_id}', true );

The Post Types Unlimited plugin automatically adds a _ptu_ prefix to the custom fields when they are saved. Make sure to include this prefix when getting the value of your own options. I will explain in greater detail with some examples later on.

How to Add Custom Options to the Post Type & Taxonomy Add New/Edit Screens

Adding options is super simple and it’s done by creating new tabs to the default metabox. You can add new tabs to both the post type and the taxonomy new/edit screens. This is done, by hooking into the ptu/posttypes/meta_box_tabs and ptu/taxonomies/meta_box_tab filters.

Here is an example of adding a new tab named “Cool Theme Settings” with a few custom options. This code will add the same settings to both the post type and taxonomy setting pages.

/**
 * Add custom options to the Post Types Unlimited Plugin.
 *
 * @link https://www.wpexplorer.com/post-types-unlimited-custom-options/
 */
function wpexplorer_add_ptu_type_tabs( array $tabs ): array {
	$tabs[] = [
		'id'     => 'themename_settings',
		'title'  => esc_html__( 'Cool Theme Settings', 'themename' ),
		'fields' => [
			[
				'name' => esc_html__( 'Check Option', 'themename' ),
				'id'   => 'check_option',
				'type' => 'checkbox',
			],
			[
				'name' => esc_html__( 'Text Option', 'themename' ),
				'id'   => 'text_option',
				'type' => 'text',
			],
			[
				'name'    => esc_html__( 'Custom Select Option', 'themename' ),
				'id'      => 'select_option',
				'type'    => 'select',
				'choices' => [
					''         => esc_html__( '- Select -', 'themename' ),
					'option_1' => esc_html__( 'Option 1', 'themename' ),
					'option_2' => esc_html__( 'Option 2', 'themename' ),
					'option_3' => esc_html__( 'Option 3', 'themename' ),
				],
			],
			[
				'name' => esc_html__( 'Image Select Option', 'themename' ),
				'id'   => 'image_size_option',
				'type' => 'image_size',
			],
		],
	];
	return $tabs;
}
add_filter( 'ptu/posttypes/meta_box_tabs', 'wpexplorer_add_ptu_type_tabs' );
add_filter( 'ptu/taxonomies/meta_box_tabs', 'wpexplorer_add_ptu_type_tabs' );

This code would add a new tab that looks as follows:

Option Field Types

The sample snippet should be pretty straight forward but it only shows how to add a few field types. Below is a table of all field types with a description and the list of extra arguments that can be added for the type.

Field TypeDescriptionExtra Args
textBasic text field.(bool) required
(int) maxlength
numberNumber type field.(int) step
(int) min
(int) max
textareaTextarea.(int) rows
checkboxCheckbox.
selectCustom select dropdown.(array) choices
multi_selectMultiple checkboxes grouped together.(array) choices
pageSelect option that returns all pages.
image_sizeSelect option that returns all defined image sizes.
taxonomySelect option that returns all registered public taxonomy names.
dashiconDashicon icon select.

Conditional (show/hide) Fields

The metabox class has the ability to show/hide tabs and fields via a condition key. You can add a new condition key to the tab array to control the tab display or to individual options to control the visibility of the option.

The conditional argument works via an array using the following format:

'condition' => [ 'setting_to_check', 'operator', 'value_to_check' ]
  • setting_to_check: (string) setting ID to check the value of.
  • operator: (string) can be “=” or “!=”.
  • value_to_check: (string) the expected value you want to be equal or not equal to.

For example, let’s say you wanted to add a tab that only displays if the post type “public” setting is enabled you can do so like such:

function wpexplorer_add_ptu_type_tabs( array $tabs ): array {
	$tabs[] = [
		'id'        => 'themename_public_settings',
		'title'     => esc_html__( 'Public Settings', 'themename' ),
		'condition' => [ 'public', '=', 'true' ], // !!! CONDITIONAL CHECK !!!
		'fields'    => [ ]
	];
	return $tabs;
}
add_filter( 'ptu/posttypes/meta_box_tabs', 'wpexplorer_add_ptu_type_tabs' );

Or lets say you are adding 2 options but the second option should only display if the first option is enabled. You can do so like such:

function wpexplorer_add_ptu_type_tabs( array $tabs ): array {
	$tabs[] = [
		'id'        => 'themename_public_settings',
		'title'     => esc_html__( 'Public Settings', 'themename' ),
		'fields'    => [
			[
				'name' => esc_html__( 'Check Option', 'themename' ),
				'id'   => 'check_option',
				'type' => 'checkbox',
			],
			[
				'name'      => esc_html__( 'Conditional Text Option', 'themename' ),
				'id'        => 'text_option',
				'type'      => 'text',
				'condition' => [ 'check_option', '=', 'true' ], // !!! CONDITIONAL CHECK !!!
			],
		]
	];
	return $tabs;
}
add_filter( 'ptu/posttypes/meta_box_tabs', 'wpexplorer_add_ptu_type_tabs' );

By using conditional checks you can provide a better user experience if certain options are not needed depending on the value of other options. Just note that the conditional functionality is very minimal and will only allow you to check a single option at a time against a single value.

Retrieving Your Custom Option Values

Now that you know how to add custom options I will explain how to get the value of those options. Earlier I explained that you will use the core get_post_meta() function to grab the value of your fields. But in order to grab the custom field value you need to pass the correct ID based on the post type or taxonomy. I will show you how to do that.

Getting the Value of a Post Type Option

Let’s say you have an option to choose the layout for the custom post type’s single posts and the option ID is “post_layout”. So, in whatever code you are using to get the current post layout, you will want to add an extra check for your custom PTU option.

Here is an example of how to get a post type option value:

if ( is_callable( 'PTU\PostTypes::get_registered_items' ) ) {
	// Get the post type.
	$post_type = get_post_type();

	// Get registered PTU post types.
	$ptu_types = PTU\PostTypes::get_registered_items();

	// Check if the current post type is part of the PTU types.
	if ( isset( $ptu_types[ $post_type ] ) ) {
		$ptu_post_layout = get_post_meta( $ptu_types[ $post_type ], '_ptu_themename_post_layout', true );
	}
}

The code works by checking to see if the current post is a PTU custom post type and if so, it uses get_post_meta to grab the custom field value. Be sure to change themename_post_layout to the ID of the option you are retrieving.

Getting the Value of a Taxonomy Option

Getting the value for a taxonomy option is very similar to that of a custom post type. The difference is you need to run a check against the registered taxonomies.

Here is an example of how to get a taxonomy option value:

if ( is_callable( '\PTU\Taxonomies::get_registered_items' ) ) {
	// Get the current taxonomy.
	$taxonomy = get_query_var( 'taxonomy' );

	// Get registered PTU taxonomies.
	$ptu_taxonomies = PTU\Taxonomies::get_registered_items();

	// Check if the taxonomy is part of the PTU taxonomies.
	if ( isset( $ptu_taxonomies[ $taxonomy ] ) ) {
		$ptu_archive_layout = get_post_meta( $ptu_taxonomies[ $taxonomy ], '_ptu_themename_archive_layout', true );
	}
}

The code works by checking to see if the current taxonomy is a PTU custom taxonomy and if so, it uses get_post_meta to grab the custom field value. Be sure to change themename_archive_layout to the ID of the option you are retrieving.

Creating a Helper Function to Retrieve Options

To follow DRY principles I would recommend adding a helper function to your theme that you can use to get the value of a PTU post type or taxonomy. Post Types Unlimited doesn’t include a helper function because it’s not needed.

Get Post Type Option Value Helper Function

Here is a helper function for returning a post type option value:

/**
 * Get the value of a PTU post type setting.
 */
function themename_get_ptu_meta( string $post_type, string $setting_id, $default = '' ) {
	if ( is_callable( 'PTU\PostTypes::get_registered_items' ) ) {
		$ptu_types = PTU\PostTypes::get_registered_items();
		if ( isset( $ptu_types[ $post_type ] ) ) {
			if ( $default && ! metadata_exists( 'post', $ptu_types[ $post_type ], $setting_id ) ) {
				return $default;
			}
			return get_post_meta( $ptu_types[ $post_type ], $setting_id, true );
		}
	}
}

And here is how you would use the function:

$post_layout = themename_get_ptu_meta( get_post_type(), 'post_layout' );

Get Taxonomy Option Value Helper Function

Here is a helper function for returning a taxonomy option value:

/**
 * Get the value of a PTU taxonomy setting.
 */
function themename_get_ptu_tax_meta( string $taxonomy, string $setting_id, $default = '' ) {
	if ( is_callable( 'PTU\Taxonomies::get_registered_items' ) ) {
		$ptu_taxonomies = PTU\Taxonomies::get_registered_items();
		if ( isset( $ptu_taxonomies[ $taxonomy ] ) ) {
			if ( $default && ! metadata_exists( 'post', $ptu_taxonomies[ $taxonomy ], $setting_id ) ) {
				return $default;
			}
			return get_post_meta( $ptu_taxonomies[ $taxonomy ], $setting_id, true );
		}
	}
}

And here is how you would use the function:

$archive_layout = themename_get_ptu_tax_meta( get_query_var( 'taxonomy' ), 'archive_layout' );

In both helper functions you can see I’ve also added a $default parameter you can use. This will allow you to pass a default value in case custom field doesn’t exist.

Conclusion

Adding options to your theme for the Post Types Unlimited Plugin is super easy and you should do it! Especially if you are selling a premium theme, it would be very nice for your users to be able to add custom post types and taxonomies to their site and have more control over how they look without any coding knowledge.

You could also just stop selling or maintaining your own custom themes and instead become an affiliate of ThemeForest and recommend/use my Total theme.

Let me know in the comments if you have any issues or questions!

The post How to Add Custom Options to the PTU WordPress Plugin appeared first on WPExplorer.

]]>
How to Add a Custom Captcha Field to WordPress Comments https://www.wpexplorer.com/how-to-add-custom-captcha-wordpress-comments/ https://www.wpexplorer.com/how-to-add-custom-captcha-wordpress-comments/#respond Wed, 21 Aug 2024 00:13:33 +0000 https://www.wpexplorer.com/?post_type=wpex_dev_tutorials&p=64649 I recently wrote an article on how to integrate CloudFlare turnstile in WordPress comments and implemented the code here at WPExplorer. However, I think using Turnstile is overkill and loading extra scripts just slows down page loading. So, I decided to code my own custom captcha field and use the Comment Blocklist to see if […]

The post How to Add a Custom Captcha Field to WordPress Comments appeared first on WPExplorer.

]]>
I recently wrote an article on how to integrate CloudFlare turnstile in WordPress comments and implemented the code here at WPExplorer. However, I think using Turnstile is overkill and loading extra scripts just slows down page loading. So, I decided to code my own custom captcha field and use the Comment Blocklist to see if I can prevent comment SPAM without any 3rd party dependencies.

In this article I will provide the code needed to add a custom captcha field to the WordPress comment form. Specifically a field named “What year is it?”. Hopefully bots aren’t smart enough to answer the question.

Step 1: Add a Custom Field to the Comments Form

To add custom fields to the WordPress comments form you can hook into the comment_form_defaults filter. This filter returns an array of comment form fields to which you can add new ones. The filter will work with both classic and block themes.

Here is a code snippet which adds a new field labeled “What Year is It?”:

/**
 * Adds a "What year is it?" field to the WordPress Comments.
 *
 * @link https://www.wpexplorer.com/how-to-add-custom-captcha-wordpress-comments/
 */
function wpexplorer_add_captcha_comment_field( $fields ) {
	$fields['captcha'] = sprintf(
		'<p class="comment-form-captcha">%s %s</p>',
		sprintf(
			'<label for="author">%s %s</label>',
			__( 'What year is it?', 'text_domain' ),
			wp_required_field_indicator()
		),
		'<input id="comment-captcha" name="captcha" size="30" type="text" required>'
	);
	return $fields;
}
add_filter( 'comment_form_default_fields', 'wpexplorer_add_captcha_comment_field' );

If you refresh your site you should see the new field added to your comments form. If you don’t, your site isn’t using the core WordPress comment form and you’ll need to figure out if your theme or a plugin is modifying things.

Step 2: Verify the Custom Captcha on Comment Submission

With the custom captcha field in place, the next step is to validate the input when a comment is submitted. We can hook into the pre_comment_on_post action hook to run any code before WordPress posts a comment.

This is the code I’m using to validate the custom captcha field:

/**
 * Hook into "pre_comment_on_post" to verify our custom captcha.
 *
 * @link https://www.wpexplorer.com/how-to-add-custom-captcha-wordpress-comments/
 */
function wpexplorer_verify_comment_captcha() {
	if ( ! is_user_logged_in() && ( empty( $_POST['captcha'] ) || (int) date( 'Y' ) !== (int) sanitize_text_field( wp_unslash( $_POST['captcha'] ) ) ) ( {
		wp_die(
			'<p>' . __( '<strong>Captcha Error:</strong> Do you not know what year it is?', 'text_domain' ) . '</p>',
			__( 'Comment Submission Failure' ),
			[
				'response'  => 200,
				'back_link' => true,
			]
		);
	}
}
add_filter( 'pre_comment_on_post', 'wpexplorer_verify_comment_captcha' );

This code will check to make sure our captcha field has a value and the value equals the current year as returned by the PHP date() function. If neither of these checks pass we kill execution using the wp_die() function and display a little message.

Conclusion

As you can see, adding a custom captcha field to your WordPress comments is very simple. It only requires a couple functions. Services like Akismet are expensive and most of the free anti-spam plugins are bloated or require 3rd party services like reCaptcha.

I will give this custom captcha field a go on the site and see how it works out. If the site keeps getting comment spam, I will try switching to a honeypot field.

Let me know in the comments how you prevent comment or other SPAM on your site and be sure to check out our list of the best anti spam plugins for WordPress.

The post How to Add a Custom Captcha Field to WordPress Comments appeared first on WPExplorer.

]]>
How to Add Custom Post Types to the WP RSS Feed https://www.wpexplorer.com/how-to-add-custom-post-types-to-rss-feed/ https://www.wpexplorer.com/how-to-add-custom-post-types-to-rss-feed/#respond Tue, 20 Aug 2024 19:20:29 +0000 https://www.wpexplorer.com/?post_type=wpex_dev_tutorials&p=64647 By default the main RSS feed of your WordPress site only includes standard posts. WordPress does create extra feeds for custom post types, but what if you wanted those posts in your main feed? In this tutorial I’ll show you the code needed to include custom post types into the main RSS feed in WordPress. […]

The post How to Add Custom Post Types to the WP RSS Feed appeared first on WPExplorer.

]]>
By default the main RSS feed of your WordPress site only includes standard posts. WordPress does create extra feeds for custom post types, but what if you wanted those posts in your main feed? In this tutorial I’ll show you the code needed to include custom post types into the main RSS feed in WordPress.

Let’s dive straight into the code. We simply need to hook into the request filter which filters the query variables that are passed to the default main SQL query for a given page in WordPress. We’ll need to make sure we are targeting the RSS feed and that the post_type variable hasn’t already been defined.

The code to add a custom post type to your RSS feed looks like this:

/**
 * Modify the RSS feed post types.
 *
 * @link https://www.wpexplorer.com/how-to-add-custom-post-types-to-rss-feed/
 */
add_filter( 'request', function( $query_vars ) {
    if ( isset( $query_vars['feed'] ) && ! isset( $query_vars['post_type'] ) ) {
        $query_vars['post_type'] = [ 'post', 'YOUR_CUSTOM_POST_TYPE_NAME' ];
    }
    return $query_vars;
} );

Make sure to modify where it says YOUR_CUSTOM_POST_TYPE_NAME accordingly. Also, note that what we are doing is setting the value of the post_type variable so we need to return an array of all the post types we want included.

Important RSS Caching Notice: If you add the code snippet to your site and visit your RSS feed you may not see the custom posts included. WordPress caches your RSS feed to keep it fast. In order to clear the cache you can create a new post or save any existing post.

And if you wanted to include all custom post types in your RSS feed instead of returning an array of post types you can use the core get_post_types() function. You can see an example snippet below:

/**
 * Include all custom post types in the main RSS feed.
 *
 * @link https://www.wpexplorer.com/how-to-add-custom-post-types-to-rss-feed/
 */
add_filter( 'request', function( $query_vars ) {
    if ( isset( $query_vars['feed'] ) && ! isset( $query_vars['post_type'] ) ) {
        $query_vars['post_type'] = get_post_types( [ 'public' => true ], 'names' );
    }
    return $query_vars;
} );

Should You Include Custom Posts in the Main RSS Feed?

Whether you should or shouldn’t include custom post types in your main RSS feed really depends on your site. On the Total Theme Documentation site all of the documentation articles are added under a “docs” custom post type. And I don’t add any standard posts to the site. So in this example the RSS feed would be empty by default. Thus, I use a little code to set the RSS feed use the docs post type.

I think in most cases you probably would keep your custom posts separate from the main feed. Posts such as portfolio, staff, testimonials and products don’t make sense added to an RSS feed. I really can’t think of many scenarios where you would need to include custom posts into the main feed.

But, if you do want to include them, it’s easy!

How to Disable a Custom Post Type RSS Feed?

If you’ve decided to include a custom post type into your main RSS feed you may want to remove the post type specific feed. Personally, I use Yoast SEO on all my sites and I generally use their settings that removes all the RSS feeds excerpt the main one like such:

If you are looking for the code to remove a specific post type RSS feed it’s a bit complex because we need to do a couple things.

Disable Feed Permalink Structure for the Post Type

If you are registering your custom post type yourself then you can simply edit your register_post_type function arguments and set the rewrite feed argument to false. Otherwise you can hook into the register_post_type_args filter to modify the post type arguments like such:

/**
 * Remove rss feed permalink structure for a custom post type.
 *
 * @link https://www.wpexplorer.com/how-to-add-custom-post-types-to-rss-feed/
 */
add_filter( 'register_post_type_args', function( $args, $post_type ) {
	if ( 'YOUR_CUSTOM_POST_TYPE_NAME' === $post_type ) {
		if ( ! isset( $args['rewrite'] ) ) {
			$args['rewrite'] = [];
		}
		$args['rewrite']['feeds'] = false;
	}
	return $args;
}, 10, 2 );

By disabling the permalink structure for the post type RSS feeds will make it so if you go to your-site.com/post-type/feed/ the URL will return a 404. Make sure you go go to Settings > Permalinks and re-save the settings to flush your permalinks after adding this code.

Remove <head> Links that Point to the Post Type RSS Feed

Simply removing the feed permalink structure doesn’t actually disable the custom post type feed. WordPress will instead link to the feed using the format: your-site.com/post-type?feed=rss2. So you will want to remove these links for SEO reasons. To remove the meta tags from the site header we can use some code like this:

/**
 * Remove meta links to a custom post type RSS feed.
 *
 * @link https://www.wpexplorer.com/how-to-add-custom-post-types-to-rss-feed/
 */
add_action( 'wp', function() {
	if ( is_post_type_archive( 'YOUR_CUSTOM_POST_TYPE_NAME' ) ) {
		remove_action('wp_head', 'feed_links_extra', 3 );
	}
} );

This code will remove the custom post type RSS feed from the archive. Of course the alternative is to set the has_archive argument when registering your post type to false. Which you would generally do most of the time so that you can use a static page for your custom post type and have more control over the layout.

The post How to Add Custom Post Types to the WP RSS Feed appeared first on WPExplorer.

]]>
Block Theme Anatomy: Structure & Files https://www.wpexplorer.com/block-theme-anatomy/ https://www.wpexplorer.com/block-theme-anatomy/#respond Mon, 19 Aug 2024 22:46:03 +0000 https://www.wpexplorer.com/?post_type=wpex_dev_tutorials&p=64585 So you’ve decided to create a block theme but not sure where to start? In this guide I will give you an overview of a block theme’s file structure. In other words, the block theme “anatomy”. What folders & files can be inside a block theme, which ones are required and what they all do. […]

The post Block Theme Anatomy: Structure & Files appeared first on WPExplorer.

]]>
So you’ve decided to create a block theme but not sure where to start? In this guide I will give you an overview of a block theme’s file structure. In other words, the block theme “anatomy”. What folders & files can be inside a block theme, which ones are required and what they all do.

To start, I recommend you download the twenty twenty four theme. This way you have something you can look at and then modify to create your own block theme.

Important: This guide assumes you are an experienced WordPress developer but are unfamiliar with block themes. Perhaps you have only worked with classic themes in the past. I am also not going to explain how to create and modify block theme files. The purpose of this article is simply to show you what files make up a block theme & what they are used for.

Block Theme Structure

A basic block theme consists of a folder with a style.css file and a templates/index.html file inside. The structure of a more robust theme may look something like the following screenshot taken from our Mesa WPEX theme.

Below you will find various tables with all the required and optional folders and files that make up a WordPress block theme.

Required Folders

The following folders are required inside your block theme:

Folder nameDescription
templatesThis folder contains the main template files. An index.html file is required inside this folder.

Optional Folders

Technically you can add ANY folder inside your block theme. The following are optional folders you can add that WordPress will use for specific purposes.

Folder nameDescription
partsPlace global template parts in this folder.
patternsPlace your custom patterns in this folder.
stylesPlace your custom styles (skins) in this folder.

Required Files

The following files are the ONLY ones required for a block theme to show up in the WordPress admin and function.

File nameDescription
style.cssThis file will contain your theme’s “header” which provides information to WordPress about your theme such as it’s name, description, version, etc. You should review the official style.css documentation on how to properly set up this file.
templates/index.htmlThis is the main file that will be used for the display of any archive, post or page if no alternative template exists.

Required Files for the WordPress.org Repository

The following files are required in your block theme if you plan to upload it to the WordPress repository.

File nameDescription
readme.txtThis file provides theme information to WordPress such as the description, installation instructions, credits, licenses, copyright, changelog and other. I couldn’t find any documentation on the WordPress.org codex for a theme’s readme.txt file but it’s basically the same as the plugin’s readme.txt file.
screenshot.pngThis file is used for the screenshot that displays in the WordPress admin under Appearance > Themes. Even if you are not creating a theme for the WordPress.org repository I would recommend including this file because it looks nicer then a blank square.

Optional Files

Technically speaking ANY file or folder can be added inside your block theme, so keep this in mind. However, there are specific folders and files you can add to your block theme to accomplish various tasks.

File NameDescription
rtl.cssYou can include an rtl.css file in your theme which will automatically load if the website’s language direction is right-to-left. These days, you shouldn’t need this file because you can write direction aware CSS via modern properties. Such as using margin-inline-end instead of margin-right.
theme.jsonThis file is used to define your global settings & styles for your block theme. While this is an optional file, you will likely be creating one for every block theme. See official theme.json docs.
functions.phpThis file is always loaded and can be used to add PHP code to your block theme. You can also use this file to include other PHP files. In a simple block theme you may only be using this file to enqueue the style.css file if the file has actual CSS in it (not needed if your style.css file is used only to define your theme details).
templates/{file-name.html}Above I mentioned that a templates/index.html file is required but you can have other files inside the templates folder to define the layout for different parts of the site. See the section in this article regarding “block theme template files“.
parts/{file-name.html}Inside the parts folder you can include HTML files to register block template parts. These are templates that can be used inside other templates and can be modified globally in the site editor. In a basic block theme you will probably include a parts/header.html and parts/footer.html.
patterns/{file-name.php}If you want to create re-usable template areas (aka patterns) you would place a file for each pattern inside the patterns folder. Note that, patterns are PHP files instead of HTML files.
styles/{file-name}.jsonInside the styles folder you can place JSON files to register “skins” for your theme. Each file is coded the same as the theme.json file with any modifications you want to make for the skin.

Block Theme Template Files List

When creating your block theme you won’t just have a template/index.html file. You will want to create different layouts for the different parts of your site. Below is a list of the different template files you can add to your block theme. WordPress will automatically choose and display the appropriate template based on visited page.

The following template files can be added to your block theme’s templates folder to modify the display of various parts of your site.

File nameDescription
home.htmlFile used for the “home” page. In WordPress the “home” page is the one that displays your latest posts. So, if you are using a static homepage & defined a posts page under Settings > Reading this file will be used for the posts page and not the static one.
singular.htmlFile used when viewing single posts (standard and custom). This is a fallback for the single.html file or single-{post_type} file.
single.htmlFile used for the single post display.
single-{post_type}.htmlFile used when viewing a specific custom post type post.
archive-{post_type}.htmlFile used when viewing a post type archive. This archive will only exist when a the custom post type has_archive parameter is set to true.
page.htmlFile used when viewing a standard page.
category.htmlFile used when viewing a singular category archive.
tag.htmlFile used when viewing a singular tag archive.
author.htmlFile used when viewing an author’s archive.
date.htmlFile used when displaying date based archives such as site.com/2024/. It’s generally recommended to display these archives for SEO reasons.
archive.htmlFile used when displaying a category, tag or date archive if the more specific ones mentioned above don’t exist.
search.htmlFile used for the search results page.
attachment.htmlFile used when viewing a single attachment such as an image or video. It’s recommended to disable these archives for SEO reasons.
image.htmlFile used when displaying a single image page. This file will override the attachment.html file.
404.htmlFile used when displaying a 404 error page.

Block Themes are Simple!

As you can see there are very few files required to create a block theme but there are many optional files. The block theme file and template structure is actually very simple and easy to understand. Hopefully if you were a bit lost, this guide helped you.

Let me know in the comments below if you have any questions or issues.

The post Block Theme Anatomy: Structure & Files appeared first on WPExplorer.

]]>