/wp-includes/bookmark.php

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