diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..0163872
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,25 @@
+# This file is for unifying the coding style for different editors and IDEs.
+# It is based on https://core.trac.wordpress.org/browser/trunk/.editorconfig.
+# See https://editorconfig.org for more information about the standard.
+
+# WordPress Coding Standards
+# https://make.wordpress.org/core/handbook/coding-standards/
+
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+indent_style = tab
+
+[*.yml]
+indent_style = space
+indent_size = 2
+
+[*.md]
+trim_trailing_whitespace = false
+
+[*.txt]
+end_of_line = crlf
diff --git a/.github/workflows/cs-lint.yml b/.github/workflows/cs-lint.yml
new file mode 100644
index 0000000..fe4dac4
--- /dev/null
+++ b/.github/workflows/cs-lint.yml
@@ -0,0 +1,70 @@
+name: CS & Lint
+
+on:
+ # Run on all pushes and on all pull requests.
+ # Prevent the "push" build from running when there are only irrelevant changes.
+ push:
+ paths-ignore:
+ - "**.md"
+ pull_request:
+ # Allow manually triggering the workflow.
+ workflow_dispatch:
+
+jobs:
+ checkcs:
+ name: "Basic CS and QA checks"
+ runs-on: ubuntu-latest
+
+ env:
+ XMLLINT_INDENT: " "
+
+ steps:
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: "7.4"
+ coverage: none
+ tools: cs2pr
+
+ # Show PHP lint violations inline in the file diff.
+ # @link https://github.com/marketplace/actions/xmllint-problem-matcher
+ - name: Register PHP lint violations to appear as file diff comments
+ uses: korelstar/phplint-problem-matcher@v1
+
+ # Show XML violations inline in the file diff.
+ # @link https://github.com/marketplace/actions/xmllint-problem-matcher
+ - name: Register XML violations to appear as file diff comments
+ uses: korelstar/xmllint-problem-matcher@v1
+
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ # Validate the composer.json file.
+ # @link https://getcomposer.org/doc/03-cli.md#validate
+ - name: Validate Composer installation
+ run: composer validate --no-check-all
+
+ # Install dependencies and handle caching in one go.
+ # @link https://github.com/marketplace/actions/install-composer-dependencies
+ - name: Install Composer dependencies
+ uses: ramsey/composer-install@v1
+
+ # Lint PHP.
+ - name: Lint PHP against parse errors
+ run: composer lint-ci | cs2pr
+
+ # Needed as runs-on: system doesn't have xml-lint by default.
+ # @link https://github.com/marketplace/actions/xml-lint
+ - name: Lint phpunit.xml.dist
+ uses: ChristophWurst/xmllint-action@v1
+ with:
+ xml-file: ./phpunit.xml.dist
+ xml-schema-file: ./vendor/phpunit/phpunit/phpunit.xsd
+
+ # Check the code-style consistency of the PHP files.
+# - name: Check PHP code style
+# continue-on-error: true
+# run: vendor/bin/phpcs --report-full --report-checkstyle=./phpcs-report.xml
+
+# - name: Show PHPCS results in PR
+# run: cs2pr ./phpcs-report.xml
diff --git a/.github/workflows/integrate.yml b/.github/workflows/integrate.yml
deleted file mode 100644
index 7f90c50..0000000
--- a/.github/workflows/integrate.yml
+++ /dev/null
@@ -1,71 +0,0 @@
-name: Run PHPUnit and PHPCS
-
-on: [push]
-
-jobs:
- test:
- name: WP ${{ matrix.wordpress }} on PHP ${{ matrix.php }}
- # Ubuntu-20.x includes MySQL 8.0, which causes `caching_sha2_password` issues with PHP < 7.4
- # https://www.php.net/manual/en/mysqli.requirements.php
- # TODO: change to ubuntu-latest when we no longer support PHP < 7.4
- runs-on: ubuntu-18.04
- continue-on-error: ${{ matrix.allowed_failure }}
-
- env:
- WP_VERSION: ${{ matrix.wordpress }}
-
- strategy:
- fail-fast: false
- matrix:
- php: ["5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0"]
- wordpress: ["5.5", "5.6", "5.7"]
- allowed_failure: [false]
- # https://make.wordpress.org/core/2020/11/23/wordpress-and-php-8-0/
- exclude:
- - php: "8.0"
- wordpress: "5.5"
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v2
-
- - name: Set up PHP ${{ matrix.php }}
- uses: shivammathur/setup-php@v2
- with:
- php-version: ${{ matrix.php }}
- coverage: pcov
- # https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions
- extensions: curl, dom, exif, fileinfo, hash, json, mbstring, mysqli, openssl, pcre, imagick, xml, zip
-
- - name: Install Composer dependencies (PHP < 8.0 )
- if: ${{ matrix.php < 8.0 }}
- uses: ramsey/composer-install@v1
-
- - name: Install Composer dependencies (PHP >= 8.0)
- if: ${{ matrix.php >= 8.0 }}
- uses: ramsey/composer-install@v1
- with:
- composer-options: --ignore-platform-reqs
-
- - name: Setup Problem Matchers for PHPUnit
- run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
-
- - name: Show PHP and PHPUnit version info
- run: |
- php --version
- ./vendor/bin/phpunit --version
-
- - name: Start MySQL service
- run: sudo /etc/init.d/mysql start
-
- - name: Install WordPress environment
- run: composer prepare ${{ matrix.wordpress }}
-
- - name: Run integration tests (single site)
- run: composer integration
-
- - name: Run integration tests (multisite)
- run: composer integration-ms
-
- - name: Run PHPCS
- run: composer cs
diff --git a/.github/workflows/integrations.yml b/.github/workflows/integrations.yml
new file mode 100644
index 0000000..8f5577e
--- /dev/null
+++ b/.github/workflows/integrations.yml
@@ -0,0 +1,85 @@
+name: Run PHPUnit
+
+on:
+ # Run on all pushes and on all pull requests.
+ # Prevent the "push" build from running when there are only irrelevant changes.
+ push:
+ paths-ignore:
+ - "**.md"
+ pull_request:
+ # Allow manually triggering the workflow.
+ workflow_dispatch:
+
+jobs:
+ test:
+ name: WP ${{ matrix.wordpress }} on PHP ${{ matrix.php }}
+ # Ubuntu-20.x includes MySQL 8.0, which causes `caching_sha2_password` issues with PHP < 7.4
+ # https://www.php.net/manual/en/mysqli.requirements.php
+ # TODO: change to ubuntu-latest when we no longer support PHP < 7.4
+ runs-on: ubuntu-18.04
+
+ env:
+ WP_VERSION: ${{ matrix.wordpress }}
+
+ strategy:
+ matrix:
+ wordpress: ["5.5", "5.6", "5.7"]
+ php: ["5.6", "7.0", "7.1", "7.2", "7.3", "7.4"]
+ include:
+ - php: "8.0"
+ # Ignore platform requirements, so that PHPUnit 7.5 can be installed on PHP 8.0 (and above).
+ composer-options: "--ignore-platform-reqs"
+ extensions: pcov
+ ini-values: pcov.directory=., "pcov.exclude=\"~(vendor|tests)~\""
+ coverage: pcov
+ exclude:
+ - php: "8.0"
+ wordpress: "5.5"
+ fail-fast: false
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ - name: Setup PHP ${{ matrix.php }}
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: ${{ matrix.extensions }}
+ ini-values: ${{ matrix.ini-values }}
+ coverage: ${{ matrix.coverage }}
+
+ - name: Setup problem matchers for PHP
+ run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
+
+ # Setup PCOV since we're using PHPUnit < 8 which has it integrated. Requires PHP 7.1.
+ # Ignore platform reqs to make it install on PHP 8.
+ # https://github.com/krakjoe/pcov-clobber
+ - name: Setup PCOV
+ if: ${{ matrix.php == 8.0 }}
+ run: |
+ composer require pcov/clobber --ignore-platform-reqs
+ vendor/bin/pcov clobber
+
+ - name: Setup Problem Matchers for PHPUnit
+ run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
+
+ - name: Install Composer dependencies
+ uses: ramsey/composer-install@v1
+ with:
+ composer-options: "${{ matrix.composer-options }}"
+
+ - name: Start MySQL Service
+ run: sudo systemctl start mysql.service
+
+ - name: Prepare environment for integration tests
+ run: composer prepare-ci
+
+ - name: Run integration tests (single site)
+ if: ${{ matrix.php != 8.0 }}
+ run: composer test
+ - name: Run integration tests (single site with code coverage)
+ if: ${{ matrix.php == 8.0 }}
+ run: composer coverage-ci
+ - name: Run integration tests (multisite)
+ run: composer test-ms
diff --git a/.gitignore b/.gitignore
index 81e9d35..d8a7996 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,2 @@
-.svn
-wpcom-helper
-.DS_Store
-.vscode/
composer.lock
vendor/
diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist
new file mode 100644
index 0000000..3b843d8
--- /dev/null
+++ b/.phpcs.xml.dist
@@ -0,0 +1,70 @@
+
+
+ Custom ruleset for safe-report-comments plugin.
+
+
+
+
+
+ .
+
+ /vendor/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/class-safe-report-comments.php b/class-safe-report-comments.php
new file mode 100644
index 0000000..8b6844d
--- /dev/null
+++ b/class-safe-report-comments.php
@@ -0,0 +1,659 @@
+admin_notices = get_transient( $this->plugin_prefix . '_notices' );
+ if ( ! is_array( $this->admin_notices ) ) {
+ $this->admin_notices = array();
+ }
+ $this->admin_notices = array_unique( $this->admin_notices );
+ $this->auto_init = $auto_init;
+
+ if ( ! is_admin() || ( defined( 'DOING_AJAX' ) && true === DOING_AJAX ) ) {
+ add_action( 'init', array( $this, 'frontend_init' ) );
+ } elseif ( is_admin() ) {
+ add_action( 'admin_init', array( $this, 'backend_init' ) );
+ }
+ add_action( 'comment_unapproved_to_approved', array( $this, 'mark_comment_moderated' ), 10, 1 );
+
+ /**
+ * Apply some filters to easily alter the frontend messages. Example:
+ * add_filter( 'safe_report_comments_thank_you_message', 'alter_message' );
+ */
+ foreach ( $this->filter_vars as $var ) {
+ $this->{$var} = apply_filters( 'safe_report_comments_' . $var, $this->{$var} );
+ }
+ }
+
+ /**
+ * Prevent __destruct
+ */
+ public function __destruct() {
+ }
+
+ /**
+ * Initialize backend functions
+ * - register_admin_panel
+ * - admin_header
+ */
+ public function backend_init() {
+ do_action( 'safe_report_comments_backend_init' );
+
+ add_settings_field( $this->plugin_prefix . '_enabled', __( 'Allow comment flagging', 'safe-report-comments' ), array( $this, 'comment_flag_enable' ), 'discussion', 'default' );
+ register_setting( 'discussion', $this->plugin_prefix . '_enabled' );
+
+ if ( ! $this->is_enabled() ) {
+ return;
+ }
+
+ add_settings_field( $this->plugin_prefix . '_threshold', __( 'Flagging threshold', 'safe-report-comments' ), array( $this, 'comment_flag_threshold' ), 'discussion', 'default' );
+ register_setting( 'discussion', $this->plugin_prefix . '_threshold', array( $this, 'check_threshold' ) );
+ add_filter( 'manage_edit-comments_columns', array( $this, 'add_comment_reported_column' ) );
+ add_action( 'manage_comments_custom_column', array( $this, 'manage_comment_reported_column' ), 10, 2 );
+
+ add_action( 'admin_menu', array( $this, 'register_admin_panel' ) );
+ add_action( 'admin_head', array( $this, 'admin_header' ) );
+ }
+
+ /**
+ * Initialize frontend functions
+ */
+ public function frontend_init() {
+ if ( ! $this->is_enabled() ) {
+ return;
+ }
+
+ if ( ! $this->plugin_url ) {
+ $this->plugin_url = plugins_url( false, __FILE__ );
+ }
+
+ do_action( 'safe_report_comments_frontend_init' );
+
+ add_action( 'wp_ajax_safe_report_comments_flag_comment', array( $this, 'flag_comment' ) );
+ add_action( 'wp_ajax_nopriv_safe_report_comments_flag_comment', array( $this, 'flag_comment' ) );
+
+ add_action( 'wp_enqueue_scripts', array( $this, 'action_enqueue_scripts' ) );
+
+ if ( $this->auto_init ) {
+ add_filter( 'comment_reply_link', array( $this, 'add_flagging_link' ) );
+ }
+ add_action( 'comment_report_abuse_link', array( $this, 'print_flagging_link' ) );
+
+ add_action( 'template_redirect', array( $this, 'add_test_cookie' ) ); // need to do this at template_redirect because is_feed isn't available yet.
+ }
+
+ /**
+ * Enqueues scripts on front end.
+ */
+ public function action_enqueue_scripts() {
+
+ // Use home_url() if domain mapped to avoid cross-domain issues.
+ if ( home_url() != site_url() ) {
+ $ajaxurl = home_url( '/wp-admin/admin-ajax.php' );
+ } else {
+ $ajaxurl = admin_url( 'admin-ajax.php' );
+ }
+
+ $ajaxurl = apply_filters( 'safe_report_comments_ajax_url', $ajaxurl );
+
+ wp_enqueue_script( $this->plugin_prefix . '-ajax-request', $this->plugin_url . '/js/ajax.js', array( 'jquery' ), '1.0', true );
+ wp_localize_script( $this->plugin_prefix . '-ajax-request', 'SafeCommentsAjax', array( 'ajaxurl' => $ajaxurl ) ); // slightly dirty but needed due to possible problems with mapped domains.
+ }
+
+ /**
+ * Set a cookie now to see if they are supported by the browser.
+ * Don't add cookie if it's already set; and don't do it for feeds.
+ */
+ public function add_test_cookie() {
+ if ( ! is_feed() && ! isset( $_COOKIE[ TEST_COOKIE ] ) ) {
+ @setcookie( TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN );
+ if ( SITECOOKIEPATH != COOKIEPATH ) {
+ @setcookie( TEST_COOKIE, 'WP Cookie check', 0, SITECOOKIEPATH, COOKIE_DOMAIN );
+ }
+ }
+ }
+
+ /**
+ * Add necessary header scripts.
+ * Currently only used for admin notices.
+ */
+ public function admin_header() {
+ // print admin notice in case of notice strings given.
+ if ( ! empty( $this->admin_notices ) ) {
+ add_action( 'admin_notices', array( $this, 'print_admin_notice' ) );
+ }
+ echo '';
+ }
+
+ /**
+ * Add admin error messages.
+ *
+ * @param string $message Admin notice text.
+ */
+ protected function add_admin_notice( $message ) {
+ $this->admin_notices[] = $message;
+ set_transient( $this->plugin_prefix . '_notices', $this->admin_notices, 3600 );
+ }
+
+ /**
+ * Print a notification / error msg.
+ */
+ public function print_admin_notice() {
+ ?>
+
+ admin_notices as $notice ) {
+ ?>
+
+
+
+ admin_notices = array();
+ delete_transient( $this->plugin_prefix . '_notices' );
+ }
+
+ /**
+ * Callback for settings field.
+ */
+ public function comment_flag_enable() {
+ $enabled = $this->is_enabled();
+ ?>
+
+ plugin_prefix . '_threshold' );
+ ?>
+
+ plugin_prefix . '_enabled' );
+ if ( 1 == $enabled ) {
+ $enabled = true;
+ } else {
+ $enabled = false;
+ }
+ return $enabled;
+ }
+
+ /**
+ * Validate threshold, callback for settings field.
+ *
+ * @param int $value Threshold value.
+ * @return int Valid threshold value between 1 and 100.
+ */
+ public function check_threshold( $value ) {
+ if ( (int) $value <= 0 || (int) $value > 100 ) {
+ $this->add_admin_notice( __( 'Please revise your flagging threshold and enter a number between 1 and 100', 'safe-report-comments' ) );
+ }
+ return (int) $value;
+ }
+
+ /**
+ * Helper function to serialize cookie values.
+ *
+ * @param array $value Cookie data.
+ * @return string Encoded cookie data.
+ */
+ private function serialize_cookie( $value ) {
+ $value = $this->clean_cookie_data( $value );
+ return base64_encode( wp_json_encode( $value ) );
+ }
+
+ /**
+ * Helper function to unserialize cookie values.
+ *
+ * @param string $value Encoded cookie data.
+ * @return array Decoded cookie data.
+ */
+ private function unserialize_cookie( $value ) {
+ $data = json_decode( base64_decode( $value ) );
+ return $this->clean_cookie_data( $data );
+ }
+
+ /**
+ * Validate cookie data for numeric values.
+ *
+ * @param mixed $data Given cookie data.
+ * @return array Cookie data array with only numeric keys and values.
+ */
+ private function clean_cookie_data( $data ) {
+ $clean_data = array();
+
+ if ( ! is_array( $data ) ) {
+ $data = array();
+ }
+
+ foreach ( $data as $comment_id => $count ) {
+ if ( is_numeric( $comment_id ) && is_numeric( $count ) ) {
+ $clean_data[ $comment_id ] = $count;
+ }
+ }
+
+ return $clean_data;
+ }
+
+ /**
+ * Mark a comment as being moderated so it will not be autoflagged again.
+ *
+ * Called via comment transient from unapproved to approved.
+ *
+ * @param WP_Comment $comment Comment to mark.
+ */
+ public function mark_comment_moderated( $comment ) {
+ if ( isset( $comment->comment_ID ) ) {
+ update_comment_meta( $comment->comment_ID, $this->plugin_prefix . '_moderated', true );
+ }
+ }
+
+ /**
+ * Check if this comment was flagged by the user before.
+ *
+ * @param int $comment_id Comment to check.
+ * @return bool Whether comment has already been flagged by user.
+ */
+ public function already_flagged( $comment_id ) {
+
+ // check if cookies are enabled and use cookie store.
+ if ( isset( $_COOKIE[ TEST_COOKIE ] ) ) {
+ if ( isset( $_COOKIE[ $this->storagecookie ] ) ) {
+ $data = $this->unserialize_cookie( sanitize_text_field( $_COOKIE[ $this->storagecookie ] ) );
+ if ( is_array( $data ) && isset( $data[ $comment_id ] ) ) {
+ return true;
+ }
+ }
+ }
+
+ $remote_addr = filter_input( INPUT_SERVER, 'REMOTE_ADDR', FILTER_VALIDATE_IP );
+ $remote_addr = sanitize_text_field( $remote_addr );
+
+ // in case we don't have cookies. fall back to transients, block based on IP/User Agent.
+ $transient = get_transient( md5( $this->storagecookie . $remote_addr ) );
+ if ( $transient ) {
+ if (
+ // check if no cookie and transient is set.
+ ( ! isset( $_COOKIE[ TEST_COOKIE ] ) && isset( $transient[ $comment_id ] ) ) ||
+ // or check if cookies are enabled and comment is not flagged but transients show a relatively high number and assume fraud.
+ ( isset( $_COOKIE[ TEST_COOKIE ] ) && isset( $transient[ $comment_id ] ) && $transient[ $comment_id ] >= $this->no_cookie_grace )
+ ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Report a comment and send it to moderation if threshold is reached.
+ *
+ * @param int $comment_id Comment to mark.
+ */
+ public function mark_flagged( $comment_id ) {
+ $data = array();
+ if ( isset( $_COOKIE[ TEST_COOKIE ] ) ) {
+ if ( isset( $_COOKIE[ $this->storagecookie ] ) ) {
+ $data = $this->unserialize_cookie( sanitize_text_field( $_COOKIE[ $this->storagecookie ] ) );
+ if ( ! isset( $data[ $comment_id ] ) ) {
+ $data[ $comment_id ] = 0;
+ }
+ $data[ $comment_id ]++;
+ $cookie = $this->serialize_cookie( $data );
+ @setcookie( $this->storagecookie, $cookie, time() + $this->cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN );
+ if ( SITECOOKIEPATH != COOKIEPATH ) {
+ @setcookie( $this->storagecookie, $cookie, time() + $this->cookie_lifetime, SITECOOKIEPATH, COOKIE_DOMAIN );
+ }
+ } else {
+ if ( ! isset( $data[ $comment_id ] ) ) {
+ $data[ $comment_id ] = 0;
+ }
+ $data[ $comment_id ]++;
+ $cookie = $this->serialize_cookie( $data );
+ @setcookie( $this->storagecookie, $cookie, time() + $this->cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN );
+ if ( SITECOOKIEPATH != COOKIEPATH ) {
+ @setcookie( $this->storagecookie, $cookie, time() + $this->cookie_lifetime, SITECOOKIEPATH, COOKIE_DOMAIN );
+ }
+ }
+ }
+
+ $remote_addr = filter_input( INPUT_SERVER, 'REMOTE_ADDR', FILTER_VALIDATE_IP );
+ $remote_addr = sanitize_text_field( $remote_addr );
+
+ // in case we don't have cookies. fall back to transients, block based on IP, shorter timeout to keep mem usage low and don't lock out whole companies.
+ $transient = get_transient( md5( $this->storagecookie . $remote_addr ) );
+ if ( ! $transient ) {
+ set_transient( md5( $this->storagecookie . $remote_addr ), array( $comment_id => 1 ), $this->transient_lifetime );
+ } else {
+ if ( ! isset( $transient[ $comment_id ] ) ) {
+ $transient[ $comment_id ] = 0;
+ }
+ $transient[ $comment_id ]++;
+ set_transient( md5( $this->storagecookie . $remote_addr ), $transient, $this->transient_lifetime );
+ }
+
+
+ $threshold = (int) get_option( $this->plugin_prefix . '_threshold' );
+ $current_reports = get_comment_meta( $comment_id, $this->plugin_prefix . '_reported', true );
+ $current_reports++;
+ update_comment_meta( $comment_id, $this->plugin_prefix . '_reported', $current_reports );
+
+
+ // we will not flag a comment twice. the moderator is the boss here.
+ $already_reported = get_comment_meta( $comment_id, $this->plugin_prefix . '_reported', true );
+ $already_moderated = get_comment_meta( $comment_id, $this->plugin_prefix . '_moderated', true );
+ if ( true == $already_reported && true == $already_moderated ) {
+ // But maybe the boss wants to allow comments to be reflagged.
+ if ( ! apply_filters( 'safe_report_comments_allow_moderated_to_be_reflagged', false ) ) {
+ return;
+ }
+ }
+
+ if ( $current_reports >= $threshold ) {
+ do_action( 'safe_report_comments_mark_flagged', $comment_id );
+ wp_set_comment_status( $comment_id, 'hold' );
+ }
+ }
+
+ /**
+ * Die() with or without screen based on JS availability.
+ *
+ * @param string $message Message to print.
+ */
+ private function cond_die( $message ) {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ if ( isset( $_REQUEST['no_js'] ) && true == (bool) $_REQUEST['no_js'] ) {
+ wp_die( esc_html( $message ), esc_html__( 'Safe Report Comments Notice', 'safe-report-comments' ), array( 'response' => 200 ) );
+ } else {
+ die( esc_html( $message ) );
+ }
+ }
+
+ /**
+ * Ajax callback to flag/report a comment.
+ *
+ * @todo Confirm this callback only receives POST data
+ */
+ public function flag_comment() {
+ if ( empty( $_REQUEST['comment_id'] ) || (int) $_REQUEST['comment_id'] != $_REQUEST['comment_id'] ) {
+ $this->cond_die( $this->invalid_values_message );
+ }
+
+ $comment_id = (int) $_REQUEST['comment_id'];
+ if ( $this->already_flagged( $comment_id ) ) {
+ $this->cond_die( $this->already_flagged_message );
+ }
+
+ // checking if nonces help.
+ if ( ! isset( $_REQUEST['sc_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_REQUEST['sc_nonce'] ), $this->plugin_prefix . '_' . $this->nonce_key ) ) {
+ $this->cond_die( $this->invalid_nonce_message );
+ } else {
+ $this->mark_flagged( $comment_id );
+ $this->cond_die( $this->thank_you_message );
+ }
+ }
+
+ /**
+ * Print the link for flagging comments.
+ *
+ * @param int $comment_id The comment ID.
+ * @param string $result_id Used as attribute ID in markup.
+ * @param string $text Text of link.
+ */
+ public function print_flagging_link( $comment_id = '', $result_id = '', $text = 'Report comment' ) {
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaping done in get_flagging_link
+ echo $this->get_flagging_link( $comment_id, $result_id, $text );
+ }
+
+ /**
+ * Output Link to report a comment
+ *
+ * @param int $comment_id The comment ID.
+ * @param string $result_id Used as attribute ID in markup.
+ * @param string $text Text of link.
+ */
+ public function get_flagging_link( $comment_id = '', $result_id = '', $text = 'Report comment' ) {
+ global $in_comment_loop;
+ if ( empty( $comment_id ) && ! $in_comment_loop ) {
+ return esc_html__( 'Wrong usage of print_flagging_link().', 'safe-report-comments' );
+ }
+ if ( empty( $comment_id ) ) {
+ $comment_id = get_comment_ID();
+ } else {
+ $comment_id = (int) $comment_id;
+ if ( ! get_comment( $comment_id ) ) {
+ return esc_html__( 'This comment does not exist.', 'safe-report-comments' );
+ }
+ }
+ if ( empty( $result_id ) ) {
+ $result_id = 'safe-comments-result-' . $comment_id;
+ }
+
+ $result_id = apply_filters( 'safe_report_comments_result_id', $result_id );
+ $text = apply_filters( 'safe_report_comments_flagging_link_text', $text );
+
+ $nonce = wp_create_nonce( $this->plugin_prefix . '_' . $this->nonce_key );
+ $params = array(
+ 'action' => 'safe_report_comments_flag_comment',
+ 'sc_nonce' => $nonce,
+ 'comment_id' => $comment_id,
+ 'result_id' => $result_id,
+ 'no_js' => true,
+ );
+
+ if ( $this->already_flagged( $comment_id ) ) {
+ return esc_html( $this->already_flagged_note );
+ }
+
+ // @todo Confirm that $result_id is unnecessary in JS call (and its associated ajax callback).
+ return apply_filters(
+ 'safe_report_comments_flagging_link',
+ '
+ ' . esc_html( $text ) . ''
+ );
+ }
+
+ /**
+ * Callback function to automatically hook in the report link after the comment reply link.
+ * If you want to control the placement on your own define no_autostart_safe_report_comments in your functions.php file and initialize the class
+ * with $safe_report_comments = new Safe_Report_Comments( $auto_init = false );
+ *
+ * @param string $comment_reply_link Comment reply link markup.
+ * @return string Modified comment reply link markup.
+ */
+ public function add_flagging_link( $comment_reply_link ) {
+ if ( ! preg_match_all( '#^(.*)(]+>)(.+)()(.*)$#msiU', $comment_reply_link, $matches ) ) {
+ return '' . $comment_reply_link;
+ }
+
+ $comment_reply_link = $matches[1][0] . $matches[2][0] . $matches[4][0] . $matches[5][0] . '' . $matches[6][0];
+ return apply_filters( 'safe_report_comments_comment_reply_link', $comment_reply_link );
+ }
+
+ /**
+ * Callback function to add the report counter to comments screen. Remove action manage_edit-comments_columns if not desired.
+ *
+ * @param array $comment_columns Comments screen columns.
+ * @return array Modified comments screen columns.
+ */
+ public function add_comment_reported_column( $comment_columns ) {
+ $comment_columns['comment_reported'] = _x( 'Reported', 'column name', 'safe-report-comments' );
+ return $comment_columns;
+ }
+
+ /**
+ * Callback function to handle custom column. remove action manage_comments_custom_column if not desired.
+ *
+ * @param string $column_name Column name.
+ * @param int $comment_id Comment ID.
+ */
+ public function manage_comment_reported_column( $column_name, $comment_id ) {
+ switch ( $column_name ) {
+ case 'comment_reported':
+ $reports = 0;
+ $already_reported = get_comment_meta( $comment_id, $this->plugin_prefix . '_reported', true );
+ if ( $already_reported > 0 ) {
+ $reports = (int) $already_reported;
+ }
+ echo esc_html( $reports );
+ break;
+ default:
+ break;
+ }
+ }
+
+}
diff --git a/composer.json b/composer.json
index faa7a70..23c4bac 100644
--- a/composer.json
+++ b/composer.json
@@ -1,55 +1,61 @@
{
- "name": "automattic/safe-report-comments",
- "description": "Allows visitors to report a comment as inappropriate.",
- "homepage": "https://github.com/Automattic/safe-report-comments/",
- "type": "wordpress-plugin",
- "license": "GPL-2.0+",
- "authors": [
- {
- "name": "Automattic",
- "homepage": "http://automattic.com/"
- }
- ],
- "support": {
- "issues": "https://github.com/Automattic/safe-report-comments/issues",
- "source": "https://github.com/Automattic/safe-report-comments"
- },
- "require": {
- "composer/installers": "~1.0",
- "php": ">=5.6"
- },
- "require-dev": {
- "automattic/vipwpcs": "^2.2",
- "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7",
- "php-parallel-lint/php-parallel-lint": "^1.0",
- "phpcompatibility/phpcompatibility-wp": "^2.1",
- "phpunit/phpunit": "^4 || ^5 || ^6 || ^7",
- "squizlabs/php_codesniffer": "^3.5",
- "wp-coding-standards/wpcs": "^2.3.0",
- "yoast/phpunit-polyfills": "^0.2.0"
- },
- "scripts": {
- "cs": [
- "@php ./vendor/bin/phpcs -p -s -v -n . --standard=\"WordPress-VIP-Go\" --extensions=php --ignore=\"/vendor/*,/node_modules/*,/tests/*\""
- ],
- "cbf": [
- "@php ./vendor/bin/phpcbf -p -s -v -n . --standard=\"WordPress-VIP-Go\" --extensions=php --ignore=\"/vendor/*,/node_modules/*,/tests/*\""
- ],
- "lint": [
- "@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . -e php --exclude vendor --exclude .git"
- ],
- "lint-ci": [
- "@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . -e php --exclude vendor --exclude .git --checkstyle"
- ],
- "prepare": [
- "bash bin/install-wp-tests.sh wordpress_test root root localhost"
- ],
- "integration": [
- "@php ./vendor/bin/phpunit --testsuite WP_Tests"
- ],
- "integration-ms": [
- "@putenv WP_MULTISITE=1",
- "@composer integration"
- ]
- }
+ "name": "automattic/safe-report-comments",
+ "type": "wordpress-plugin",
+ "description": "Allows visitors to report a comment as inappropriate.",
+ "homepage": "https://github.com/Automattic/safe-report-comments/",
+ "license": "GPL-2.0-or-later",
+ "authors": [
+ {
+ "name": "Automattic",
+ "homepage": "https://automattic.com/"
+ }
+ ],
+ "require": {
+ "php": ">=5.6",
+ "composer/installers": "~1.0"
+ },
+ "require-dev": {
+ "automattic/vipwpcs": "^2.2",
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7",
+ "php-parallel-lint/php-parallel-lint": "^1.0",
+ "phpcompatibility/phpcompatibility-wp": "^2.1",
+ "phpunit/phpunit": "^4 || ^5 || ^6 || ^7",
+ "squizlabs/php_codesniffer": "^3.5",
+ "wp-coding-standards/wpcs": "^2.3.0",
+ "yoast/phpunit-polyfills": "^0.2.0"
+ },
+ "scripts": {
+ "cbf": [
+ "@php ./vendor/bin/phpcbf"
+ ],
+ "coverage": [
+ "@php ./vendor/bin/phpunit --coverage-html ./build/coverage-html"
+ ],
+ "coverage-ci": [
+ "@php ./vendor/bin/phpunit"
+ ],
+ "cs": [
+ "@php ./vendor/bin/phpcs"
+ ],
+ "lint": [
+ "@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . -e php --exclude vendor --exclude .git"
+ ],
+ "lint-ci": [
+ "@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . -e php --exclude vendor --exclude .git --checkstyle"
+ ],
+ "prepare-ci": [
+ "bash bin/install-wp-tests.sh wordpress_test root root localhost"
+ ],
+ "test": [
+ "@php ./vendor/bin/phpunit --testsuite WP_Tests"
+ ],
+ "test-ms": [
+ "@putenv WP_MULTISITE=1",
+ "@composer test"
+ ]
+ },
+ "support": {
+ "issues": "https://github.com/Automattic/safe-report-comments/issues",
+ "source": "https://github.com/Automattic/safe-report-comments"
+ }
}
diff --git a/phpunit.xml b/phpunit.xml.dist
similarity index 100%
rename from phpunit.xml
rename to phpunit.xml.dist
diff --git a/safe-report-comments.php b/safe-report-comments.php
index 073aa60..032eb8e 100644
--- a/safe-report-comments.php
+++ b/safe-report-comments.php
@@ -10,497 +10,13 @@
* Author URI: http://automattic.com
* License: GPLv2
*
- * @phpcs:disable WordPressVIPMinimum.Functions.RestrictedFunctions.cookies_setcookie
- * @phpcs:disable WordPressVIPMinimum.Variables.RestrictedVariables.cache_constraints___COOKIE
+ * @package Safe_Report_Comments
*/
-if ( !class_exists( "Safe_Report_Comments" ) ) {
-
- class Safe_Report_Comments {
-
- private $_plugin_prefix = 'srcmnt';
- private $_admin_notices = array();
- private $_nonce_key = 'flag_comment_nonce';
- private $_auto_init = true;
- private $_storagecookie = 'sfrc_flags';
-
- public $plugin_url = false;
-
- public $thank_you_message = 'Thank you for your feedback. We will look into it.';
- public $invalid_nonce_message = 'It seems you already reported this comment. ';
- public $invalid_values_message = 'Cheating huh? ';
- public $already_flagged_message = 'It seems you already reported this comment. ';
- public $already_flagged_note = ''; // displayed instead of the report link when a comment was flagged.
-
- public $filter_vars = array( 'thank_you_message', 'invalid_nonce_message', 'invalid_values_message', 'already_flagged_message', 'already_flagged_note' );
-
- // amount of possible attempts transient hits per comment before a COOKIE enabled negative check is considered invalid
- // transient hits will be counted up per ip any time a user flags a comment
- // this number should be always lower than your threshold to avoid manipulation
- public $no_cookie_grace = 3;
- public $cookie_lifetime = 604800; // lifetime of the cookie ( 1 week ). After this duration a user can report a comment again
- public $transient_lifetime = 86400; // lifetime of fallback transients. lower to keep things usable and c
-
- public function __construct( $auto_init=true ) {
-
- $this->_admin_notices = get_transient( $this->_plugin_prefix . '_notices' );
- if ( ! is_array( $this->_admin_notices ) ) {
- $this->_admin_notices = array();
- }
- $this->_admin_notices = array_unique( $this->_admin_notices );
- $this->_auto_init = $auto_init;
-
- if ( !is_admin() || ( defined( 'DOING_AJAX' ) && true === DOING_AJAX ) ) {
- add_action( 'init', array( $this, 'frontend_init' ) );
- } else if ( is_admin() ) {
- add_action( 'admin_init', array( $this, 'backend_init' ) );
- }
- add_action( 'comment_unapproved_to_approved', array( $this, 'mark_comment_moderated' ), 10, 1 );
-
- // apply some filters to easily alter the frontend messages
- // add_filter( 'safe_report_comments_thank_you_message', 'alter_message' ); // this or similar will do the job
- foreach ( $this->filter_vars as $var ) {
- $this->{$var} = apply_filters( 'safe_report_comments_' . $var , $this->{$var} );
- }
- }
-
- public function __destruct() {
-
- }
-
- /*
- * Initialize backend functions
- * - register_admin_panel
- * - admin_header
- */
- public function backend_init() {
- do_action( 'safe_report_comments_backend_init' );
-
- add_settings_field( $this->_plugin_prefix . '_enabled', __( 'Allow comment flagging' ), array( $this, 'comment_flag_enable' ), 'discussion', 'default' );
- register_setting( 'discussion', $this->_plugin_prefix . '_enabled' );
-
- if ( ! $this->is_enabled() ) {
- return;
- }
-
- add_settings_field( $this->_plugin_prefix . '_threshold', __( 'Flagging threshold' ), array( $this, 'comment_flag_threshold' ), 'discussion', 'default' );
- register_setting( 'discussion', $this->_plugin_prefix . '_threshold', array( $this, 'check_threshold' ) );
- add_filter('manage_edit-comments_columns', array( $this, 'add_comment_reported_column' ) );
- add_action('manage_comments_custom_column', array( $this, 'manage_comment_reported_column' ), 10, 2);
-
- add_action( 'admin_menu', array( $this, 'register_admin_panel' ) );
- add_action( 'admin_head', array( $this, 'admin_header' ) );
- }
-
- /*
- * Initialize frontend functions
- */
- public function frontend_init() {
-
- if ( ! $this->is_enabled() ) {
- return;
- }
-
- if ( ! $this->plugin_url ) {
- $this->plugin_url = plugins_url( false, __FILE__ );
- }
-
- do_action( 'safe_report_comments_frontend_init' );
-
- add_action( 'wp_ajax_safe_report_comments_flag_comment', array( $this, 'flag_comment' ) );
- add_action( 'wp_ajax_nopriv_safe_report_comments_flag_comment', array( $this, 'flag_comment' ) );
-
- add_action( 'wp_enqueue_scripts', array( $this, 'action_enqueue_scripts' ) );
-
- if ( $this->_auto_init ) {
- add_filter( 'comment_reply_link', array( $this, 'add_flagging_link' ) );
- }
- add_action( 'comment_report_abuse_link', array( $this, 'print_flagging_link' ) );
-
- add_action( 'template_redirect', array( $this, 'add_test_cookie' ) ); // need to do this at template_redirect because is_feed isn't available yet
- }
-
- public function action_enqueue_scripts() {
-
- // Use home_url() if domain mapped to avoid cross-domain issues
- if ( home_url() != site_url() ) {
- $ajaxurl = home_url( '/wp-admin/admin-ajax.php' );
- } else {
- $ajaxurl = admin_url( 'admin-ajax.php' );
- }
-
- $ajaxurl = apply_filters( 'safe_report_comments_ajax_url', $ajaxurl );
-
- wp_enqueue_script( $this->_plugin_prefix . '-ajax-request', $this->plugin_url . '/js/ajax.js', array( 'jquery' ) );
- wp_localize_script( $this->_plugin_prefix . '-ajax-request', 'SafeCommentsAjax', array( 'ajaxurl' => $ajaxurl ) ); // slightly dirty but needed due to possible problems with mapped domains
- }
-
- public function add_test_cookie() {
- //Set a cookie now to see if they are supported by the browser.
- // Don't add cookie if it's already set; and don't do it for feeds
- if ( ! is_feed() && ! isset( $_COOKIE[ TEST_COOKIE ] ) ) {
- @setcookie(TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN);
- if ( SITECOOKIEPATH != COOKIEPATH ) {
- @setcookie(TEST_COOKIE, 'WP Cookie check', 0, SITECOOKIEPATH, COOKIE_DOMAIN);
- }
- }
- }
-
- /*
- * Add necessary header scripts
- * Currently only used for admin notices
- */
- public function admin_header() {
- // print admin notice in case of notice strings given
- if ( !empty( $this->_admin_notices ) ) {
- add_action('admin_notices' , array( $this, 'print_admin_notice' ) );
- }
-?>
-
-_admin_notices[] = $message;
- set_transient( $this->_plugin_prefix . '_notices', $this->_admin_notices, 3600 );
- }
-
- /*
- * Print a notification / error msg
- */
- public function print_admin_notice() {
- ?>Safe Comments:
_admin_notices as $notice ) {
- ?>
-
-
_admin_notices = array();
- delete_transient( $this->_plugin_prefix . '_notices' );
- }
-
- /*
- * Callback for settings field
- */
- public function comment_flag_enable() {
- $enabled = $this->is_enabled();
- ?>
-
- _plugin_prefix . '_threshold' );
- ?>
-
- _plugin_prefix . '_enabled' );
- if ( $enabled == 1 ) {
- $enabled = true;
- } else {
- $enabled = false;
- }
- return $enabled;
- }
-
- /*
- * Validate threshold, callback for settings field
- */
- public function check_threshold( $value ) {
- if ( (int) $value <= 0 || (int) $value > 100 ) {
- $this->add_admin_notice( __('Please revise your flagging threshold and enter a number between 1 and 100') );
- }
- return (int) $value;
- }
-
- /*
- * Helper functions to (un)/serialize cookie values
- */
- private function serialize_cookie( $value ) {
- $value = $this->clean_cookie_data( $value );
- return base64_encode( json_encode( $value ) );
- }
- private function unserialize_cookie( $value ) {
- $data = json_decode( base64_decode( $value ) );
- return $this->clean_cookie_data( $data );
- }
-
- private function clean_cookie_data( $data ) {
- $clean_data = array();
-
- if ( ! is_array( $data ) ) {
- $data = array();
- }
-
- foreach ( $data as $comment_id => $count ) {
- if ( is_numeric( $comment_id ) && is_numeric( $count ) ) {
- $clean_data[ $comment_id ] = $count;
- }
- }
-
- return $clean_data;
- }
-
- /*
- * Mark a comment as being moderated so it will not be autoflagged again
- * called via comment transient from unapproved to approved
- */
- public function mark_comment_moderated( $comment ) {
- if ( isset( $comment->comment_ID ) ) {
- update_comment_meta( $comment->comment_ID, $this->_plugin_prefix . '_moderated', true );
- }
- }
-
- /*
- * Check if this comment was flagged by the user before
- */
- public function already_flagged( $comment_id ) {
-
- // check if cookies are enabled and use cookie store
- if ( isset( $_COOKIE[ TEST_COOKIE ] ) ) {
- if ( isset( $_COOKIE[ $this->_storagecookie ] ) ) {
- $data = $this->unserialize_cookie( $_COOKIE[ $this->_storagecookie ] );
- if ( is_array( $data ) && isset( $data[ $comment_id ] ) ) {
- return true;
- }
- }
- }
-
- $remote_addr = filter_input( INPUT_SERVER, 'REMOTE_ADDR', FILTER_VALIDATE_IP );
- $remote_addr = sanitize_text_field( $remote_addr );
-
- // in case we don't have cookies. fall back to transients, block based on IP/User Agent
- if ( $transient = get_transient( md5( $this->_storagecookie . $remote_addr ) ) ) {
- if (
- // check if no cookie and transient is set
- ( !isset( $_COOKIE[ TEST_COOKIE ] ) && isset( $transient[ $comment_id ] ) ) ||
- // or check if cookies are enabled and comment is not flagged but transients show a relatively high number and assume fraud
- ( isset( $_COOKIE[ TEST_COOKIE ] ) && isset( $transient[ $comment_id ] ) && $transient[ $comment_id ] >= $this->no_cookie_grace )
- ) {
- return true;
- }
- }
- return false;
- }
-
- /*
- * Report a comment and send it to moderation if threshold is reached
- */
- public function mark_flagged( $comment_id ) {
- $data = array();
- if ( isset( $_COOKIE[ TEST_COOKIE ] ) ) {
- if ( isset( $_COOKIE[ $this->_storagecookie ] ) ) {
- $data = $this->unserialize_cookie( $_COOKIE[ $this->_storagecookie ] );
- if ( ! isset( $data[ $comment_id ] ) ) {
- $data[ $comment_id ] = 0;
- }
- $data[ $comment_id ]++;
- $cookie = $this->serialize_cookie( $data );
- @setcookie( $this->_storagecookie, $cookie, time()+$this->cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN );
- if ( SITECOOKIEPATH != COOKIEPATH ) {
- @setcookie( $this->_storagecookie, $cookie, time()+$this->cookie_lifetime, SITECOOKIEPATH, COOKIE_DOMAIN);
- }
- } else {
- if ( ! isset( $data[ $comment_id ] ) ) {
- $data[ $comment_id ] = 0;
- }
- $data[ $comment_id ]++;
- $cookie = $this->serialize_cookie( $data );
- @setcookie( $this->_storagecookie, $cookie, time()+$this->cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN );
- if ( SITECOOKIEPATH != COOKIEPATH ) {
- @setcookie( $this->_storagecookie, $cookie, time()+$this->cookie_lifetime, SITECOOKIEPATH, COOKIE_DOMAIN);
- }
- }
- }
-
- $remote_addr = filter_input( INPUT_SERVER, 'REMOTE_ADDR', FILTER_VALIDATE_IP );
- $remote_addr = sanitize_text_field( $remote_addr );
-
- // in case we don't have cookies. fall back to transients, block based on IP, shorter timeout to keep mem usage low and don't lock out whole companies
- $transient = get_transient( md5( $this->_storagecookie . $remote_addr ) );
- if ( !$transient ) {
- set_transient( md5( $this->_storagecookie . $remote_addr ), array( $comment_id => 1), $this->transient_lifetime );
- } else {
- if ( ! isset( $transient[ $comment_id ] ) ) {
- $transient[ $comment_id ] = 0;
- }
- $transient[ $comment_id ]++;
- set_transient( md5( $this->_storagecookie . $remote_addr ), $transient, $this->transient_lifetime );
- }
-
-
- $threshold = (int) get_option( $this->_plugin_prefix . '_threshold' );
- $current_reports = get_comment_meta( $comment_id, $this->_plugin_prefix . '_reported', true );
- $current_reports++;
- update_comment_meta( $comment_id, $this->_plugin_prefix . '_reported', $current_reports );
-
-
- // we will not flag a comment twice. the moderator is the boss here.
- $already_reported = get_comment_meta( $comment_id, $this->_plugin_prefix . '_reported', true );
- $already_moderated = get_comment_meta( $comment_id, $this->_plugin_prefix . '_moderated', true );
- if ( true == $already_reported && true == $already_moderated ) {
- // But maybe the boss wants to allow comments to be reflagged
- if ( ! apply_filters( 'safe_report_comments_allow_moderated_to_be_reflagged', false ) ) {
- return;
- }
- }
-
- if ( $current_reports >= $threshold ) {
- do_action( 'safe_report_comments_mark_flagged', $comment_id );
- wp_set_comment_status( $comment_id, 'hold' );
- }
- }
-
- /*
- * Die() with or without screen based on JS availability
- */
- private function cond_die( $message ) {
- if ( isset( $_REQUEST['no_js'] ) && true == (boolean) $_REQUEST['no_js'] ) {
- wp_die( esc_html( $message ), esc_html("Safe Report Comments Notice"), array('response' => 200 ) );
- } else {
- die( esc_html( $message ) );
- }
- }
-
- /*
- * Ajax callback to flag/report a comment
- */
- public function flag_comment() {
- if ( empty( $_REQUEST[ 'comment_id' ] ) || (int) $_REQUEST[ 'comment_id' ] != $_REQUEST[ 'comment_id' ] ) {
- $this->cond_die( __( $this->invalid_values_message ) );
- }
-
- $comment_id = (int) $_REQUEST[ 'comment_id' ];
- if ( $this->already_flagged( $comment_id ) ) {
- $this->cond_die( __( $this->already_flagged_message ) );
- }
-
- // checking if nonces help
- if ( ! isset( $_REQUEST[ 'sc_nonce' ] ) || ! wp_verify_nonce( $_REQUEST[ 'sc_nonce' ], $this->_plugin_prefix . '_' . $this->_nonce_key ) ) {
- $this->cond_die( __( $this->invalid_nonce_message ) );
- } else {
- $this->mark_flagged( $comment_id );
- $this->cond_die( __( $this->thank_you_message ) );
- }
-
- }
-
- public function print_flagging_link( $comment_id='', $result_id='', $text='Report comment' ) {
- //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaping done in get_flagging_link
- echo $this->get_flagging_link( $comment_id='', $result_id='', $text='Report comment' );
- }
-
- /*
- * Output Link to report a comment
- */
- public function get_flagging_link( $comment_id='', $result_id='', $text='Report comment' ) {
- global $in_comment_loop;
- if ( empty( $comment_id ) && !$in_comment_loop ) {
- return __( 'Wrong usage of print_flagging_link().' );
- }
- if ( empty( $comment_id ) ) {
- $comment_id = get_comment_ID();
- }
- else {
- $comment_id = (int) $comment_id;
- if ( !get_comment( $comment_id ) ) {
- return __( 'This comment does not exist.' );
- }
- }
- if ( empty( $result_id ) ) {
- $result_id = 'safe-comments-result-' . $comment_id;
- }
-
- $result_id = apply_filters( 'safe_report_comments_result_id', $result_id );
- $text = apply_filters( 'safe_report_comments_flagging_link_text', $text );
-
- $nonce = wp_create_nonce( $this->_plugin_prefix . '_' . $this->_nonce_key );
- $params = array(
- 'action' => 'safe_report_comments_flag_comment',
- 'sc_nonce' => $nonce,
- 'comment_id' => $comment_id,
- 'result_id' => $result_id,
- 'no_js' => true,
- );
-
- if ( $this->already_flagged( $comment_id ) ) {
- return __( $this->already_flagged_note );
- }
-
- return apply_filters( 'safe_report_comments_flagging_link', '
- ' . esc_html( $text ) . '' );
-
-
- }
-
- /*
- * Callback function to automatically hook in the report link after the comment reply link.
- * If you want to control the placement on your own define no_autostart_safe_report_comments in your functions.php file and initialize the class
- * with $safe_report_comments = new Safe_Report_Comments( $auto_init = false );
- */
- public function add_flagging_link( $comment_reply_link ) {
- if ( !preg_match_all( '#^(.*)(]+>)(.+)()(.*)$#msiU', $comment_reply_link, $matches ) ) {
- return '' . $comment_reply_link;
- }
-
- $comment_reply_link = $matches[1][0] . $matches[2][0] . $matches[4][0] . $matches[5][0] . '' . $matches[6][0];
- return apply_filters( 'safe_report_comments_comment_reply_link', $comment_reply_link );
- }
-
- /*
- * Callback function to add the report counter to comments screen. Remove action manage_edit-comments_columns if not desired
- */
- public function add_comment_reported_column( $comment_columns ) {
- $comment_columns['comment_reported'] = _x('Reported', 'column name');
- return $comment_columns;
- }
-
- /*
- * Callback function to handle custom column. remove action manage_comments_custom_column if not desired
- */
- public function manage_comment_reported_column( $column_name, $comment_id ) {
- switch ( $column_name ) {
- case 'comment_reported':
- $reports = 0;
- $already_reported = get_comment_meta( $comment_id, $this->_plugin_prefix . '_reported', true );
- if ( $already_reported > 0 ) {
- $reports = (int) $already_reported;
- }
- echo esc_html( $reports );
- break;
- default:
- break;
- }
- }
-
- }
+if ( ! class_exists( 'Safe_Report_Comments' ) ) {
+ require_once __DIR__ . '/class-safe-report-comments.php';
}
-if ( !defined( 'no_autostart_safe_report_comments' ) ) {
- $safe_report_comments = new Safe_Report_Comments;
+if ( ! defined( 'no_autostart_safe_report_comments' ) ) {
+ $safe_report_comments = new Safe_Report_Comments();
}
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index fc83ef7..7df12a4 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -14,4 +14,3 @@ function _manually_load_plugin() {
require $_tests_dir . '/includes/bootstrap.php';
-require dirname( __FILE__ ) . '/safe-report-comments-testcase.php';
diff --git a/tests/safe-report-comments-testcase.php b/tests/safe-report-comments-testcase.php
deleted file mode 100644
index dc890fc..0000000
--- a/tests/safe-report-comments-testcase.php
+++ /dev/null
@@ -1,13 +0,0 @@
-_toc = $safe_report_comments;
- }
-}