ru-se.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

bookmark.php (15332B)


      1 <?php
      2 /**
      3  * Link/Bookmark API
      4  *
      5  * @package WordPress
      6  * @subpackage Bookmark
      7  */
      8 
      9 /**
     10  * Retrieve Bookmark data
     11  *
     12  * @since 2.1.0
     13  *
     14  * @global wpdb $wpdb WordPress database abstraction object.
     15  *
     16  * @param int|stdClass $bookmark
     17  * @param string       $output   Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
     18  *                               correspond to an stdClass object, an associative array, or a numeric array,
     19  *                               respectively. Default OBJECT.
     20  * @param string       $filter   Optional. How to sanitize bookmark fields. Default 'raw'.
     21  * @return array|object|null Type returned depends on $output value.
     22  */
     23 function get_bookmark( $bookmark, $output = OBJECT, $filter = 'raw' ) {
     24 	global $wpdb;
     25 
     26 	if ( empty( $bookmark ) ) {
     27 		if ( isset( $GLOBALS['link'] ) ) {
     28 			$_bookmark = & $GLOBALS['link'];
     29 		} else {
     30 			$_bookmark = null;
     31 		}
     32 	} elseif ( is_object( $bookmark ) ) {
     33 		wp_cache_add( $bookmark->link_id, $bookmark, 'bookmark' );
     34 		$_bookmark = $bookmark;
     35 	} else {
     36 		if ( isset( $GLOBALS['link'] ) && ( $GLOBALS['link']->link_id == $bookmark ) ) {
     37 			$_bookmark = & $GLOBALS['link'];
     38 		} else {
     39 			$_bookmark = wp_cache_get( $bookmark, 'bookmark' );
     40 			if ( ! $_bookmark ) {
     41 				$_bookmark = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->links WHERE link_id = %d LIMIT 1", $bookmark ) );
     42 				if ( $_bookmark ) {
     43 					$_bookmark->link_category = array_unique( wp_get_object_terms( $_bookmark->link_id, 'link_category', array( 'fields' => 'ids' ) ) );
     44 					wp_cache_add( $_bookmark->link_id, $_bookmark, 'bookmark' );
     45 				}
     46 			}
     47 		}
     48 	}
     49 
     50 	if ( ! $_bookmark ) {
     51 		return $_bookmark;
     52 	}
     53 
     54 	$_bookmark = sanitize_bookmark( $_bookmark, $filter );
     55 
     56 	if ( OBJECT === $output ) {
     57 		return $_bookmark;
     58 	} elseif ( ARRAY_A === $output ) {
     59 		return get_object_vars( $_bookmark );
     60 	} elseif ( ARRAY_N === $output ) {
     61 		return array_values( get_object_vars( $_bookmark ) );
     62 	} else {
     63 		return $_bookmark;
     64 	}
     65 }
     66 
     67 /**
     68  * Retrieve single bookmark data item or field.
     69  *
     70  * @since 2.3.0
     71  *
     72  * @param string $field    The name of the data field to return.
     73  * @param int    $bookmark The bookmark ID to get field.
     74  * @param string $context  Optional. The context of how the field will be used.
     75  * @return string|WP_Error
     76  */
     77 function get_bookmark_field( $field, $bookmark, $context = 'display' ) {
     78 	$bookmark = (int) $bookmark;
     79 	$bookmark = get_bookmark( $bookmark );
     80 
     81 	if ( is_wp_error( $bookmark ) ) {
     82 		return $bookmark;
     83 	}
     84 
     85 	if ( ! is_object( $bookmark ) ) {
     86 		return '';
     87 	}
     88 
     89 	if ( ! isset( $bookmark->$field ) ) {
     90 		return '';
     91 	}
     92 
     93 	return sanitize_bookmark_field( $field, $bookmark->$field, $bookmark->link_id, $context );
     94 }
     95 
     96 /**
     97  * Retrieves the list of bookmarks
     98  *
     99  * Attempts to retrieve from the cache first based on MD5 hash of arguments. If
    100  * that fails, then the query will be built from the arguments and executed. The
    101  * results will be stored to the cache.
    102  *
    103  * @since 2.1.0
    104  *
    105  * @global wpdb $wpdb WordPress database abstraction object.
    106  *
    107  * @param string|array $args {
    108  *     Optional. String or array of arguments to retrieve bookmarks.
    109  *
    110  *     @type string   $orderby        How to order the links by. Accepts 'id', 'link_id', 'name', 'link_name',
    111  *                                    'url', 'link_url', 'visible', 'link_visible', 'rating', 'link_rating',
    112  *                                    'owner', 'link_owner', 'updated', 'link_updated', 'notes', 'link_notes',
    113  *                                    'description', 'link_description', 'length' and 'rand'.
    114  *                                    When `$orderby` is 'length', orders by the character length of
    115  *                                    'link_name'. Default 'name'.
    116  *     @type string   $order          Whether to order bookmarks in ascending or descending order.
    117  *                                    Accepts 'ASC' (ascending) or 'DESC' (descending). Default 'ASC'.
    118  *     @type int      $limit          Amount of bookmarks to display. Accepts any positive number or
    119  *                                    -1 for all.  Default -1.
    120  *     @type string   $category       Comma-separated list of category IDs to include links from.
    121  *                                    Default empty.
    122  *     @type string   $category_name  Category to retrieve links for by name. Default empty.
    123  *     @type int|bool $hide_invisible Whether to show or hide links marked as 'invisible'. Accepts
    124  *                                    1|true or 0|false. Default 1|true.
    125  *     @type int|bool $show_updated   Whether to display the time the bookmark was last updated.
    126  *                                    Accepts 1|true or 0|false. Default 0|false.
    127  *     @type string   $include        Comma-separated list of bookmark IDs to include. Default empty.
    128  *     @type string   $exclude        Comma-separated list of bookmark IDs to exclude. Default empty.
    129  *     @type string   $search         Search terms. Will be SQL-formatted with wildcards before and after
    130  *                                    and searched in 'link_url', 'link_name' and 'link_description'.
    131  *                                    Default empty.
    132  * }
    133  * @return object[] List of bookmark row objects.
    134  */
    135 function get_bookmarks( $args = '' ) {
    136 	global $wpdb;
    137 
    138 	$defaults = array(
    139 		'orderby'        => 'name',
    140 		'order'          => 'ASC',
    141 		'limit'          => -1,
    142 		'category'       => '',
    143 		'category_name'  => '',
    144 		'hide_invisible' => 1,
    145 		'show_updated'   => 0,
    146 		'include'        => '',
    147 		'exclude'        => '',
    148 		'search'         => '',
    149 	);
    150 
    151 	$parsed_args = wp_parse_args( $args, $defaults );
    152 
    153 	$key   = md5( serialize( $parsed_args ) );
    154 	$cache = wp_cache_get( 'get_bookmarks', 'bookmark' );
    155 
    156 	if ( 'rand' !== $parsed_args['orderby'] && $cache ) {
    157 		if ( is_array( $cache ) && isset( $cache[ $key ] ) ) {
    158 			$bookmarks = $cache[ $key ];
    159 			/**
    160 			 * Filters the returned list of bookmarks.
    161 			 *
    162 			 * The first time the hook is evaluated in this file, it returns the cached
    163 			 * bookmarks list. The second evaluation returns a cached bookmarks list if the
    164 			 * link category is passed but does not exist. The third evaluation returns
    165 			 * the full cached results.
    166 			 *
    167 			 * @since 2.1.0
    168 			 *
    169 			 * @see get_bookmarks()
    170 			 *
    171 			 * @param array $bookmarks   List of the cached bookmarks.
    172 			 * @param array $parsed_args An array of bookmark query arguments.
    173 			 */
    174 			return apply_filters( 'get_bookmarks', $bookmarks, $parsed_args );
    175 		}
    176 	}
    177 
    178 	if ( ! is_array( $cache ) ) {
    179 		$cache = array();
    180 	}
    181 
    182 	$inclusions = '';
    183 	if ( ! empty( $parsed_args['include'] ) ) {
    184 		$parsed_args['exclude']       = '';  // Ignore exclude, category, and category_name params if using include.
    185 		$parsed_args['category']      = '';
    186 		$parsed_args['category_name'] = '';
    187 
    188 		$inclinks = wp_parse_id_list( $parsed_args['include'] );
    189 		if ( count( $inclinks ) ) {
    190 			foreach ( $inclinks as $inclink ) {
    191 				if ( empty( $inclusions ) ) {
    192 					$inclusions = ' AND ( link_id = ' . $inclink . ' ';
    193 				} else {
    194 					$inclusions .= ' OR link_id = ' . $inclink . ' ';
    195 				}
    196 			}
    197 		}
    198 	}
    199 	if ( ! empty( $inclusions ) ) {
    200 		$inclusions .= ')';
    201 	}
    202 
    203 	$exclusions = '';
    204 	if ( ! empty( $parsed_args['exclude'] ) ) {
    205 		$exlinks = wp_parse_id_list( $parsed_args['exclude'] );
    206 		if ( count( $exlinks ) ) {
    207 			foreach ( $exlinks as $exlink ) {
    208 				if ( empty( $exclusions ) ) {
    209 					$exclusions = ' AND ( link_id <> ' . $exlink . ' ';
    210 				} else {
    211 					$exclusions .= ' AND link_id <> ' . $exlink . ' ';
    212 				}
    213 			}
    214 		}
    215 	}
    216 	if ( ! empty( $exclusions ) ) {
    217 		$exclusions .= ')';
    218 	}
    219 
    220 	if ( ! empty( $parsed_args['category_name'] ) ) {
    221 		$parsed_args['category'] = get_term_by( 'name', $parsed_args['category_name'], 'link_category' );
    222 		if ( $parsed_args['category'] ) {
    223 			$parsed_args['category'] = $parsed_args['category']->term_id;
    224 		} else {
    225 			$cache[ $key ] = array();
    226 			wp_cache_set( 'get_bookmarks', $cache, 'bookmark' );
    227 			/** This filter is documented in wp-includes/bookmark.php */
    228 			return apply_filters( 'get_bookmarks', array(), $parsed_args );
    229 		}
    230 	}
    231 
    232 	$search = '';
    233 	if ( ! empty( $parsed_args['search'] ) ) {
    234 		$like   = '%' . $wpdb->esc_like( $parsed_args['search'] ) . '%';
    235 		$search = $wpdb->prepare( ' AND ( (link_url LIKE %s) OR (link_name LIKE %s) OR (link_description LIKE %s) ) ', $like, $like, $like );
    236 	}
    237 
    238 	$category_query = '';
    239 	$join           = '';
    240 	if ( ! empty( $parsed_args['category'] ) ) {
    241 		$incategories = wp_parse_id_list( $parsed_args['category'] );
    242 		if ( count( $incategories ) ) {
    243 			foreach ( $incategories as $incat ) {
    244 				if ( empty( $category_query ) ) {
    245 					$category_query = ' AND ( tt.term_id = ' . $incat . ' ';
    246 				} else {
    247 					$category_query .= ' OR tt.term_id = ' . $incat . ' ';
    248 				}
    249 			}
    250 		}
    251 	}
    252 	if ( ! empty( $category_query ) ) {
    253 		$category_query .= ") AND taxonomy = 'link_category'";
    254 		$join            = " INNER JOIN $wpdb->term_relationships AS tr ON ($wpdb->links.link_id = tr.object_id) INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_taxonomy_id = tr.term_taxonomy_id";
    255 	}
    256 
    257 	if ( $parsed_args['show_updated'] ) {
    258 		$recently_updated_test = ', IF (DATE_ADD(link_updated, INTERVAL 120 MINUTE) >= NOW(), 1,0) as recently_updated ';
    259 	} else {
    260 		$recently_updated_test = '';
    261 	}
    262 
    263 	$get_updated = ( $parsed_args['show_updated'] ) ? ', UNIX_TIMESTAMP(link_updated) AS link_updated_f ' : '';
    264 
    265 	$orderby = strtolower( $parsed_args['orderby'] );
    266 	$length  = '';
    267 	switch ( $orderby ) {
    268 		case 'length':
    269 			$length = ', CHAR_LENGTH(link_name) AS length';
    270 			break;
    271 		case 'rand':
    272 			$orderby = 'rand()';
    273 			break;
    274 		case 'link_id':
    275 			$orderby = "$wpdb->links.link_id";
    276 			break;
    277 		default:
    278 			$orderparams = array();
    279 			$keys        = array( 'link_id', 'link_name', 'link_url', 'link_visible', 'link_rating', 'link_owner', 'link_updated', 'link_notes', 'link_description' );
    280 			foreach ( explode( ',', $orderby ) as $ordparam ) {
    281 				$ordparam = trim( $ordparam );
    282 
    283 				if ( in_array( 'link_' . $ordparam, $keys, true ) ) {
    284 					$orderparams[] = 'link_' . $ordparam;
    285 				} elseif ( in_array( $ordparam, $keys, true ) ) {
    286 					$orderparams[] = $ordparam;
    287 				}
    288 			}
    289 			$orderby = implode( ',', $orderparams );
    290 	}
    291 
    292 	if ( empty( $orderby ) ) {
    293 		$orderby = 'link_name';
    294 	}
    295 
    296 	$order = strtoupper( $parsed_args['order'] );
    297 	if ( '' !== $order && ! in_array( $order, array( 'ASC', 'DESC' ), true ) ) {
    298 		$order = 'ASC';
    299 	}
    300 
    301 	$visible = '';
    302 	if ( $parsed_args['hide_invisible'] ) {
    303 		$visible = "AND link_visible = 'Y'";
    304 	}
    305 
    306 	$query  = "SELECT * $length $recently_updated_test $get_updated FROM $wpdb->links $join WHERE 1=1 $visible $category_query";
    307 	$query .= " $exclusions $inclusions $search";
    308 	$query .= " ORDER BY $orderby $order";
    309 	if ( -1 != $parsed_args['limit'] ) {
    310 		$query .= ' LIMIT ' . $parsed_args['limit'];
    311 	}
    312 
    313 	$results = $wpdb->get_results( $query );
    314 
    315 	if ( 'rand()' !== $orderby ) {
    316 		$cache[ $key ] = $results;
    317 		wp_cache_set( 'get_bookmarks', $cache, 'bookmark' );
    318 	}
    319 
    320 	/** This filter is documented in wp-includes/bookmark.php */
    321 	return apply_filters( 'get_bookmarks', $results, $parsed_args );
    322 }
    323 
    324 /**
    325  * Sanitizes all bookmark fields.
    326  *
    327  * @since 2.3.0
    328  *
    329  * @param stdClass|array $bookmark Bookmark row.
    330  * @param string         $context  Optional. How to filter the fields. Default 'display'.
    331  * @return stdClass|array Same type as $bookmark but with fields sanitized.
    332  */
    333 function sanitize_bookmark( $bookmark, $context = 'display' ) {
    334 	$fields = array(
    335 		'link_id',
    336 		'link_url',
    337 		'link_name',
    338 		'link_image',
    339 		'link_target',
    340 		'link_category',
    341 		'link_description',
    342 		'link_visible',
    343 		'link_owner',
    344 		'link_rating',
    345 		'link_updated',
    346 		'link_rel',
    347 		'link_notes',
    348 		'link_rss',
    349 	);
    350 
    351 	if ( is_object( $bookmark ) ) {
    352 		$do_object = true;
    353 		$link_id   = $bookmark->link_id;
    354 	} else {
    355 		$do_object = false;
    356 		$link_id   = $bookmark['link_id'];
    357 	}
    358 
    359 	foreach ( $fields as $field ) {
    360 		if ( $do_object ) {
    361 			if ( isset( $bookmark->$field ) ) {
    362 				$bookmark->$field = sanitize_bookmark_field( $field, $bookmark->$field, $link_id, $context );
    363 			}
    364 		} else {
    365 			if ( isset( $bookmark[ $field ] ) ) {
    366 				$bookmark[ $field ] = sanitize_bookmark_field( $field, $bookmark[ $field ], $link_id, $context );
    367 			}
    368 		}
    369 	}
    370 
    371 	return $bookmark;
    372 }
    373 
    374 /**
    375  * Sanitizes a bookmark field.
    376  *
    377  * Sanitizes the bookmark fields based on what the field name is. If the field
    378  * has a strict value set, then it will be tested for that, else a more generic
    379  * filtering is applied. After the more strict filter is applied, if the `$context`
    380  * is 'raw' then the value is immediately return.
    381  *
    382  * Hooks exist for the more generic cases. With the 'edit' context, the {@see 'edit_$field'}
    383  * filter will be called and passed the `$value` and `$bookmark_id` respectively.
    384  *
    385  * With the 'db' context, the {@see 'pre_$field'} filter is called and passed the value.
    386  * The 'display' context is the final context and has the `$field` has the filter name
    387  * and is passed the `$value`, `$bookmark_id`, and `$context`, respectively.
    388  *
    389  * @since 2.3.0
    390  *
    391  * @param string $field       The bookmark field.
    392  * @param mixed  $value       The bookmark field value.
    393  * @param int    $bookmark_id Bookmark ID.
    394  * @param string $context     How to filter the field value. Accepts 'raw', 'edit', 'db',
    395  *                            'display', 'attribute', or 'js'. Default 'display'.
    396  * @return mixed The filtered value.
    397  */
    398 function sanitize_bookmark_field( $field, $value, $bookmark_id, $context ) {
    399 	$int_fields = array( 'link_id', 'link_rating' );
    400 	if ( in_array( $field, $int_fields, true ) ) {
    401 		$value = (int) $value;
    402 	}
    403 
    404 	switch ( $field ) {
    405 		case 'link_category': // array( ints )
    406 			$value = array_map( 'absint', (array) $value );
    407 			// We return here so that the categories aren't filtered.
    408 			// The 'link_category' filter is for the name of a link category, not an array of a link's link categories.
    409 			return $value;
    410 
    411 		case 'link_visible': // bool stored as Y|N
    412 			$value = preg_replace( '/[^YNyn]/', '', $value );
    413 			break;
    414 		case 'link_target': // "enum"
    415 			$targets = array( '_top', '_blank' );
    416 			if ( ! in_array( $value, $targets, true ) ) {
    417 				$value = '';
    418 			}
    419 			break;
    420 	}
    421 
    422 	if ( 'raw' === $context ) {
    423 		return $value;
    424 	}
    425 
    426 	if ( 'edit' === $context ) {
    427 		/** This filter is documented in wp-includes/post.php */
    428 		$value = apply_filters( "edit_{$field}", $value, $bookmark_id );
    429 
    430 		if ( 'link_notes' === $field ) {
    431 			$value = esc_html( $value ); // textarea_escaped
    432 		} else {
    433 			$value = esc_attr( $value );
    434 		}
    435 	} elseif ( 'db' === $context ) {
    436 		/** This filter is documented in wp-includes/post.php */
    437 		$value = apply_filters( "pre_{$field}", $value );
    438 	} else {
    439 		/** This filter is documented in wp-includes/post.php */
    440 		$value = apply_filters( "{$field}", $value, $bookmark_id, $context );
    441 
    442 		if ( 'attribute' === $context ) {
    443 			$value = esc_attr( $value );
    444 		} elseif ( 'js' === $context ) {
    445 			$value = esc_js( $value );
    446 		}
    447 	}
    448 
    449 	// Restore the type for integer fields after esc_attr().
    450 	if ( in_array( $field, $int_fields, true ) ) {
    451 		$value = (int) $value;
    452 	}
    453 
    454 	return $value;
    455 }
    456 
    457 /**
    458  * Deletes the bookmark cache.
    459  *
    460  * @since 2.7.0
    461  *
    462  * @param int $bookmark_id Bookmark ID.
    463  */
    464 function clean_bookmark_cache( $bookmark_id ) {
    465 	wp_cache_delete( $bookmark_id, 'bookmark' );
    466 	wp_cache_delete( 'get_bookmarks', 'bookmark' );
    467 	clean_object_term_cache( $bookmark_id, 'link' );
    468 }