diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..c89bd9c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,34 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**Before submitting an issue please check that you’ve completed the following steps:** +- Made sure you’re on the latest version +- Used the search feature to ensure that the bug hasn’t been reported before + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Additional context** +Add any other context about the problem here. + +**Backlog Grooming (for WP Media dev team use only)** +- [ ] Reproduce the problem +- [ ] Identify the root cause +- [ ] Scope a solution +- [ ] Estimate the effort diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..066b2d9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..81a73aa --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,39 @@ +## Description + +Please include a summary of the change and which issue is fixed/closed. Please also include relevant motivation and context. List any dependencies that are required for this change. + +Fixes #(issue number) + +## Type of change + +Please delete options that are not relevant. + +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] Enhancement (non-breaking change which improves an existing functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] This change requires a documentation update + +## Is the solution different from the one proposed during the grooming? + +Please describe in this section if there is any change to the solution, and why. + +## How Has This Been Tested? + +Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration + +- [ ] Test A +- [ ] Test B + +# Checklist: + +Please delete the options that are not relevant. + +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my own code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes +- [ ] Any dependent changes have been merged and published in downstream modules diff --git a/.github/workflows/lint_phpcs.yml b/.github/workflows/lint_phpcs.yml new file mode 100644 index 0000000..03527f5 --- /dev/null +++ b/.github/workflows/lint_phpcs.yml @@ -0,0 +1,39 @@ +name: PHP CodeSniffer lint + +on: + pull_request: + branches: + - trunk + - develop + - branch-* + - feature/* + +jobs: + run: + runs-on: ${{ matrix.operating-system }} + + strategy: + fail-fast: false + matrix: + operating-system: [ubuntu-latest] + php-versions: ['7.4'] + + name: WPRocket lint with PHPCS. PHP ${{ matrix.php-versions }} on ${{ matrix.operating-system }}. + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + coverage: none # XDebug can be enabled here 'coverage: xdebug' + tools: composer:v2 + + - name: Install dependencies + run: composer install --prefer-dist --no-interaction --no-scripts + + - name: Lint with phpcs + run: | + vendor/bin/phpcs --config-set installed_paths ../../phpcompatibility/phpcompatibility-paragonie,../../phpcompatibility/phpcompatibility-wp,../../wp-coding-standards/wpcs,../../phpcompatibility/php-compatibility + composer phpcs diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..512008b --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,69 @@ +name: Unit/Integration tests + +on: + pull_request: + branches: + - trunk + - develop + - branch-* + - feature/* + +jobs: + run: + runs-on: ${{ matrix.operating-system }} + + strategy: + fail-fast: true + matrix: + operating-system: [ubuntu-latest] + php-versions: ['7.4', '8.0'] + wp-versions: ['latest'] + + name: WP ${{ matrix.wp-versions }} with PHP ${{ matrix.php-versions }} on ${{ matrix.operating-system }}. + + env: + WP_TESTS_DIR: "/tmp/tests/phpunit" + WP_CORE_DIR: "/tmp/wordpress-develop" + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + coverage: none # XDebug can be enabled here 'coverage: xdebug' + tools: composer:v2, phpunit + + - name: Start mysql service + run: sudo /etc/init.d/mysql start + + - name: Setup problem matchers for PHP + run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" + + - name: Setup problem matchers for PHPUnit + run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + + - name: Get composer cache directory + id: composercache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composercache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --prefer-dist --no-interaction + + - name: Install tests + run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1:3306 ${{ matrix.wp-versions }} + + - name: Mysql8 auth plugin workaround + run: sudo mysql -u root -proot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root';" + + - name: Test + run: composer run-tests diff --git a/.gitignore b/.gitignore index 723ef36..a9955cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,9 @@ -.idea \ No newline at end of file +.idea +vendor +vendor-prefixed +inc/Dependencies/* +inc/classes/* +build +package-lock.json +node_modules +composer.lock \ No newline at end of file diff --git a/README.md b/README.md index c8f2fd9..2fad2d3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,23 @@ # wordpress-debug-hooks Wordpress Debug Hooks + +# Getting started + +## Installing the plugin + +### From the GitHub repository + +- Clone the repository +- In the repository folder, run the following commands: + + `composer i` + + `composer install --no-scripts --no-dev --ignore-platform-reqs` + +- Build a .zip archive of the repository. +- Upload it as a new plugin on your WordPress website. + +### Using the plugin + +Once the plugin is installed and activated, a new admin sub-menu "WP Hooks" must be available under "Tools". This view lists all the hooks and their callbacks found on your WordPress website. + diff --git a/bin/generator b/bin/generator new file mode 100755 index 0000000..af769eb --- /dev/null +++ b/bin/generator @@ -0,0 +1,10 @@ +#!/usr/bin/env php + [db-host] [wp-version] [skip-database-creation]" + exit 1 +fi + +DB_NAME=$1 +DB_USER=$2 +DB_PASS=$3 +DB_HOST=${4-localhost} +WP_VERSION=${5-latest} +SKIP_DB_CREATE=${6-false} + +TMPDIR=${TMPDIR-/tmp} +TMPDIR=$(echo $TMPDIR | sed -e "s/\/$//") +WP_TESTS_DIR=${WP_TESTS_DIR-$TMPDIR/wordpress-tests-lib} +WP_CORE_DIR=${WP_CORE_DIR-$TMPDIR/wordpress/} + +download() { + if [ `which curl` ]; then + curl -s "$1" > "$2"; + elif [ `which wget` ]; then + wget -nv -O "$2" "$1" + fi +} + +if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then + WP_TESTS_TAG="branches/$WP_VERSION" +elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then + if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then + # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x + WP_TESTS_TAG="tags/${WP_VERSION%??}" + else + WP_TESTS_TAG="tags/$WP_VERSION" + fi +elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then + WP_TESTS_TAG="trunk" +else + # http serves a single offer, whereas https serves multiple. we only want one + download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json + grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json + LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//') + if [[ -z "$LATEST_VERSION" ]]; then + echo "Latest WordPress version could not be found" + exit 1 + fi + WP_TESTS_TAG="tags/$LATEST_VERSION" +fi + +set -ex + +install_wp() { + + if [ -d $WP_CORE_DIR ]; then + return; + fi + + mkdir -p $WP_CORE_DIR + + if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then + mkdir -p $TMPDIR/wordpress-nightly + download https://wordpress.org/nightly-builds/wordpress-latest.zip $TMPDIR/wordpress-nightly/wordpress-nightly.zip + unzip -q $TMPDIR/wordpress-nightly/wordpress-nightly.zip -d $TMPDIR/wordpress-nightly/ + mv $TMPDIR/wordpress-nightly/wordpress/* $WP_CORE_DIR + else + if [ $WP_VERSION == 'latest' ]; then + local ARCHIVE_NAME='latest' + elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+ ]]; then + # https serves multiple offers, whereas http serves single. + download https://api.wordpress.org/core/version-check/1.7/ $TMPDIR/wp-latest.json + if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then + # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x + LATEST_VERSION=${WP_VERSION%??} + else + # otherwise, scan the releases and get the most up to date minor version of the major release + local VERSION_ESCAPED=`echo $WP_VERSION | sed 's/\./\\\\./g'` + LATEST_VERSION=$(grep -o '"version":"'$VERSION_ESCAPED'[^"]*' $TMPDIR/wp-latest.json | sed 's/"version":"//' | head -1) + fi + if [[ -z "$LATEST_VERSION" ]]; then + local ARCHIVE_NAME="wordpress-$WP_VERSION" + else + local ARCHIVE_NAME="wordpress-$LATEST_VERSION" + fi + else + local ARCHIVE_NAME="wordpress-$WP_VERSION" + fi + download https://wordpress.org/${ARCHIVE_NAME}.tar.gz $TMPDIR/wordpress.tar.gz + tar --strip-components=1 -zxmf $TMPDIR/wordpress.tar.gz -C $WP_CORE_DIR + fi + + download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php +} + +install_test_suite() { + # portable in-place argument for both GNU sed and Mac OSX sed + if [[ $(uname -s) == 'Darwin' ]]; then + local ioption='-i .bak' + else + local ioption='-i' + fi + + # set up testing suite if it doesn't yet exist + if [ ! -d $WP_TESTS_DIR ]; then + # set up testing suite + mkdir -p $WP_TESTS_DIR + svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes + svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data + fi + + if [ ! -f wp-tests-config.php ]; then + download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php + # remove all forward slashes in the end + WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::") + sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php + fi + +} + +install_db() { + + if [ ${SKIP_DB_CREATE} = "true" ]; then + return 0 + fi + + # parse DB_HOST for port or socket references + local PARTS=(${DB_HOST//\:/ }) + local DB_HOSTNAME=${PARTS[0]}; + local DB_SOCK_OR_PORT=${PARTS[1]}; + local EXTRA="" + + if ! [ -z $DB_HOSTNAME ] ; then + if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then + EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" + elif ! [ -z $DB_SOCK_OR_PORT ] ; then + EXTRA=" --socket=$DB_SOCK_OR_PORT" + elif ! [ -z $DB_HOSTNAME ] ; then + EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" + fi + fi + + # create database + mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA +} + +install_wp +install_test_suite +install_db diff --git a/bin/phpcs-changed.sh b/bin/phpcs-changed.sh new file mode 100644 index 0000000..5980fbd --- /dev/null +++ b/bin/phpcs-changed.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +FILES=$(git ls-files -om --exclude-standard); +if [ -n "$FILES" ]; then + phpcs "$FILES" +fi diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..158e75c --- /dev/null +++ b/composer.json @@ -0,0 +1,121 @@ +{ + "name": "wp-launchpad/launchpad", + "description": "Framework to create a modern PHP plugin in no time", + "keywords": [ + "wordpress", + "framework", + "plugin" + ], + "license": "GPL-2.0-or-later", + "authors": [ + { + "name": "CrochetFeve0251" + } + ], + "type": "wordpress-plugin", + "config": { + "sort-packages": true, + "preferred-install": { + "wp-media/phpunit": "source" + }, + "process-timeout": 0, + "allow-plugins": { + "composer/installers": true, + "mnsami/composer-custom-directory-installer": true, + "dealerdirect/phpcodesniffer-composer-installer": true + } + }, + "repositories": [ + { + "type": "composer", + "url": "https://wpackagist.org" + } + ], + "require": { + "php": ">=7.0", + "composer/installers": "^1.0 || ^2.0" + }, + "require-dev": { + "php": "^7 || ^8", + "brain/monkey": "^2.0", + "brianhenryie/strauss": "^0.14.0", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "league/container": "^3.3", + "mnsami/composer-custom-directory-installer": "^2.0", + "phpcompatibility/phpcompatibility-wp": "^2.0", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^7.5 || ^8 || ^9", + "psr/container": "1.0.0", + "roave/security-advisories": "dev-master", + "squizlabs/php_codesniffer": "^3.10", + "szepeviktor/phpstan-wordpress": "^0.7.0", + "wp-coding-standards/wpcs": "^2", + "wp-launchpad/autoresolver": "^0.2", + "wp-launchpad/build": "^0.0.8", + "wp-launchpad/cli": "^1.0.2", + "wp-launchpad/cli-installer": "^0.0", + "wp-launchpad/core": "^0.2", + "wp-media/phpunit": "^3.0" + }, + "autoload": { + "psr-4": { + "DebugHooks\\": "inc/" + } + }, + "autoload-dev": { + "psr-4": { + "DebugHooks\\Tests\\": "tests/" + } + }, + "extra": { + "installer-paths": { + "vendor/{$vendor}/{$name}/": [ + "type:wordpress-plugin" + ] + }, + "strauss": { + "target_directory": "vendor-prefixed", + "namespace_prefix": "DebugHooks\\Dependencies\\", + "classmap_prefix": "DebugHooks", + "constant_prefix": "DEBUG_HOOKS_", + "packages": [ + "league/container", + "wp-launchpad/core", + "wp-launchpad/autoresolver" + ] + } + }, + "scripts": { + "strauss": [ + "vendor/bin/strauss" + ], + "test-unit": "\"vendor/bin/phpunit\" --testsuite unit --colors=always --configuration tests/Unit/phpunit.xml.dist", + "test-integration": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --exclude-group AdminOnly", + "test-integration-adminonly": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group AdminOnly", + "run-tests": [ + "@test-unit", + "@test-integration", + "@test-integration-adminonly" + ], + "run-stan": "vendor/bin/phpstan analyze --memory-limit=2G --no-progress", + "install-codestandards": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run", + "phpcs": "phpcs --basepath=.", + "phpcs-changed": "./bin/phpcs-changed.sh", + "phpcs:fix": "phpcbf", + "post-install-cmd": [ + "\"bin/generator\" auto-install", + "composer update --no-interaction --no-scripts", + "@strauss", + "composer dump-autoload" + ], + "post-update-cmd": [ + "\"bin/generator\" auto-install", + "composer update --no-interaction --no-scripts", + "@strauss", + "composer dump-autoload" + ], + "code-coverage": "\"vendor/bin/phpunit\" --testsuite unit --colors=always --configuration tests/Unit/phpunit.xml.dist --coverage-clover=tests/report/coverage.clover" + }, + "minimum-stability": "stable", + "prefer-stable": true +} diff --git a/configs/parameters.php b/configs/parameters.php new file mode 100644 index 0000000..dce8167 --- /dev/null +++ b/configs/parameters.php @@ -0,0 +1,19 @@ + $debug_hooks_plugin_name, + 'plugin_slug' => sanitize_key( $debug_hooks_plugin_name ), + 'plugin_version' => '0.1.1', + 'plugin_launcher_file' => $debug_hooks_plugin_launcher_path . '/debug-hooks.php', + 'plugin_launcher_path' => $debug_hooks_plugin_launcher_path, + 'plugin_inc_path' => realpath( $debug_hooks_plugin_launcher_path . 'inc/' ) . '/', + 'prefix' => 'debug_hooks_', + 'translation_key' => 'debughooks', + 'is_mu_plugin' => false, +]; diff --git a/configs/providers.php b/configs/providers.php new file mode 100644 index 0000000..e2417a5 --- /dev/null +++ b/configs/providers.php @@ -0,0 +1,7 @@ +'; - echo 'HookTypeNameLocationParameters'; - - foreach ( $wp_filter as $filter_name => $item ) { - - foreach ( $item->callbacks as $callback_item ) { - foreach ( $callback_item as $callback ) { - if ( is_array( $callback['function'] ) ) { - //class - $this->handle_class_type( $filter_name, $callback['function'] ); - } else if ( is_string( $callback['function'] ) ) { - //function - $this->handle_function_type( $filter_name, $callback['function'] ); - } else { - echo "Type is: " . gettype( $callback['function'] ) . ''; - } +use function DebugHooks\Dependencies\LaunchpadCore\boot; - } - echo ' '; - } - - } - - echo ""; - } - - private function handle_class_type( $filter_name, $callback_function ) { - echo '' . $filter_name . 'Class'; - $class_name = is_string( $callback_function[0] ) ? $callback_function[0] : get_class( $callback_function[0] ); - echo '' . $class_name . '::' . $callback_function[1] . ''; - - try { - $class = new \ReflectionClass( $class_name ); - $class_file = $class->getFileName(); - - echo 'Class: ' . $class_file . ''; - - $method_parameters = $class->getMethod( $callback_function[1] )->getParameters(); - if ( is_array( $method_parameters ) && $method_parameters ) { - echo ''; - foreach ( $method_parameters as $method_parameter ) { - echo $method_parameter->getName() . '
'; - } - echo ''; - }else{ - echo ''; - } - } catch ( \Exception $e ) { - echo "Error: " . $e->getMessage() . ""; - } - - echo ''; - } - - private function handle_function_type( $filter_name, $callback_function ) { - echo '' . $filter_name . 'Function'; - echo '' . $callback_function . ''; - - try { - $func = new \ReflectionFunction( $callback_function ); - echo '' . $func->getFileName() . ''; +defined( 'ABSPATH' ) || exit; - $func_parameters = $func->getParameters(); - if ( is_array( $func_parameters ) && $func_parameters ) { - echo ''; - foreach ( $func_parameters as $parameter ) { - echo $parameter->getName() . '
'; - } - echo ''; - }else{ - echo ''; - } - } catch (\Exception $e) { - echo "Error: " . $e->getMessage() . ""; - } - echo ''; - } -} +require __DIR__ . '/vendor-prefixed/wp-launchpad/core/inc/boot.php'; -add_action( 'plugins_loaded', [ WPDH_Main::get_instance(), 'add_hooks' ] ); +boot( __FILE__ ); diff --git a/inc/Admin/HookBrowser/ServiceProvider.php b/inc/Admin/HookBrowser/ServiceProvider.php new file mode 100644 index 0000000..10ef9f1 --- /dev/null +++ b/inc/Admin/HookBrowser/ServiceProvider.php @@ -0,0 +1,18 @@ +'; + echo 'HookTypeNameLocationParameters'; + + foreach ( $wp_filter as $filter_name => $item ) { + + foreach ( $item->callbacks as $callback_item ) { + foreach ( $callback_item as $callback ) { + if ( is_array( $callback['function'] ) ) { + // class. + $this->handle_class_type( $filter_name, $callback['function'] ); + } elseif ( is_string( $callback['function'] ) ) { + // function. + $this->handle_function_type( $filter_name, $callback['function'] ); + } else { + echo "Type is: " . esc_html( gettype( $callback['function'] ) ) . ''; + } + } + echo ' '; + } + } + + echo ''; + } + + /** + * Displays class object in the callbacks in WP Hooks page. + * + * @param string $filter_name Name of filter being processed. + * @param array $callback_function Function callback entry from the callback array of the filter being processed. + */ + private function handle_class_type( $filter_name, $callback_function ) { + echo '' . esc_html( $filter_name ) . 'Class'; + $class_name = is_string( $callback_function[0] ) ? $callback_function[0] : get_class( $callback_function[0] ); + echo '' . esc_html( $class_name ) . '::' . esc_html( $callback_function[1] ) . ''; + + try { + $class = new \ReflectionClass( $class_name ); + $class_file = $class->getFileName(); + + echo 'Class: ' . esc_html( $class_file ) . ''; + + $method_parameters = $class->getMethod( $callback_function[1] )->getParameters(); + if ( is_array( $method_parameters ) && $method_parameters ) { + echo ''; + foreach ( $method_parameters as $method_parameter ) { + echo esc_html( $method_parameter->getName() ) . '
'; + } + echo ''; + }else { + echo ''; + } + } catch ( \Exception $e ) { + echo "Error: " . esc_html( $e->getMessage() ) . ''; + } + + echo ''; + } + + /** + * Displays functions in the callbacks in WP Hooks page. + * + * @param string $filter_name Name of filter being processed. + * @param array $callback_function Function callback entry from the callback array of the filter being processed. + */ + private function handle_function_type( $filter_name, $callback_function ) { + echo '' . esc_html( $filter_name ) . 'Function'; + echo '' . esc_html( $callback_function ) . ''; + + try { + $func = new \ReflectionFunction( $callback_function ); + echo '' . esc_html( $func->getFileName() ) . ''; + + $func_parameters = $func->getParameters(); + if ( is_array( $func_parameters ) && $func_parameters ) { + echo ''; + foreach ( $func_parameters as $parameter ) { + echo esc_html( $parameter->getName() ) . '
'; + } + echo ''; + }else { + echo ''; + } + } catch ( \Exception $e ) { + echo "Error: " . esc_html( $e->getMessage() ) . ''; + } + echo ''; + } +} diff --git a/languages/.gitignore b/languages/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..091de6c --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,75 @@ + + + The custom ruleset for Rocket launcher. + + + + + + + . + + /inc/deprecated/* + /inc/Engine/Container/* + /inc/Dependencies/* + /inc/classes/dependencies/* + /inc/vendors/* + /tests/* + /vendor/* + /vendor-prefixed/* + /node_modules/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/Fixtures/classes/WP.php b/tests/Fixtures/classes/WP.php new file mode 100644 index 0000000..f433b98 --- /dev/null +++ b/tests/Fixtures/classes/WP.php @@ -0,0 +1,8 @@ +code = $code; + $this->message = $message; + $this->error_data = $error_data; + } + + public function get_error_code() { + return $this->code; + } + + public function get_error_message() { + return $this->message; + } + + public function get_error_data() { + return $this->error_data; + } + } +} \ No newline at end of file diff --git a/tests/Fixtures/classes/wpdb.php b/tests/Fixtures/classes/wpdb.php new file mode 100644 index 0000000..f9fb742 --- /dev/null +++ b/tests/Fixtures/classes/wpdb.php @@ -0,0 +1,66 @@ +is_post( $sql ) ) { + return $this->posts_results; + } + + if ( $this->is_term( $sql ) ) { + return $this->terms_results; + } + + return []; + } + + public function setTerms( $results ) { + $this->term_taxonomy = 'terms'; + $this->terms_results = $results; + } + + public function setPosts( $results ) { + $this->posts = 'posts'; + $this->posts_results = $results; + } + + private function is_post( $sql ) { + return $this->starts_with( $sql, 'SELECT MAX(ID) as ID, post_type' ); + } + + private function is_term( $sql ) { + return $this->starts_with( $sql, 'SELECT MAX( term_id ) AS ID, taxonomy' ); + } + + private function starts_with( $string, $starting_string ) { + $string = trim( $string ); + $len = strlen( $starting_string ); + + return ( substr( $string, 0, $len ) === $starting_string ); + } + + public function query( $query ) { + return true; + } + + public function get_col() { + return $this->as_table_rows; + } + + public function prepare( $sql ) { + return true; + } + + public function setTableRows( $rows ) { + $this->as_table_rows = $rows; + } + } +} \ No newline at end of file diff --git a/tests/Fixtures/inc/.gitignore b/tests/Fixtures/inc/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/tests/Integration/ActionTrait.php b/tests/Integration/ActionTrait.php new file mode 100644 index 0000000..99df6d9 --- /dev/null +++ b/tests/Integration/ActionTrait.php @@ -0,0 +1,31 @@ +original_wp_filter = $wp_filter[ $event_name ]->callbacks; + + foreach ( $this->original_wp_filter[ $priority ] as $key => $config ) { + + // Skip if not this tests callback. + if ( substr( $key, - strlen( $method_name ) ) !== $method_name ) { + continue; + } + + $wp_filter[ $event_name ]->callbacks = [ + $priority => [ $key => $config ], + ]; + } + } + + protected function restoreWpAction( $event_name ) { + global $wp_filter; + $wp_filter[ $event_name ]->callbacks = $this->original_wp_filter; + + } +} diff --git a/tests/Integration/AdminTestCase.php b/tests/Integration/AdminTestCase.php new file mode 100644 index 0000000..7cca748 --- /dev/null +++ b/tests/Integration/AdminTestCase.php @@ -0,0 +1,79 @@ +error_level = error_reporting(); + error_reporting( $this->error_level & ~E_WARNING ); + } + + public function tear_down() { + $_POST = []; + $_GET = []; + unset( $GLOBALS['post'], $GLOBALS['comment'] ); + + error_reporting( $this->error_level ); + set_current_screen( 'front' ); + if ( $this->user_id > 0 ) { + wp_delete_user( $this->user_id ); + } + + parent::tear_down(); + } + + protected function setRoleCap( $role_type, $cap ) { + $role = get_role( $role_type ); + $role->add_cap( $cap ); + } + + protected function removeRoleCap( $role_type, $cap ) { + $role = get_role( $role_type ); + $role->remove_cap( $cap ); + } + + protected function setCurrentUser( $role ) { + $this->user_id = $this->factory->user->create( [ 'role' => $role ] ); + wp_set_current_user( $this->user_id ); + } + + protected function fireAdminInit() { + do_action( 'admin_init' ); + } + + protected function hasCallbackRegistered( $event, $class, $method, $priority = 10 ) { + global $wp_filter; + + $this->assertArrayHasKey( $event, $wp_filter ); + $this->assertArrayHasKey( $priority, $wp_filter[ $event ]->callbacks ); + + $object = null; + foreach ( $wp_filter['post_tag_row_actions']->callbacks[ $priority ] as $key => $callback ) { + if ( isset( $callback['function'][1] ) && $method === $callback['function'][1] ) { + $object = $callback['function'][0]; + break; + } + } + $this->assertInstanceOf( $class, $object ); + } + + protected function setEditTagsAsCurrentScreen( $tax = 'category' ) { + set_current_screen( "edit-tags.php?taxonomy={$tax}" ); + } +} diff --git a/tests/Integration/AjaxTestCase.php b/tests/Integration/AjaxTestCase.php new file mode 100644 index 0000000..f1c187d --- /dev/null +++ b/tests/Integration/AjaxTestCase.php @@ -0,0 +1,67 @@ + $value ) { + if ( ! empty( $transient ) ) { + set_transient( $transient, $value ); + } else { + delete_transient( $transient ); + } + } + + parent::tear_down_after_class(); + } + + public function set_up() { + parent::set_up(); + + if ( empty( $this->config ) ) { + $this->loadTestDataConfig(); + } + } + + public function tear_down() { + unset( $_POST['action'], $_POST['nonce'] ); + $this->action = null; + + parent::tear_down(); + } + + public function configTestData() { + if ( empty( $this->config ) ) { + $this->loadTestDataConfig(); + } + + return isset( $this->config['test_data'] ) + ? $this->config['test_data'] + : $this->config; + } + + protected function loadTestDataConfig() { + $obj = new ReflectionObject( $this ); + $filename = $obj->getFileName(); + + $this->config = $this->getTestData( dirname( $filename ), basename( $filename, '.php' ) ); + } +} diff --git a/tests/Integration/FilterTrait.php b/tests/Integration/FilterTrait.php new file mode 100644 index 0000000..dd8af16 --- /dev/null +++ b/tests/Integration/FilterTrait.php @@ -0,0 +1,31 @@ +original_wp_filter = $wp_filter[ $event_name ]->callbacks; + + foreach ( $this->original_wp_filter[ $priority ] as $key => $config ) { + + // Skip if not this tests callback. + if ( substr( $key, - strlen( $method_name ) ) !== $method_name ) { + continue; + } + + $wp_filter[ $event_name ]->callbacks = [ + $priority => [ $key => $config ], + ]; + } + } + + protected function restoreWpFilter( $event_name ) { + global $wp_filter; + $wp_filter[ $event_name ]->callbacks = $this->original_wp_filter; + + } +} diff --git a/tests/Integration/TestCase.php b/tests/Integration/TestCase.php new file mode 100644 index 0000000..ab3844a --- /dev/null +++ b/tests/Integration/TestCase.php @@ -0,0 +1,58 @@ + $value ) { + if ( ! empty( $transient ) ) { + set_transient( $transient, $value ); + } else { + delete_transient( $transient ); + } + } + } + + public function set_up() { + parent::set_up(); + + if ( empty( $this->config ) ) { + $this->loadTestDataConfig(); + } + } + + public function configTestData() { + if ( empty( $this->config ) ) { + $this->loadTestDataConfig(); + } + + return isset( $this->config['test_data'] ) + ? $this->config['test_data'] + : $this->config; + } + + protected function loadTestDataConfig() { + $obj = new ReflectionObject( $this ); + $filename = $obj->getFileName(); + + $this->config = $this->getTestData( dirname( $filename ), basename( $filename, '.php' ) ); + } +} diff --git a/tests/Integration/bootstrap.php b/tests/Integration/bootstrap.php new file mode 100644 index 0000000..faae994 --- /dev/null +++ b/tests/Integration/bootstrap.php @@ -0,0 +1,16 @@ + + + + + ../../inc + + + + + inc + + + \ No newline at end of file diff --git a/tests/Unit/TestCase.php b/tests/Unit/TestCase.php new file mode 100644 index 0000000..14ad57b --- /dev/null +++ b/tests/Unit/TestCase.php @@ -0,0 +1,36 @@ +config ) ) { + $this->loadTestDataConfig(); + } + } + + public function configTestData() { + if ( empty( $this->config ) ) { + $this->loadTestDataConfig(); + } + + return isset( $this->config['test_data'] ) + ? $this->config['test_data'] + : $this->config; + } + + protected function loadTestDataConfig() { + $obj = new ReflectionObject( $this ); + $filename = $obj->getFileName(); + + $this->config = $this->getTestData( dirname( $filename ), basename( $filename, '.php' ) ); + } +} diff --git a/tests/Unit/bootstrap.php b/tests/Unit/bootstrap.php new file mode 100644 index 0000000..d32172b --- /dev/null +++ b/tests/Unit/bootstrap.php @@ -0,0 +1,35 @@ + + + + + ../../inc + + + + + inc + + +