le_li.
* Default 'linkcat'.
* @type string $category_before The HTML or text to prepend to $title_before if $categorize is true.
* String must contain '%id' and '%class' to inherit the category ID and
* the $class argument used for formatting in themes.
* Default '
'.
* @type string $category_after The HTML or text to append to $title_after if $categorize is true.
* Default ''.
* @type string $category_orderby How to order the bookmark category based on term scheme if $categorize
* is true. Default 'name'.
* @type string $category_order Whether to order categories in ascending or descending order if
* $categorize is true. Accepts 'ASC' (ascending) or 'DESC' (descending).
* Default 'ASC'.
* }
* @return void|string Void if 'echo' argument is true, HTML list of bookmarks if 'echo' is false.
*/
function wp_list_bookmarks( $args = '' ) {
$defaults = array(
'orderby' => 'name',
'order' => 'ASC',
'limit' => -1,
'category' => '',
'exclude_category' => '',
'category_name' => '',
'hide_invisible' => 1,
'show_updated' => 0,
'echo' => 1,
'categorize' => 1,
'title_li' => __( 'Bookmarks' ),
'title_before' => '',
'title_after' => '
',
'category_orderby' => 'name',
'category_order' => 'ASC',
'class' => 'linkcat',
'category_before' => '',
'category_after' => '',
);
$parsed_args = wp_parse_args( $args, $defaults );
$output = '';
if ( ! is_array( $parsed_args['class'] ) ) {
$parsed_args['class'] = explode( ' ', $parsed_args['class'] );
}
$parsed_args['class'] = array_map( 'sanitize_html_class', $parsed_args['class'] );
$parsed_args['class'] = trim( implode( ' ', $parsed_args['class'] ) );
if ( $parsed_args['categorize'] ) {
$cats = get_terms(
array(
'taxonomy' => 'link_category',
'name__like' => $parsed_args['category_name'],
'include' => $parsed_args['category'],
'exclude' => $parsed_args['exclude_category'],
'orderby' => $parsed_args['category_orderby'],
'order' => $parsed_args['category_order'],
'hierarchical' => 0,
)
);
if ( empty( $cats ) ) {
$parsed_args['categorize'] = false;
}
}
if ( $parsed_args['categorize'] ) {
// Split the bookmarks into ul's for each category.
foreach ( (array) $cats as $cat ) {
$params = array_merge( $parsed_args, array( 'category' => $cat->term_id ) );
$bookmarks = get_bookmarks( $params );
if ( empty( $bookmarks ) ) {
continue;
}
$output .= str_replace(
array( '%id', '%class' ),
array( "linkcat-$cat->term_id", $parsed_args['class'] ),
$parsed_args['category_before']
);
/**
* Filters the category name.
*
* @since 2.2.0
*
* @param string $cat_name The category name.
*/
$catname = apply_filters( 'link_category', $cat->name );
$output .= $parsed_args['title_before'];
$output .= $catname;
$output .= $parsed_args['title_after'];
$output .= "\n\t\n";
$output .= _walk_bookmarks( $bookmarks, $parsed_args );
$output .= "\n\t
\n";
$output .= $parsed_args['category_after'] . "\n";
}
} else {
// Output one single list using title_li for the title.
$bookmarks = get_bookmarks( $parsed_args );
if ( ! empty( $bookmarks ) ) {
if ( ! empty( $parsed_args['title_li'] ) ) {
$output .= str_replace(
array( '%id', '%class' ),
array( 'linkcat-' . $parsed_args['category'], $parsed_args['class'] ),
$parsed_args['category_before']
);
$output .= $parsed_args['title_before'];
$output .= $parsed_args['title_li'];
$output .= $parsed_args['title_after'];
$output .= "\n\t\n";
$output .= _walk_bookmarks( $bookmarks, $parsed_args );
$output .= "\n\t
\n";
$output .= $parsed_args['category_after'] . "\n";
} else {
$output .= _walk_bookmarks( $bookmarks, $parsed_args );
}
}
}
/**
* Filters the bookmarks list before it is echoed or returned.
*
* @since 2.5.0
*
* @param string $html The HTML list of bookmarks.
*/
$html = apply_filters( 'wp_list_bookmarks', $output );
if ( $parsed_args['echo'] ) {
echo $html;
} else {
return $html;
}
}
Default empty array.
* @return int|false The Unix timestamp of the next time the event will occur. False if the event doesn't exist.
*/
function wp_next_scheduled( $hook, $args = array() ) {
$next_event = wp_get_scheduled_event( $hook, $args );
if ( ! $next_event ) {
return false;
}
return $next_event->timestamp;
}
/**
* Sends a request to run cron through HTTP request that doesn't halt page loading.
*
* @since 2.1.0
* @since 5.1.0 Return values added.
*
* @param int $gmt_time Optional. Unix timestamp (UTC). Default 0 (current time is used).
* @return bool True if spawned, false if no events spawned.
*/
function spawn_cron( $gmt_time = 0 ) {
if ( ! $gmt_time ) {
$gmt_time = microtime( true );
}
if ( defined( 'DOING_CRON' ) || isset( $_GET['doing_wp_cron'] ) ) {
return false;
}
/*
* Get the cron lock, which is a Unix timestamp of when the last cron was spawned
* and has not finished running.
*
* Multiple processes on multiple web servers can run this code concurrently,
* this lock attempts to make spawning as atomic as possible.
*/
$lock = (float) get_transient( 'doing_cron' );
if ( $lock > $gmt_time + 10 * MINUTE_IN_SECONDS ) {
$lock = 0;
}
// Don't run if another process is currently running it or more than once every 60 sec.
if ( $lock + WP_CRON_LOCK_TIMEOUT > $gmt_time ) {
return false;
}
// Sanity check.
$crons = wp_get_ready_cron_jobs();
if ( empty( $crons ) ) {
return false;
}
$keys = array_keys( $crons );
if ( isset( $keys[0] ) && $keys[0] > $gmt_time ) {
return false;
}
if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) {
if ( 'GET' !== $_SERVER['REQUEST_METHOD'] || defined( 'DOING_AJAX' ) || defined( 'XMLRPC_REQUEST' ) ) {
return false;
}
$doing_wp_cron = sprintf( '%.22F', $gmt_time );
set_transient( 'doing_cron', $doing_wp_cron );
ob_start();
wp_redirect( add_query_arg( 'doing_wp_cron', $doing_wp_cron, wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
echo ' ';
// Flush any buffers and send the headers.
wp_ob_end_flush_all();
flush();
require_once ABSPATH . 'wp-cron.php';
return true;
}
// Set the cron lock with the current unix timestamp, when the cron is being spawned.
$doing_wp_cron = sprintf( '%.22F', $gmt_time );
set_transient( 'doing_cron', $doing_wp_cron );
/**
* Filters the cron request arguments.
*
* @since 3.5.0
* @since 4.5.0 The `$doing_wp_cron` parameter was added.
*
* @param array $cron_request_array {
* An array of cron request URL arguments.
*
* @type string $url The cron request URL.
* @type int $key The 22 digit GMT microtime.
* @type array $args {
* An array of cron request arguments.
*
* @type int $timeout The request timeout in seconds. Default .01 seconds.
* @type bool $blocking Whether to set blocking for the request. Default false.
* @type bool $sslverify Whether SSL should be verified for the request. Default false.
* }
* }
* @param string $doing_wp_cron The unix timestamp of the cron lock.
*/
$cron_request = apply_filters(
'cron_request',
array(
'url' => add_query_arg( 'doing_wp_cron', $doing_wp_cron, site_url( 'wp-cron.php' ) ),
'key' => $doing_wp_cron,
'args' => array(
'timeout' => 0.01,
'blocking' => false,
/** This filter is documented in wp-includes/class-wp-http-streams.php */
'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
),
),
$doing_wp_cron
);
$result = wp_remote_post( $cron_request['url'], $cron_request['args'] );
return ! is_wp_error( $result );
}
/**
* Registers _wp_cron() to run on the {@see 'wp_loaded'} action.
*
* If the {@see 'wp_loaded'} action has already fired, this function calls
* _wp_cron() directly.
*
* Warning: This function may return Boolean FALSE, but may also return a non-Boolean
* value which evaluates to FALSE. For information about casting to booleans see the
* {@link https://www.php.net/manual/en/language.types.boolean.php PHP documentation}. Use
* the `===` operator for testing the return value of this function.
*
* @since 2.1.0
* @since 5.1.0 Return value added to indicate success or failure.
* @since 5.7.0 Functionality moved to _wp_cron() to which this becomes a wrapper.
*
* @return false|int|void On success an integer indicating number of events spawned (0 indicates no
* events needed to be spawned), false if spawning fails for one or more events or
* void if the function registered _wp_cron() to run on the action.
*/
function wp_cron() {
if ( did_action( 'wp_loaded' ) ) {
return _wp_cron();
}
add_action( 'wp_loaded', '_wp_cron', 20 );
}
/**
* Runs scheduled callbacks or spawns cron for all scheduled events.
*
* Warning: This function may return Boolean FALSE, but may also return a non-Boolean
* value which evaluates to FALSE. For information about casting to booleans see the
* {@link https://www.php.net/manual/en/language.types.boolean.php PHP documentation}. Use
* the `===` operator for testing the return value of this function.
*
* @since 5.7.0
* @access private
*
* @return int|false On success an integer indicating number of events spawned (0 indicates no
* events needed to be spawned), false if spawning fails for one or more events.
*/
function _wp_cron() {
// Prevent infinite loops caused by lack of wp-cron.php.
if ( str_contains( $_SERVER['REQUEST_URI'], '/wp-cron.php' )
|| ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON )
) {
return 0;
}
$crons = wp_get_ready_cron_jobs();
if ( empty( $crons ) ) {
return 0;
}
$gmt_time = microtime( true );
$keys = array_keys( $crons );
if ( isset( $keys[0] ) && $keys[0] > $gmt_time ) {
return 0;
}
$schedules = wp_get_schedules();
$results = array();
foreach ( $crons as $timestamp => $cronhooks ) {
if ( $timestamp > $gmt_time ) {
break;
}
foreach ( (array) $cronhooks as $hook => $args ) {
if ( isset( $schedules[ $hook ]['callback'] )
&& ! call_user_func( $schedules[ $hook ]['callback'] )
) {
continue;
}
$results[] = spawn_cron( $gmt_time );
break 2;
}
}
if ( in_array( false, $results, true ) ) {
return false;
}
return count( $results );
}
/**
* Retrieves supported event recurrence schedules.
*
* The default supported recurrences are 'hourly', 'twicedaily', 'daily', and 'weekly'.
* A plugin may add more by hooking into the {@see 'cron_schedules'} filter.
* The filter accepts an array of arrays. The outer array has a key that is the name
* of the schedule, for example 'monthly'. The value is an array with two keys,
* one is 'interval' and the other is 'display'.
*
* The 'interval' is a number in seconds of when the cron job should run.
* So for 'hourly' the time is `HOUR_IN_SECONDS` (60 * 60 or 3600). For 'monthly',
* the value would be `MONTH_IN_SECONDS` (30 * 24 * 60 * 60 or 2592000).
*
* The 'display' is the description. For the 'monthly' key, the 'display'
* would be `__( 'Once Monthly' )`.
*
* For your plugin, you will be passed an array. You can easily add your
* schedule by doing the following.
*
* // Filter parameter variable name is 'array'.
* $array['monthly'] = array(
* 'interval' => MONTH_IN_SECONDS,
* 'display' => __( 'Once Monthly' )
* );
*
* @since 2.1.0
* @since 5.4.0 The 'weekly' schedule was added.
*
* @return array {
* The array of cron schedules keyed by the schedule name.
*
* @type array ...$0 {
* Cron schedule information.
*
* @type int $interval The schedule interval in seconds.
* @type string $display The schedule display name.
* }
* }
*/
function wp_get_schedules() {
$schedules = array(
'hourly' => array(
'interval' => HOUR_IN_SECONDS,
'display' => __( 'Once Hourly' ),
),
'twicedaily' => array(
'interval' => 12 * HOUR_IN_SECONDS,
'display' => __( 'Twice Daily' ),
),
'daily' => array(
'interval' => DAY_IN_SECONDS,
'display' => __( 'Once Daily' ),
),
'weekly' => array(
'interval' => WEEK_IN_SECONDS,
'display' => __( 'Once Weekly' ),
),
);
/**
* Filters the non-default cron schedules.
*
* @since 2.1.0
*
* @param array $new_schedules {
* An array of non-default cron schedules keyed by the schedule name. Default empty array.
*
* @type array ...$0 {
* Cron schedule information.
*
* @type int $interval The schedule interval in seconds.
* @type string $display The schedule display name.
* }
* }
*/
return array_merge( apply_filters( 'cron_schedules', array() ), $schedules );
}
/**
* Retrieves the name of the recurrence schedule for an event.
*
* @see wp_get_schedules() for available schedules.
*
* @since 2.1.0
* @since 5.1.0 {@see 'get_schedule'} filter added.
*
* @param string $hook Action hook to identify the event.
* @param array $args Optional. Arguments passed to the event's callback function.
* Default empty array.
* @return string|false Schedule name on success, false if no schedule.
*/
function wp_get_schedule( $hook, $args = array() ) {
$schedule = false;
$event = wp_get_scheduled_event( $hook, $args );
if ( $event ) {
$schedule = $event->schedule;
}
/**
* Filters the schedule name for a hook.
*
* @since 5.1.0
*
* @param string|false $schedule Schedule for the hook. False if not found.
* @param string $hook Action hook to execute when cron is run.
* @param array $args Arguments to pass to the hook's callback function.
*/
return apply_filters( 'get_schedule', $schedule, $hook, $args );
}
/**
* Retrieves cron jobs ready to be run.
*
* Returns the results of _get_cron_array() limited to events ready to be run,
* ie, with a timestamp in the past.
*
* @since 5.1.0
*
* @return array[] Array of cron job arrays ready to be run.
*/
function wp_get_ready_cron_jobs() {
/**
* Filter to override retrieving ready cron jobs.
*
* Returning an array will short-circuit the normal retrieval of ready
* cron jobs, causing the function to return the filtered value instead.
*
* @since 5.1.0
*
* @param null|array[] $pre Array of ready cron tasks to return instead. Default null
* to continue using results from _get_cron_array().
*/
$pre = apply_filters( 'pre_get_ready_cron_jobs', null );
if ( null !== $pre ) {
return $pre;
}
$crons = _get_cron_array();
$gmt_time = microtime( true );
$results = array();
foreach ( $crons as $timestamp => $cronhooks ) {
if ( $timestamp > $gmt_time ) {
break;
}
$results[ $timestamp ] = $cronhooks;
}
return $results;
}
//
// Private functions.
//
/**
* Retrieves cron info array option.
*
* @since 2.1.0
* @since 6.1.0 Return type modified to consistently return an array.
* @access private
*
* @return array[] Array of cron events.
*/
function _get_cron_array() {
$cron = get_option( 'cron' );
if ( ! is_array( $cron ) ) {
return array();
}
if ( ! isset( $cron['version'] ) ) {
$cron = _upgrade_cron_array( $cron );
}
unset( $cron['version'] );
return $cron;
}
/**
* Updates the cron option with the new cron array.
*
* @since 2.1.0
* @since 5.1.0 Return value modified to outcome of update_option().
* @since 5.7.0 The `$wp_error` parameter was added.
*
* @access private
*
* @param array[] $cron Array of cron info arrays from _get_cron_array().
* @param bool $wp_error Optional. Whether to return a WP_Error on failure. Default false.
* @return bool|WP_Error True if cron array updated. False or WP_Error on failure.
*/
function _set_cron_array( $cron, $wp_error = false ) {
if ( ! is_array( $cron ) ) {
$cron = array();
}
$cron['version'] = 2;
$result = update_option( 'cron', $cron );
if ( $wp_error && ! $result ) {
return new WP_Error(
'could_not_set',
__( 'The cron event list could not be saved.' )
);
}
return $result;
}
/**
* Upgrades a cron info array.
*
* This function upgrades the cron info array to version 2.
*
* @since 2.1.0
* @access private
*
* @param array $cron Cron info array from _get_cron_array().
* @return array An upgraded cron info array.
*/
function _upgrade_cron_array( $cron ) {
if ( isset( $cron['version'] ) && 2 === $cron['version'] ) {
return $cron;
}
$new_cron = array();
foreach ( (array) $cron as $timestamp => $hooks ) {
foreach ( (array) $hooks as $hook => $args ) {
$key = md5( serialize( $args['args'] ) );
$new_cron[ $timestamp ][ $hook ][ $key ] = $args;
}
}
$new_cron['version'] = 2;
update_option( 'cron', $new_cron );
return $new_cron;
}