MS_Rule_Media_Model

Rule model.

Defined (1)

The class is defined in the following location(s).

/app/rule/media/class-ms-rule-media-model.php  
  1. class MS_Rule_Media_Model extends MS_Rule { 
  2.  
  3. /** 
  4. * Rule type. 
  5. * @since 1.0.0 
  6. * @var string $rule_type 
  7. */ 
  8. protected $rule_type = MS_Rule_Media::RULE_ID; 
  9.  
  10. /** 
  11. * Media protection type constants. 
  12. * @since 1.0.0 
  13. * @var string $protection_type 
  14. */ 
  15. const PROTECTION_TYPE_BASIC = 'protection_type_basic'; 
  16. const PROTECTION_TYPE_COMPLETE = 'protection_type_complete'; 
  17. const PROTECTION_TYPE_HYBRID = 'protection_type_hybrid'; 
  18.  
  19. /** 
  20. * Media protection file change prefix. 
  21. * @since 1.0.0 
  22. * @var string 
  23. */ 
  24. const FILE_PROTECTION_PREFIX = 'ms_'; 
  25.  
  26. /** 
  27. * Media protection file seed/token. 
  28. * @since 1.0.0 
  29. * @var string 
  30. */ 
  31. const FILE_PROTECTION_INCREMENT = 2771; 
  32.  
  33. /** 
  34. * Returns the active flag for a specific rule. 
  35. * State depends on Add-on 
  36. * @since 1.0.0 
  37. * @return bool 
  38. */ 
  39. static public function is_active() { 
  40. return MS_Model_Addon::is_enabled( MS_Model_Addon::ADDON_MEDIA ); 
  41.  
  42.  
  43. /** 
  44. * Verify access to the current content. 
  45. * This rule will return NULL (not relevant), because the media-item is 
  46. * protected via the download URL and not by protecting the current page. 
  47. * @since 1.0.0 
  48. * @param string $id The content id to verify access. 
  49. * @return bool|null True if has access, false otherwise. 
  50. * Null means: Rule not relevant for current page. 
  51. */ 
  52. public function has_access( $id, $admin_has_access = true ) { 
  53. return null; 
  54.  
  55. /** 
  56. * Get the protection type available. 
  57. * @since 1.0.0 
  58. * @return array { 
  59. * The protection type => Description. 
  60. * @type string $protection_type The media protection type. 
  61. * @type string $description The media protection description. 
  62. * } 
  63. */ 
  64. public static function get_protection_types() { 
  65. $settings = MS_Factory::load( 'MS_Model_Settings' ); 
  66. $mask = $settings->downloads['masked_url']; 
  67. $example1 = MS_Helper_Utility::home_url( $mask . date( '/Y/m/' ) . 'my-image.jpg' ); 
  68. $example2 = MS_Helper_Utility::home_url( $mask . '/ms_12345.jpg' ); 
  69. $example3 = MS_Helper_Utility::home_url( $mask . '/?ms_file=ms_12345.jpg' ); 
  70. $example1 = '<br /><small>' . __( 'Example:', 'membership2' ) . ' ' . $example1 . '</small>'; 
  71. $example2 = '<br /><small>' . __( 'Example:', 'membership2' ) . ' ' . $example2 . '</small>'; 
  72. $example3 = '<br /><small>' . __( 'Example:', 'membership2' ) . ' ' . $example3 . '</small>'; 
  73.  
  74. $protection_types = array( 
  75. self::PROTECTION_TYPE_BASIC => __( 'Basic protection (default)', 'membership2' ) . $example1,  
  76. self::PROTECTION_TYPE_COMPLETE => __( 'Complete protection', 'membership2' ) . $example2,  
  77. self::PROTECTION_TYPE_HYBRID => __( 'Hybrid protection', 'membership2' ) . $example3,  
  78. ); 
  79.  
  80. return apply_filters( 
  81. 'ms_rule_media_model_get_protection_types',  
  82. $protection_types 
  83. ); 
  84.  
  85. /** 
  86. * Validate protection type. 
  87. * @since 1.0.0 
  88. * @param string $type The protection type to validate. 
  89. * @return boolean True if is valid. 
  90. */ 
  91. public static function is_valid_protection_type( $type ) { 
  92. $valid = false; 
  93. $types = self::get_protection_types(); 
  94.  
  95. if ( array_key_exists( $type, $types ) ) { 
  96. $valid = true; 
  97.  
  98. return apply_filters( 
  99. 'ms_rule_media_model_is_valid_protection_type',  
  100. $valid 
  101. ); 
  102.  
  103. /** 
  104. * Starts the output buffering to replace all links in the final HTML 
  105. * document. 
  106. * Related filter: 
  107. * - init 
  108. * @since 1.0.0 
  109. */ 
  110. public function buffer_start() { 
  111. ob_start( array( $this, 'protect_download_content' ) ); 
  112.  
  113. /** 
  114. * Ends the output buffering and calls the output_callback function. 
  115. * Related filter: 
  116. * - shutdown 
  117. * @since 1.0.0 
  118. */ 
  119. public function buffer_end() { 
  120. if ( ob_get_level() ) { 
  121. ob_end_flush(); 
  122.  
  123. /** 
  124. * Set initial protection. 
  125. * @since 1.0.0 
  126. */ 
  127. public function initialize() { 
  128. parent::protect_content(); 
  129.  
  130. if ( MS_Model_Addon::is_enabled( MS_Model_Addon::ADDON_MEDIA ) ) { 
  131. // Start buffering during init action, though output should only 
  132. // happen a lot later... This way we're save. 
  133. $this->add_action( 'init', 'buffer_start' ); 
  134.  
  135. // Process the buffer right in the end. 
  136. $this->add_action( 'shutdown', 'buffer_end' ); 
  137.  
  138. $this->add_action( 'parse_request', 'handle_download_protection', 3 ); 
  139.  
  140. /** 
  141. * Protect media file. 
  142. * Search content and mask media filename and path. 
  143. * This function is called as output_callback for ob_start() - as a result 
  144. * we cannot echo/output anything in this function! The return value of the 
  145. * function will be displayed to the user. 
  146. * @since 1.0.0 
  147. * @param string $the_content The content before filter. 
  148. * @return string The content with masked media url. 
  149. */ 
  150. public function protect_download_content( $the_content ) { 
  151. do_action( 
  152. 'ms_rule_media_model_protect_download_content_before',  
  153. $the_content,  
  154. $this 
  155. ); 
  156.  
  157. $download_settings = MS_Plugin::instance()->settings->downloads; 
  158.  
  159. if ( ! MS_Model_Addon::is_enabled( MS_Model_Addon::ADDON_MEDIA ) ) { 
  160. return $the_content; 
  161.  
  162. $upload_dir = wp_upload_dir(); 
  163. $original_url = trailingslashit( $upload_dir['baseurl'] ); 
  164. $new_path = trailingslashit( 
  165. trailingslashit( get_option( 'home' ) ) . 
  166. $download_settings['masked_url'] 
  167. ); 
  168.  
  169. /** 
  170. * Find all the urls in the post and then we'll check if they are protected 
  171. * Regex from http://blog.mattheworiordan.com/post/13174566389/url-regular-expression-for-links-with-or-without-the 
  172. */ 
  173. $url_exp = '/((([A-Za-z]{3, 9}:(?:\/\/)?)' . 
  174. '(?:[-;:&=\+\$, \w]+@)?'. 
  175. '[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$, \w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?' . 
  176. '\??(?:[-\+=&;%@.\w_]*)#?(?:[.\!\/\\w]*))?)/'; 
  177.  
  178. $matches = array(); 
  179. if ( preg_match_all( $url_exp, $the_content, $matches ) ) { 
  180. $home = untrailingslashit( get_option( 'home' ) ); 
  181.  
  182. /** 
  183. * $matches[0] .. Full link 'http://example.com/blog/img.png?ver=1' 
  184. * $matches[1] .. Full link 'http://example.com/blog/img.png?ver=1' 
  185. * $matches[2] .. Domain only 'http://example.com' 
  186. * $matches[3] .. Protocol 'http://' 
  187. * $matches[4] .. File path '/blog/img.png?ver=1' 
  188. */ 
  189. if ( ! empty( $matches ) && ! empty( $matches[2] ) ) { 
  190. $links = (array) $matches[0]; 
  191. $paths = (array) $matches[4]; 
  192.  
  193. foreach ( $links as $key => $link ) { 
  194. // Ignore all external links 
  195. if ( 0 !== strpos( $link, $home ) ) { continue; } 
  196.  
  197. // The file is on local site - is it a valid attachment? 
  198. $file = basename( $paths[ $key ] ); 
  199. $post_id = $this->get_attachment_id( $link ); 
  200.  
  201. // Ignore links that have no relevant wp_posts entry. 
  202. if ( empty( $post_id ) ) { continue; } 
  203. $f_info = $this->extract_file_info( $file ); 
  204.  
  205. // We have a protected file - so we'll mask it! 
  206. switch ( $download_settings['protection_type'] ) { 
  207. case self::PROTECTION_TYPE_COMPLETE: 
  208. $protected_filename = self::FILE_PROTECTION_PREFIX . 
  209. ( $post_id + (int) self::FILE_PROTECTION_INCREMENT ) . 
  210. $f_info->size_extension . 
  211. '.' . pathinfo( $f_info->filename, PATHINFO_EXTENSION ); 
  212.  
  213. $the_content = str_replace( 
  214. $link,  
  215. $new_path . $protected_filename,  
  216. $the_content 
  217. ); 
  218. break; 
  219.  
  220. case self::PROTECTION_TYPE_HYBRID: 
  221. $protected_filename = self::FILE_PROTECTION_PREFIX . 
  222. ($post_id + (int) self::FILE_PROTECTION_INCREMENT ) . 
  223. $f_info->size_extension . 
  224. '.' . pathinfo( $f_info->filename, PATHINFO_EXTENSION ); 
  225.  
  226. $the_content = str_replace( 
  227. $link,  
  228. $new_path . '?ms_file=' . $protected_filename,  
  229. $the_content 
  230. ); 
  231. break; 
  232.  
  233. case self::PROTECTION_TYPE_BASIC: 
  234. default: 
  235. $the_content = str_replace( 
  236. $link,  
  237. str_replace( 
  238. $original_url,  
  239. $new_path,  
  240. $link 
  241. ),  
  242. $the_content 
  243. ); 
  244. break; 
  245.  
  246. return apply_filters( 
  247. 'ms_rule_media_model_protect_download_content',  
  248. $the_content,  
  249. $this 
  250. ); 
  251.  
  252. /** 
  253. * Extract filename and size extension info. 
  254. * @since 1.0.0 
  255. * @param string $file The filename to extract info from. 
  256. * @return array { 
  257. * @type string $filename The filename. 
  258. * @type string $size_extension The wordpress thumbnail size extension. Default empty. 
  259. * } 
  260. */ 
  261. public function extract_file_info( $file ) { 
  262. // See if the filename has a size extension and if so, strip it out 
  263. $filename_exp_full = '/(.+)\-(\d+[x]\d+)\.(.+)$/'; 
  264. $filename_exp_min = '/(.+)\.(.+)$/'; 
  265. $filematch = array(); 
  266.  
  267. if ( preg_match( $filename_exp_full, $file, $filematch ) ) { 
  268. // Image with an image size attached 
  269. $type = strtolower( $filematch[3] ); 
  270. $filename = $filematch[1] . '.' . $type; 
  271. $size_extension = '-' . $filematch[2]; 
  272. } elseif ( preg_match( $filename_exp_min, $file, $filematch ) ) { 
  273. // Image without an image size definition 
  274. $type = strtolower( $filematch[2] ); 
  275. $filename = $filematch[1] . '.' . $type; 
  276. $size_extension = ''; 
  277. } else { 
  278. // Image without an extension. 
  279. $type = ''; 
  280. $filename = $file; 
  281. $size_extension = ''; 
  282.  
  283. $info = (object) array( 
  284. 'filename' => $filename,  
  285. 'size_extension' => $size_extension,  
  286. 'type' => $type,  
  287. ); 
  288.  
  289. return apply_filters( 
  290. 'ms_rule_media_model_extract_file_info',  
  291. $info,  
  292. $file,  
  293. $this 
  294. ); 
  295.  
  296. /** 
  297. * Get attachment post_id using the filename. 
  298. * @since 1.0.0 
  299. * @param string $filename The filename to obtain the post_id. 
  300. * @return int The post ID or 0 if not found. 
  301. */ 
  302. public function get_attachment_id( $url ) { 
  303. static $Uploads_Url = null; 
  304. static $Uploads_Url_Len = 0; 
  305. global $wpdb; 
  306.  
  307. // First let WordPress try to find the Attachment ID. 
  308. $id = url_to_postid( $url ); 
  309.  
  310. if ( $id ) { 
  311. // Make sure the result ID is a valid attachment ID. 
  312. if ( 'attachment' != get_post_type( $id ) ) { 
  313. $id = 0; 
  314. } else { 
  315. // Manual attempt: Get the filename from the URL and use a custom query. 
  316.  
  317. if ( null === $Uploads_Url ) { 
  318. $uploads = wp_upload_dir(); 
  319. $Uploads_Url = trailingslashit( $uploads['baseurl'] ); 
  320. $Uploads_Url_Len = strlen( $Uploads_Url ); 
  321.  
  322. if ( false !== strpos( $url, $Uploads_Url ) ) { 
  323. $url = substr( $url, $Uploads_Url_Len ); 
  324.  
  325. // See if we cached that URL already. 
  326. $id = wp_cache_get( $url, 'ms_attachment_id' ); 
  327.  
  328. if ( empty( $id ) ) { 
  329. $sql = " 
  330. SELECT wposts.ID 
  331. FROM $wpdb->posts wposts 
  332. INNER JOIN $wpdb->postmeta wpostmeta ON wposts.ID = wpostmeta.post_id 
  333. WHERE 
  334. wposts.post_type = 'attachment' 
  335. AND wpostmeta.meta_key = '_wp_attached_file' 
  336. AND wpostmeta.meta_value = %s 
  337. "; 
  338. $sql = $wpdb->prepare( $sql, $url ); 
  339. $id = $wpdb->get_var( $sql ); 
  340.  
  341. wp_cache_set( $url, $id, 'ms_attachment_id' ); 
  342.  
  343. return apply_filters( 
  344. 'ms_rule_get_attachment_id',  
  345. absint( $id ),  
  346. $url,  
  347. $this 
  348. ); 
  349.  
  350. /** 
  351. * Handle protected media access. 
  352. * Search for masked file and show the proper content, or no access image if don't have access. 
  353. * Realted Action Hooks: 
  354. * - parse_request 
  355. * @since 1.0.0 
  356. * @param WP_Query $query The WP_Query object to filter. 
  357. */ 
  358. public function handle_download_protection( $query ) { 
  359. do_action( 
  360. 'ms_rule_media_model_handle_download_protection_before',  
  361. $query,  
  362. $this 
  363. ); 
  364.  
  365. $the_file = false; 
  366. $requested_item = false; 
  367. $download_settings = MS_Plugin::instance()->settings->downloads; 
  368. $protection_type = $download_settings['protection_type']; 
  369.  
  370. if ( ! MS_Model_Addon::is_enabled( MS_Model_Addon::ADDON_MEDIA ) ) { 
  371. return; 
  372.  
  373. if ( ! empty( $query->query_vars['protectedfile'] ) ) { 
  374. $requested_item = explode( '/', $query->query_vars['protectedfile'] ); 
  375. $requested_item = array_pop( $requested_item ); 
  376. } elseif ( ! empty( $_GET['ms_file'] ) 
  377. && self::PROTECTION_TYPE_HYBRID == $protection_type 
  378. ) { 
  379. $requested_item = $_GET['ms_file']; 
  380.  
  381. if ( ! empty( $requested_item ) ) { 
  382. // At this point we know that the requested post is an attachment. 
  383. $f_info = $this->extract_file_info( $requested_item ); 
  384.  
  385. switch ( $protection_type ) { 
  386. case self::PROTECTION_TYPE_COMPLETE: 
  387. case self::PROTECTION_TYPE_HYBRID: 
  388. // Work out the post_id again 
  389. $attachment_id = preg_replace( 
  390. '/^' . self::FILE_PROTECTION_PREFIX . '/',  
  391. '',  
  392. $f_info->filename 
  393. ); 
  394. $attachment_id -= (int) self::FILE_PROTECTION_INCREMENT; 
  395.  
  396. $the_file = $this->restore_filename( $attachment_id, $f_info->size_extension ); 
  397. break; 
  398.  
  399. default: 
  400. case self::PROTECTION_TYPE_BASIC: 
  401. $home = untrailingslashit( get_option( 'home' ) ); 
  402. $attachment_id = $this->get_attachment_id( $home . $f_info->filename ); 
  403. $the_file = $this->restore_filename( $attachment_id, $f_info->size_extension ); 
  404. break; 
  405.  
  406. if ( ! empty( $the_file ) 
  407. && ! empty( $attachment_id ) 
  408. && is_numeric( $attachment_id ) 
  409. ) { 
  410. if ( $this->can_access_file( $attachment_id ) ) { 
  411. $upload_dir = wp_upload_dir(); 
  412. $file = trailingslashit( $upload_dir['basedir'] ) . $the_file; 
  413. $this->output_file( $file ); 
  414. } else { 
  415. $this->show_no_access_image(); 
  416.  
  417. do_action( 
  418. 'ms_rule_media_model_handle_download_protection_after',  
  419. $query,  
  420. $this 
  421. ); 
  422.  
  423. /** 
  424. * Checks if the current user can access the specified attachment. 
  425. * @since 1.0.0 
  426. * @param int $attachment_id 
  427. * @return bool 
  428. */ 
  429. public function can_access_file( $attachment_id ) { 
  430. $access = false; 
  431.  
  432. if ( MS_Model_Member::is_normal_admin() ) { 
  433. return true; 
  434.  
  435. /** 
  436. * Default protection mode: 
  437. * Protect Attachments based on the parent post. 
  438. */ 
  439. $parent_id = get_post_field( 'post_parent', $attachment_id ); 
  440.  
  441. if ( ! $parent_id ) { 
  442. $access = true; 
  443. } else { 
  444. $member = MS_Model_Member::get_current_member(); 
  445. foreach ( $member->subscriptions as $subscription ) { 
  446. $membership = $subscription->get_membership(); 
  447. $access = $membership->has_access_to_post( $parent_id ); 
  448. if ( $access ) { break; } 
  449.  
  450. return apply_filters( 
  451. 'ms_rule_media_can_access_file',  
  452. $access,  
  453. $attachment_id 
  454. ); 
  455.  
  456. /** 
  457. * Restore filename from post_id. 
  458. * @since 1.0.0 
  459. * @todo refactory hack to get extension. 
  460. * @param int $post_id The attachment post_id. 
  461. * @param string $size_extension The image size extension. 
  462. * @return string The attachment filename. 
  463. */ 
  464. public function restore_filename( $post_id, $size_extension ) { 
  465. $img_filename = null; 
  466.  
  467. if ( ! empty( $post_id ) && is_numeric( $post_id ) ) { 
  468. $img_filename = get_post_meta( $post_id, '_wp_attached_file', true ); 
  469. if ( ! empty( $size_extension ) ) { 
  470. // Add back in a size extension if we need to 
  471. $img_filename = str_replace( 
  472. '.' . pathinfo( $img_filename, PATHINFO_EXTENSION ),  
  473. $size_extension . '.' . pathinfo( $img_filename, PATHINFO_EXTENSION ),  
  474. $img_filename 
  475. ); 
  476.  
  477. // hack to remove any double extensions :/ need to change when work out a neater way 
  478. $img_filename = str_replace( 
  479. $size_extension . $size_extension,  
  480. $size_extension,  
  481. $img_filename 
  482. ); 
  483.  
  484. return apply_filters( 
  485. 'ms_rule_restore_filename',  
  486. $img_filename,  
  487. $post_id,  
  488. $this 
  489. ); 
  490.  
  491. /** 
  492. * Output file to the browser. 
  493. * @since 1.0.0 
  494. * @param string $file The complete path to the file. 
  495. */ 
  496. private function output_file( $file ) { 
  497. do_action( 'ms_rule_media_model_output_file_before', $file, $this ); 
  498.  
  499. if ( ! is_file( $file ) ) { 
  500. status_header( 404 ); 
  501. die( '404 — File not found.' ); 
  502.  
  503. $mime = wp_check_filetype( $file ); 
  504. if ( empty( $mime['type'] ) && function_exists( 'mime_content_type' ) ) { 
  505. $mime['type'] = mime_content_type( $file ); 
  506.  
  507. if ( $mime['type'] ) { 
  508. $mimetype = $mime['type']; 
  509. } else { 
  510. $mimetype = 'image/' . substr( $file, strrpos( $file, '.' ) + 1 ); 
  511.  
  512. header( 'Content-type: ' . $mimetype ); 
  513. if ( false === strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS' ) ) { 
  514. header( 'Content-Length: ' . filesize( $file ) ); 
  515.  
  516. $last_modified = gmdate( 'D, d M Y H:i:s', filemtime( $file ) ); 
  517. $etag = '"' . md5( $last_modified ) . '"'; 
  518. header( "Last-Modified: $last_modified GMT" ); 
  519. header( 'ETag: ' . $etag ); 
  520. header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + 100000000 ) . ' GMT' ); 
  521.  
  522. // Support for Conditional GET 
  523. if ( isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ) { 
  524. $client_etag = stripslashes( $_SERVER['HTTP_IF_NONE_MATCH'] ); 
  525. } else { 
  526. $client_etag = false; 
  527.  
  528. if ( ! isset( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) { 
  529. $_SERVER['HTTP_IF_MODIFIED_SINCE'] = false; 
  530.  
  531. $client_last_modified = trim( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ); 
  532. // If string is empty, return 0. If not, attempt to parse into a timestamp 
  533. $client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0; 
  534.  
  535. // Make a timestamp for our most recent modification... 
  536. $modified_timestamp = strtotime( $last_modified ); 
  537.  
  538. if ( $client_last_modified && $client_etag ) { 
  539. $valid_etag = ( $client_modified_timestamp >= $modified_timestamp ) 
  540. && ( $client_etag === $etag ); 
  541. } else { 
  542. $valid_etag = ( $client_modified_timestamp >= $modified_timestamp ) 
  543. || ( $client_etag === $etag ); 
  544.  
  545. if ( $valid_etag ) { 
  546. status_header( 304 ); 
  547. exit; 
  548.  
  549. // If we made it this far, just serve the file 
  550. readfile( $file ); 
  551.  
  552. do_action( 'ms_rule_media_model_output_file_after', $file, $this ); 
  553.  
  554. die(); 
  555.  
  556. /** 
  557. * Show no access image. 
  558. * @since 1.0.0 
  559. */ 
  560. private function show_no_access_image() { 
  561. $no_access_file = apply_filters( 
  562. 'ms_rule_media_model_show_no_access_image_path',  
  563. MS_Plugin::instance()->dir . 'app/assets/images/no-access.png' 
  564. ); 
  565.  
  566. $this->output_file( $no_access_file ); 
  567.  
  568. do_action( 'ms_rule_show_no_access_image_after', $this ); 
  569.  
  570. /** 
  571. * Get content to protect. 
  572. * @since 1.0.0 
  573. * @param $args The query post args 
  574. * @see @link http://codex.wordpress.org/Class_Reference/WP_Query 
  575. * @return array The contents array. 
  576. */ 
  577. public function get_contents( $args = null ) { 
  578. $args = self::get_query_args( $args ); 
  579. $posts = get_posts( $args ); 
  580.  
  581. $contents = array(); 
  582. foreach ( $posts as $content ) { 
  583. $content->id = $content->ID; 
  584. $content->type = MS_Rule_Media::RULE_ID; 
  585. $content->name = $content->post_name; 
  586. $content->access = $this->can_access_file( $content->id ); 
  587.  
  588. $contents[ $content->id ] = $content; 
  589.  
  590. return apply_filters( 
  591. 'ms_rule_media_model_get_contents',  
  592. $contents,  
  593. $args,  
  594. $this 
  595. ); 
  596.  
  597. /** 
  598. * Get the total content count. 
  599. * @since 1.0.0 
  600. * @param $args The query post args 
  601. * @see @link http://codex.wordpress.org/Class_Reference/WP_Query 
  602. * @return int The total content count. 
  603. */ 
  604. public function get_content_count( $args = null ) { 
  605. $args = self::get_query_args( $args ); 
  606. $query = new WP_Query( $args ); 
  607.  
  608. $count = $query->found_posts; 
  609.  
  610. return apply_filters( 
  611. 'ms_rule_media_model_get_content_count',  
  612. $count,  
  613. $args 
  614. ); 
  615.  
  616. /** 
  617. * Get the default query args. 
  618. * @since 1.0.0 
  619. * @param string $args The query post args. 
  620. * @see @link http://codex.wordpress.org/Class_Reference/WP_Query 
  621. * @return array The parsed args. 
  622. */ 
  623. public function get_query_args( $args = null ) { 
  624. $defaults = array( 
  625. 'orderby' => 'post_date',  
  626. 'order' => 'DESC',  
  627. 'post_type' => 'attachment',  
  628. 'post_status' => 'any',  
  629. ); 
  630. $args = wp_parse_args( $args, $defaults ); 
  631.  
  632. return parent::prepare_query_args( $args, 'get_posts' );