PageRenderTime 52ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/broken-link-checker/modules/containers/comment.php

https://bitbucket.org/lgorence/quickpress
PHP | 427 lines | 270 code | 55 blank | 102 comment | 48 complexity | 3e54a172238893b620ca98056743fa63 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, AGPL-1.0
  1. <?php
  2. /*
  3. Plugin Name: Comments
  4. Description:
  5. Version: 1.0
  6. Author: Janis Elsts
  7. ModuleID: comment
  8. ModuleCategory: container
  9. ModuleClassName: blcCommentManager
  10. */
  11. class blcComment extends blcContainer{
  12. /**
  13. * Retrieve the comment wrapped by this container.
  14. * The fetched object will also be cached in the $wrapped_object variable.
  15. *
  16. * @access protected
  17. *
  18. * @param bool $ensure_consistency
  19. * @return object The comment.
  20. */
  21. function get_wrapped_object($ensure_consistency = false){
  22. if( $ensure_consistency || is_null($this->wrapped_object) ){
  23. $this->wrapped_object = &get_comment($this->container_id);
  24. }
  25. return $this->wrapped_object;
  26. }
  27. /**
  28. * Update the comment wrapped by the container with values currently in the $wrapped_object.
  29. *
  30. * @access protected
  31. *
  32. * @return bool|WP_Error True on success, an error if something went wrong.
  33. */
  34. function update_wrapped_object(){
  35. if ( is_null($this->wrapped_object) ){
  36. return new WP_Error(
  37. 'no_wrapped_object',
  38. __('Nothing to update', 'broken-link-checker')
  39. );
  40. }
  41. $data = (array)$this->wrapped_object;
  42. if ( wp_update_comment($data) ){
  43. return true;
  44. } else {
  45. return new WP_Error(
  46. 'update_failed',
  47. sprintf(__('Updating comment %d failed', 'broken-link-checker'), $this->container_id)
  48. );
  49. }
  50. }
  51. /**
  52. * Delete the comment corresponding to this container.
  53. * This will actually move the comment to the trash in newer versions of WP.
  54. *
  55. * @return bool|WP_error
  56. */
  57. function delete_wrapped_object(){
  58. if ( EMPTY_TRASH_DAYS ){
  59. return $this->trash_wrapped_object();
  60. } else {
  61. if ( wp_delete_comment($this->container_id, true) ){
  62. return true;
  63. } else {
  64. return new WP_Error(
  65. 'delete_failed',
  66. sprintf(
  67. __('Failed to delete comment %d', 'broken-link-checker'),
  68. $this->container_id
  69. )
  70. );
  71. }
  72. }
  73. }
  74. /**
  75. * Delete the comment corresponding to this container.
  76. * This will actually move the comment to the trash in newer versions of WP.
  77. *
  78. * @return bool|WP_error
  79. */
  80. function trash_wrapped_object(){
  81. if ( wp_trash_comment($this->container_id) ){
  82. return true;
  83. } else {
  84. return new WP_Error(
  85. 'trash_failed',
  86. sprintf(
  87. __('Can\'t move comment %d to the trash', 'broken-link-checker'),
  88. $this->container_id
  89. )
  90. );
  91. }
  92. }
  93. /**
  94. * Check if the current user can delete/trash this comment.
  95. *
  96. * @return bool
  97. */
  98. function current_user_can_delete(){
  99. //TODO: Fix for custom post types? WP itself doesn't care, at least in 3.0.
  100. $comment = &$this->get_wrapped_object();
  101. return current_user_can('edit_post', $comment->comment_post_ID);
  102. }
  103. function can_be_trashed(){
  104. return defined('EMPTY_TRASH_DAYS') && EMPTY_TRASH_DAYS;
  105. }
  106. /**
  107. * Get the default link text to use for links found in a specific container field.
  108. * For links in the comment body there is no default link text. For author links,
  109. * the link text will be equal to the author name + comment type (if any).
  110. *
  111. * @param string $field
  112. * @return string
  113. */
  114. function default_link_text($field = ''){
  115. if ( $field == 'comment_author_url' ){
  116. $w = $this->get_wrapped_object();
  117. if ( !is_null($w) ){
  118. $text = $w->comment_author;
  119. //This lets us identify pingbacks & trackbacks.
  120. if ( !empty($w->comment_type) ){
  121. $text .= sprintf(' [%s]', $w->comment_type);
  122. }
  123. return $text;
  124. }
  125. }
  126. return '';
  127. }
  128. function ui_get_action_links($container_field){
  129. $actions = array();
  130. $comment = $this->get_wrapped_object();
  131. $post = get_post($comment->comment_post_ID); /* @var StdClass $post */
  132. //Display Edit & Delete/Trash links only if the user has the right caps.
  133. $user_can = current_user_can('edit_post', $comment->comment_post_ID);
  134. if ( $user_can ){
  135. $actions['edit'] = "<a href='". $this->get_edit_url() ."' title='" . esc_attr__('Edit comment') . "'>". __('Edit') . '</a>';
  136. $del_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "delete-comment_$comment->comment_ID" ) );
  137. $trash_url = esc_url( admin_url("comment.php?action=trashcomment&p=$post->ID&c=$comment->comment_ID&$del_nonce") );
  138. $delete_url = esc_url( admin_url("comment.php?action=deletecomment&p=$post->ID&c=$comment->comment_ID&$del_nonce") );
  139. if ( !constant('EMPTY_TRASH_DAYS') ) {
  140. $actions['delete'] = "<a href='$delete_url' class='delete:the-comment-list:comment-$comment->comment_ID::delete=1 delete vim-d vim-destructive submitdelete'>" . __('Delete Permanently') . '</a>';
  141. } else {
  142. $actions['trash'] = "<a href='$trash_url' class='delete:the-comment-list:comment-$comment->comment_ID::trash=1 delete vim-d vim-destructive submitdelete' title='" . esc_attr__( 'Move this comment to the trash' ) . "'>" . _x('Trash', 'verb') . '</a>';
  143. }
  144. }
  145. $actions['view'] = '<span class="view"><a href="' . get_comment_link($this->container_id) . '" title="' . esc_attr(__('View comment', 'broken-link-checker')) . '" rel="permalink">' . __('View') . '</a>';
  146. return $actions;
  147. }
  148. function ui_get_source($container_field = '', $context = 'display'){
  149. //Display a comment icon.
  150. if ( $container_field == 'comment_author_url' ){
  151. $image = 'user_comment.png';
  152. } else {
  153. $image = 'comment.png';
  154. }
  155. $image = sprintf(
  156. '<img src="%s/broken-link-checker/images/%s" class="blc-small-image" title="%3$s" alt="%3$s"> ',
  157. WP_PLUGIN_URL,
  158. $image,
  159. __('Comment', 'broken-link-checker')
  160. );
  161. $comment = $this->get_wrapped_object();
  162. //Display a small text sample from the comment
  163. $text_sample = strip_tags($comment->comment_content);
  164. $text_sample = blcUtility::truncate($text_sample, 65);
  165. $html = sprintf(
  166. '<a href="%s" title="%s"><b>%s</b> &mdash; %s</a>',
  167. $this->get_edit_url(),
  168. esc_attr__('Edit comment'),
  169. esc_attr($comment->comment_author),
  170. $text_sample
  171. );
  172. //Don't show the image in email notifications.
  173. if ( $context != 'email' ){
  174. $html = $image . $html;
  175. }
  176. return $html;
  177. }
  178. function get_edit_url(){
  179. return esc_url(admin_url("comment.php?action=editcomment&c={$this->container_id}"));
  180. }
  181. function base_url(){
  182. $comment_permalink = get_comment_link($this->container_id);
  183. return substr($comment_permalink, 0, strpos($comment_permalink, '#'));
  184. }
  185. }
  186. class blcCommentManager extends blcContainerManager {
  187. var $container_class_name = 'blcComment';
  188. var $fields = array(
  189. 'comment_author_url' => 'url_field',
  190. 'comment_content' => 'html',
  191. );
  192. function init(){
  193. parent::init();
  194. add_action('post_comment', array(&$this, 'hook_post_comment'), 10, 2);
  195. add_action('edit_comment', array(&$this, 'hook_edit_comment'));
  196. add_action('transition_comment_status', array(&$this, 'hook_comment_status'), 10, 3);
  197. add_action('trashed_post_comments', array(&$this, 'hook_trashed_post_comments'), 10, 2);
  198. add_action('untrash_post_comments', array(&$this, 'hook_untrash_post_comments'));
  199. }
  200. function hook_post_comment($comment_id, $comment_status){
  201. if ( $comment_status == '1' ) {
  202. $container = blcContainerHelper::get_container(array($this->container_type, $comment_id));
  203. $container->mark_as_unsynched();
  204. }
  205. }
  206. function hook_edit_comment($comment_id){
  207. if ( wp_get_comment_status($comment_id) == 'approved' ){
  208. $container = blcContainerHelper::get_container(array($this->container_type, $comment_id));
  209. $container->mark_as_unsynched();
  210. }
  211. }
  212. function hook_comment_status($new_status, $old_status, $comment){
  213. //We only care about approved comments.
  214. if ( ($new_status == 'approved') || ($old_status == 'approved') ){
  215. $container = blcContainerHelper::get_container(array($this->container_type, $comment->comment_ID));
  216. if ($new_status == 'approved') {
  217. $container->mark_as_unsynched();
  218. } else {
  219. $container->delete();
  220. blc_cleanup_links();
  221. }
  222. }
  223. }
  224. function hook_trashed_post_comments($post_id, $statuses){
  225. foreach($statuses as $comment_id => $comment_status){
  226. if ( $comment_status == '1' ){
  227. $container = blcContainerHelper::get_container(array($this->container_type, $comment_id));
  228. $container->delete();
  229. }
  230. }
  231. blc_cleanup_links();
  232. }
  233. function hook_untrash_post_comments($post_id){
  234. //Unlike with the 'trashed_post_comments' hook, WP doesn't pass the list of (un)trashed
  235. //comments to callbacks assigned to the 'untrash_post_comments' and 'untrashed_post_comments'
  236. //actions. Therefore, we must read it from the appropriate metadata entry.
  237. $statuses = get_post_meta($post_id, '_wp_trash_meta_comments_status', true);
  238. if ( empty($statuses) || !is_array($statuses) ) return;
  239. foreach ( $statuses as $comment_id => $comment_status ){
  240. if ( $comment_status == '1' ){ //if approved
  241. $container = blcContainerHelper::get_container(array($this->container_type, $comment_id));
  242. $container->mark_as_unsynched();
  243. }
  244. }
  245. }
  246. /**
  247. * Create or update synchronization records for all comments.
  248. *
  249. * @param bool $forced If true, assume that all synch. records are gone and will need to be recreated from scratch.
  250. * @return void
  251. */
  252. function resynch($forced = false){
  253. global $wpdb; /* @var wpdb $wpdb */
  254. global $blclog;
  255. if ( $forced ){
  256. //Create new synchronization records for all comments.
  257. $blclog->log('...... Creating synch. records for comments');
  258. $q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
  259. SELECT comment_ID, '{$this->container_type}', 0
  260. FROM {$wpdb->comments}
  261. WHERE
  262. {$wpdb->comments}.comment_approved = '1'";
  263. $wpdb->query( $q );
  264. $blclog->log(sprintf('...... %d rows affected', $wpdb->rows_affected));
  265. } else {
  266. //Delete synch records corresponding to comments that no longer exist
  267. //or have been trashed/spammed/unapproved.
  268. $blclog->log('...... Deleting synch. records for removed comments');
  269. $q = "DELETE synch.*
  270. FROM
  271. {$wpdb->prefix}blc_synch AS synch LEFT JOIN {$wpdb->comments} AS comments
  272. ON comments.comment_ID = synch.container_id
  273. WHERE
  274. synch.container_type = '{$this->container_type}'
  275. AND (comments.comment_ID IS NULL OR comments.comment_approved <> '1')";
  276. $wpdb->query( $q );
  277. $blclog->log(sprintf('...... %d rows affected', $wpdb->rows_affected));
  278. //Create synch. records for comments that don't have them.
  279. $blclog->log('...... Creating synch. records for new comments');
  280. $q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
  281. SELECT comment_ID, '{$this->container_type}', 0
  282. FROM
  283. {$wpdb->comments} AS comments LEFT JOIN {$wpdb->prefix}blc_synch AS synch
  284. ON (synch.container_id = comments.comment_ID and synch.container_type='{$this->container_type}')
  285. WHERE
  286. comments.comment_approved = '1'
  287. AND synch.container_id IS NULL";
  288. $wpdb->query($q);
  289. $blclog->log(sprintf('...... %d rows affected', $wpdb->rows_affected));
  290. /*
  291. Note that there is no way to detect comments that were *edited* (not added - those
  292. will be caught by the above query) while the plugin was inactive. Unlike with posts,
  293. WP doesn't track comment modification times.
  294. */
  295. }
  296. }
  297. /**
  298. * Get the message to display after $n comments have been deleted.
  299. *
  300. * @param int $n Number of deleted comments.
  301. * @return string A delete confirmation message, e.g. "5 comments were deleted"
  302. */
  303. function ui_bulk_delete_message($n){
  304. if ( EMPTY_TRASH_DAYS ){
  305. return $this->ui_bulk_trash_message($n);
  306. } else {
  307. return sprintf(
  308. _n(
  309. "%d comment has been deleted.",
  310. "%d comments have been deleted.",
  311. $n,
  312. 'broken-link-checker'
  313. ),
  314. $n
  315. );
  316. }
  317. }
  318. /**
  319. * Get the message to display after $n comments have been moved to the trash.
  320. *
  321. * @param int $n Number of trashed comments.
  322. * @return string A delete confirmation message, e.g. "5 comments were moved to trash"
  323. */
  324. function ui_bulk_trash_message($n){
  325. return sprintf(
  326. _n(
  327. "%d comment moved to the Trash.",
  328. "%d comments moved to the Trash.",
  329. $n,
  330. 'broken-link-checker'
  331. ),
  332. $n
  333. );
  334. }
  335. /**
  336. * Instantiate multiple containers of the container type managed by this class.
  337. *
  338. * @param array $containers Array of assoc. arrays containing container data.
  339. * @param string $purpose An optional code indicating how the retrieved containers will be used.
  340. * @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
  341. *
  342. * @return array of blcPostContainer indexed by "container_type|container_id"
  343. */
  344. function get_containers($containers, $purpose = '', $load_wrapped_objects = false){
  345. global $wpdb; /* @var wpdb $wpdb */
  346. $containers = $this->make_containers($containers);
  347. //Preload comment data if it is likely to be useful later
  348. $preload = $load_wrapped_objects || in_array($purpose, array(BLC_FOR_DISPLAY, BLC_FOR_PARSING));
  349. if ( $preload ){
  350. $comment_ids = array();
  351. foreach($containers as $container){ /* @var blcContainer $container */
  352. $comment_ids[] = $container->container_id;
  353. }
  354. //There's no WP function for retrieving multiple comments by their IDs,
  355. //so we query the DB directly.
  356. $q = "SELECT * FROM {$wpdb->comments} WHERE comment_ID IN (" . implode(', ', $comment_ids) . ")";
  357. $comments = $wpdb->get_results($q);
  358. foreach($comments as $comment){
  359. //Cache the comment in the internal WP object cache
  360. $comment = get_comment($comment); /* @var StdClass $comment */
  361. //Attach it to the container
  362. $key = $this->container_type . '|' . $comment->comment_ID;
  363. if ( isset($containers[$key]) ){
  364. $containers[$key]->wrapped_object = $comment;
  365. }
  366. }
  367. }
  368. return $containers;
  369. }
  370. }
  371. ?>