diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml new file mode 100644 index 0000000..5556d7e --- /dev/null +++ b/.github/workflows/code-quality.yml @@ -0,0 +1,31 @@ +name: PHP Code Linting + +on: + pull_request: + push: + branches: + - main + - master + +jobs: + php-lint: + name: PHP Lint + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + + - uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + + - name: Validate Composer configuration + run: composer validate + + - name: Install PHP dependencies + uses: ramsey/composer-install@83af392bf5f031813d25e6fe4cd626cdba9a2df6 + with: + composer-options: '--prefer-dist --no-progress --no-interaction' + + - name: Run tests + run: composer run-script phpcs diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index 73081f2..ded2c42 100644 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -90,6 +90,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/devtools/composer.json b/devtools/composer.json index 79d3d90..ce64f8d 100644 --- a/devtools/composer.json +++ b/devtools/composer.json @@ -2,6 +2,7 @@ "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^1.0", "phpcompatibility/phpcompatibility-wp": "^2.1", + "slevomat/coding-standard": "^8.15", "wp-cli/i18n-command": "^2.6", "wp-coding-standards/wpcs": "^3.1" }, diff --git a/includes/classes/class-ns-featured-posts-admin.php b/includes/classes/class-ns-featured-posts-admin.php index c9c50c8..a4b8110 100644 --- a/includes/classes/class-ns-featured-posts-admin.php +++ b/includes/classes/class-ns-featured-posts-admin.php @@ -5,6 +5,7 @@ * @package NS_Featured_Posts */ +use Nilambar\AdminNotice\Notice; use Nilambar\Optioner\Optioner; /** @@ -73,8 +74,6 @@ private function __construct() { $this->options = $plugin->get_options(); - - // Add an action link pointing to the options page. $base_file = $this->plugin_slug . '/' . $this->plugin_slug . '.php'; add_filter( 'plugin_action_links_' . $base_file, array( $this, 'add_plugin_action_links' ) ); @@ -107,9 +106,13 @@ private function __construct() { add_action( 'wp_ajax_nsfp_nsbl_get_posts', array( $this, 'get_posts_ajax_callback' ) ); } + /** + * Setup admin notice. + * + * @since 2.0.10 + */ public function setup_custom_notice() { - // Setup notice. - \Nilambar\AdminNotice\Notice::init( + Notice::init( array( 'slug' => $this->plugin_slug, 'name' => esc_html__( 'NS Featured Posts', 'ns-featured-posts' ), @@ -366,7 +369,7 @@ public function ajax_handler_featured_toggle() { ); // Nonce check. - $nonce = isset( $_POST['nonce'] ) ? $_POST['nonce'] : null; // phpcs:ignore WordPress.Security.NonceVerification + $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : null; // phpcs:ignore WordPress.Security.NonceVerification if ( ! wp_verify_nonce( $nonce, 'ajax-nonce' ) ) { $output['message'] = esc_html__( 'Nonce verification failed.', 'ns-featured-posts' ); @@ -374,23 +377,23 @@ public function ajax_handler_featured_toggle() { wp_send_json( $output ); } - $uno = isset( $_POST['uno'] ) ? rest_sanitize_boolean( $_POST['uno'] ) : false; + $uno = isset( $_POST['uno'] ) ? rest_sanitize_boolean( sanitize_text_field( wp_unslash( $_POST['uno'] ) ) ) : false; - $max_posts = isset( $_POST['max_posts'] ) ? absint( $_POST['max_posts'] ) : 0; - $max_status = isset( $_POST['max_status'] ) ? rest_sanitize_boolean( $_POST['max_status'] ) : false; + $max_posts = isset( $_POST['max_posts'] ) ? absint( sanitize_text_field( wp_unslash( $_POST['max_posts'] ) ) ) : 0; + $max_status = isset( $_POST['max_status'] ) ? rest_sanitize_boolean( sanitize_text_field( wp_unslash( $_POST['max_status'] ) ) ) : false; - $ns_featured = isset( $_POST['ns_featured'] ) ? $_POST['ns_featured'] : null; + $ns_featured = isset( $_POST['ns_featured'] ) ? sanitize_text_field( wp_unslash( $_POST['ns_featured'] ) ) : null; $post_id = 0; if ( isset( $_POST['post_id'] ) ) { - $post_id = (int) $_POST['post_id']; + $post_id = (int) sanitize_text_field( wp_unslash( $_POST['post_id'] ) ); } $post_type = null; if ( isset( $_POST['post_type'] ) ) { - $post_type = (string) $_POST['post_type']; + $post_type = (string) sanitize_text_field( wp_unslash( $_POST['post_type'] ) ); } if ( ! empty( $post_id ) && ! empty( $post_type ) && null !== $ns_featured ) { @@ -476,8 +479,8 @@ private function get_other_posts( $post_id, $post_type ) { $qargs = array( 'posts_per_page' => -1, 'post__not_in' => array( $post_id ), - 'meta_key' => '_is_ns_featured_post', - 'meta_value' => 'yes', + 'meta_key' => '_is_ns_featured_post', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key + 'meta_value' => 'yes', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value 'post_type' => $post_type, 'post_status' => array( 'publish', 'pending', 'draft', 'auto-draft', 'future', 'private', 'inherit', 'trash' ), ); @@ -491,6 +494,13 @@ private function get_other_posts( $post_id, $post_type ) { return $output; } + /** + * Load settings assets. + * + * @since 2.0.0 + * + * @param string $hook Hook name. + */ public function load_settings_assets( $hook ) { if ( 'settings_page_ns-featured-posts' !== $hook ) { return; @@ -524,7 +534,6 @@ public function load_assets() { ); wp_localize_script( 'nspf-admin', 'NSFP_OBJ', $localize_args ); - } /** @@ -592,7 +601,7 @@ public function save_featured_meta_box( $post_id ) { } // If our nonce isn't there, or we can't verify it, bail. - if ( ! isset( $_POST['nsfp_featured_metabox_nonce'] ) || ! wp_verify_nonce( $_POST['nsfp_featured_metabox_nonce'], plugin_basename( __FILE__ ) ) ) { + if ( ! isset( $_POST['nsfp_featured_metabox_nonce'] ) || ! wp_verify_nonce( $_POST['nsfp_featured_metabox_nonce'], plugin_basename( __FILE__ ) ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput return $post_id; } @@ -662,7 +671,7 @@ public function custom_table_filtering() { $selected_now = ''; if ( isset( $_GET['filter-ns-featured-posts'] ) ) { - $selected_now = esc_attr( $_GET['filter-ns-featured-posts'] ); + $selected_now = sanitize_text_field( wp_unslash( $_GET['filter-ns-featured-posts'] ) ); } echo ''; @@ -685,13 +694,11 @@ public function custom_query_filtering( $query ) { $qv = &$query->query_vars; if ( is_admin() && 'edit.php' === $pagenow ) { - if ( ! isset( $qv['meta_query'] ) ) { - $qv['meta_query'] = array(); + $qv['meta_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query } if ( ! empty( $_GET['filter-ns-featured-posts'] ) ) { - if ( 'yes' === $_GET['filter-ns-featured-posts'] ) { $qv['meta_query'][] = array( 'key' => '_is_ns_featured_post', @@ -726,10 +733,8 @@ public function custom_query_filtering( $query ) { * Adding filtering link. * * @since 1.0.0 - * - * @param WP_Query $wp_query Instance of WP_Query object. */ - public function custom_filtering_query_for_listing( $wp_query ) { + public function custom_filtering_query_for_listing() { if ( is_admin() ) { $allowed = $this->get_allowed_post_types(); @@ -749,7 +754,7 @@ public function custom_filtering_query_for_listing( $wp_query ) { * @param array $views Views. */ public function add_views_link( $views ) { - $post_type = ( ( isset( $_GET['post_type'] ) && '' !== $_GET['post_type'] ) ? $_GET['post_type'] : 'post' ); + $post_type = ( ( isset( $_GET['post_type'] ) && '' !== $_GET['post_type'] ) ? sanitize_text_field( wp_unslash( $_GET['post_type'] ) ) : 'post' ); $count = $this->get_total_featured_count( $post_type ); $class = ( isset( $_GET['featured'] ) && 'yes' === $_GET['featured'] ) ? 'current' : ''; @@ -783,8 +788,8 @@ public function get_total_featured_count( $post_type ) { $args = array( 'post_type' => $post_type, 'posts_per_page' => -1, - 'meta_key' => '_is_ns_featured_post', - 'meta_value' => 'yes', + 'meta_key' => '_is_ns_featured_post', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key + 'meta_value' => 'yes', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value 'post_status' => array( 'publish', 'pending', 'draft', 'auto-draft', 'future', 'private', 'inherit', 'trash' ), ); @@ -806,9 +811,11 @@ public function register_custom_widgets() { * Render sidebar. * * @since 2.0.0 + * + * @param Optioner $optioner_object Instance of Optioner. */ - public function render_sidebar( $object ) { - $object->render_sidebar_box( + public function render_sidebar( $optioner_object ) { + $optioner_object->render_sidebar_box( array( 'title' => 'Help & Support', 'icon' => 'dashicons-editor-help', @@ -817,15 +824,15 @@ public function render_sidebar( $object ) { Wanna help make this plugin better? Review and rate this plugin on WordPress.org', ), - $object + $optioner_object ); - $object->render_sidebar_box( + $optioner_object->render_sidebar_box( array( 'title' => 'Recent Blog Posts', 'content' => '', ), - $object + $optioner_object ); } @@ -870,9 +877,9 @@ public function show_admin_message() { * @since 2.0.0 * * @param array $attributes Attributes. - * @param bool $echo Whether to echo or not. + * @param bool $display Whether to echo or not. */ - public function render_attr( $attributes, $echo = true ) { + public function render_attr( $attributes, $display = true ) { if ( empty( $attributes ) ) { return; } @@ -880,7 +887,6 @@ public function render_attr( $attributes, $echo = true ) { $html = ''; foreach ( $attributes as $name => $value ) { - $esc_value = ''; if ( 'class' === $name && is_array( $value ) ) { @@ -889,7 +895,6 @@ public function render_attr( $attributes, $echo = true ) { if ( false !== $value && 'href' === $name ) { $esc_value = esc_url( $value ); - } elseif ( false !== $value ) { $esc_value = esc_attr( $value ); } @@ -897,13 +902,18 @@ public function render_attr( $attributes, $echo = true ) { $html .= false !== $value ? sprintf( ' %s="%s"', esc_html( $name ), $esc_value ) : esc_html( " {$name}" ); } - if ( ! empty( $html ) && true === $echo ) { + if ( ! empty( $html ) && true === $display ) { echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } else { return $html; } } + /** + * AJAX callback for feed items. + * + * @since 2.0.0 + */ public function get_posts_ajax_callback() { $output = array(); @@ -920,6 +930,11 @@ public function get_posts_ajax_callback() { } } + /** + * Returns blog feed items. + * + * @since 2.0.0 + */ public function get_blog_feed_items() { $output = array(); diff --git a/includes/classes/class-ns-featured-posts.php b/includes/classes/class-ns-featured-posts.php index 03bece1..6c4cc9b 100644 --- a/includes/classes/class-ns-featured-posts.php +++ b/includes/classes/class-ns-featured-posts.php @@ -122,14 +122,12 @@ public static function get_instance() { public static function activate( $network_wide ) { if ( function_exists( 'is_multisite' ) && is_multisite() ) { - if ( $network_wide ) { // Get all blog ids. $blog_ids = self::get_blog_ids(); foreach ( $blog_ids as $blog_id ) { - switch_to_blog( $blog_id ); self::single_activate(); } @@ -153,14 +151,12 @@ public static function activate( $network_wide ) { public static function deactivate( $network_wide ) { if ( function_exists( 'is_multisite' ) && is_multisite() ) { - if ( $network_wide ) { // Get all blog ids. $blog_ids = self::get_blog_ids(); foreach ( $blog_ids as $blog_id ) { - switch_to_blog( $blog_id ); self::single_deactivate(); } @@ -203,7 +199,7 @@ private static function get_blog_ids() { $ids = array(); - $output = $wpdb->get_results( "SELECT blog_id FROM $wpdb->blogs WHERE archived = '0' AND spam = '0' AND deleted = '0'", ARRAY_A ); + $output = $wpdb->get_results( "SELECT blog_id FROM $wpdb->blogs WHERE archived = '0' AND spam = '0' AND deleted = '0'", ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery if ( $output ) { $ids = wp_list_pluck( $output, 'blog_id' ); @@ -285,7 +281,6 @@ public function migrate_options() { if ( $opt ) { if ( isset( $opt['nsfp_posttypes'] ) && ! empty( $opt['nsfp_posttypes'] ) ) { - $values = array_keys( $opt['nsfp_posttypes'] ); $values = array_filter( $values ); diff --git a/includes/widgets/nsfp-featured-post-widget.php b/includes/widgets/nsfp-featured-post-widget.php index c5e5833..9bf29d9 100644 --- a/includes/widgets/nsfp-featured-post-widget.php +++ b/includes/widgets/nsfp-featured-post-widget.php @@ -47,10 +47,10 @@ public function widget( $args, $instance ) { $number = 5; } - $post_type = isset( $instance['post_type'] ) ? esc_attr( $instance['post_type'] ) : 'post'; - $post_orderby = isset( $instance['post_orderby'] ) ? esc_attr( $instance['post_orderby'] ) : 'date'; - $post_order = isset( $instance['post_order'] ) ? esc_attr( $instance['post_order'] ) : 'desc'; - $show_date = isset( $instance['show_date'] ) ? $instance['show_date'] : false; + $post_type = isset( $instance['post_type'] ) ? esc_attr( $instance['post_type'] ) : 'post'; + $post_orderby = isset( $instance['post_orderby'] ) ? esc_attr( $instance['post_orderby'] ) : 'date'; + $post_order = isset( $instance['post_order'] ) ? esc_attr( $instance['post_order'] ) : 'desc'; + $show_date = isset( $instance['show_date'] ) ? $instance['show_date'] : false; $nsfp_query = new WP_Query( apply_filters( @@ -60,8 +60,8 @@ public function widget( $args, $instance ) { 'no_found_rows' => true, 'post_status' => 'publish', 'ignore_sticky_posts' => true, - 'meta_key' => '_is_ns_featured_post', - 'meta_value' => 'yes', + 'meta_key' => '_is_ns_featured_post', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key + 'meta_value' => 'yes', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value 'post_type' => $post_type, 'orderby' => $post_orderby, 'order' => $post_order, @@ -182,7 +182,7 @@ public function form( $instance ) { 'comment_count' => esc_html__( 'Comment Count', 'ns-featured-posts' ), 'menu_order' => esc_html__( 'Menu Order', 'ns-featured-posts' ), ); - $orderby_args = array( + $orderby_args = array( 'name' => $this->get_field_name( 'post_orderby' ), 'id' => $this->get_field_id( 'post_orderby' ), 'selected' => $instance['post_orderby'], @@ -197,7 +197,7 @@ public function form( $instance ) { 'desc' => esc_html__( 'Descending', 'ns-featured-posts' ), 'asc' => esc_html__( 'Ascending', 'ns-featured-posts' ), ); - $order_args = array( + $order_args = array( 'name' => $this->get_field_name( 'post_order' ), 'id' => $this->get_field_id( 'post_order' ), 'selected' => $instance['post_order'], @@ -226,13 +226,12 @@ protected function render_select_dropdown( $choices, $main_args ) { return; } - $defaults = array( 'id' => '', 'name' => '', 'selected' => 0, 'echo' => true, - ); + ); $r = wp_parse_args( $main_args, $defaults ); @@ -252,7 +251,7 @@ protected function render_select_dropdown( $choices, $main_args ) { } if ( $r['echo'] ) { - echo $output; + echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } return $output; diff --git a/ns-featured-posts.php b/ns-featured-posts.php index 25eba8a..6197727 100644 --- a/ns-featured-posts.php +++ b/ns-featured-posts.php @@ -20,7 +20,7 @@ } define( 'NS_FEATURED_POSTS_VERSION', '2.0.13' ); -define( 'NS_FEATURED_POSTS_BASENAME', basename( dirname( __FILE__ ) ) ); +define( 'NS_FEATURED_POSTS_BASENAME', basename( __DIR__ ) ); define( 'NS_FEATURED_POSTS_DIR', rtrim( plugin_dir_path( __FILE__ ), '/' ) ); define( 'NS_FEATURED_POSTS_URL', rtrim( plugin_dir_url( __FILE__ ), '/' ) );
Review and rate this plugin on WordPress.org