I’ve been searching for a plugin that can track all external links clicked on a blog. Unfortunately the ones that I’ve found are intended to track total clicks per link rather than tracking which user clicked on which link. Is there a plugin that will enable me to track links based on the username?

If not, I can write a script to intercept each click, save the username to a db and then redirect to the correct page. But I need some way to determine username before the link is clicked. Is there a plugin that will enable me to insert a parameter (username) to any url/link in a blog post?

For example: http://myblog.com/myscript.php?url=http%3A//www.google.com&user={{username}}

I’ve looked at the wordpress API and it seems easy enough to retrieve user account info but if I’m linking to a custom script (rather than a wordpress page) which wordpress files do I need to include so that I’ll have access to the WP_User object?

// include “someWordPressFile.php”;
$user = wp_get_current_user();
  • Have jQuery intercept all clicks and to a send a get request to admin-ajax.php. There you can handle the DB update and track the user. Just ignore the _no_priv handler to only trigger for logged in users.
    – jgraup
    Nov 6, 2016 at 20:04

3 Answers 3


I do not know of an existing plugin that does what you want.

Using a custom script is quite difficult, I would not try this. Mainly because you do not know which WP functions you can use/which functions need others to work, ...

If you want to track links then I would use an ajax event send a "click" event to WordPress when someone clicks on a link. Also you do not need to include the username in the URL, since you can always use get_current_user_id() to determine the logged in users ID.

The solution could be a simple script, with this structure:

// 1. Add a javascript for click-tracking on every WordPress page.
add_action( 'wp_footer', 'add_tracking_script' );
function add_tracking_script() {
      function domain(url) {
        return url.replace('http://','').replace('https://','').split('/')[0];

      var local_domain = domain('<?php echo site_url() ?>');

      jQuery('a').on('click', function(){
        var link_url = jQuery(this).attr('href');

        if (domain(link_url) === local_domain) {return true;}
        window.wp.ajax.send('tracking-click', {url: link_url})
        return true;

// 2. Add the ajax handler for the tracking.
add_action( 'wp_ajax_tracking-click', 'ajax_handler_tracking' );
function ajax_handler_tracking() {
  $user_id = get_current_user_id();
  $url = $_REQUEST['url'];

  // Save the user_id + $url to your DB table...



If you get an JS error window.wp.ajax.send is undefined then you also need to add this php code to tell WordPress that you want to use window.wp

// 3. Make sure WordPress loads the window.wp object:
add_action( 'wp_enqueue_scripts', 'add_wp_utils' );
function add_wp_utils() {
    wp_enqueue_script( 'wp-utils' );

FYI: You can find a bit more information on window.wp.ajax in this post https://wordpress.stackexchange.com/a/245275/31140

  • Thank you! Just what I was looking for. Made a couple of changes to the onclick code to skip the domain() function.
    – tium
    Nov 6, 2016 at 21:25
  • How do you have access to window.wp.ajax.send ? I keep getting undefined.
    – jgraup
    Nov 7, 2016 at 16:49
  • @jgraup This function is not always available. you need to add this to your functions.php code: wp_enqueue_scripts( 'wp-utils' ); - this will add the javascript object window.wp to your website
    – Philipp
    Nov 7, 2016 at 18:49
  • @Philipp - that's pretty handy. Are there docs on this script?
    – jgraup
    Nov 7, 2016 at 19:10

I realize someone basically made my comment and added as an answer. Here is a fully working version using the built in REST API for variety. It was a little tricky finding docks on authenticated requests, but this should be a drop in.

// send authorization info
beforeSend: function(xhr) {

    // attach REST nonce for logged in user requests -- otherwise will end up no-priv
    xhr.setRequestHeader ('X-WP-Nonce', '<?php echo wp_create_nonce( 'wp_rest' ); ?>');

On an click to an external link, an ajax call is made to a custom REST route. The link is then added to an array of urls in the users meta and incremented for count data.

After a few external clicks you can check the metadata for the user and see all the clicks and counts.


add_action( 'rest_api_init', function() {

    // namespace of url
    $namespace = 'v2';

    // route
    $base = '/link/count/';

    // register request
    register_rest_route( $namespace, $base, array (

            // hide from discovery
            'show_in_index' => false,

            // only accept POST methods
            'methods'       => 'POST',

            // handler
            'callback'      => 'add_link_count',

            // validate args
            'args' => array(
                'link' => array(
                    'validate_callback' => function($param, $request, $key) {
                        return ! empty( $param );

            // check for logged in users
            'permission_callback' => function () {
               return is_user_logged_in();
    ) );
} );

// only add late in the footer
add_action( 'wp_footer', function() {

    // only add for logged in users
    if ( ! get_current_user_id() ) {
        (function($) {

            // only search for links with data
            $ ('a[href^="http"], a[href^="//"]').each (function() {

                // excluded specific domains
                var excludes = [
                for (i = 0; i < excludes.length; i++) {
                    if (this.href.indexOf (excludes[i]) != -1) {
                        return true; // continue each() with next link

                // filter by domain -- only track external links
                if (this.href.indexOf (location.hostname) == -1) {

                    // attach click event
                    $ (this).click (function(e) {

                        // do ajax call
                        $.ajax ({

                            // send request to REST URL
                            url: '<?php echo esc_js( get_rest_url( null, '/v2/link/count/' ) ); ?>',

                            // use the accepted method - POST
                            method: 'POST',

                            // send authorization info
                            beforeSend: function(xhr) {

                                // attach REST nonce for logged in user requests -- otherwise will end up no-priv
                                xhr.setRequestHeader ('X-WP-Nonce', '<?php echo wp_create_nonce( 'wp_rest' ); ?>');
                            data: {
                                // link to track click count
                                'link': this.href
                        }).done (function(response) {
                            // show response in the console
                            // console.log (response);

                        // block click -- for testing
                        // e.preventDefault();
        } (jQuery));

}, 30 );

// handle the REST url
function add_link_count( $request ) {

    // get the current user
    $user_id = get_current_user_id();

    // check for valid user id > 0
    if ( ! $user_id || $user_id < 1 ) {
        return new WP_REST_Response( 'Unauthorized', 403 );

    // get the link to log
    $link = $request->get_param( 'link' );

    // validate the request
    if( empty($link)) return new WP_REST_Response( 'Bad Request', 400 );

    // pull the previous click data
    $prev = get_user_meta($user_id, 'link_clicks', true);

    // generate if it doesn't already exist
    if( ! $prev || ! is_array($prev)) $prev = array();

    // make sure the value is numeric
    if( ! is_numeric($prev[$link]) ){
        $prev[$link] = 0;

    // increment based on the click

    // update the users metadata
    update_user_meta( $user_id, 'link_clicks', $prev, null );

    // return success response
    return new WP_REST_Response( 'OK', 200 );

To read to clicks back, query for users with click meta data:

function get_clicks_by_user() {
    $args  = array (
        'meta_query' => array (
            array (
                'key'     => 'link_clicks',
                'compare' => 'EXISTS',
    $user_query = new WP_User_Query( $args );
    $users = $user_query->get_results();
    $clicks_by_user = array ();
    foreach ( $users as $user ) {
        $clicks_by_user[ $user->data->user_login ] = get_user_meta( $user->ID, 'link_clicks', true );

    return $clicks_by_user;

And display the results:

echo "<pre>";
print_r(  get_clicks_by_user() );
function user_tracking_script() {
  jQuery('a').on('click', function(){
    var a = jQuery(this)[0];
    if (a.hostname === window.location.hostname) {return true;}
    window.wp.ajax.send('tracking-click', {url: a.hostname})
    return true;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.