Samuel Elh Blog

WordPress, bbPress, BuddyPress, JavaScript tutorials and snippets

Add custom fields to bbpress profile

bbPress is great free and open source plugin for the implementation of forums and user profiles and discussion on a WordPress blog/website or a multisite. It comes with great features out of the box, using WordPress API to build neat and SEO-friendly forums, with many other features.

The many advantages of bbPress is, it is easy to use, and fully extensible for the sake of bringing more features and tools. Today, we’ll go through some easy steps to add additional custom fields to bbPress profile, and displaying them on the user profile, as well as add fields for those in the bbPress profile edit, and handle processing everything.

Add custom fields to bbPress profile edit form

There are so many HTML5 field types you can add as custom fields, from checkbox to Google Maps coordinates, but for the sake of simplicity we’ll keep it simple as possible and go for an example of a simple drop down menu for letting users to select their own cities.

Finding the perfect section in profile edit to parse custom fields:

If you take a look at templates/default/bbpress/form-user-edit.php file located in the bbPress plugin folder, that is actually the code that makes up the profile edit page template. You’ll notice many do_action callback lines, that is the WordPress API used to let us extend the area and add other fields. The point is, I’ll be hooking to a specific hook, but you should always look at that file to find the appropriate hook name to use for you case, so as to parse fields in the appropriate section possible.

Here’s a hook list that might be at your help (it is not a complete one, I focused on the hooks occurring after each section fields since we’re after adding extra custom fields):

  • bbp_user_edit_after_name: Will add fields after the “Name” section in bbPress edit profile
  • bbp_user_edit_after_contact: Will parse fields after “Contact Info” section fields.
  • bbp_user_edit_after_about: Will add fields after “About Yourself” section.
  • bbp_user_edit_after_account: Will add fields after “Account” section.
  •  bbp_user_edit_after_role: Will add fields “User Role” section fields.

You may notice all the hooks point to “after” in the name, there’s also “before” hooks to parse fields before the existing ones, and you can use them as well, I just felt lazy letting them in!

You can and may also register a custom section for your data, either before everything (bbp_user_edit_before) or after (bbp_user_edit_after), and use the same HTML section containers as bbPress to get the matching style, or style your custom section accordingly.

Parse custom field into bbPress profile edit:

Once you have the appropriate action hook, hook it to function callback that prints our custom fields and embeds them. Like I mentioned earlier, I am going to add a drop-down city select for users, so the best section for the case is under “Contact Info”:

add_action( "bbp_user_edit_after_contact", "se_add_city_field" );

function se_add_city_field() {
    // a random selection of cities
    $cities = array( "Seoul", "Mexico City", "Amsterdam", "Mumbai", "Agadir", "Egypt" );
    ?>
    <div>
        <label for="city"><?php _e( 'City', 'my-domain' ); ?></label>
        <select name="city" id="city">
            <option value="">Select City</option>
            <?php foreach ( $cities as $city ) : ?>
                <option><?php echo esc_attr( $city ); ?></option>
            <?php endforeach; ?>
        </select>
    </div>
    <?php
}

Now you’ll probably notice there’s an extra field for city that has just been appended to bbPress profile edit form, below contact info fields:

city field added bbpress

That’s great. Now we are done with the step of appending the field to the edit profile form. Guess next up is processing this field upon user saving their profile and save the right data to the database? carry on.

Process custom fields while saving bbPress profile

This is quite a simple step as bbPress provides hooks to hook into profile saving.

We’ll check if the city field is set and if the city is selected, then save this city into a custom user meta (in the database), otherwise, delete the user meta for city to let the user unset their city by anytime:

// when updating our profile
add_action( "personal_options_update", "se_save_city_value" );
// when updating other users' profiles
add_action( "edit_user_profile_update", "se_save_city_value" );

function se_save_city_value( $user_id ) {
    // exclude profile.php/user-edit update
    if ( is_admin() ) return;
    // update preference
    if ( isset( $_POST['city'] ) && $_POST['city'] ) {
        return update_user_meta( $user_id, "se_city", sanitize_text_field( $_POST['city'] ) );
    } else {
        return delete_user_meta( $user_id, "se_city" );
    }
}

I hooked into two action hooks this time because I noticed bbPress fires the first one only when a user is updating their own profile, while the second one runs when updating others profiles, as any admin can edit other users which makes sense.

Now running the first test, I am selecting a city and saving profile, the city has been saved in a custom user meta with key se_city which we can use later to embed the selected city into user profile, and also to check the selected city in the profile edit screen in the drop-down menu for city:

function se_add_city_field() {
    // a random selection of cities
    $cities = array( "Seoul", "Mexico City", "Amsterdam", "Mumbai", "Agadir", "Egypt" );
    // selected city, if any
    $user_city = bbp_get_displayed_user_field('se_city');
    ?>
    <div>
        <label for="city"><?php _e( 'City', 'my-domain' ); ?></label>
        <select name="city" id="city">
            <option value="">Select City</option>
            <?php foreach ( $cities as $city ) : ?>
                <option <?php selected($user_city,$city); ?>><?php echo esc_attr( $city ); ?></option>
            <?php endforeach; ?>
        </select>
    </div>
    <?php
}

I went back to edit the function se_add_city_field() which embeds the country drop-down in the profile edit screen. To get any kind of user meta while in the bbPress profile, use

bbp_get_displayed_user_field( $meta_key )

where $meta_key is the custom user meta key, let it be ID to get the displayed user ID, or se_city to get the city we just saved (in the database, not in the real world).

I also used selected() to auto select the option that corresponds to the selected city in the drop-down. You can use checked() when dealing with radio buttons or check-boxes, or PHP to add attributes and HTML properly. It is always a neat idea to use the helper functions provided by WordPress for better performance, security and all.

Display custom fields in bbPress user profile

After all, we can say we have added custom fields to bbPress profiles and users can now edit their profiles to input their correct details. We can now embed these custom fields anywhere, let it be in their bbPress profile, in a custom bbPress profile tab, below topic or reply author details for this user, etc, etc.

For the sake of simplicity for this tutorial I am going to parse the city field in the bbPress user profile, and in the topic/reply after author details.

After bbPress user profile:

// add city after user profile details
add_action( "bbp_template_after_user_profile", "se_embed_city_profile" );

function se_embed_city_profile() {
    // selected city, if any
    $user_city = bbp_get_displayed_user_field('se_city');
    // making sure user has set their city first
    if ( !trim( $user_city ) ) return;
    // all good
    return printf(
        '<p>%s is based on <strong>%s</strong></p>',
        esc_attr( bbp_get_displayed_user_field('nickname') ),
        esc_attr( $user_city )
    );
}

I am using the bbPress function bbp_get_displayed_user_field() to get the nickname and all, because it already loads all this users’s meta which makes sense for great performance, and I am taking advantage of that, while you can use other methods to get the displayed user data, such as ID with bbp_get_displayed_user_id(), display name with

get_userdata( bbp_get_displayed_user_id() )->display_name

, etc..

Now here’s a preview of the city field displayed into my bbPress profile on my local installation:

city field bbpress profile

Great! We promised to embed the city below bbPress topics and replies as well, right after the author details, so here we go:

// add city after topic/reply author details
add_action( "bbp_theme_after_reply_author_details", "se_embed_city_forums" );

function se_embed_city_forums() {
    // topic/reply author
    $user_id = bbp_get_reply_author_id();
    // selected city, if any
    $user_city = get_user_meta( $user_id, 'se_city', true );
    // making sure user has set their city first
    if ( !trim( $user_city ) ) return;
    // all good
    return printf(
        '<p>%s is based on <strong>%s</strong></p>',
        esc_attr( bbp_get_displayed_user_field('nickname') ),
        esc_attr( $user_city )
    );
}

This time we use

bbp_get_reply_author_id()

function to get the correct user ID for the topic/reply author, and

get_user_meta()

to get the custom meta saved as city.

Here’s a preview:

city field bbpress topic-reply

Full Tutorial Code

Fin

That is it for this tutorial. I hope that helps. Feel free to discuss below. Thank You!

Using version_compare to run WordPress plugin on minimal PHP requirements

As we know, WordPress can run in an environment with very minimal technical requirements, including an outdated PHP version of 5.2, which was EOL’d couple years ago, and can run as well with the latest PHP software.

As WordPress plugin/theme developers, we get support messages and notifications frequently from users encountering errors and bugs while trying to run our plugin or theme while the minimal technical requirements aren’t met. It is not their fault that they don’t upgrade their PHP software to the min required, but it is actually our fault, could be, just mentioning in the product descriptions or documentation the minimum requirements for the product, and not limiting the code to run only when those requirements are met..

PHP comes with a useful to compare versions, since PHP 4:

version_compare( $version1, $version2, $operator )

And to get the current PHP version you can use

PHP_VERSION

predefined constant.

Using version_compare to run WordPress plugin on the correct requirements

It all depends the style and way you’re coding it. Each PHP component or method or function has a first appear version, so as you develop a plugin or a theme, you know the minimum require PHP version for a perfect setup.

An example is, using namespaces to correctly organize and load your plugin components, the minimum required version for namespaces is 5.3. Also, a good example is anonymous functions, which are introduced in same version also.

It is always handy and a good experience to alert the admin of a custom error on the screen using admin notices API (admin_notices action hook), while an install can not run your plugin correctly.

Here’s a custom notice preview:

admin notice preview

Here’s an example class to compare versions:

/**
  * Compare PHP versions
  * Making sure this blog is running enough required PHP software for
  * our plugin
  */

Class VersionCompare
{
    public $hasRequiredPHP;
    protected $min, $operator;

    public function __construct( $minVersion = '5.3', $operator = '>=' )
    {
        $this->min = $minVersion;
        $this->operator = $operator;

        if ( version_compare(PHP_VERSION, $this->min, $operator) ) {
            $this->hasRequiredPHP = true;
        } else {
            add_action( "admin_notices", array( $this, "notice" ) );
        }
    }

    public function notice()
    {
        printf(
            '<div class="error notice is-dismissible"><p>Plugin Name requires PHP %s %s.</p></div>',
            $this->operator,
            $this->min
        );
    }
}

A simple usage is instantiating the class in a custom variable, with first parameter set the PHP version we’re targeting (falls back to 5.3), and an optional operator which falls back to >= for comparing for greater than or equal our target min. PHP version.

$VersionCompare = new VersionCompare('5.4');

Now

$VersionCompare->hasRequiredPHP

will be set to true if the user has met the targeted version with the specified operator. If not, then, let’s make sure the theme or plugin stops right there and add an elegant error message on the admin screen:

if ( !isset($VersionCompare->hasRequiredPHP) || !$VersionCompare->hasRequiredPHP ) {
    return; // no min server requirements, stop, no more code below will be executed
}

Here, the full class code and a basic usage:

if ( !class_exists('VersionCompare') ) :

/**
  * Compare PHP versions
  * Making sure this blog is running enough required PHP software for
  * our plugin
  */

Class VersionCompare
{
    public $hasRequiredPHP;
    protected $min, $operator;

    public function __construct( $minVersion = '5.3', $operator = '>=' )
    {
        $this->min = $minVersion;
        $this->operator = $operator;

        if ( version_compare(PHP_VERSION, $this->min, $operator) ) {
            $this->hasRequiredPHP = true;
        } else {
            add_action( "admin_notices", array( $this, "notice" ) );
        }
    }

    public function notice()
    {
        printf(
            '<div class="error notice is-dismissible"><p>Plugin Name requires PHP %s %s.</p></div>',
            $this->operator,
            $this->min
        );
    }
}

$VersionCompare = new VersionCompare(); 

if ( !isset($VersionCompare->hasRequiredPHP) || !$VersionCompare->hasRequiredPHP ) {
    return; // no min server requirements, stop it right there
}

endif;

Now it is quite reasonable to add all the previous code to the top of your plugin/theme main loader file, for plugins, add it to the file where you specify the plugin details and properties e.g Plugin Name, Plugin URI..

Here’s an example:

<?php namespace BMC;
/*
Plugin Name: bbPress Messages Compose
Plugin URI: https://github.com/elhardoum/bbpm-compose
Description: bbPress Messages Compose
Author: Samuel Elh
Version: 0.1
Author URI: https://samelh.com
*/

// prevent direct access
defined('ABSPATH') || exit('Direct access not allowed.' . PHP_EOL);

if ( !class_exists('VersionCompare') ) :

/**
  * Compare PHP versions
  * Making sure this blog is running enough required PHP software for
  * our plugin
  */

Class VersionCompare
{
    public $hasRequiredPHP;
    protected $min, $operator;

    public function __construct( $minVersion = '5.3', $operator = '>=' )
    {
        $this->min = $minVersion;
        $this->operator = $operator;

        if ( version_compare(PHP_VERSION, $this->min, $operator) ) {
            $this->hasRequiredPHP = true;
        } else {
            add_action( "admin_notices", array( $this, "notice" ) );
        }
    }

    public function notice()
    {
        printf(
            '<div class="error notice is-dismissible"><p>Plugin Name requires PHP %s %s.</p></div>',
            $this->operator,
            $this->min
        );
    }
}

$VersionCompare = new VersionCompare('5.3'); // namespaces

if ( !isset($VersionCompare->hasRequiredPHP) || !$VersionCompare->hasRequiredPHP ) {
    return; // no min server requirements, stop it right there
}

endif;

use \BMC\Includes\Plugin, \BMC\Includes\Admin;

class BMC
{
    /** Constants **/
    public $constants;

    public function init()
    {
        // define constants
        $this->defineConstants();
    }

    # rest of code ...

There are many other implementations of this, checking for desired other plugins versions, or comparing WordPress version itself (

get_bloginfo('version')

), for making sure.

The point is, stop executing your product code when no minimal requirements are met, so as to avoid any bugs, conflicts, or errors on the screen bugging visitors and attracting attacks from robots. Instead, give a heads up to site admin to upgrade their software, or drop the plugin.

Allow/disallow user registration for email TLD

In this quick tutorial we will learn about allowing or disallowing WordPress user registration from custom TLDs and domain extensions for the user provided email.

You can either choose a set of TLDs and domain extensions to only limit and restrict registration to, or add a list of TLDs to prevent while processing user registration filtering the errors.

There is already Restrict User Registration free WordPress plugin which “Allows you to restrict registration for custom usernames, email addresses and custom email service providers”. This can be handy for denying registrations from specific email addresses or even email domains, so it is useful for this purpose.

Allowing registrations from custom TLDs:

In the following code, make sure to specify the extensions you want user registration to be restricted to, and place them into the array:

$allowed_tlds = array( "be", "nl" ); // allowing Belgium and Netherlands emails

Now as long as my email address is from a BE or NL email service provider site, then I am able to register.

Disallowing registrations from custom TLDs:

This process instead will deny registering users with specific TLDs while leaving the rest allowed. To use this, just add few extensions into the following array in follows-code.

$forbidden_tlds = array();

The code:

After you make your necessary edits, place this code into your child theme’s functions file, or with a custom plugin:

/**
* Plugin Name: Restrict mail TLD registration
* Plugin URI:  http://samelh.com
* Description: Allow/disallow user registration for email TLD
* Author:      Samuel Elh
* Author URI:  http://samelh.com
* Version:     0.1
*/

function se__verify_tld( $email ) {

	/* enter the TLDs to allow into following array, e.g array( "be", "nl", "cr" ) in lowercase */
	$allowed_tlds = array( "be", "nl" ); // allowing Belgium and Netherlands emails

	/* OR, enter few TLDs to prevent (forbidden) in lowercase */
	$forbidden_tlds = array();

	if ( empty( $email ) ) return false;
	$tld = strtolower( substr( $email, strpos( $email, '.' )+1 ) );
	if ( empty( $tld ) ) return true; // no tld caught, trigger error
	else $tld = strtolower( $tld );
	
	if ( !empty( $forbidden_tlds ) ) {
		if ( in_array($tld, $forbidden_tlds) ) {
			return true;
		}
	}

	else if ( !in_array($tld, $allowed_tlds) ) {
		return true;
	}

	return false;

}

add_filter( 'registration_errors', function( $errors, $user_login, $user_email ) {

	if ( se__verify_tld( $user_email ) ) {
		$errors->add( "tld_exception", "Sorry, you can not sign up with emails from this TLD" );
	}

    return $errors;

}, 10, 3 );

preview - Allowdisallow user registration for email TLD

Link to Github gist (downloadable plugin)

bbPress favorites total count by user ID

In this quick tip, we will try to get the total bbPress favorites made for all topics by a specific user, counting total favorites received on every topic this user has posted on the forums.

As if you don’t know, there’s this function bbp_get_topic_favoriters( int $post_ID ) that you can call to get an array of users who have favorite’d this topic we are specifying its POST ID in the first param. That is what we will use to count total bbPress favorites on all topics as we query topics by user ID who is the author of these topics.

We will use WordPress API get_posts to list all topics of the user we’re after.

function se_bbp_total_favorites_by_user( $user_id ) {
	$args = array( 'post_type' => array('topic'), 'author' => $user_id, 'posts_per_page' => -1 );
	$posts = get_posts( $args );
	$count = 0;

	if ( !empty( $posts ) ) {
		foreach ( $posts as $post ) {
			$count += count( bbp_get_topic_favoriters( $post->ID ) );
		}
	}

	return (int) $count;
}

Good, now simply call se_bbp_total_favorites_by_user( 1 ) with the user ID instead of 1 and it should be working perfect.

Caching bbPress favorites:

Please note that you should not always make query to the posts while you can do it in the first time and cache data for a later use with custom expiration interval. Caching is always the best tool out there to minimize the load time, and reduce memory and server ressource usage, and because this is simple enough, let’s just use WordPress transients for non-persistent caching, and set the timeout to a week or 2 days (DAY_IN_SECONDS * 2) or just flush every time a topic gets favorited (I don’t know how to hook into this, guess you’ll have to look into the core files for a custom hook)

Getting All Favorited Topics By User:

I have looked around the usermeta table in PMA of a local install, and I found out that all topics favorites by a user are saved in a custom user meta with the name of wp__bbp_favorites, saved in a comma-separated format. This can be used to list all topics that this user has favorited, as we’ll just look for that meta, explode the commas and we’re all set with the topics IDs.

function se_bbp_favorites_by_user( $user_id ) {
	$meta = get_user_meta( $user_id, "wp__bbp_favorites", 1 );
	if ( $meta ) {
		$meta = explode( ",", $meta );
		$meta = array_filter( $meta );
		if ( !empty( $meta ) ) {
			foreach ( $meta as $i => $topic_id ) {
				$meta[$i] = (int) $topic_id;
				/*
				* you might want to check if this post exists
				* or instead of attaching post ID only, make it post data
				* as $meta[$i] = get_post( $topic_id );
				*/
			}
		}
	} else return array();
	return $meta;
}

For this one, no need to worry about the caching (as long as you keep it simple as is) because by default, WordPress caches the user meta and loads it in memory; the cache will automatically be flushed when the user meta is updated (cool stuff right? WordPress!)

Disable XML-RPC (xmlrpc.php) in WordPress

As the titles states, this quick tutorial will help you disable access to XML-RPC in WordPress, mainly the xmlrpc.php core WordPress file.

If you have looked at some online tutorials and you were not successful to achieving the ban, then basically this tutorial will listen on init hook of WordPress fired upon WordPress initialization (before anything), and check if the current page is xmlrpc.php. If so, emulate an 403 Forbidden error and exit.

The code:

This code should be added to your child theme’s functions file, or through a custom plugin:

add_action("init", function() { 
	global $pagenow; // get current page
	if ( !empty($pagenow) && "xmlrpc.php" === $pagenow ) {
		header("HTTP/1.1 403 Forbidden" ); // Produce 403 error
		exit; // exit request
	} return;
});

blocking xmlrpc wordpress before and after

bbPress Messages – Send automatic welcome messages to new users

bbPress Messages – customizing and extending

Send automatic greeting and welcome messages to new users

In this quick tutorial we are going to talk about how to enable custom messages sent automatically to new user upon a successful registration on our WordPress blog or website.

Required plugins

For this process, you’re going to need:

  • bbPress, the parent plugin of bbPress Messages, for powering forums and communities
  • bbPress Messages: PRO ( v. 0.2.4 or greater), or lite ( v. 0.2.3 or greater ).

That’s all, and no, no BuddyPress is needed or involved.

Extending user registration system

We will be hooking into user_register, which provides us with a user ID for the currently registered user, which we will use to email the user a greeting and welcoming custom message of our own.

Make sure to provide a sender ID, and this is totally required, for the sake of simplicity I made it 1, which will be the first user on your blog and the admin. To find our your user ID, go to users, find your account, and click edit. Now in the address bar there will be something like ?user_id=ID_HERE . That’s the ID you should insert in the sender in follows-code.

 

Using BBP_messages_message::sender method

This method will allow us to insert the message. It takes 4 parameters, 3 required and one optional:

  • $user_id: (int) the recipient which we will direct the message to.
  • $message: (string) the custom message we are sending.
  • $sender: (int) the message sender user ID, which the user will be able to reply to (if possible) later upon login.
  • $notify(bool) choose whether to notify this user by email about this message or not. It defaults to true, but you can set it to false to not email.

The coding:

Add the following code, to your child theme’s functions file or with a custom plugin, and make sure to make necessary edits such as customizing the message and inserting the message sender ID.

add_action("user_register", function( $user_id ) { 
	if ( !class_exists('BBP_messages_message') ) return; // bbPress messages is not there

	$sender = 1; // admin. Please provide a valid user ID
	$message = sprintf(
		"Greetings, %s!\n\nThis is an automated message, sent to greet and thank you for signing up for a membership on our website.\n\nSee you online,\n%s &mdash; %s.",
		get_userdata( $user_id )->display_name,
		get_userdata( $sender )->display_name,
		get_bloginfo( "name" )
	); // message format

	return BBP_messages_message::sender( $user_id, $message, $sender );
});

That’s it. Hope this tutorial helps you greet and welcome your newly registered bbPress users, and point them to use the messaging functionality or provide instructions and so forth..

If you had any issues, please post in the plugin support forum provided provided by the author.

Link WordPress comment author to BuddyPress profile

In this quick tutorial, we will filter the WordPress comment author link URL and point to BuddyPress profile of this author as long as the comment was made by a verified user of your blog.

We can hook into get_comment_author_link for filtering the comment author link, and to get the BuddyPress profile link of a given user, you can use

bp_core_get_user_domain( $user_id )

for this purpose for which you specify a user ID in the first parameter.

The code:

Add the following code to your child theme’s functions file or with a custom plugin:

add_filter('get_comment_author_link', function( $link ) {

	if ( !function_exists('bp_core_get_user_domain') )
		return $link;

    global $comment;
    
    if ( !empty( $comment->user_id ) && !empty( get_userdata( $comment->user_id )->ID ) ) {

   		$link = sprintf(
   			'<a href="%s" rel="external nofollow" class="url">%s</a>',
   			bp_core_get_user_domain( $comment->user_id ),
   			strip_tags( $link )
   		);

    }

    return $link;
});

To make the avatar clickable as well, see how to add Link to WordPress Comment Avatar

Link WordPress comment author to bbPress profile

In this quick tutorial, we will filter the WordPress comment author link URL and point to bbPress profile of this author as long as the comment was made by a verified user of your blog.

We can hook into get_comment_author_link for filtering the comment author link, and to get the bbPress profile link of a given user, you can use

bbp_user_profile_url( $user_id )

for this purpose for which you specify a user ID in the first parameter.

The code:

Add the following code to your child theme’s functions file or with a custom plugin:

add_filter('get_comment_author_link', function( $link ) {

	if ( !function_exists('bbp_user_profile_url') )
		return $link;

    global $comment;
    
    if ( !empty( $comment->user_id ) && !empty( get_userdata( $comment->user_id )->ID ) ) {

   		$link = sprintf(
   			'<a href="%s" rel="external nofollow" class="url">%s</a>',
   			bbp_get_user_profile_url( $comment->user_id ),
   			strip_tags( $link )
   		);

    }

    return $link;
});

To make the avatar clickable as well, see how to add Link to WordPress Comment Avatar

Add Link to WordPress Comment Avatar

In this quick snippet of coding tutorial, we learn about adding an anchor link to WordPress comment avatar.

Link WordPress Comment Avatar

By default, if a user has left a comment on your WordPress blog through a post comment form, they can specify a link to their website, which will be assigned as anchor to the name they specified and displayed within the comments loop, and WordPress does not make this link added to the avatars.

Filtering get_avatar:

Simple work-around for achieving this is by filtering entire get_avatar output, which we will concentrate to apply this only when the queried avatar (gravatar) is used for comments, and this can be achieved by checking the second parameter provided while hooking into get_avatar, if it is a comment identifier, while it can be a user ID, email address or something else.

The coding:

Add the following code to your child theme’s functions file or with a custom plugin:

/**
  * PHP < 5.3 ? use a custom function instead of the anonymous callback
  */

add_filter('get_avatar', function( $avatar, $indent ) {

	/**
	  * check if the current queried avatar is for comments
	  */

	if ( !empty( $indent->comment_ID ) ) { // now that's a comment avatar

		/**
		  * Check if the comment poster has left a link
		  * You can link somewhere else regardless of link availability
		  * by commenting out the if statement lines and specifying a $url
		  * in the sprintf 2nd param, e.g link to bbPress, BuddyPress, author
		  * archives, etc..
		  */

		if ( "" < ( $url = get_comment_author_url( $indent->comment_ID ) ) ) {
			$avatar = sprintf(
	   			'<a href="%s" rel="external nofollow" class="url">%s</a>',
	   			$url,
	   			$avatar
			);
		}

	}

	return $avatar;

}, 10, 2);

That should make the avatar clickable in the comments section and ONLY if the comment author has left and specified a URL in the website comment form field while submitting.

Filter avatar link:

You can link to something else, such as bbPress profile

bbp_get_user_profile_url( $ident->user_id )

or BuddyPress profile

bp_core_get_user_domain( $ident->user_id )

or even to the author archives of this user ( and to know if the comment author is a verified registered user, just check if $ident->user_id is not empty ):

get_author_posts_url( $ident->user_id )

This should always work as long as you’re pulling the comment avatar by the comment ID in your comments output callback function, that if you are overriding the default WordPress’s comments callback.

An effective way of preventing spam registration with JavaScript – WordPress

As I am writing this blog post about preventing spam registration on wordPress, many weblogs out there are getting tons of new accounts registered which belong to robots and are totally untolerated spam.

Preventing Spam Registration on WordPress

There are so many ways out there, free and paid, which would help you knock off spam registration on your WordPress blog or website. One of them is CleanTalk, I love this one as it has a great database of malware checks (blacklist) and many online ready tools to verify a user before it successfully signs up.

But for me, I always prefer not to add another plugin to the load, so if it was to coding a little snippet of script that would help then that would be super. So hopefully this could help out preventing spam registration somehow.

Preventing Spam Registration – JavaScript

As many of you know, or as if you don’t know, spam bots (robots) actually run microsystems that do not have JavaScript running. This means that no DOM JavaScript is available for bots, so we will use this point to add a required (but hidden) field into the user registration form that will work with WordPress nonces too (cool, right?) which will be verified with wp_verify_nonce() function..

Every time the registration screen is requested, the form field for spam check will be added on window load, and it will be required to process the registration.

Important notice – if you are on an environment where your users prefer not to enable JavaScript, then do not use this process OR, notify your users to enable JavaScript in order to register and then switch back to disabled JS mode.

Once the field was not added, the request will be killed with a simple error message:

WordPress are you spamming go back - preventing spam registration

Are you spamming?

Or possibly if you don’t want to kill the request but show a warning message notice instead, comment out wp_die function and remove the comments for $errors->add method usage in the script code; inside se_nospam_register_validate callback function, and this would appear:

bad guy spotted spam registration wordpress - preventing spam registration

Cool! now where can I get the plugin? (no plugin, just some small snippet of non commented code) ; read on.

Preventing Spam Registration on WordPress: The code

You can use the following code to be added to your child theme’s functions file, or download the plugin from Github gist:

<?php
/**
  * Plugin Name: No Spam Registration with JavaScript
  * Plugin URI:  http://blog.samelh.com
  * Description: Prevents spam registration on your WordPress blog/website by adding a necessary form field with JavaScript on document load
  * Author:      Samuel Elh
  * Author URI:  http://samelh.com
  * Version:     0.1
  */
add_action('register_form', 'se_nospam_register_append_input');
add_action('register_post', 'se_nospam_register_validate', 10, 3);
if ( !function_exists('se_nospam_register_append_input') ) :;
function se_nospam_register_append_input()
{
?>
	<script type="text/javascript" id="se_nospam_inline_js">
		window.onload = function() { // it's all about this JS, once JS is loaded, the spamcheck field will be available..
			var e = document.getElementById('se_nospam_inline_js');
			if ( null !== e ) {
				e.outerHTML = '<input id="process-register" type="hidden" name="process-register" value="<?php echo wp_create_nonce( 'se-nospam-register' ); ?>" />';
			} return;
		}
	</script>
<?php
}
endif;
if ( !function_exists('se_nospam_register_validate') ) :;
function se_nospam_register_validate( $login, $email, $errors )
{
	$die_message = apply_filters( "se_nospam_register_error", "Are you spamming?<br/><br/> <a href=\"javascript: window.history.go(-1);\">&laquo; Go back</a>" );
    if( !isset($_POST['process-register']) ) {
    	wp_die( $die_message );
        // or just: $errors->add( 'empty_realname', "<strong>ERROR</strong>: Are you spamming?" );
    }
    else if( empty($_POST['process-register']) )
    {
    	wp_die( $die_message );
        // or just: $errors->add( 'empty_realname', "<strong>ERROR</strong>: Are you spamming?" );
    }
    else if(!wp_verify_nonce($_POST['process-register'], 'se-nospam-register'))
    {
    	wp_die( $die_message );
        // or just: $errors->add( 'empty_realname', "<strong>ERROR</strong>: Are you spamming?" );
    }
    return $errors;
}
endif;

Cool! if preventing spam registration on WordPress with this custom trick has worked for you, then that’s what matters! Yay!! Personally it helped me a lot on my product support forums website where I have bbPress installed for the forums functionality.

Preventing Spam Registration on WordPress: After

Saying that it was helpful to preventing spam registration, there should be more to do after this, right? I mean like, capturing the prevented spam registration attempts and saving some count to the database so you can see a log of how many spam bots were blocked; something like adding this code:

update_option( $name = "se_how_many_spam", ( (int) get_option( $name ) ) + 1 );

That to be added right before each wp_die in the code, And then calling

get_option( "se_how_many_spam" );

to tell how much spam was denied. Also you might want to capture the user IP to block them or something, as long as possible, saying that spam can never be tolerated. (beware, bots will call you agressive then)

Note that this can also be effective on embedded forms like registration forms added with widgets or shortcodes, as the form field for spam check will be added with JavaScript there too.

That is it for this tutorial and I am hoping this helps you as it helped me and if there is any improvements or suggestions and ideas to implement, please feel free to discuss in below comments.

Thank you!

« Older posts

© 2017 Samuel Elh - Powered by WordPress, DigitalOcean & NameCheap

Theme by Anders NorenUp ↑

Subscribe to our mailing list

Sign up to receive updates about WordPress, free and premium plugins and themes in general and tips and tricks

* indicates required