Guest User

Untitled

a guest
Sep 1st, 2014
101
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <?php
  2. /*
  3. Plugin Name: Simple Comment Editing
  4. Plugin URI: http://wordpress.org/extend/plugins/simple-comment-editing/
  5. Description: Simple comment editing for your users.
  6. Author: ronalfy
  7. Version: 1.2.1
  8. Requires at least: 3.5
  9. Author URI: http://www.ronalfy.com
  10. Contributors: ronalfy
  11. Text Domain: simple-comment-editing
  12. Domain Path: /languages
  13. */
  14. class Simple_Comment_Editing {
  15. private static $instance = null;
  16. private $comment_time = 0; //in minutes
  17. private $loading_img = '';
  18. private $allow_delete = true;
  19. private $errors;
  20.  
  21. //Singleton
  22. public static function get_instance() {
  23. if ( null == self::$instance ) {
  24. self::$instance = new self;
  25. }
  26. return self::$instance;
  27. } //end get_instance
  28.  
  29. private function __construct() {
  30. add_action( 'init', array( $this, 'init' ), 9 );
  31.  
  32. //* Localization Code */
  33. load_plugin_textdomain( 'simple-comment-editing', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
  34.  
  35. //Initialize errors
  36. $this->errors = new WP_Error();
  37. $this->errors->add( 'nonce_fail', __( 'You do not have permission to edit this comment.', 'simple-comment-editing' ) );
  38. $this->errors->add( 'edit_fail', __( 'You can no longer edit this comment', 'simple-comment-editing' ) );
  39. $this->errors->add( 'comment_empty', __( 'Your comment cannot be empty', 'simple-comment-editing' ) );
  40. $this->errors->add( 'comment_marked_spam', __( 'This comment was marked as spam', 'simple-comment-editing' ) );
  41. } //end constructor
  42.  
  43. public function init() {
  44.  
  45. if ( is_admin() && !defined( 'DOING_AJAX' ) ) return false;
  46.  
  47. //Set plugin defaults
  48. $this->comment_time = intval( apply_filters( 'sce_comment_time', 5 ) );
  49. $this->loading_img = esc_url( apply_filters( 'sce_loading_img', $this->get_plugin_url( '/images/loading.gif' ) ) );
  50. $this->allow_delete = (bool)apply_filters( 'sce_allow_delete', $this->allow_delete );
  51.  
  52. /* BEGIN ACTIONS */
  53. //When a comment is posted
  54. add_action( 'comment_post', array( $this, 'comment_posted' ),100,1 );
  55.  
  56. //Loading scripts
  57. add_action( 'wp_enqueue_scripts', array( $this, 'add_scripts' ) );
  58.  
  59. //Ajax
  60. add_action( 'wp_ajax_sce_get_time_left', array( $this, 'ajax_get_time_left' ) );
  61. add_action( 'wp_ajax_nopriv_sce_get_time_left', array( $this, 'ajax_get_time_left' ) );
  62. add_action( 'wp_ajax_sce_save_comment', array( $this, 'ajax_save_comment' ) );
  63. add_action( 'wp_ajax_nopriv_sce_save_comment', array( $this, 'ajax_save_comment' ) );
  64. add_action( 'wp_ajax_sce_delete_comment', array( $this, 'ajax_delete_comment' ) );
  65. add_action( 'wp_ajax_nopriv_sce_delete_comment', array( $this, 'ajax_delete_comment' ) );
  66.  
  67. /* Begin Filters */
  68. if ( !is_feed() && !defined( 'DOING_AJAX' ) ) {
  69. add_filter( 'comment_excerpt', array( $this, 'add_edit_interface'), 1000, 2 );
  70. add_filter( 'comment_text', array( $this, 'add_edit_interface'), 1000,2 );
  71. //Notice Thesis compatibility not here? It's not an accident.
  72. }
  73. } //end init
  74.  
  75. /**
  76. * add_edit_interface - Adds the SCE interface if a user can edit their comment
  77. *
  78. * Called via the comment_text or comment_excerpt filter to add the SCE editing interface to a comment.
  79. *
  80. * @since 1.0
  81. *
  82. */
  83. public function add_edit_interface( $comment_content, $comment = false) {
  84. if ( !$comment ) return $comment_content;
  85.  
  86. $comment_id = $comment->comment_ID;
  87. $post_id = $comment->comment_post_ID;
  88.  
  89. //Check to see if a user can edit their comment
  90. if ( !$this->can_edit( $comment_id, $post_id ) ) return $comment_content;
  91.  
  92. //Variables for later
  93. $original_content = $comment_content;
  94. $raw_content = $comment->comment_content; //For later usage in the textarea
  95.  
  96. //Yay, user can edit - Add the initial wrapper
  97. $comment_content = sprintf( '<div id="sce-comment%d" class="sce-comment">%s</div>', $comment_id, $comment_content );
  98.  
  99. //Create Overall wrapper for JS interface
  100. $comment_content .= sprintf( '<div id="sce-edit-comment%d" class="sce-edit-comment">', $comment_id );
  101.  
  102. //Edit Button
  103. $comment_content .= '<div class="sce-edit-button" style="display:none;">';
  104. $ajax_edit_url = add_query_arg( array( 'cid' => $comment_id, 'pid' => $post_id ) , wp_nonce_url( admin_url( 'admin-ajax.php' ), 'sce-edit-comment' . $comment_id ) );
  105. $comment_content .= sprintf( '<a href="%s">%s</a>', $ajax_edit_url, esc_html__( 'Click to Edit', 'simple-comment-editing' ) );
  106. $comment_content .= '<span class="sce-timer"></span>';
  107. $comment_content .= '</div><!-- .sce-edit-button -->';
  108.  
  109. //Loading button
  110. $comment_content .= '<div class="sce-loading" style="display: none;">';
  111. $comment_content .= sprintf( '<img src="%1$s" title="%2$s" alt="%2$s" />', $this->loading_img, esc_attr__( 'Loading', 'simple-comment-editing' ) );
  112. $comment_content .= '</div><!-- sce-loading -->';
  113.  
  114. //Textarea
  115. $comment_content .= '<div class="sce-textarea" style="display: none;">';
  116. $textarea_content = format_to_edit( $raw_content, 1 );
  117. $textarea_content = apply_filters( 'comment_edit_pre', $textarea_content );
  118. $comment_content .= '<div class="sce-comment-textarea">';
  119. $comment_content .= sprintf( '<textarea class="sce-comment-text" cols="45" rows="8">%s</textarea>', esc_textarea( $raw_content ) );
  120. $comment_content .= '</div><!-- .sce-comment-textarea -->';
  121. $comment_content .= '<div class="sce-comment-edit-buttons">';
  122. $comment_content .= sprintf( '<button class="sce-comment-save">%s</button>', esc_html__( 'Save', 'simple-comment-editing' ) );
  123. $comment_content .= sprintf( '<button class="sce-comment-cancel">%s</button>', esc_html__( 'Cancel', 'simple-comment-editing' ) );
  124. $comment_content .= '</div><!-- .sce-comment-edit-buttons -->';
  125. $comment_content .= '</div><!-- .sce-textarea -->';
  126.  
  127.  
  128. //End
  129. $comment_content .= '</div><!-- .sce-edit-comment -->';
  130.  
  131. return $comment_content;
  132.  
  133. } //end add_edit_interface
  134.  
  135. /**
  136. * add_scripts - Adds the necessary JavaScript for the plugin (only loads on posts/pages)
  137. *
  138. * Called via the wp_enqueue_scripts
  139. *
  140. * @since 1.0
  141. *
  142. */
  143. public function add_scripts() {
  144. if ( !is_single() && !is_page() ) return;
  145.  
  146. //Check if there are any cookies present, otherwise don't load the scripts - WPAC_PLUGIN_NAME is for wp-ajaxify-comments (if the plugin is installed, load the JavaScript file)
  147. if ( !defined( 'WPAC_PLUGIN_NAME' ) ) {
  148. if ( !isset( $_COOKIE ) || empty( $_COOKIE ) ) return;
  149. $has_cookie = false;
  150. foreach( $_COOKIE as $cookie_name => $cookie_value ) {
  151. if ( substr( $cookie_name , 0, 20 ) == 'SimpleCommentEditing' ) {
  152. $has_cookie = true;
  153. break;
  154. }
  155. }
  156. if ( !$has_cookie ) return;
  157. }
  158.  
  159. $main_script_uri = $this->get_plugin_url( '/js/simple-comment-editing.min.js' );
  160. if ( defined( 'SCRIPT_DEBUG' ) ) {
  161. if ( SCRIPT_DEBUG == true ) {
  162. $main_script_uri = $this->get_plugin_url( '/js/simple-comment-editing.js' );
  163. }
  164. }
  165. wp_enqueue_script( 'simple-comment-editing', $main_script_uri, array( 'jquery', 'wp-ajax-response' ), '20140414', true );
  166. wp_localize_script( 'simple-comment-editing', 'simple_comment_editing', array(
  167. 'minutes' => __( 'minutes', 'simple-comment-editing' ),
  168. 'minute' => __( 'minute', 'simple-comment-editing' ),
  169. 'and' => __( 'and', 'simple-comment-editing' ),
  170. 'seconds' => __( 'seconds', 'simple-comment-editing' ),
  171. 'second' => __( 'second', 'simple-comment-editing' ),
  172. 'confirm_delete' => __( 'Do you want to delete this comment?', 'simple-comment-editing' ),
  173. 'comment_deleted' => __( 'Your comment has been removed.', 'simple-comment-editing' ),
  174. 'empty_comment' => $this->errors->get_error_message( 'comment_empty' ),
  175. 'allow_delete' => $this->allow_delete
  176. ) );
  177. } //end add_scripts
  178.  
  179. /**
  180. * ajax_get_time_left - Returns a JSON object of minutes/seconds of the time left to edit a comment
  181. *
  182. * Returns a JSON object of minutes/seconds of the time left to edit a comment
  183. *
  184. * @since 1.0
  185. *
  186. * @param int $_POST[ 'comment_id' ] The Comment ID
  187. * @param int $_POST[ 'post_id' ] The Comment's Post ID
  188. * @return JSON object e.g. {minutes:4,seconds:5}
  189. */
  190. public function ajax_get_time_left() {
  191. global $wpdb;
  192. $comment_id = absint( $_POST[ 'comment_id' ] );
  193. $post_id = absint( $_POST[ 'post_id' ] );
  194.  
  195. $comment_time = absint( $this->comment_time );
  196. $query = $wpdb->prepare( "SELECT ( $comment_time * 60 - (UNIX_TIMESTAMP('" . current_time('mysql') . "') - UNIX_TIMESTAMP(comment_date))) comment_time FROM {$wpdb->comments} where comment_ID = %d", $comment_id );
  197. $comment_time_result = $wpdb->get_row( $query, ARRAY_A );
  198.  
  199. $time_left = absint( $comment_time_result[ 'comment_time' ] );
  200. $minutes = floor( $time_left / 60 );
  201. $seconds = $time_left - ( $minutes * 60 );
  202. $response = array(
  203. 'minutes' => $minutes,
  204. 'comment_id' => $comment_id,
  205. 'seconds' => $seconds
  206. );
  207. die( json_encode( $response ) );
  208. } //end ajax_get_time_left
  209.  
  210. /**
  211. * ajax_delete_comment- Removes a WordPress comment, but saves it to the trash
  212. *
  213. * Returns a JSON object of the saved comment
  214. *
  215. * @since 1.1.0
  216. *
  217. * @param int $_POST[ 'comment_id' ] The Comment ID
  218. * @param int $_POST[ 'post_id' ] The Comment's Post ID
  219. * @param string $_POST[ 'nonce' ] The nonce to check against
  220. * @return JSON object
  221. */
  222. public function ajax_delete_comment() {
  223. $comment_id = absint( $_POST[ 'comment_id' ] );
  224. $post_id = absint( $_POST[ 'post_id' ] );
  225. $nonce = $_POST[ 'nonce' ];
  226.  
  227. $return = array();
  228. $return[ 'errors' ] = false;
  229.  
  230. //Do a nonce check
  231. if ( !wp_verify_nonce( $nonce, 'sce-edit-comment' . $comment_id ) ) {
  232. $return[ 'errors' ] = true;
  233. $return[ 'remove' ] = true;
  234. $return[ 'error' ] = $this->errors->get_error_message( 'nonce_fail' );
  235. die( json_encode( $return ) );
  236. }
  237.  
  238. //Check to see if the user can edit the comment
  239. if ( !$this->can_edit( $comment_id, $post_id ) || $this->allow_delete == false ) {
  240. $return[ 'errors' ] = true;
  241. $return[ 'remove' ] = true;
  242. $return[ 'error' ] = $this->errors->get_error_message( 'edit_fail' );
  243. die( json_encode( $return ) );
  244. }
  245.  
  246. wp_delete_comment( $comment_id ); //Save to trash for admin retrieval
  247. $return[ 'error' ] = '';
  248. die( json_encode( $return ) );
  249. } //end ajax_delete_comment
  250.  
  251. /**
  252. * ajax_save_comment - Saves a comment to the database, returns the updated comment via JSON
  253. *
  254. * Returns a JSON object of the saved comment
  255. *
  256. * @since 1.0
  257. *
  258. * @param string $_POST[ 'comment_content' ] The comment to save
  259. * @param int $_POST[ 'comment_id' ] The Comment ID
  260. * @param int $_POST[ 'post_id' ] The Comment's Post ID
  261. * @param string $_POST[ 'nonce' ] The nonce to check against
  262. * @return JSON object
  263. */
  264. public function ajax_save_comment() {
  265. $new_comment_content = trim( $_POST[ 'comment_content' ] );
  266. $comment_id = absint( $_POST[ 'comment_id' ] );
  267. $post_id = absint( $_POST[ 'post_id' ] );
  268. $nonce = $_POST[ 'nonce' ];
  269.  
  270. $return = array();
  271. $return[ 'errors' ] = false;
  272. $return[ 'remove' ] = false; //If set to true, removes the editing interface
  273.  
  274. //Do a nonce check
  275. if ( !wp_verify_nonce( $nonce, 'sce-edit-comment' . $comment_id ) ) {
  276. $return[ 'errors' ] = true;
  277. $return[ 'remove' ] = true;
  278. $return[ 'error' ] = $this->errors->get_error_message( 'nonce_fail' );
  279. die( json_encode( $return ) );
  280. }
  281.  
  282. //Check to see if the user can edit the comment
  283. if ( !$this->can_edit( $comment_id, $post_id ) ) {
  284. $return[ 'errors' ] = true;
  285. $return[ 'remove' ] = true;
  286. $return[ 'error' ] = $this->errors->get_error_message( 'edit_fail' );
  287. die( json_encode( $return ) );
  288. }
  289.  
  290. //Check that the content isn't empty
  291. if ( '' == $new_comment_content || 'undefined' == $new_comment_content ) {
  292. $return[ 'errors' ] = true;
  293. $return[ 'error' ] = $this->errors->get_error_message( 'comment_empty' );
  294. die( json_encode( $return ) );
  295. }
  296.  
  297. //Get original comment
  298. $comment_to_save = get_comment( $comment_id, ARRAY_A);
  299.  
  300. //Check the comment
  301. if ( $comment_to_save['comment_approved'] == 1 ) {
  302. if ( check_comment( $comment_to_save['comment_author'], $comment_to_save['comment_author_email'], $comment_to_save['comment_author_url'], $new_comment_content, $comment_to_save['comment_author_IP'], $comment_to_save['comment_agent'], $comment_to_save['comment_type'] ) ) {
  303. $comment_to_save['comment_approved'] = 1;
  304. } else {
  305. $comment_to_save['comment_approved'] = 0;
  306. }
  307. }
  308.  
  309. //Check comment against blacklist
  310. if ( wp_blacklist_check( $comment_to_save['comment_author'], $comment_to_save['comment_author_email'], $comment_to_save['comment_author_url'], $new_comment_content, $comment_to_save['comment_author_IP'], $comment_to_save['comment_agent'] ) ) {
  311. $comment_to_save['comment_approved'] = 'spam';
  312. }
  313.  
  314. //Now save the comment
  315. $comment_to_save[ 'comment_content' ] = $new_comment_content;
  316. wp_update_comment( $comment_to_save );
  317.  
  318. //If the comment was marked as spam, return an error
  319. if ( $comment_to_save['comment_approved'] === 'spam' ) {
  320. $return[ 'errors' ] = true;
  321. $return[ 'remove' ] = true;
  322. $return[ 'error' ] = $this->errors->get_error_message( 'comment_marked_spam' );
  323. $this->remove_comment_cookie( $comment_to_save );
  324. die( json_encode( $return ) );
  325. }
  326.  
  327. //Check the new comment for spam with Akismet
  328. if ( function_exists( 'akismet_check_db_comment' ) ) {
  329. if ( akismet_verify_key( get_option( 'wordpress_api_key' ) ) != "failed" ) { //Akismet
  330. $response = akismet_check_db_comment( $comment_id );
  331. if ($response == "true") { //You have spam
  332. wp_set_comment_status( $comment_id, 'spam');
  333. $return[ 'errors' ] = true;
  334. $return[ 'remove' ] = true;
  335. $return[ 'error' ] = $this->errors->get_error_message( 'comment_marked_spam' );
  336. $this->remove_comment_cookie( $comment_to_save );
  337. die( json_encode( $return ) );
  338. }
  339. }
  340. }
  341.  
  342. //Now get the new comment again for security
  343. if ( isset( $GLOBALS['comment'] ) ) unset( $GLOBALS['comment'] ); //caching
  344. $comment_to_return = get_comment ( $comment_id ); //todo - cached
  345. $comment_content_to_return = $comment_to_return->comment_content;
  346.  
  347. //Format the comment for returning
  348. if ( function_exists( 'mb_convert_encoding' ) ) {
  349. $comment_content_to_return = mb_convert_encoding( $comment_content_to_return, ''. get_option( 'blog_charset' ) . '', mb_detect_encoding( $comment_content_to_return, "UTF-8, ISO-8859-1, ISO-8859-15", true ) );
  350. }
  351. $comment_content_to_return = apply_filters( 'comment_text', apply_filters( 'get_comment_text', $comment_content_to_return ) );
  352.  
  353. //Ajax response
  354. $return[ 'comment_text' ] = $comment_content_to_return;
  355. $return[ 'error' ] = '';
  356. die( json_encode( $return ) );
  357. } //end ajax_save_comment
  358.  
  359.  
  360. /**
  361. * can_edit - Returns true/false if a user can edit a comment
  362. *
  363. * Retrieves a cookie to see if a comment can be edited or not
  364. *
  365. * @since 1.0
  366. *
  367. * @param int $comment_id The Comment ID
  368. * @param int $post_id The Comment's Post ID
  369. * @return bool true if can edit, false if not
  370. */
  371. public function can_edit( $comment_id, $post_id ) {
  372. global $comment;
  373. if ( !is_object( $comment ) ) $comment = get_comment( $comment_id, OBJECT );
  374.  
  375. //Check to see if time has elapsed for the comment
  376. $comment_timestamp = strtotime( $comment->comment_date );
  377. $time_elapsed = current_time( 'timestamp', get_option( 'gmt_offset' ) ) - $comment_timestamp;
  378. $minuted_elapsed = round( ( ( ( $time_elapsed % 604800 ) % 86400 ) % 3600 ) / 60 );
  379. if ( ( $minuted_elapsed - $this->comment_time ) > 0 ) return false;
  380.  
  381. //Now check to see if the cookie is present
  382. if ( !isset( $_COOKIE ) || !is_array( $_COOKIE ) || empty( $_COOKIE ) ) return false;
  383.  
  384. //Now check for post meta and cookie values being the same
  385. $cookie_hash = md5( $comment->comment_author_IP . $comment->comment_date_gmt );
  386. if ( !isset( $_COOKIE[ 'SimpleCommentEditing' . $comment_id . $cookie_hash] ) ) return false;
  387. $post_meta_hash = get_post_meta( $post_id, '_' . $comment_id, true );
  388.  
  389.  
  390.  
  391. //Check to see if the cookie value matches the post meta hash
  392. $cookie_value = $_COOKIE[ 'SimpleCommentEditing' . $comment_id . $cookie_hash ];
  393. if ( $cookie_value !== $post_meta_hash ) return false;
  394.  
  395. //All is well, the person/place/thing can edit the comment
  396. return true;
  397. } //end can_edit
  398.  
  399. /**
  400. * comment_posted - WordPress action comment_post
  401. *
  402. * Called when a comment has been posted - Stores a cookie for later editing
  403. *
  404. * @since 1.0
  405. *
  406. * @param int $comment_id The Comment ID
  407. */
  408. public function comment_posted( $comment_id ) {
  409. $comment = get_comment( $comment_id, OBJECT );
  410. $post_id = $comment->comment_post_ID;
  411. $comment_status = $comment->comment_approved;
  412.  
  413. //Do some initial checks to weed out those who shouldn't be able to have editable comments
  414. if ( 'spam' === $comment_status ) return; //Marked as spam - no editing allowed
  415. //if ( current_user_can( 'moderate_comments' ) ) return; //They can edit comments anyway, don't do anything
  416. //if ( current_user_can( 'edit_post', $post_id ) ) return; //Post author - User can edit comments for the post anyway
  417.  
  418. //Get hash and random security key - Stored in the style of Ajax Edit Comments
  419. $hash = md5( $comment->comment_author_IP . $comment->comment_date_gmt );
  420. $rand = '_wpAjax' . $hash . md5( wp_generate_password( 30, true, true ) );
  421. update_post_meta( $post_id, '_' . $comment_id, $rand );
  422.  
  423. //Now store a cookie
  424. $cookie_name = 'SimpleCommentEditing' . $comment_id . $hash;
  425. $cookie_value = $rand;
  426. $cookie_expire = time() + ( 60 * $this->comment_time );
  427. setcookie( $cookie_name, $cookie_value, $cookie_expire, COOKIEPATH,COOKIE_DOMAIN);
  428.  
  429. //Update the security key count (use the same names/techniques as Ajax Edit Comments
  430. $security_key_count = absint( get_option( 'ajax-edit-comments_security_key_count' ) );
  431. if ( !$security_key_count ) {
  432. $security_key_count = 1;
  433. } else {
  434. $security_key_count += 1;
  435. }
  436.  
  437. //Now delete security keys (use the same names/techniques as Ajax Edit Comments
  438. $min_security_keys = absint( apply_filters( 'sce_security_key_min', 100 ) );
  439. if ( $security_key_count >= $min_security_keys ) {
  440. global $wpdb;
  441. $comment_id_to_exclude = "_" . $comment_id;
  442. /* Only delete the first 50 to make sure the bottom 50 aren't suddenly without to the ability to edit comments - Props Marco Pereirinha */
  443. $wpdb->query( $wpdb->prepare( "delete from {$wpdb->postmeta} where left(meta_value, 6) = 'wpAjax' and meta_key <> %s ORDER BY {$wpdb->postmeta}.meta_id ASC LIMIT 50 ", $comment_id_to_exclude ) );
  444. $security_key_count = 1;
  445. }
  446. update_option( 'ajax-edit-comments_security_key_count', $security_key_count );
  447. } //end comment_posted
  448.  
  449.  
  450.  
  451. public function get_plugin_dir( $path = '' ) {
  452. $dir = rtrim( plugin_dir_path(__FILE__), '/' );
  453. if ( !empty( $path ) && is_string( $path) )
  454. $dir .= '/' . ltrim( $path, '/' );
  455. return $dir;
  456. }
  457. //Returns the plugin url
  458. public function get_plugin_url( $path = '' ) {
  459. $dir = rtrim( plugin_dir_url(__FILE__), '/' );
  460. if ( !empty( $path ) && is_string( $path) )
  461. $dir .= '/' . ltrim( $path, '/' );
  462. return $dir;
  463. }
  464.  
  465. /**
  466. * remove_comment_cookie - Removes a comment cookie
  467. *
  468. * Removes a comment cookie based on the passed comment
  469. *
  470. * @since 1.0
  471. *
  472. * @param associative array $comment The results from get_comment( $id, ARRAY_A )
  473. */
  474. private function remove_comment_cookie( $comment ) {
  475. if ( !is_array( $comment ) ) return;
  476.  
  477. $hash = md5( $comment[ 'comment_author_IP' ] . $comment[ 'comment_date_gmt' ] );
  478. $comment_id = $comment[ 'comment_ID' ];
  479.  
  480. //Expire the cookie
  481. $cookie_name = 'SimpleCommentEditing' . $comment_id . $hash;
  482. setcookie( $cookie_name, '', time() - 60, COOKIEPATH,COOKIE_DOMAIN);
  483.  
  484. } //end remove_comment_cookie
  485.  
  486. } //end class Simple_Comment_Editing
  487.  
  488. add_action( 'plugins_loaded', 'sce_instantiate' );
  489. function sce_instantiate() {
  490. Simple_Comment_Editing::get_instance();
  491. } //end sce_instantiate
RAW Paste Data