/**
 * Count a user's relevant actions for a given step
 *
 * @since  1.0.0
 * @param  integer $user_id The given user's ID
 * @param  integer $step_id The given step's ID
 * @return integer          The total activity count
 */
function badgeos_get_step_activity_count($user_id = 0, $step_id = 0)
{
    // Assume the user has no relevant activities
    $activities = array();
    // Grab the requirements for this step
    $step_requirements = badgeos_get_step_requirements($step_id);
    // Determine which type of trigger we're using and return the corresponding activities
    switch ($step_requirements['trigger_type']) {
        case 'specific-achievement':
            // Get our parent achievement
            $parent_achievement = badgeos_get_parent_of_achievement($step_id);
            // If the user has any interaction with this achievement, only get activity since that date
            if ($parent_achievement && ($date = badgeos_achievement_last_user_activity($parent_achievement->ID, $user_id))) {
                $since = $date;
            } else {
                $since = 0;
            }
            // Get our achievement activity
            $achievements = badgeos_get_user_achievements(array('user_id' => absint($user_id), 'achievement_id' => absint($step_requirements['achievement_post']), 'since' => $since));
            $activities = count($achievements);
            break;
        case 'any-achievement':
            $activities = badgeos_get_user_trigger_count($user_id, 'badgeos_unlock_' . $step_requirements['achievement_type']);
            break;
        case 'all-achievements':
            $activities = badgeos_get_user_trigger_count($user_id, 'badgeos_unlock_all_' . $step_requirements['achievement_type']);
            break;
        default:
            $activities = badgeos_get_user_trigger_count($user_id, $step_requirements['trigger_type']);
            break;
    }
    // Available filter for overriding user activity
    return absint(apply_filters('badgeos_step_activity', $activities, $user_id, $step_id));
}
/**
 * Generate HTML markup for an achievement's required steps
 *
 * This will generate an unorderd list (<ul>) if steps are non-sequential
 * and an ordered list (<ol>) if steps require sequentiality.
 *
 * @since  1.0.0
 * @param  array   $steps           An achievement's required steps
 * @param  integer $achievement_id  The given achievement's ID
 * @param  integer $user_id         The given user's ID
 * @return string                   The markup for our list
 */
function badgeos_get_required_achievements_for_achievement_list_markup($steps = array(), $achievement_id = 0, $user_id = 0)
{
    // If we don't have any steps, or our steps aren't an array, return nothing
    if (!$steps || !is_array($steps)) {
        return null;
    }
    // Grab the current post ID if no achievement_id was specified
    if (!$achievement_id) {
        global $post;
        $achievement_id = $post->ID;
    }
    $count = count($steps);
    // If we have no steps, return nothing
    if (!$count) {
        return null;
    }
    // Grab the current user's ID if none was specifed
    if (!$user_id) {
        $user_id = wp_get_current_user()->ID;
    }
    // Setup our variables
    $output = $step_output = '';
    $container = badgeos_is_achievement_sequential() ? 'ol' : 'ul';
    // Concatenate our output
    foreach ($steps as $step) {
        // check if user has earned this Achievement, and add an 'earned' class
        $earned_status = badgeos_get_user_achievements(array('user_id' => absint($user_id), 'achievement_id' => absint($step->ID), 'since' => absint(badgeos_achievement_last_user_activity($achievement_id, $user_id)))) ? 'user-has-earned' : 'user-has-not-earned';
        // get step title and if it doesn't have a title get the step trigger type post-meta
        $title = !empty($step->post_title) ? $step->post_title : get_post_meta($step->ID, '_badgeos_trigger_type', true);
        $step_output .= '<li class="' . apply_filters('badgeos_step_class', $earned_status, $step) . '">' . apply_filters('badgeos_step_title_display', $title, $step) . '</li>';
    }
    $post_type_object = get_post_type_object($step->post_type);
    $output .= '<h4>' . apply_filters('badgeos_steps_heading', sprintf(__('%1$d Required %2$s', 'badgeos'), $count, $post_type_object->labels->name), $steps) . '</h4>';
    $output .= '<' . $container . ' class="badgeos-required-achievements">';
    $output .= $step_output;
    $output .= '</' . $container . '><!-- .badgeos-required-achievements -->';
    // Return our output
    return $output;
}
<?php

add_filter('badgeos_achievement_data_meta_box_fields', function ($fields) {
    $prefix = "_badgeos_";
    $fields[] = array('name' => __('Time limit', 'timelimit-add-on-for-badgeos'), 'desc' => ' ' . __('Number of minutes this badge cannot be earned after it has been awarded. (set to 0 for unlimited).', 'timelimit-add-on-for-badgeos'), 'id' => $prefix . 'time_limit', 'type' => 'text_small', 'std' => '0');
    return $fields;
});
add_filter('user_deserves_achievement', function ($return, $user_id, $achievement_id) {
    // If we're not working with a step, bail
    if ('step' != get_post_type($achievement_id)) {
        return $return;
    }
    // grab the achievement
    $parent_achievement = badgeos_get_parent_of_achievement($achievement_id);
    if (!$parent_achievement) {
        return $return;
    }
    $achievement_id = $parent_achievement->ID;
    $timelimit = absint(get_post_meta($achievement_id, '_badgeos_time_limit', true));
    $last_activity = badgeos_achievement_last_user_activity(absint($achievement_id), absint($user_id));
    if ($timelimit && $last_activity && time() - $last_activity < $timelimit * 60) {
        return false;
    }
    return $return;
}, 15, 3);