Author profile visitors in last 7 days in front end without plugins

The first thing you need to approach is a counter. You said “author profile” so I assume that you are talking about WP’s author page, which is an archive template identified by is_author(). And I assumed you are counting the number of visits to the author page – not visits to pages/posts by that author (which would make the counter discussed below an entirely different process).

There are some unknowns in your question – like will this only ever be a 7 day counter? Will it only ever count unique IP addresses? etc. So I made the example here fairly generic and somewhat flexible.

The Counter

I chose to store the data in wp_options. Depending on the actual production use, a dedicated table may be appropriate – and you could certainly do more with that. But including that in this answer would be pretty complex. So I made it simple by using the options table. Keep in mind (both you and anyone viewing/using this later) that may not be appropriate in all use cases.

I chose to store a unique option for each author, making the option name “my_author_counter_{ID}” where the ID is the author ID. That way there’s a unique counter for each author – that keeps it from getting too messy and overly large for an option value. If a custom table was handling this, that probably would not be necessary since you could query based on author ID.

So each author counter is an array keyed by the UNIX timestamp value where the array value is the visitor’s IP address. That gives us some raw data that is slightly flexible depending on how you want to display it.

I commented each step of what’s happening in the counter code below:

/**
 * This is your data counter retrieval/update.
 * The actual count evaluation will occur where
 * you actually display the value.
 */
add_action( 'template_redirect', 'my_author_counter' );
function my_author_counter() {

    // Is this an author page?
    if ( is_author() ) {
        global $post, $author_id, $author_counts;

        // Which author is being viewed?
        $author_id = $post->post_author;

        // Counter setting based on author ID.
        $option_name="my_author_counter" . $author_id;

        // Get the counter data.
        $author_counts = get_option( $option_name );

        // Check for empty counter, set as array no value exists.
        $author_counts = ( $author_counts ) ? $author_counts : array();

        // Add current visit to raw data (IP keyed by timestamp).
        $author_counts[ time() ] = $_SERVER['REMOTE_ADDR'];

        /*
         * Didn't know if this would ONLY ever display count over
         * the last 7 days, so it does not include any data removal.
         * With that in mind, this could grow over time to be too 
         * big. So depending on actual production use a expired/old 
         * data removal step should be included before the value is
         * updated in the database. 
         */

        // Save updated count data.
        update_option( $option_name, $author_counts );

    }
}

The counter simply gets the author ID (if we are on an author page), gets the counter for that author, adds the necessary new entry, and saves it. As noted, I did not include a “maintenance” step for removing stale data in case your “7 day” window was generic (i.e. that you might also use a 30 day or something else). Since we’re storing in wp_options and not a dedicated table, you may want to include a process for removing old data at some point without resetting the counter to zero.

The Display

Once you’ve established the counter, you can display wherever and however you want. There are many approaches to this. I’ve just put together one possibility of about a dozen different ideas I had.

I used the get_the_archive_description filter hook to add my counter display to the archive description. Of course that assumes your template uses the function the_archive_description() to display a description under the title in an archive template.

Note again that we use the conditional is_author() to determine if it’s an author page. Otherwise we don’t want our filter to kick in.

Here’s my display filter with explanatory comments:

add_filter( 'get_the_archive_description', 'display_my_author_counter' );
function display_my_author_counter( $content ) {

    // Is this an author page?
    if ( is_author() ) {

        // Global values picked up from my_author_counter().
        global $post, $author_id, $author_counts;

        /** This is where you'd manage the raw data ($author_counts) for display ($display_value). **/

        // Handle raw $author_counts values for desired display.
        // Start with an zero for our display value.
        $display_value = 0;
        // Our counter collects all visits by IP. Get only unique IP addresses.
        $unique_counts = array_unique( $author_counts );
        // Loop through the unique IP values and check the timestamp. Only get the last 7 days.
        foreach ( $unique_counts as $timestamp => $ip ) {
            if ( $timestamp > strtotime( '-7 day' ) ) { 
                // Increment the display count by 1.
                $display_value++;
            }
        }

        /** END manage the raw data ($author_counts) for display ($display_value ). **/

        // Add the display count to the archive description.
        $content = $content . "This author page has been viewed " . $display_value . " times";
    }

    return $content;
}

Like the counter itself, there is a lot of room for different approaches. I’m handling the actual count when we display – that leaves you room to have different displays and values (if desired) depending on where/how it’s used. I’m setting a display count as 0, and then getting only the unique IPs from the

raw stats array. Then looping through that by timestamp, if the stat is from the last 7 days, we increment the display count by 1.

That would give you a display of the number of unique IPs that viewed the author page over the last 7 day.

UPDATE – Calculate Unique IP by Day

Here’s an example of your comment question about unique IPs by day. Rather than repost the entire snippet, this is just the section between the comments in the snippet above where you’ve manage the raw data for display. Hopefully, this shows how you can use this to change how you display the data.

// Start with an zero for our display value.
$display_value = 0;

// Handle a loop for each day, 0 - 7.
for ( $day = 0; $day <= 7; $day++ ) { 

    // Set up an empty container for IPs
    $unique_ips = array();

    // Loop through the unique IP values and check the timestamp. Only get the last 7 days.
    foreach ( $author_counts as $timestamp => $ip ) {
        // Check the day.
        if (  $timestamp > strtotime( '-' . $day . ' day' )  && $timestamp < strtotime( '-' . $day + 1 . ' day' ) ) {
            if ( ! in_array( $ip, $unique_ips ) ) {
                // Add the IP to our unique IP array.
                $unique_ips[] = $ip;
                // Increment our count.
                $display_value++;
            }
        }
    }
}

The idea with this different display is to loop through a “day counter” that we can use for calculating the day (i.e. between day 1 and day 2, then day 2 and day 3, etc). Then we can evaluate each of those for unique IPs. If I coded it right, this should do what you were asking about in the comments.

UPDATE 2 – Delete Unnecessary Stats

As indicated in the counter snippet (the first snippet above), I didn’t insert a process for cleaning out unnecessary/unwanted data. That is something that at some point you would have to address in order to keep the wp_options setting to a manageable size.

I left a section in the codes snippet that could be used for that purpose, depending on what the desired process would be. That could be holding onto data for a week, a month, a year, or whatever.

Here’s a simple example of what you could slip in there to manage removing old data before the option is updated. This would remove any stats from the array that are more than 8 days old (leaving a buffer for the 7 day display we focuses on in the example):

    foreach ( $author_counts as $timestamp => $ip ) {
        if ( $timestamp < strtotime('-8 days') ) {
            unset( $author_counts[ $timestamp ] );
        }           
    }