From 0dc693b68d9d839cdde7bcd78ba41872eefe889e Mon Sep 17 00:00:00 2001 From: Colin Stewart <79332690+costdev@users.noreply.github.com> Date: Thu, 26 Jun 2025 18:10:59 +0100 Subject: [PATCH] Add and apply coding standards. (#129) Signed-off-by: costdev <79332690+costdev@users.noreply.github.com> Signed-off-by: Colin Stewart <79332690+costdev@users.noreply.github.com> Co-authored-by: Andy Fragen --- .cache/.gitkeep | 0 .distignore | 2 + .gitattributes | 2 + .github/workflows/coding-standards.yml | 64 ++++++++ .gitignore | 5 + composer.json | 10 +- inc/assets/namespace.php | 8 +- inc/avatars/namespace.php | 15 +- inc/dashboard-widgets/namespace.php | 17 ++- inc/default-repo/namespace.php | 9 +- inc/disable-openverse/namespace.php | 6 +- inc/icons/namespace.php | 3 +- inc/icons/svg.php | 4 +- inc/importers/namespace.php | 62 ++++---- inc/namespace.php | 5 +- inc/pings/namespace.php | 194 +++++++++++++------------ inc/repositories/namespace.php | 3 + inc/salts/namespace.php | 24 +-- inc/settings/namespace.php | 34 +++-- inc/version-check/namespace.php | 6 +- package.json | 2 + phpcs.xml.dist | 75 ++++++++++ plugin.php | 6 +- 23 files changed, 375 insertions(+), 181 deletions(-) create mode 100644 .cache/.gitkeep create mode 100644 .github/workflows/coding-standards.yml create mode 100644 phpcs.xml.dist diff --git a/.cache/.gitkeep b/.cache/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.distignore b/.distignore index 4943693..2936d46 100644 --- a/.distignore +++ b/.distignore @@ -1,11 +1,13 @@ # Main .git/ .github/ +.cache/ bin/ node_modules/ tests/ phpunit.xml.dist wp-tests-config-sample.php +phpcs.xml.dist composer.json composer.lock package.json diff --git a/.gitattributes b/.gitattributes index 75707fb..3bee9f5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,10 +3,12 @@ /.git export-ignore /.github export-ignore /bin export-ignore +/.cache export-ignore /node_modules export-ignore /tests export-ignore phpunit.xml.dist export-ignore wp-tests-config-sample.php export-ignore +phpcs.xml.dist export-ignore composer.json export-ignore composer.lock export-ignore package.json export-ignore diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml new file mode 100644 index 0000000..18695c7 --- /dev/null +++ b/.github/workflows/coding-standards.yml @@ -0,0 +1,64 @@ +name: PHP coding standards + +on: + push: + branches: + - main + pull_request: + branches: + - main + workflow_dispatch: + +# Cancels all previous workflow runs for pull requests that have not completed. +concurrency: + # The concurrency group contains the workflow name and the branch name for pull requests + # or the commit hash for any other events. + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }} + cancel-in-progress: true + +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + +jobs: + # Runs the PHP coding standards checks. + # + # Violations are reported inline with annotations. + # + # Performs the following steps: + # - Checks out the repository. + # - Sets up PHP. + # - Installs Composer dependencies. + # - Make Composer packages available globally. + # - Runs PHPCS on the full codebase (warnings excluded). + # - Ensures version-controlled files are not modified or deleted. + phpcs: + name: Run coding standards checks + runs-on: ubuntu-latest + permissions: + contents: read + timeout-minutes: 20 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + + - name: Set up PHP + uses: shivammathur/setup-php@cf4cade2721270509d5b1c766ab3549210a39a2a # v2.33.0 + with: + coverage: none + + - name: Install Composer dependencies + uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # v3.1.1 + + - name: Make Composer packages available globally + run: echo "${PWD}/vendor/bin" >> $GITHUB_PATH + + - name: Run PHPCS on all files + id: phpcs-files + run: phpcs . -n --report-full + + - name: Ensure version-controlled files are not modified during the checks + run: git diff --exit-code diff --git a/.gitignore b/.gitignore index 45371e6..d30c911 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,14 @@ +/.cache/ /node_modules/ *.bak /.vscode /vendor/ .phpunit.result.cache phpunit.xml +phpcs.xml /tests/phpunit/cache /tests/phpunit/coverage wp-tests-config.php + +# Track placeholders so that empty directories stay in the repo. +!.gitkeep diff --git a/composer.json b/composer.json index 3ae2707..d2f9e76 100644 --- a/composer.json +++ b/composer.json @@ -13,12 +13,18 @@ }, "require-dev": { "yoast/phpunit-polyfills": "*", - "nimut/phpunit-merger": "*" + "nimut/phpunit-merger": "*", + "humanmade/coding-standards": "^1.2" }, "config": { - "lock": false + "lock": false, + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } }, "scripts": { + "lint": "@php ./vendor/bin/phpcs .", + "format": "@php ./vendor/bin/phpcbf .", "test": [ "Composer\\Config::disableProcessTimeout", "@php ./vendor/phpunit/phpunit/phpunit" diff --git a/inc/assets/namespace.php b/inc/assets/namespace.php index fa4ceba..1c51625 100644 --- a/inc/assets/namespace.php +++ b/inc/assets/namespace.php @@ -13,8 +13,8 @@ const DEFAULT_EMOJI_BASE = 'https://cdn.jsdelivr.net/gh/jdecked/twemoji@15.1.0/a * Bootstrap. */ function bootstrap() { - add_filter( 'emoji_url', __NAMESPACE__ . '\\replace_emoji_url' ); - add_filter( 'emoji_svg_url', __NAMESPACE__ . '\\replace_emoji_svg_url' ); + add_filter( 'emoji_url', __NAMESPACE__ . '\\replace_emoji_url' ); + add_filter( 'emoji_svg_url', __NAMESPACE__ . '\\replace_emoji_svg_url' ); } /** @@ -36,7 +36,7 @@ function get_emoji_base_url() : string { * @return string The base URL. */ function replace_emoji_url() { - return get_emoji_base_url() . '72x72/'; + return get_emoji_base_url() . '72x72/'; } /** @@ -45,5 +45,5 @@ function replace_emoji_url() { * @return string The base URL. */ function replace_emoji_svg_url() { - return get_emoji_base_url() . 'svg/'; + return get_emoji_base_url() . 'svg/'; } diff --git a/inc/avatars/namespace.php b/inc/avatars/namespace.php index 72753dd..d913fc9 100644 --- a/inc/avatars/namespace.php +++ b/inc/avatars/namespace.php @@ -1,4 +1,9 @@ display_name; wp_enqueue_media(); - wp_enqueue_script( 'fair-avatars', esc_url( plugin_dir_url( \FAIR\PLUGIN_FILE ) . 'assets/js/fair-avatars.js' ), ['jquery','wp-a11y','wp-i18n'], \FAIR\VERSION, true ); + wp_enqueue_script( 'fair-avatars', esc_url( plugin_dir_url( \FAIR\PLUGIN_FILE ) . 'assets/js/fair-avatars.js' ), [ 'jquery', 'wp-a11y', 'wp-i18n' ], \FAIR\VERSION, true ); wp_localize_script( 'fair-avatars', 'fairAvatars', [ 'defaultImg' => generate_default_avatar( $display_name ), @@ -54,7 +59,7 @@ function enqueue_media_scripts( $hook_suffix ) { ); // Some inline CSS for our fields. - $setup_css = ' + $setup_css = ' span.fair-avatar-desc { display: block; margin-top: 5px; @@ -105,6 +110,8 @@ function add_avatar_upload_field( $description, $profile_user ) { * @param int $user_id User ID. */ function save_avatar_upload( $user_id ) { + check_admin_referer( 'update-user_' . $user_id ); + if ( ! current_user_can( 'edit_user', $user_id ) ) { return; } @@ -137,7 +144,7 @@ function save_avatar_upload( $user_id ) { function filter_avatar( $avatar, $id_or_email, $size, $default, $alt, $args ) { $avatar_url = get_avatar_url( $id_or_email, $args ); - $class = array( 'avatar', 'avatar-' . (int) $size, 'photo' ); + $class = [ 'avatar', 'avatar-' . (int) $size, 'photo' ]; if ( ! empty( $args['class'] ) ) { $class = array_merge( $class, (array) $args['class'] ); } diff --git a/inc/dashboard-widgets/namespace.php b/inc/dashboard-widgets/namespace.php index f2e44c7..b418fad 100644 --- a/inc/dashboard-widgets/namespace.php +++ b/inc/dashboard-widgets/namespace.php @@ -1,4 +1,9 @@ 'event', 'title' => $event['title']['rendered'], 'url' => $url, @@ -128,7 +132,7 @@ function get_community_events() { 'latitude' => $event['camp_lat'] ?? 0, 'longitude' => $event['camp_lng'] ?? 0, ], - ); + ]; } // Resort events by start date. @@ -171,9 +175,9 @@ function render_news_widget() : void { '%2$s %3$s', /* translators: If a Rosetta site exists (e.g. https://es.fair.pm/news/), then use that. Otherwise, leave untranslated. */ esc_url( _x( 'https://fair.pm/', 'Events and News dashboard widget', 'fair' ) ), - __( 'News' ), + __( 'News', 'fair' ), /* translators: Hidden accessibility text. */ - __( '(opens in a new tab)' ) + __( '(opens in a new tab)', 'fair' ) ); ?> @@ -185,7 +189,7 @@ function render_news_widget() : void { 'https://thewp.world/events/', __( 'Events (by The WP World)', 'fair' ), /* translators: Hidden accessibility text. */ - __( '(opens in a new tab)' ) + __( '(opens in a new tab)', 'fair' ) ); ?>

@@ -240,6 +244,7 @@ function set_help_content_fair_planet_urls() : void { $planet_fair_url = rtrim( $planet_fair_url, '/' ); $new_tab_content = preg_replace( + /* phpcs:ignore WordPress.WP.CapitalPDangit.Misspelled */ '/https?:\/\/planet\.wordpress\.org/', $planet_fair_url, $tab['content'], diff --git a/inc/default-repo/namespace.php b/inc/default-repo/namespace.php index 11acb74..4eccaef 100644 --- a/inc/default-repo/namespace.php +++ b/inc/default-repo/namespace.php @@ -7,8 +7,6 @@ namespace FAIR\Default_Repo; -use WP_Error; - /** * Bootstrap. */ @@ -39,8 +37,9 @@ function get_default_repo_domain() : string { * and themes APIs. Only these get passed to the chosen FAIR repo, as the others are * handled in other modules. * - * @param array $args - * @param string $url + * @param bool|array $status Filtered value, or false to proceed. + * @param array $args HTTP request arguments. + * @param string $url The request URL. * @return bool|array Replaced value, or false to proceed. */ function replace_repo_api_urls( $status, $args, $url ) { @@ -76,7 +75,7 @@ function replace_repo_api_urls( $status, $args, $url ) { * This tab only makes sense for WordPress.org, so is not supported by * other repositories. * - * @param array $tabs + * @param array $tabs Tabs in the plugin browser. */ function remove_favorites_tab( array $tabs ) : array { unset( $tabs['favorites'] ); diff --git a/inc/disable-openverse/namespace.php b/inc/disable-openverse/namespace.php index e642859..2f4da02 100644 --- a/inc/disable-openverse/namespace.php +++ b/inc/disable-openverse/namespace.php @@ -11,7 +11,7 @@ namespace FAIR\Disable_Openverse; * Bootstrap the module functionality. */ function bootstrap() { - add_filter( 'block_editor_settings_all', __NAMESPACE__ . '\\disable_openverse_block_editor_settings' ); + add_filter( 'block_editor_settings_all', __NAMESPACE__ . '\\disable_openverse_block_editor_settings' ); } /** @@ -21,6 +21,6 @@ function bootstrap() { * @return array The modified block editor settings. */ function disable_openverse_block_editor_settings( array $settings ) : array { - $settings['enableOpenverseMediaCategory'] = false; - return $settings; + $settings['enableOpenverseMediaCategory'] = false; + return $settings; } diff --git a/inc/icons/namespace.php b/inc/icons/namespace.php index ef9f834..f132ce2 100644 --- a/inc/icons/namespace.php +++ b/inc/icons/namespace.php @@ -8,7 +8,6 @@ namespace FAIR\Icons; use FAIR; -use stdClass; /** * Bootstrap @@ -40,7 +39,7 @@ function set_default_icon( $transient ) { * @return string */ function set_random_color() { - $rand = str_pad( dechex( rand( 0x000000, 0xFFFFFF ) ), 6, 0, STR_PAD_LEFT ); + $rand = str_pad( dechex( wp_rand( 0x000000, 0xFFFFFF ) ), 6, 0, STR_PAD_LEFT ); return $rand; } diff --git a/inc/icons/svg.php b/inc/icons/svg.php index 42773f3..bf3be46 100644 --- a/inc/icons/svg.php +++ b/inc/icons/svg.php @@ -5,6 +5,7 @@ * @package FAIR */ +// phpcs:ignore HM.Security.ValidatedSanitizedInput.MissingUnslash, HM.Security.ValidatedSanitizedInput.InputNotSanitized $color = isset( $_GET['color'] ) ? sanitize_hex_color( '#' . stripslashes( $_GET['color'] ) ) : ''; /** @@ -29,7 +30,7 @@ function sanitize_hex_color( $color ) { header( 'Content-Type: image/svg+xml' ); // Echo the SVG content. -// phpcs:ignore HM.Security.EscapeOutput.OutputNotEscaped +// phpcs:disable HM.Security.EscapeOutput.OutputNotEscaped echo ' @@ -56,3 +57,4 @@ echo ' '; +// phpcs:enable HM.Security.EscapeOutput.OutputNotEscaped diff --git a/inc/importers/namespace.php b/inc/importers/namespace.php index 10702bf..4e00c4f 100644 --- a/inc/importers/namespace.php +++ b/inc/importers/namespace.php @@ -7,8 +7,6 @@ namespace FAIR\Importers; -use WP_Error; - /** * Bootstrap. */ @@ -84,50 +82,50 @@ function get_popular_importers_gte_46() { return [ // slug => name, description, plugin slug, and register_importer() slug. 'blogger' => [ - 'name' => 'Blogger' , - 'description' => 'Import posts, comments, and users from a Blogger blog.' , + 'name' => 'Blogger', + 'description' => 'Import posts, comments, and users from a Blogger blog.', 'plugin-slug' => 'blogger-importer', 'importer-id' => 'blogger', ], 'wpcat2tag' => [ - 'name' => 'Categories and Tags Converter' , - 'description' => 'Convert existing categories to tags or tags to categories, selectively.' , + 'name' => 'Categories and Tags Converter', + 'description' => 'Convert existing categories to tags or tags to categories, selectively.', 'plugin-slug' => 'wpcat2tag-importer', 'importer-id' => 'wp-cat2tag', ], 'livejournal' => [ - 'name' => 'LiveJournal' , - 'description' => 'Import posts from LiveJournal using their API.' , + 'name' => 'LiveJournal', + 'description' => 'Import posts from LiveJournal using their API.', 'plugin-slug' => 'livejournal-importer', 'importer-id' => 'livejournal', ], 'movabletype' => [ - 'name' => 'Movable Type and TypePad' , - 'description' => 'Import posts and comments from a Movable Type or TypePad blog.' , + 'name' => 'Movable Type and TypePad', + 'description' => 'Import posts and comments from a Movable Type or TypePad blog.', 'plugin-slug' => 'movabletype-importer', 'importer-id' => 'mt', ], 'opml' => [ - 'name' => 'Blogroll' , - 'description' => 'Import links in OPML format.' , + 'name' => 'Blogroll', + 'description' => 'Import links in OPML format.', 'plugin-slug' => 'opml-importer', 'importer-id' => 'opml', ], 'rss' => [ - 'name' => 'RSS' , - 'description' => 'Import posts from an RSS feed.' , + 'name' => 'RSS', + 'description' => 'Import posts from an RSS feed.', 'plugin-slug' => 'rss-importer', 'importer-id' => 'rss', ], 'tumblr' => [ - 'name' => 'Tumblr' , - 'description' => 'Import posts & media from Tumblr using their API.' , + 'name' => 'Tumblr', + 'description' => 'Import posts & media from Tumblr using their API.', 'plugin-slug' => 'tumblr-importer', 'importer-id' => 'tumblr', ], 'wordpress' => [ 'name' => 'WordPress', - 'description' => 'Import posts, pages, comments, custom fields, categories, and tags from a WordPress export file.' , + 'description' => 'Import posts, pages, comments, custom fields, categories, and tags from a WordPress export file.', 'plugin-slug' => 'wordpress-importer', 'importer-id' => 'wordpress', ], @@ -147,50 +145,50 @@ function get_popular_importers_lt_46() { return [ // slug => name, description, plugin slug, and register_importer() slug. 'blogger' => [ - 'name' => 'Blogger' , - 'description' => 'Install the Blogger importer to import posts, comments, and users from a Blogger blog.' , + 'name' => 'Blogger', + 'description' => 'Install the Blogger importer to import posts, comments, and users from a Blogger blog.', 'plugin-slug' => 'blogger-importer', 'importer-id' => 'blogger', ], 'wpcat2tag' => [ - 'name' => 'Categories and Tags Converter' , - 'description' => 'Install the category/tag converter to convert existing categories to tags or tags to categories, selectively.' , + 'name' => 'Categories and Tags Converter', + 'description' => 'Install the category/tag converter to convert existing categories to tags or tags to categories, selectively.', 'plugin-slug' => 'wpcat2tag-importer', 'importer-id' => 'wpcat2tag', ], 'livejournal' => [ - 'name' => 'LiveJournal' , - 'description' => 'Install the LiveJournal importer to import posts from LiveJournal using their API.' , + 'name' => 'LiveJournal', + 'description' => 'Install the LiveJournal importer to import posts from LiveJournal using their API.', 'plugin-slug' => 'livejournal-importer', 'importer-id' => 'livejournal', ], 'movabletype' => [ - 'name' => 'Movable Type and TypePad' , - 'description' => 'Install the Movable Type importer to import posts and comments from a Movable Type or TypePad blog.' , + 'name' => 'Movable Type and TypePad', + 'description' => 'Install the Movable Type importer to import posts and comments from a Movable Type or TypePad blog.', 'plugin-slug' => 'movabletype-importer', 'importer-id' => 'mt', ], 'opml' => [ - 'name' => 'Blogroll' , - 'description' => 'Install the blogroll importer to import links in OPML format.' , + 'name' => 'Blogroll', + 'description' => 'Install the blogroll importer to import links in OPML format.', 'plugin-slug' => 'opml-importer', 'importer-id' => 'opml', ], 'rss' => [ - 'name' => 'RSS' , - 'description' => 'Install the RSS importer to import posts from an RSS feed.' , + 'name' => 'RSS', + 'description' => 'Install the RSS importer to import posts from an RSS feed.', 'plugin-slug' => 'rss-importer', 'importer-id' => 'rss', ], 'tumblr' => [ - 'name' => 'Tumblr' , - 'description' => 'Install the Tumblr importer to import posts & media from Tumblr using their API.' , + 'name' => 'Tumblr', + 'description' => 'Install the Tumblr importer to import posts & media from Tumblr using their API.', 'plugin-slug' => 'tumblr-importer', 'importer-id' => 'tumblr', ], 'wordpress' => [ 'name' => 'WordPress', - 'description' => 'Install the WordPress importer to import posts, pages, comments, custom fields, categories, and tags from a WordPress export file.' , + 'description' => 'Install the WordPress importer to import posts, pages, comments, custom fields, categories, and tags from a WordPress export file.', 'plugin-slug' => 'wordpress-importer', 'importer-id' => 'wordpress', ], diff --git a/inc/namespace.php b/inc/namespace.php index 7b56b3b..cc5a90a 100644 --- a/inc/namespace.php +++ b/inc/namespace.php @@ -11,6 +11,9 @@ use Fragen\Git_Updater; const NS_SEPARATOR = '\\'; +/** + * Bootstrap. + */ function bootstrap() { // Prevent accidental re-initialization of the plugin. static $did_init = false; @@ -22,7 +25,7 @@ function bootstrap() { register_class_path( __NAMESPACE__, __DIR__ . '/inc' ); - // Modules: + // Modules. Avatars\bootstrap(); Credits\bootstrap(); Dashboard_Widgets\bootstrap(); diff --git a/inc/pings/namespace.php b/inc/pings/namespace.php index 6d42999..ea757e9 100644 --- a/inc/pings/namespace.php +++ b/inc/pings/namespace.php @@ -1,4 +1,9 @@ 403 ] ); - return; - } + $key = get_indexnow_key(); + if ( ! $key || $key !== get_query_var( 'fair_indexnow_key' ) ) { + $error = 'Invalid key: ' . get_query_var( 'fair_indexnow_key' ); + wp_die( esc_html( $error ), 'IndexNow Key Error', [ 'response' => 403 ] ); + return; + } - // Set the content type to text/plain - header( 'Content-Type: text/plain' ); - header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + YEAR_IN_SECONDS ) . ' GMT' ); - header( 'Cache-Control: public, max-age=' . YEAR_IN_SECONDS ); + // Set the content type to text/plain. + header( 'Content-Type: text/plain' ); + header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + YEAR_IN_SECONDS ) . ' GMT' ); + header( 'Cache-Control: public, max-age=' . YEAR_IN_SECONDS ); - // Output the key - echo $key; - exit; + // Output the key. + echo esc_html( $key ); + exit; } /** @@ -103,66 +109,68 @@ function handle_key_file_request() { * @param WP_Post $post Post object. */ function ping_indexnow( $new_status, $old_status, $post ) : void { - // Only ping for published posts. - if ( 'publish' !== $new_status ) { - return; - } + // Only ping for published posts. + if ( 'publish' !== $new_status ) { + return; + } - // Skip revisions and autosaves. - if ( wp_is_post_revision( $post ) || wp_is_post_autosave( $post ) ) { - return; - } + // Skip revisions and autosaves. + if ( wp_is_post_revision( $post ) || wp_is_post_autosave( $post ) ) { + return; + } - // Skip non-public post types. - if ( ! is_post_type_viewable( $post->post_type ) ) { - return; - } + // Skip non-public post types. + if ( ! is_post_type_viewable( $post->post_type ) ) { + return; + } - $key = get_option( 'fair_indexnow_key' ); - if ( ! $key ) { - return; - } + $key = get_option( 'fair_indexnow_key' ); + if ( ! $key ) { + return; + } - $url = get_permalink( $post ); - if ( ! $url ) { - return; - } + $url = get_permalink( $post ); + if ( ! $url ) { + return; + } - // Allow for filtering the URL list. - $url_list = apply_filters( 'fair_indexnow_url_list', [ $url ] ); + // Allow for filtering the URL list. + $url_list = apply_filters( 'fair_indexnow_url_list', [ $url ] ); - // Allow for filtering the key location. - $key_location = apply_filters( 'fair_indexnow_key_location', trailingslashit( home_url( 'fair-indexnow-' . $key ) ) ); + // Allow for filtering the key location. + $key_location = apply_filters( 'fair_indexnow_key_location', trailingslashit( home_url( 'fair-indexnow-' . $key ) ) ); - // The "false" on the end of the x-source-info header determines whether this is a manual submission or not. - $data = [ - 'host' => wp_parse_url( home_url(), PHP_URL_HOST ), - 'key' => $key, - 'keyLocation' => $key_location, - 'urlList' => $url_list, - ]; - $request = [ - 'body' => wp_json_encode( $data, JSON_UNESCAPED_SLASHES ), - 'headers' => [ - 'Content-Type' => 'application/json; charset=utf-8', - 'x-source-info' => 'https://example.com/fair-wp/indexnow/false', // TODO: replace example.com with the domain we end up using. - ], - ]; + // The "false" on the end of the x-source-info header determines whether this is a manual submission or not. + $data = [ + 'host' => wp_parse_url( home_url(), PHP_URL_HOST ), + 'key' => $key, + 'keyLocation' => $key_location, + 'urlList' => $url_list, + ]; + $request = [ + 'body' => wp_json_encode( $data, JSON_UNESCAPED_SLASHES ), + 'headers' => [ + 'Content-Type' => 'application/json; charset=utf-8', + 'x-source-info' => 'https://example.com/fair-wp/indexnow/false', // TODO: replace example.com with the domain we end up using. + ], + ]; - // Ping IndexNow. - $response = wp_remote_post( - 'https://api.indexnow.org/indexnow', - $request - ); + // Ping IndexNow. + $response = wp_remote_post( + 'https://api.indexnow.org/indexnow', + $request + ); - // Log the response for debugging. As per https://www.indexnow.org/documentation#response, either 200 or 202 is acceptable. - if ( is_wp_error( $response ) ) { - error_log( 'IndexNow ping failed: ' . $response->get_error_message() . print_r( $request, true ) ); - return; - } + // Log the response for debugging. As per https://www.indexnow.org/documentation#response, either 200 or 202 is acceptable. + if ( is_wp_error( $response ) ) { + /* phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r */ + error_log( 'IndexNow ping failed: ' . $response->get_error_message() . print_r( $request, true ) ); + return; + } - $status = wp_remote_retrieve_response_code( $response ); - if ( ! in_array( $status, [ 200, 202 ], true ) ) { - error_log( 'IndexNow ping failed: ' . $status . print_r( $request, true ) ); - } + $status = wp_remote_retrieve_response_code( $response ); + if ( ! in_array( $status, [ 200, 202 ], true ) ) { + /* phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r */ + error_log( 'IndexNow ping failed: ' . $status . print_r( $request, true ) ); + } } diff --git a/inc/repositories/namespace.php b/inc/repositories/namespace.php index 48dd624..94edc7e 100644 --- a/inc/repositories/namespace.php +++ b/inc/repositories/namespace.php @@ -7,5 +7,8 @@ namespace FAIR\Repositories; +/** + * Bootstrap. + */ function bootstrap() { } diff --git a/inc/salts/namespace.php b/inc/salts/namespace.php index 0ea2476..a0674be 100644 --- a/inc/salts/namespace.php +++ b/inc/salts/namespace.php @@ -23,8 +23,8 @@ function bootstrap() { * Replace the call to retrieve generated salt values. * * @param bool|array $value Filtered value, or false to proceed. - * @param array $args - * @param string $url + * @param array $args HTTP request arguments. + * @param string $url The request URL. * @return bool|array Replaced value, or false to proceed. */ function replace_salt_generation_via_api( $value, $args, $url ) { @@ -65,13 +65,13 @@ function get_salt_generation_response() { function generate_salt_response_body() { // Grab my key names. - $get_key_names = define_salt_keynames(); + $get_key_names = define_salt_keynames(); - $salt_defines = ''; + $salt_defines = ''; // Now loop my key names and add a salt to each one. foreach ( $get_key_names as $keyname ) { - $salt_defines .= 'define( \'' . $keyname . '\', \'' . generate_salt_string() . '\' );' . "\n"; + $salt_defines .= 'define( \'' . $keyname . '\', \'' . generate_salt_string() . '\' );' . "\n"; } // Send back the string. @@ -137,7 +137,7 @@ function generate_string_via_random_int() { // Set a max amount. $define_max = mb_strlen( CHARACTER_SET, '8bit' ) - 1; - $saltgrain = ''; + $saltgrain = ''; // Loop through to generate each character of the string. for ( $i = 0; $i < 64; ++$i ) { @@ -155,13 +155,13 @@ function generate_string_via_random_int() { function generate_string_via_openssl_random() { // Generate some bytes to begin. - $set_bytes = openssl_random_pseudo_bytes( 138 ); + $set_bytes = openssl_random_pseudo_bytes( 138 ); // Now encode it to make sure it's a usable string. $saltshaker = base64_encode( $set_bytes ); // Establish the first 64 characters. - $saltgrain = substr( $saltshaker, 0, 64 ); + $saltgrain = substr( $saltshaker, 0, 64 ); return esc_attr( $saltgrain ); } @@ -173,13 +173,13 @@ function generate_string_via_openssl_random() { */ function generate_string_via_mt_rand() { - $saltgrain = ''; + $saltgrain = ''; // Loop through to generate each character of the string. for ( $i = 0; $i < 64; $i++ ) { // Randomly select an index from the character set using mt_rand(). - $set_index = mt_rand( 0, strlen( CHARACTER_SET ) - 1 ); + $set_index = wp_rand( 0, strlen( CHARACTER_SET ) - 1 ); // Append the character to the string. $saltgrain .= CHARACTER_SET[ $set_index ]; @@ -212,13 +212,13 @@ function generate_string_via_str_shuffle() { */ function generate_string_via_substr() { - $saltgrain = ''; + $saltgrain = ''; // Loop through to generate each character of the string. for ( $i = 0; $i < 64; $i++ ) { // Append the character to the string. - $saltgrain .= substr( CHARACTER_SET, mt_rand( 0, strlen( CHARACTER_SET ) - 1 ), 1 ); + $saltgrain .= substr( CHARACTER_SET, wp_rand( 0, strlen( CHARACTER_SET ) - 1 ), 1 ); } return esc_attr( $saltgrain ); diff --git a/inc/settings/namespace.php b/inc/settings/namespace.php index 40236b2..60b64a4 100644 --- a/inc/settings/namespace.php +++ b/inc/settings/namespace.php @@ -7,6 +7,8 @@ namespace FAIR\Settings; +/* phpcs:disable Squiz.PHP.EmbeddedPhp.ContentBeforeOpen, Squiz.PHP.EmbeddedPhp.ContentAfterOpen, Squiz.PHP.EmbeddedPhp.ContentBeforeEnd */ + /** * Bootstrap. */ @@ -69,17 +71,25 @@ function render_settings_page() { ?>

-

AspirePress' - ); ?>

-

FAIR GitHub', - 'FAQ' - ); ?>

+

+ AspirePress' + ); + ?> +

+

+ FAIR GitHub', + 'FAQ' + ); + ?> +

@@ -138,7 +148,7 @@ function save_settings() : bool { return false; } - $raw = is_array( $_POST['fair_settings'] ) ? $_POST['fair_settings'] : []; + $raw = is_array( $_POST['fair_settings'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['fair_settings'] ) ) : []; $settings = get_option( 'fair_settings', [] ); diff --git a/inc/version-check/namespace.php b/inc/version-check/namespace.php index 07c180c..8789990 100644 --- a/inc/version-check/namespace.php +++ b/inc/version-check/namespace.php @@ -61,8 +61,8 @@ function bootstrap() { * Replace the browser version check. * * @param bool|array $value Filtered value, or false to proceed. - * @param array $args - * @param string $url + * @param array $args HTTP request arguments. + * @param string $url The request URL. * @return bool|array Replaced value, or false to proceed. */ function replace_browser_version_check( $value, $args, $url ) { @@ -139,7 +139,7 @@ function get_php_branches() { // Index data by branch. $indexed = []; foreach ( $data as $ver ) { - if ( empty( $ver['branch' ] ) ) { + if ( empty( $ver['branch'] ) ) { continue; } diff --git a/package.json b/package.json index ad25dfe..b857963 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,8 @@ }, "scripts": { "env": "wp-env", + "lint:php": "wp-env run cli --env-cwd=wp-content/plugins/plugin composer run lint", + "format:php": "wp-env run cli --env-cwd=wp-content/plugins/plugin composer run format", "test:php:install-deps": "wp-env run tests-cli --env-cwd=wp-content/plugins/plugin composer install", "test:php": "wp-env run tests-cli --env-cwd=wp-content/plugins/plugin composer run test", "test:php:multisite": "wp-env run tests-cli --env-cwd=wp-content/plugins/plugin composer run test:multisite", diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 0000000..16ad499 --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,75 @@ + + + Coding standards for the FAIR plugin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + inc/updater/* + + + languages/* + + + wp-tests-config-sample\.php + + + + plugin\.php + + + + + tests/phpunit/* + + + tests/phpunit/* + + + + inc/icons/svg\.php + + + + + tests/phpunit/* + + + tests/phpunit/* + + + + + plugin\.php + inc/icons/svg\.php + tests/phpunit/bootstrap\.php + + diff --git a/plugin.php b/plugin.php index e2758d0..12d03e7 100644 --- a/plugin.php +++ b/plugin.php @@ -37,7 +37,11 @@ require_once __DIR__ . '/inc/version-check/namespace.php'; // External dependencies. require_once __DIR__ . '/inc/updater/class-lite.php'; -// Load translations. +/** + * Load translations. + * + * @return void + */ function load_textdomain() { load_plugin_textdomain( 'fair', false, dirname( plugin_basename( PLUGIN_FILE ) ) . '/languages' ); }