diff --git a/.distignore b/.distignore index f3aedc0b..19556d45 100644 --- a/.distignore +++ b/.distignore @@ -2,7 +2,9 @@ /.git /.github /.wordpress-org +/bin /node_modules +/tests /vendor # Files @@ -10,10 +12,15 @@ /.editorconfig /.gitattributes /.gitignore +/.phpunit.result.cache +/.sonarcloud.properties /.stylelintrc.json /composer.json /composer.lock /package.json /package-lock.json /phpcs.xml +/phpunit.xml +/phpunit.coverage.xml +/phpunit.report.xml /README.md diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 50788e22..30b9bc6e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,6 +1,45 @@ -name: Coding Standards +name: Tests on: [push, pull_request] jobs: + unit: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - php: '5.6' + wordpress: '4.7' + - php: '7.4' + wordpress: '5.9' + - php: '8.0' + wordpress: '6.0' + - php: '8.1' + wordpress: 'latest' + - php: '8.1' + wordpress: 'nightly' + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{matrix.php}} + tools: composer + - name: Install + run: composer install --no-interaction + - name: Build + run: composer build + - name: Setup DB + uses: shogo82148/actions-setup-mysql@v1 + with: + mysql-version: 'mysql-5.7' + root-password: "root" + - name: Setup WP + run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 "${{ matrix.wordpress }}" + - name: PHP unit tests + run: composer test + quality: runs-on: ubuntu-latest steps: diff --git a/.gitignore b/.gitignore index f5833602..d2694b1a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ .idea/ +.phpunit.result.cache css/*.min.css vendor/ node_modules/ composer.lock package-lock.json +phpunit.*.xml diff --git a/.sonarcloud.properties b/.sonarcloud.properties new file mode 100644 index 00000000..67986297 --- /dev/null +++ b/.sonarcloud.properties @@ -0,0 +1,9 @@ +# Path to sources. +sonar.sources=inc,js,css,cachify.php +sonar.exclusions=**/*.min.css,**/*.min.js +#sonar.inclusions= + +# Path to tests. +sonar.tests=tests +#sonar.test.exclusions= +#sonar.test.inclusions= diff --git a/bin/install-wp-tests.sh b/bin/install-wp-tests.sh new file mode 100644 index 00000000..b9447efd --- /dev/null +++ b/bin/install-wp-tests.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env bash + +if [ $# -lt 3 ]; then + echo "usage: $0 [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 + + # Modify the WP_UnitTestCase class to use the polyfilled version for PHPUnit cross-compatibility. + # This is a dirty "backport" of the polyfills used in WP 5.9 and might fail with future updates. + if [ ! -f "$WP_TESTS_DIR"/includes/abstract-testcase.php ]; then + local testcase_file="$WP_TESTS_DIR"/includes/testcase.php + sed $ioption 's/class WP_UnitTestCase extends PHPUnit_Framework_TestCase /class WP_UnitTestCase extends Yoast\\PHPUnitPolyfills\\TestCases\\TestCase /' "$testcase_file" + sed $ioption 's/setUpBeforeClass[(][)]/set_up_before_class()/g' "$testcase_file" + sed $ioption 's/tearDownAfterClass[(][)]/tear_down_after_class()/g' "$testcase_file" + sed $ioption 's/setUp[(][)]/set_up()/g' "$testcase_file" + sed $ioption 's/tearDown[(][)]/tear_down()/g' "$testcase_file" + 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/composer.json b/composer.json index c3405e4e..ee42659f 100644 --- a/composer.json +++ b/composer.json @@ -28,9 +28,11 @@ "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^v0.7", "matthiasmullie/minify": "^1.3", + "phpunit/phpunit": "^5|^7|^9", "squizlabs/php_codesniffer": "^3.7", "phpcompatibility/phpcompatibility-wp": "^2.1", - "wp-coding-standards/wpcs": "^2.3" + "wp-coding-standards/wpcs": "^2.3", + "yoast/phpunit-polyfills": "^1.0" }, "scripts": { "post-install-cmd": [ @@ -63,6 +65,9 @@ ], "lint-php": [ "phpcs --standard=phpcs.xml -s" + ], + "test": [ + "phpunit" ] }, "config": { diff --git a/inc/class-cachify-apc.php b/inc/class-cachify-apc.php index 39761f4f..0e8c17c9 100644 --- a/inc/class-cachify-apc.php +++ b/inc/class-cachify-apc.php @@ -16,10 +16,9 @@ final class Cachify_APC { /** * Availability check * - * @since 2.0.7 - * @change 2.0.7 + * @return bool TRUE when installed * - * @return boolean true/false TRUE when installed + * @since 2.0.7 */ public static function is_available() { return extension_loaded( 'apc' ); @@ -28,10 +27,9 @@ public static function is_available() { /** * Caching method as string * - * @since 2.1.2 - * @change 2.1.2 + * @return string Caching method * - * @return string Caching method + * @since 2.1.2 */ public static function stringify_method() { return 'APC'; @@ -40,13 +38,13 @@ public static function stringify_method() { /** * Store item in cache * - * @since 2.0 - * @change 2.3.0 + * @param string $hash Hash of the entry. + * @param string $data Content of the entry. + * @param int $lifetime Lifetime of the entry. + * @param bool $sig_detail Show details in signature. * - * @param string $hash Hash of the entry. - * @param string $data Content of the entry. - * @param integer $lifetime Lifetime of the entry. - * @param bool $sig_detail Show details in signature. + * @since 2.0 + * @since 2.3.0 added $sigDetail parameter */ public static function store_item( $hash, $data, $lifetime, $sig_detail ) { /* Do not store empty data. */ @@ -66,11 +64,11 @@ public static function store_item( $hash, $data, $lifetime, $sig_detail ) { /** * Read item from cache * - * @since 2.0 - * @change 2.0 + * @param string $hash Hash of the entry. * - * @param string $hash Hash of the entry. - * @return mixed Content of the entry + * @return mixed Content of the entry + * + * @since 2.0 */ public static function get_item( $hash ) { return ( function_exists( 'apc_exists' ) ? apc_exists( $hash ) : apc_fetch( $hash ) ); @@ -79,11 +77,10 @@ public static function get_item( $hash ) { /** * Delete item from cache * - * @since 2.0 - * @change 2.0 + * @param string $hash Hash of the entry. + * @param string $url URL of the entry [optional]. * - * @param string $hash Hash of the entry. - * @param string $url URL of the entry [optional]. + * @since 2.0 */ public static function delete_item( $hash, $url = '' ) { apc_delete( $hash ); @@ -92,8 +89,7 @@ public static function delete_item( $hash, $url = '' ) { /** * Clear the cache * - * @since 2.0.0 - * @change 2.0.7 + * @since 2.0 */ public static function clear_cache() { if ( ! self::is_available() ) { @@ -106,8 +102,7 @@ public static function clear_cache() { /** * Print the cache * - * @since 2.0 - * @change 2.0 + * @since 2.0 */ public static function print_cache() { return; @@ -116,10 +111,9 @@ public static function print_cache() { /** * Get the cache size * - * @since 2.0 - * @change 2.0 + * @return mixed Cache size * - * @return mixed Cache size + * @since 2.0 */ public static function get_stats() { /* Info */ @@ -136,11 +130,12 @@ public static function get_stats() { /** * Generate signature * - * @since 2.0 - * @change 2.3.0 + * @param bool $detail Show details in signature. + * + * @return string Signature string * - * @param bool $detail Show details in signature. - * @return string Signature string + * @since 2.0 + * @since 2.3.0 added $detail parameter */ private static function _cache_signature( $detail ) { return sprintf( diff --git a/inc/class-cachify-cli.php b/inc/class-cachify-cli.php index 7317f191..4dc81d4c 100644 --- a/inc/class-cachify-cli.php +++ b/inc/class-cachify-cli.php @@ -16,11 +16,10 @@ final class Cachify_CLI { /** * Flush Cache Callback * - * @since 2.3.0 - * @change 2.3.0 - * * @param array $args the CLI arguments as array. * @param array $assoc_args the CLI arguments as associative array. + * + * @since 2.3.0 */ public static function flush_cache( $args, $assoc_args ) { // Set default arguments. @@ -38,11 +37,10 @@ public static function flush_cache( $args, $assoc_args ) { /** * Get cache size * - * @since 2.3.0 - * @change 2.3.0 - * * @param array $args the CLI arguments as array. * @param array $assoc_args the CLI arguments as associative array. + * + * @since 2.3.0 */ public static function get_cache_size( $args, $assoc_args ) { // Set default arguments. @@ -62,8 +60,7 @@ public static function get_cache_size( $args, $assoc_args ) { /** * Register CLI Commands * - * @since 2.3.0 - * @change 2.3.0 + * @since 2.3.0 */ public static function add_commands() { // Add flush command. diff --git a/inc/class-cachify-db.php b/inc/class-cachify-db.php index 86011462..003c0394 100644 --- a/inc/class-cachify-db.php +++ b/inc/class-cachify-db.php @@ -16,10 +16,9 @@ final class Cachify_DB { /** * Availability check * - * @since 2.0.7 - * @change 2.0.7 + * @return bool TRUE when installed * - * @return boolean true/false TRUE when installed + * @since 2.0.7 */ public static function is_available() { return true; @@ -28,10 +27,9 @@ public static function is_available() { /** * Caching method as string * - * @since 2.1.2 - * @change 2.1.2 + * @return string Caching method * - * @return string Caching method + * @since 2.1.2 */ public static function stringify_method() { return 'DB'; @@ -40,17 +38,17 @@ public static function stringify_method() { /** * Store item in cache * - * @since 2.0 - * @change 2.0 + * @param string $hash Hash of the entry. + * @param string $data Content of the entry. + * @param int $lifetime Lifetime of the entry. * - * @param string $hash Hash of the entry. - * @param string $data Content of the entry. - * @param integer $lifetime Lifetime of the entry. + * @since 2.0 */ public static function store_item( $hash, $data, $lifetime ) { /* Do not store empty data. */ if ( empty( $data ) ) { trigger_error( __METHOD__ . ': Empty input.', E_USER_WARNING ); + return; } @@ -73,11 +71,11 @@ public static function store_item( $hash, $data, $lifetime ) { /** * Read item from cache * - * @since 2.0 - * @change 2.0 + * @param string $hash Hash of the entry. + * + * @return mixed Content of the entry * - * @param string $hash Hash of the entry. - * @return mixed Content of the entry + * @since 2.0 */ public static function get_item( $hash ) { return get_transient( $hash ); @@ -86,11 +84,10 @@ public static function get_item( $hash ) { /** * Delete item from cache * - * @since 2.0 - * @change 2.0 + * @param string $hash Hash of the entry. + * @param string $url URL of the entry [optional]. * - * @param string $hash Hash of the entry. - * @param string $url URL of the entry [optional]. + * @since 2.0 */ public static function delete_item( $hash, $url = '' ) { delete_transient( $hash ); @@ -99,8 +96,7 @@ public static function delete_item( $hash, $url = '' ) { /** * Clear the cache * - * @since 2.0 - * @change 2.0 + * @since 2.0 */ public static function clear_cache() { /* Init */ @@ -113,11 +109,11 @@ public static function clear_cache() { /** * Print the cache * - * @since 2.0 - * @change 2.3.0 + * @param bool $sig_detail Show details in signature. + * @param array $cache Array of cache values. * - * @param bool $sig_detail Show details in signature. - * @param array $cache Array of cache values. + * @since 2.0 + * @since 2.3.0 added $sig_detail parameter */ public static function print_cache( $sig_detail, $cache ) { /* No array? */ @@ -141,16 +137,16 @@ public static function print_cache( $sig_detail, $cache ) { /** * Get the cache size * - * @since 2.0 - * @change 2.0 + * @return int Column size * - * @return integer Column size + * @since 2.0 */ public static function get_stats() { /* Init */ global $wpdb; /* Read */ + return $wpdb->get_var( 'SELECT SUM( CHAR_LENGTH(option_value) ) FROM `' . $wpdb->options . "` WHERE `option_name` LIKE ('\_transient%.cachify')" ); @@ -159,12 +155,13 @@ public static function get_stats() { /** * Generate signature * - * @since 2.0 - * @change 2.3.0 + * @param bool $detail Show details in signature. + * @param array $meta Content of metadata. + * + * @return string Signature string * - * @param bool $detail Show details in signature. - * @param array $meta Content of metadata. - * @return string Signature string + * @since 2.0 + * @since 2.3.0 added $detail parameter */ private static function _cache_signature( $detail, $meta ) { /* No array? */ @@ -210,10 +207,9 @@ private static function _cache_signature( $detail, $meta ) { /** * Return query count * - * @since 0.1 - * @change 2.0 + * @return int Number of queries * - * @return integer Number of queries + * @since 0.1 */ private static function _page_queries() { return $GLOBALS['wpdb']->num_queries; @@ -222,10 +218,9 @@ private static function _page_queries() { /** * Return execution time * - * @since 0.1 - * @change 2.0 + * @return int Execution time in seconds * - * @return integer Execution time in seconds + * @since 0.1 */ private static function _page_timer() { return timer_stop( 0, 2 ); @@ -234,10 +229,9 @@ private static function _page_timer() { /** * Return memory consumption * - * @since 0.7 - * @change 2.0 + * @return string Formatted memory size * - * @return string Formatted memory size + * @since 0.7 */ private static function _page_memory() { return ( function_exists( 'memory_get_usage' ) ? size_format( memory_get_usage(), 2 ) : 0 ); diff --git a/inc/class-cachify-hdd.php b/inc/class-cachify-hdd.php index f971baa6..8d521a1e 100644 --- a/inc/class-cachify-hdd.php +++ b/inc/class-cachify-hdd.php @@ -16,10 +16,9 @@ final class Cachify_HDD { /** * Availability check * - * @since 2.0.7 - * @change 2.0.7 + * @return bool TRUE when installed * - * @return boolean true/false TRUE when installed + * @since 2.0.7 */ public static function is_available() { $option = get_option( 'permalink_structure' ); @@ -29,9 +28,9 @@ public static function is_available() { /** * Returns if gzip file creation is enabled * - * @since 2.4.0 - * * @return bool + * + * @since 2.4.0 */ public static function is_gzip_enabled() { /** @@ -45,10 +44,9 @@ public static function is_gzip_enabled() { /** * Caching method as string * - * @since 2.1.2 - * @change 2.1.2 + * @return string Caching method * - * @return string Caching method + * @since 2.1.2 */ public static function stringify_method() { return 'HDD'; @@ -57,13 +55,13 @@ public static function stringify_method() { /** * Store item in cache * - * @since 2.0 - * @change 2.3.0 + * @param string $hash Hash of the entry [ignored]. + * @param string $data Content of the entry. + * @param int $lifetime Lifetime of the entry [ignored]. + * @param bool $sig_detail Show details in signature. * - * @param string $hash Hash of the entry [ignored]. - * @param string $data Content of the entry. - * @param integer $lifetime Lifetime of the entry [ignored]. - * @param bool $sig_detail Show details in signature. + * @since 2.0 + * @since 2.3.0 added $sig_details parameter */ public static function store_item( $hash, $data, $lifetime, $sig_detail ) { /* Do not store empty data. */ @@ -81,10 +79,9 @@ public static function store_item( $hash, $data, $lifetime, $sig_detail ) { /** * Read item from cache * - * @since 2.0 - * @change 2.0 + * @return bool True if cache is present. * - * @return boolean True if cache is present. + * @since 2.0 */ public static function get_item() { return is_readable( @@ -95,11 +92,10 @@ public static function get_item() { /** * Delete item from cache * - * @since 2.0 - * @change 2.0 + * @param string $hash Hash of the entry [ignored]. + * @param string $url URL of the entry. * - * @param string $hash Hash of the entry [ignored]. - * @param string $url URL of the entry. + * @since 2.0 */ public static function delete_item( $hash, $url ) { self::_clear_dir( @@ -110,8 +106,7 @@ public static function delete_item( $hash, $url ) { /** * Clear the cache * - * @since 2.0 - * @change 2.0 + * @since 2.0 */ public static function clear_cache() { self::_clear_dir( @@ -123,8 +118,7 @@ public static function clear_cache() { /** * Print the cache * - * @since 2.0 - * @change 2.3 + * @since 2.0 */ public static function print_cache() { $filename = self::_file_html(); @@ -138,10 +132,9 @@ public static function print_cache() { /** * Get the cache size * - * @since 2.0 - * @change 2.0 + * @return int Directory size * - * @return integer Directory size + * @since 2.0 */ public static function get_stats() { return self::_dir_size( CACHIFY_CACHE_DIR ); @@ -150,11 +143,12 @@ public static function get_stats() { /** * Generate signature * - * @since 2.0 - * @change 2.3.0 + * @param bool $detail Show details in signature. * - * @param bool $detail Show details in signature. - * @return string Signature string + * @return string Signature string + * + * @since 2.0 + * @since 2.3.0 added $detail parameter */ private static function _cache_signature( $detail ) { return sprintf( @@ -171,10 +165,9 @@ private static function _cache_signature( $detail ) { /** * Initialize caching process * - * @since 2.0 - * @change 2.0 + * @param string $data Cache content. * - * @param string $data Cache content. + * @since 2.0 */ private static function _create_files( $data ) { $file_path = self::_file_path(); @@ -200,11 +193,10 @@ private static function _create_files( $data ) { /** * Create cache file * - * @since 2.0 - * @change 2.0 + * @param string $file Path to cache file. + * @param string $data Cache content. * - * @param string $file Path to cache file. - * @param string $data Cache content. + * @since 2.0 */ private static function _create_file( $file, $data ) { /* Writable? */ @@ -230,11 +222,10 @@ private static function _create_file( $file, $data ) { /** * Clear directory * - * @since 2.0 - * @change 2.0.5 + * @param string $dir Directory path. + * @param bool $recursive true for clearing subdirectories as well. * - * @param string $dir Directory path. - * @param boolean $recursive true for clearing subdirectories as well. + * @since 2.0 */ private static function _clear_dir( $dir, $recursive = false ) { /* Remote training slash */ @@ -285,11 +276,11 @@ private static function _clear_dir( $dir, $recursive = false ) { /** * Get directory size * - * @since 2.0 - * @change 2.0 + * @param string $dir Directory path. + * + * @return mixed Directory size * - * @param string $dir Directory path. - * @return mixed Directory size + * @since 2.0 */ public static function _dir_size( $dir = '.' ) { /* Is directory? */ @@ -330,11 +321,11 @@ public static function _dir_size( $dir = '.' ) { /** * Path to cache file * - * @since 2.0 - * @change 2.0 + * @param string $path Request URI or permalink [optional]. * - * @param string $path Request URI or permalink [optional]. - * @return string Path to cache file + * @return string Path to cache file + * + * @since 2.0 */ private static function _file_path( $path = null ) { $prefix = is_ssl() ? 'https-' : ''; @@ -362,11 +353,11 @@ private static function _file_path( $path = null ) { /** * Path to HTML file * - * @since 2.0 - * @change 2.3.0 + * @param string $file_path File path [optional]. + * + * @return string Path to HTML file * - * @param string $file_path File path [optional]. - * @return string Path to HTML file + * @since 2.0 */ private static function _file_html( $file_path = '' ) { return ( empty( $file_path ) ? self::_file_path() : $file_path ) . 'index.html'; @@ -375,11 +366,11 @@ private static function _file_html( $file_path = '' ) { /** * Path to GZIP file * - * @since 2.0 - * @change 2.3.0 + * @param string $file_path File path [optional]. * - * @param string $file_path File path [optional]. - * @return string Path to GZIP file + * @return string Path to GZIP file + * + * @since 2.0 */ private static function _file_gzip( $file_path = '' ) { return ( empty( $file_path ) ? self::_file_path() : $file_path ) . 'index.html.gz'; @@ -447,6 +438,5 @@ private static function _user_can_delete( $file ) { } return true; - } } diff --git a/inc/class-cachify-memcached.php b/inc/class-cachify-memcached.php index 27cfb013..688fbe5f 100644 --- a/inc/class-cachify-memcached.php +++ b/inc/class-cachify-memcached.php @@ -16,18 +16,18 @@ final class Cachify_MEMCACHED { /** * Memcached-Object * - * @since 2.0.7 - * @var object + * @var object + * + * @since 2.0.7 */ private static $_memcached; /** * Availability check * - * @since 2.0.7 - * @change 2.0.7 + * @return bool TRUE when installed * - * @return boolean true/false TRUE when installed + * @since 2.0.7 */ public static function is_available() { return class_exists( 'Memcached' ) @@ -38,10 +38,9 @@ public static function is_available() { /** * Caching method as string * - * @since 2.1.2 - * @change 2.1.2 + * @return string Caching method * - * @return string Caching method + * @since 2.1.2 */ public static function stringify_method() { return 'Memcached'; @@ -50,13 +49,13 @@ public static function stringify_method() { /** * Store item in cache * - * @param string $hash Hash of the entry [ignored]. - * @param string $data Content of the entry. - * @param integer $lifetime Lifetime of the entry. - * @param bool $sig_detail Show details in signature. + * @param string $hash Hash of the entry [ignored]. + * @param string $data Content of the entry. + * @param int $lifetime Lifetime of the entry. + * @param bool $sig_detail Show details in signature. * - * @since 2.0.7 - * @change 2.3.0 + * @since 2.0.7 + * @since 2.3.0 added $sig_detail parameter */ public static function store_item( $hash, $data, $lifetime, $sig_detail ) { /* Do not store empty data. */ @@ -81,11 +80,11 @@ public static function store_item( $hash, $data, $lifetime, $sig_detail ) { /** * Read item from cache * - * @since 2.0.7 - * @change 2.0.7 + * @param string $hash Hash of the entry. + * + * @return mixed Content of the entry * - * @param string $hash Hash of the entry. - * @return mixed Content of the entry + * @since 2.0.7 */ public static function get_item( $hash ) { /* Server connect */ @@ -102,11 +101,10 @@ public static function get_item( $hash ) { /** * Delete item from cache * - * @since 2.0.7 - * @change 2.0.7 + * @param string $hash Hash of the entry. + * @param string $url URL of the entry [optional]. * - * @param string $hash Hash of the entry. - * @param string $url URL of the entry [optional]. + * @since 2.0.7 */ public static function delete_item( $hash, $url = '' ) { /* Server connect */ @@ -123,8 +121,7 @@ public static function delete_item( $hash, $url = '' ) { /** * Clear the cache * - * @since 2.0.7 - * @change 2.0.7 + * @since 2.0.7 */ public static function clear_cache() { /* Server connect */ @@ -143,8 +140,7 @@ public static function clear_cache() { /** * Print the cache * - * @since 2.0.7 - * @change 2.0.7 + * @since 2.0.7 */ public static function print_cache() { return; @@ -153,10 +149,9 @@ public static function print_cache() { /** * Get the cache size * - * @since 2.0.7 - * @change 2.0.7 + * @return mixed Cache size * - * @return mixed Cache size + * @since 2.0.7 */ public static function get_stats() { /* Server connect */ @@ -186,11 +181,12 @@ public static function get_stats() { /** * Generate signature * - * @since 2.0.7 - * @change 2.3.0 + * @param bool $detail Show details in signature. * - * @param bool $detail Show details in signature. - * @return string Signature string + * @return string Signature string + * + * @since 2.0.7 + * @since 2.3.0 added $detail parameter */ private static function _cache_signature( $detail ) { return sprintf( @@ -207,11 +203,11 @@ private static function _cache_signature( $detail ) { /** * Path of cache file * - * @since 2.0.7 - * @change 2.0.7 + * @param string $path Request URI or permalink [optional]. + * + * @return string Path to cache file * - * @param string $path Request URI or permalink [optional]. - * @return string Path to cache file + * @since 2.0.7 */ private static function _file_path( $path = null ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.InputNotValidated @@ -230,12 +226,11 @@ private static function _file_path( $path = null ) { /** * Connect to Memcached server * - * @since 2.0.7 - * @change 2.1.8 + * @hook array cachify_memcached_servers Array with memcached servers * - * @hook array cachify_memcached_servers Array with memcached servers + * @return bool TRUE on success * - * @return boolean true/false TRUE on success + * @since 2.0.7 */ private static function _connect_server() { /* Not enabled? */ diff --git a/inc/class-cachify.php b/inc/class-cachify.php index 7724bcec..9166a60d 100644 --- a/inc/class-cachify.php +++ b/inc/class-cachify.php @@ -16,32 +16,36 @@ final class Cachify { /** * Plugin options * - * @since 2.0 - * @var array + * @var array + * + * @since 2.0 */ private static $options; /** * Caching method * - * @since 2.0 - * @var object + * @var object + * + * @since 2.0 */ private static $method; /** - * Whether we are on an Nginx server or not. + * Whether we are on a Nginx server or not. + * + * @var bool * * @since 2.2.5 - * @var boolean */ private static $is_nginx; /** * Method settings * - * @since 2.0.9 - * @var integer + * @var int + * + * @since 2.0.9 */ const METHOD_DB = 0; const METHOD_APC = 1; @@ -51,8 +55,9 @@ final class Cachify { /** * Minify settings * - * @since 2.0.9 - * @var integer + * @var int + * + * @since 2.0.9 */ const MINIFY_DISABLED = 0; const MINIFY_HTML_ONLY = 1; @@ -61,7 +66,7 @@ final class Cachify { /** * REST endpoints * - * @var string + * @var string */ const REST_NAMESPACE = 'cachify/v1'; const REST_ROUTE_FLUSH = 'flush'; @@ -69,8 +74,7 @@ final class Cachify { /** * Pseudo constructor * - * @since 2.0.5 - * @change 2.0.5 + * @since 2.0.5 */ public static function instance() { new self(); @@ -79,10 +83,7 @@ public static function instance() { /** * Constructor * - * @since 1.0.0 - * @change 2.2.2 - * - * @return void + * @since 1.0 */ public function __construct() { /* Set defaults */ @@ -173,8 +174,7 @@ public function __construct() { /** * Deactivation hook * - * @since 2.1.0 - * @change 2.1.0 + * @since 2.1.0 */ public static function on_deactivation() { /* Remove hdd cache cron when hdd is selected */ @@ -191,8 +191,7 @@ public static function on_deactivation() { /** * Activation hook * - * @since 1.0 - * @change 2.1.0 + * @since 1.0 */ public static function on_activation() { /* Multisite & Network */ @@ -217,10 +216,10 @@ public static function on_activation() { /** * Plugin installation on new WPMS site. * - * @since 1.0 - * @since 2.4 supports WP_Site argument - * * @param int|WP_Site $new_site New site ID or object. + * + * @since 1.0 + * @since 2.4.0 supports WP_Site argument */ public static function install_later( $new_site ) { /* No network plugin */ @@ -241,8 +240,7 @@ public static function install_later( $new_site ) { /** * Actual installation of the options * - * @since 1.0 - * @change 2.0 + * @since 1.0 */ private static function _install_backend() { add_option( @@ -257,8 +255,7 @@ private static function _install_backend() { /** * Uninstalling of the plugin per MU blog. * - * @since 1.0 - * @change 2.1.0 + * @since 1.0 */ public static function on_uninstall() { /* Global */ @@ -288,10 +285,10 @@ public static function on_uninstall() { /** * Uninstalling of the plugin for WPMS site. * - * @since 1.0 - * @since 2.4 supports WP_Site argument - * * @param int|WP_Site $old_site Old site ID or object. + * + * @since 1.0 + * @since 2.4.0 supports WP_Site argument */ public static function uninstall_later( $old_site ) { /* No network plugin */ @@ -312,8 +309,7 @@ public static function uninstall_later( $old_site ) { /** * Actual uninstalling of the plugin * - * @since 1.0 - * @change 1.0 + * @since 1.0 */ private static function _uninstall_backend() { /* Option */ @@ -326,10 +322,9 @@ private static function _uninstall_backend() { /** * Get IDs of installed blogs * - * @since 1.0 - * @change 1.0 + * @return array Blog IDs * - * @return array Blog IDs + * @since 1.0 */ private static function _get_blog_ids() { /* Global */ @@ -380,8 +375,7 @@ public static function register_scripts() { /** * Register the language file * - * @since 2.1.3 - * @change 2.3.2 + * @since 2.1.3 */ public static function register_textdomain() { load_plugin_textdomain( 'cachify' ); @@ -390,8 +384,7 @@ public static function register_textdomain() { /** * Set default options * - * @since 2.0 - * @change 2.0.7 + * @since 2.0 */ private static function _set_default_vars() { /* Options */ @@ -418,10 +411,9 @@ private static function _set_default_vars() { /** * Get options * - * @since 2.0 - * @change 2.3.0 + * @return array Array of option values * - * @return array Array of option values + * @since 2.0 */ private static function _get_options() { return wp_parse_args( @@ -445,7 +437,7 @@ private static function _get_options() { * * @since 1.0 * @since 2.1.9 - * @since 2.4 Removed $data parameter and return value. + * @since 2.4.0 Removed $data parameter and return value. */ public static function robots_txt() { /* HDD only */ @@ -457,7 +449,7 @@ public static function robots_txt() { /** * HDD Cache expiration cron action. * - * @since 2.4 + * @since 2.4.0 */ public static function run_hdd_cache_cron() { Cachify_HDD::clear_cache(); @@ -470,7 +462,7 @@ public static function run_hdd_cache_cron() { * * @return array Array of non-default schedules with our tasks added. * - * @since 2.4 + * @since 2.4.0 */ public static function add_cron_cache_expiration( $schedules ) { $schedules['cachify_cache_expire'] = array( @@ -483,11 +475,11 @@ public static function add_cron_cache_expiration( $schedules ) { /** * Add the action links * - * @since 1.0 - * @change 1.0 + * @param array $data Initial array with action links. * - * @param array $data Initial array with action links. - * @return array Merged array with action links. + * @return array Merged array with action links. + * + * @since 1.0 */ public static function action_links( $data ) { /* Permissions? */ @@ -515,12 +507,12 @@ public static function action_links( $data ) { /** * Meta links of the plugin * - * @since 0.5 - * @change 2.0.5 + * @param array $input Initial array with meta links. + * @param string $page Current page. + * + * @return array Merged array with meta links. * - * @param array $input Initial array with meta links. - * @param string $page Current page. - * @return array Merged array with meta links. + * @since 0.5 */ public static function row_meta( $input, $page ) { /* Permissions */ @@ -540,11 +532,11 @@ public static function row_meta( $input, $page ) { /** * Add cache properties to dashboard * - * @since 2.0.0 - * @change 2.2.2 + * @param array $items Initial array with dashboard items. * - * @param array $items Initial array with dashboard items. - * @return array Merged array with dashboard items. + * @return array Merged array with dashboard items. + * + * @since 2.0.0 */ public static function add_dashboard_count( $items = array() ) { /* Skip */ @@ -597,10 +589,9 @@ public static function add_dashboard_count( $items = array() ) { /** * Get the cache size * - * @since 2.0.6 - * @change 2.0.6 + * @return int Cache size in bytes. * - * @return integer Cache size in bytes. + * @since 2.0.6 */ public static function get_cache_size() { $size = get_transient( 'cachify_cache_size' ); @@ -627,13 +618,13 @@ public static function get_cache_size() { /** * Add flush icon to admin bar menu * - * @since 1.2 - * @change 2.2.2 - * @change 2.4.0 Adjust icon for flush request via AJAX + * @hook mixed cachify_user_can_flush_cache * - * @hook mixed cachify_user_can_flush_cache + * @param object $wp_admin_bar Object of menu items. * - * @param object $wp_admin_bar Object of menu items. + * @since 1.2 + * @since 2.2.2 + * @since 2.4.0 Adjust icon for flush request via AJAX */ public static function add_flush_icon( $wp_admin_bar ) { /* Quit */ @@ -675,9 +666,9 @@ public static function add_flush_icon( $wp_admin_bar ) { /** * Returns the dashicon class for the success state in admin bar flush button * - * @since 2.4.0 - * * @return string + * + * @since 2.4.0 */ public static function get_dashicon_success_class() { global $wp_version; @@ -691,11 +682,11 @@ public static function get_dashicon_success_class() { /** * Add a script to query the REST endpoint and animate the flush icon in admin bar menu * - * @since 2.4.0 + * @hook mixed cachify_user_can_flush_cache ? * - * @hook mixed cachify_user_can_flush_cache ? + * @param object $wp_admin_bar Object of menu items. * - * @param object $wp_admin_bar Object of menu items. + * @since 2.4.0 */ public static function add_flush_icon_script( $wp_admin_bar ) { /* Quit */ @@ -724,7 +715,7 @@ public static function add_flush_icon_script( $wp_admin_bar ) { /** * Registers an REST endpoint for the flush operation * - * @change 2.4.0 + * @since 2.4.0 */ public static function add_flush_rest_endpoint() { register_rest_route( @@ -747,9 +738,9 @@ public static function add_flush_rest_endpoint() { /** * Check if user can manage options * - * @since 2.4.0 + * @return bool * - * @return bool + * @since 2.4.0 */ public static function user_can_manage_options() { return current_user_can( 'manage_options' ); @@ -758,13 +749,13 @@ public static function user_can_manage_options() { /** * Process plugin's meta actions * - * @since 0.5 - * @change 2.2.2 - * @change 2.4.0 Extract cache flushing to own method and always redirect to referer with new value for `_cachify` param. - * * @hook mixed cachify_user_can_flush_cache * - * @param array $data Metadata of the plugin. + * @param array $data Metadata of the plugin. + * + * @since 0.5 + * @since 2.2.2 + * @since 2.4.0 Extract cache flushing to own method and always redirect to referer with new value for `_cachify` param. */ public static function process_flush_request( $data ) { /* Skip if not a flush request */ @@ -861,10 +852,10 @@ public static function flush_cache() { /** * Notice after successful flushing of the cache * - * @since 1.2 - * @change 2.2.2 + * @hook mixed cachify_user_can_flush_cache * - * @hook mixed cachify_user_can_flush_cache + * @since 1.2 + * @since 2.2.2 */ public static function flush_notice() { /* No admin */ @@ -881,12 +872,12 @@ public static function flush_notice() { /** * Remove page from cache or flush on comment edit * - * @since 0.1.0 - * @change 2.1.2 + * @param int $id Comment ID. * - * @param integer $id Comment ID. + * @since 0.1.0 + * @since 2.1.2 * - * @deprecated 2.4 Use comment_edit($id, $comment) instead. + * @deprecated 2.4.0 Use comment_edit($id, $comment) instead. */ public static function edit_comment( $id ) { self::comment_edit( $id, array( 'comment_approved' => 1 ) ); @@ -895,10 +886,10 @@ public static function edit_comment( $id ) { /** * Remove page from cache or flush on comment edit. * - * @since 2.4 Replacement for edit_comment($id) with additional comment parameter. - * * @param integer $id Comment ID. * @param array $comment Comment data. + * + * @since 2.4.0 Replacement for edit_comment($id) with additional comment parameter. */ public static function comment_edit( $id, $comment ) { $approved = (int) $comment['comment_approved']; @@ -918,15 +909,14 @@ public static function comment_edit( $id, $comment ) { /** * Remove page from cache or flush on new comment * - * @since 0.1.0 - * @change 2.1.2 - * * @param mixed $approved Comment status. * @param array $comment Array of properties. * * @return mixed Comment status. * - * @deprecated 2.4 Use new_comment($id, $approved) instead. + * @since 0.1 + * @since 2.1.2 + * @since 2.4.0 Replacement for edit_comment($id) with additional comment parameter. */ public static function pre_comment( $approved, $comment ) { self::new_comment( $comment['comment_ID'], $approved ); @@ -937,12 +927,12 @@ public static function pre_comment( $approved, $comment ) { /** * Remove page from cache or flush on new comment * - * @since 0.1.0 - * @since 2.1.2 - * @since 2.4 Renamed with ID parameter instead of comment array. - * * @param integer|string $id Comment ID. * @param integer|string $approved Comment status. + * + * @since 0.1.0 + * @since 2.1.2 + * @since 2.4.0 Renamed with ID parameter instead of comment array. */ public static function new_comment( $id, $approved ) { /* Approved comment? */ @@ -958,14 +948,14 @@ public static function new_comment( $id, $approved ) { /** * Remove page from cache or flush on comment edit * - * @since 0.1 - * @change 2.1.2 + * @param string $new_status New status. + * @param string $old_status Old status. + * @param object $comment The comment. * - * @param string $new_status New status. - * @param string $old_status Old status. - * @param object $comment The comment. + * @since 0.1 + * @since 2.1.2 * - * @deprecated 2.4 Use comment_status($new_status, $old_status, $comment) instead. + * @deprecated 2.4.0 Use comment_status($new_status, $old_status, $comment) instead. */ public static function touch_comment( $new_status, $old_status, $comment ) { self::comment_status( $new_status, $old_status, $comment ); @@ -974,13 +964,13 @@ public static function touch_comment( $new_status, $old_status, $comment ) { /** * Remove page from cache or flush on comment edit. * - * @since 0.1 - * @since 2.1.2 - * @since 2.4 Renamed from touch_comment(). - * * @param string $new_status New status. * @param string $old_status Old status. * @param WP_Comment $comment The comment. + * + * @since 0.1 + * @since 2.1.2 + * @since 2.4.0 Renamed from touch_comment(). */ public static function comment_status( $new_status, $old_status, $comment ) { if ( 'approved' === $old_status || 'approved' === $new_status ) { @@ -995,8 +985,8 @@ public static function comment_status( $new_status, $old_status, $comment ) { /** * Generate publish hook for custom post types * - * @since 2.1.7 Make the function public - * @since 2.0.3 + * @since 2.0.3 + * @since 2.1.7 Make the function public * * @deprecated no longer used since 2.4 */ @@ -1023,11 +1013,10 @@ public static function register_publish_hooks() { /** * Removes the post type cache on post updates * - * @since 2.0.3 - * @change 2.3.0 + * @param int $post_id Post ID. + * @param object $post Post object. * - * @param integer $post_id Post ID. - * @param object $post Post object. + * @since 2.0.3 * * @deprecated no longer used since 2.4 */ @@ -1058,11 +1047,11 @@ public static function publish_post_types( $post_id, $post ) { /** * Removes the post type cache if saved or updated * + * @param int $id Post ID. + * * @since 2.0.3 * @since 2.1.7 Make the function public. - * @since 2.4 Renamed to save_update_trash_post with $id parameter. - * - * @param integer $id Post ID. + * @since 2.4.0 Renamed to save_update_trash_post with $id parameter. */ public static function save_update_trash_post( $id ) { $status = get_post_status( $id ); @@ -1076,12 +1065,12 @@ public static function save_update_trash_post( $id ) { /** * Removes the post type cache before an existing post type is updated in the db * + * @param int $id Post ID. + * @param array $data Post data. + * * @since 2.0.3 * @since 2.3.0 - * @since 2.4 Renamed to post_update. - * - * @param integer $id Post ID. - * @param array $data Post data. + * @since 2.4.0 Renamed to post_update. */ public static function post_update( $id, $data ) { $new_status = $data['post_status']; @@ -1096,9 +1085,9 @@ public static function post_update( $id, $data ) { /** * Clear cache when any post type has been created or updated * - * @since 2.4 + * @param int|WP_Post $post Post ID or object. * - * @param integer|WP_Post $post Post ID or object. + * @since 2.4.0 */ public static function flush_cache_for_posts( $post ) { if ( is_int( $post ) ) { @@ -1125,9 +1114,9 @@ public static function flush_cache_for_posts( $post ) { /** * Flush post cache on WooCommerce stock changes. * - * @since 2.4 - * * @param int|WC_Product $product Product ID or object. + * + * @since 2.4.0 */ public static function flush_woocommerce( $product ) { if ( is_int( $product ) ) { @@ -1142,10 +1131,9 @@ public static function flush_woocommerce( $product ) { /** * Removes a page (id) from cache * - * @since 2.0.3 - * @change 2.1.3 + * @param int $post_id Post ID. * - * @param integer $post_id Post ID. + * @since 2.0.3 */ public static function remove_page_cache_by_post_id( $post_id ) { $post_id = (int) $post_id; @@ -1159,10 +1147,9 @@ public static function remove_page_cache_by_post_id( $post_id ) { /** * Removes a page url from cache * - * @since 0.1 - * @change 2.1.3 + * @param string $url Page URL. * - * @param string $url Page URL. + * @since 0.1 */ public static function remove_page_cache_by_url( $url ) { $url = (string) $url; @@ -1183,10 +1170,9 @@ public static function remove_page_cache_by_url( $url ) { /** * Get cache validity * - * @since 2.0.0 - * @change 2.1.7 + * @return int Validity period in seconds. * - * @return integer Validity period in seconds. + * @since 2.0.0 */ private static function _cache_expires() { return HOUR_IN_SECONDS * self::$options['cache_expires']; @@ -1195,9 +1181,9 @@ private static function _cache_expires() { /** * Determine if cache details should be printed in signature * - * @since 2.3.0 + * @return bool Show details in signature. * - * @return bool Show details in signature. + * @since 2.3.0 */ private static function _signature_details() { return 1 === self::$options['sig_detail']; @@ -1206,12 +1192,12 @@ private static function _signature_details() { /** * Get hash value for caching * - * @since 0.1 - * @change 2.0 - * @change 2.4.0 Fix issue with port in URL. + * @param string $url URL to hash [optional]. * - * @param string $url URL to hash [optional]. - * @return string Cachify hash value. + * @return string Cachify hash value. + * + * @since 0.1 + * @since 2.0 */ private static function _cache_hash( $url = '' ) { $prefix = is_ssl() ? 'https-' : ''; @@ -1229,11 +1215,12 @@ private static function _cache_hash( $url = '' ) { /** * Split by comma * - * @since 0.9.1 - * @change 1.0 + * @param string $input String to split. + * + * @return array Splitted values. * - * @param string $input String to split. - * @return array Splitted values. + * @since 0.9.1 + * @since 1.0 */ private static function _preg_split( $input ) { return (array) preg_split( '/,/', $input, -1, PREG_SPLIT_NO_EMPTY ); @@ -1242,10 +1229,9 @@ private static function _preg_split( $input ) { /** * Check for index page * - * @since 0.6 - * @change 1.0 + * @return bool TRUE if index * - * @return boolean TRUE if index + * @since 0.6 */ private static function _is_index() { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.InputNotValidated @@ -1255,10 +1241,9 @@ private static function _is_index() { /** * Check for mobile devices * - * @since 0.9.1 - * @change 2.3.0 + * @return bool TRUE if mobile * - * @return boolean TRUE if mobile + * @since 0.9.1 */ private static function _is_mobile() { $templatedir = get_template_directory(); @@ -1268,10 +1253,9 @@ private static function _is_mobile() { /** * Check if user is logged in or marked * - * @since 2.0.0 - * @change 2.0.5 + * @return bool TRUE on "marked" users * - * @return boolean $diff TRUE on "marked" users + * @since 2.0.0 */ private static function _is_logged_in() { /* Logged in */ @@ -1297,7 +1281,7 @@ private static function _is_logged_in() { /** * Register all hooks to flush the total cache * - * @since 2.4.0 + * @since 2.4.0 */ public static function register_flush_cache_hooks() { /* Define all default flush cache hooks */ @@ -1310,8 +1294,9 @@ public static function register_flush_cache_hooks() { 'create_term' => 10, 'delete_term' => 10, 'edit_terms' => 10, - 'delete_user' => 10, + 'user_register' => 10, 'edit_user_profile_update' => 10, + 'delete_user' => 10, /* third party */ 'autoptimize_action_cachepurged' => 10, ); @@ -1328,13 +1313,11 @@ public static function register_flush_cache_hooks() { /** * Define exclusions for caching * - * @since 0.2 - * @change 2.3.0 - * @change 2.4.0 Add check for sitemap feature and skip cache for other request methods than GET. + * @hook bool cachify_skip_cache * - * @return boolean TRUE on exclusion + * @return bool TRUE on exclusion * - * @hook boolean cachify_skip_cache + * @since 0.2 */ private static function _skip_cache() { @@ -1403,19 +1386,26 @@ private static function _skip_cache() { return true; } + /* Content Negotiation */ + + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + if ( isset( $_SERVER['HTTP_ACCEPT'] ) && false === strpos( $_SERVER['HTTP_ACCEPT'], 'text/html' ) ) { + return true; + } + return false; } /** * Minify HTML code * - * @since 0.9.2 - * @change 2.0.9 + * @hook array cachify_minify_ignore_tags + * + * @param string $data Original HTML code. * - * @param string $data Original HTML code. - * @return string Minified code + * @return string Minified code * - * @hook array cachify_minify_ignore_tags + * @since 0.9.2 */ private static function _minify_cache( $data ) { /* Disabled? */ @@ -1474,11 +1464,10 @@ private static function _minify_cache( $data ) { /** * Flush total cache * - * @since 0.1 - * @change 2.0 - * @change 2.4.0 Do not flush cache for post revisions. + * @param bool $clear_all_methods Flush all caching methods (default: FALSE). * - * @param bool $clear_all_methods Flush all caching methods (default: FALSE). + * @since 0.1 + * @since 2.0 */ public static function flush_total_cache( $clear_all_methods = false ) { // We do not need to flush the cache for saved post revisions. @@ -1514,11 +1503,12 @@ public static function flush_total_cache( $clear_all_methods = false ) { /** * Assign the cache * - * @since 0.1 - * @change 2.0 + * @param string $data Content of the page. + * + * @return string Content of the page. * - * @param string $data Content of the page. - * @return string Content of the page. + * @since 0.1 + * @since 2.0 */ public static function set_cache( $data ) { /* Empty? */ @@ -1529,13 +1519,13 @@ public static function set_cache( $data ) { /** * Filters whether the buffered data should actually be cached * - * @since 2.3 - * * @param bool $should_cache Whether the data should be cached. * @param string $data The actual data. * @param object $method Instance of the selected caching method. * @param string $cache_hash The cache hash. * @param int $cache_expires Cache validity period. + * + * @since 2.3.0 */ $should_cache = apply_filters( 'cachify_store_item', @@ -1551,12 +1541,12 @@ public static function set_cache( $data ) { /** * Filters the buffered data itself * - * @since 2.4 - * * @param string $data The actual data. * @param object $method Instance of the selected caching method. * @param string $cache_hash The cache hash. * @param int $cache_expires Cache validity period. + * + * @since 2.4.0 */ $data = apply_filters( 'cachify_modify_output', $data, self::$method, self::_cache_hash(), self::_cache_expires() ); @@ -1578,8 +1568,7 @@ public static function set_cache( $data ) { /** * Manage the cache. * - * @since 0.1 - * @change 2.3 + * @since 0.1 */ public static function manage_cache() { /* No caching? */ @@ -1616,10 +1605,9 @@ public static function manage_cache() { /** * Register CSS * - * @since 1.0 - * @change 2.3.0 + * @param string $hook Current hook. * - * @param string $hook Current hook. + * @since 1.0 */ public static function add_admin_resources( $hook ) { /* Hooks check */ @@ -1664,8 +1652,7 @@ public static function admin_dashboard_dark_mode_styles() { /** * Add options page * - * @since 1.0 - * @change 2.2.2 + * @since 1.0 */ public static function add_page() { add_options_page( @@ -1683,10 +1670,9 @@ public static function add_page() { /** * Available caching methods * - * @since 2.0.0 - * @change 2.1.3 + * @return array Array of actually available methods. * - * @return array Array of actually available methods. + * @since 2.0 */ private static function _method_select() { /* Defaults */ @@ -1718,10 +1704,9 @@ private static function _method_select() { /** * Minify cache dropdown * - * @since 2.1.3 - * @change 2.1.3 + * @return array Key => value array * - * @return array Key => value array + * @since 2.1.3 */ private static function _minify_select() { return array( @@ -1734,8 +1719,7 @@ private static function _minify_select() { /** * Register settings * - * @since 1.0 - * @change 1.0 + * @since 1.0 */ public static function register_settings() { register_setting( @@ -1751,11 +1735,12 @@ public static function register_settings() { /** * Validate options * - * @since 1.0.0 - * @change 2.1.3 + * @param array $data Array of form values. + * + * @return array Array of validated values. * - * @param array $data Array of form values. - * @return array Array of validated values. + * @since 1.0 + * @since 2.1.3 */ public static function validate_options( $data ) { /* Empty data? */ @@ -1793,8 +1778,7 @@ public static function validate_options( $data ) { /** * Display options page * - * @since 1.0 - * @change 2.3.0 + * @since 1.0 */ public static function options_page() { $options = self::_get_options(); @@ -1843,11 +1827,11 @@ public static function options_page() { /** * Return an array with all settings tabs applicable in context of current plugin options. * - * @since 2.3.0 - * @change 2.3.0 - * * @param array $options the options. + * * @return array + * + * @since 2.3.0 */ private static function _get_tabs( $options ) { /* Settings tab is always present */ diff --git a/inc/setup/cachify.hdd.htaccess.php b/inc/setup/cachify.hdd.htaccess.php index 1f64549a..4ab3335c 100644 --- a/inc/setup/cachify.hdd.htaccess.php +++ b/inc/setup/cachify.hdd.htaccess.php @@ -26,6 +26,7 @@ RewriteRule .* - [E=CACHIFY_DIR:/] {{GZIP}} # Main Rules + RewriteCond %{HTTP_ACCEPT} .*text/html.* RewriteCond %{REQUEST_METHOD} GET RewriteCond %{QUERY_STRING} ="" RewriteCond %{REQUEST_URI} !^/(wp-admin|wp-content/cache)/.* diff --git a/inc/setup/cachify.hdd.nginx.php b/inc/setup/cachify.hdd.nginx.php index 7aaf1f04..38b001c6 100644 --- a/inc/setup/cachify.hdd.nginx.php +++ b/inc/setup/cachify.hdd.nginx.php @@ -24,6 +24,9 @@ if ( $query_string ) { return 405; } + if ( $http_accept !~* "text/html" ) { + return 405; + } if ( $request_method = POST ) { return 405; } diff --git a/inc/setup/cachify.memcached.nginx.php b/inc/setup/cachify.memcached.nginx.php index 2b737b8c..ca3b1518 100644 --- a/inc/setup/cachify.memcached.nginx.php +++ b/inc/setup/cachify.memcached.nginx.php @@ -26,6 +26,11 @@ if ( $query_string ) { return 405; } + + if ( $http_accept !~* "text/html" ) { + return 405; + } + if ( $request_method = POST ) { return 405; } diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 00000000..b16e11ae --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,25 @@ + + + + + cachify.php + inc + + + + + + + + ./tests/ + + + + + + diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 00000000..2a307196 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,30 @@ +Test Me

Test Content.

', + 3600 + ); + + $cached = Cachify_DB::get_item( '965b4abf2414e45036ab90c9d3f8dbc7' ); + self::assertIsArray( $cached, 'item was not stored' ); + self::assertEquals( + 'Test Me

Test Content.

', + $cached['data'], + 'unexpected data in cache' + ); + self::assertIsInt( $cached['meta']['queries'], 'number of queries not filled' ); + self::assertIsString( $cached['meta']['timer'], 'timing not filled' ); + self::assertIsString( $cached['meta']['memory'], 'memory not filled' ); + self::assertIsInt( $cached['meta']['time'], 'time not filled' ); + + // Another item. + Cachify_DB::store_item( + 'ef7e4a0540f6cde19e6eb658c69b0064', + 'Test 2

Test Content #2.

', + 3600 + ); + self::assertIsArray( Cachify_DB::get_item( 'ef7e4a0540f6cde19e6eb658c69b0064' ), 'second item was not stored' ); + + // Delete the first item. + Cachify_DB::delete_item( '965b4abf2414e45036ab90c9d3f8dbc7' ); + self::assertFalse( Cachify_DB::get_item( '965b4abf2414e45036ab90c9d3f8dbc7' ), 'first item was not deleted' ); + self::assertIsArray( Cachify_DB::get_item( 'ef7e4a0540f6cde19e6eb658c69b0064' ), 'second item should still be present' ); + } +} diff --git a/tests/test-cachify-hdd.php b/tests/test-cachify-hdd.php new file mode 100644 index 00000000..80bf3656 --- /dev/null +++ b/tests/test-cachify-hdd.php @@ -0,0 +1,105 @@ +Test Me

Test Content.

', + 3600, // Ignored. + false + ); + self::assertTrue( Cachify_HDD::get_item() ); + self::assertTrue( is_file( CACHIFY_CACHE_DIR . DIRECTORY_SEPARATOR . 'example.org/testme/index.html' ) ); + $cached = file_get_contents( CACHIFY_CACHE_DIR . DIRECTORY_SEPARATOR . 'example.org/testme/index.html' ); + self::assertStringStartsWith( + 'Test Me

Test Content.

+ +', $cached ); + + // Another item. + self::go_to( '/test2/' ); + Cachify_HDD::store_item( + 'ef7e4a0540f6cde19e6eb658c69b0064', // Ignored. + 'Test 2

Test Content #2.

', + 3600, // Ignored. + true + ); + self::assertTrue( is_file( CACHIFY_CACHE_DIR . DIRECTORY_SEPARATOR . 'example.org/test2/index.html' ) ); + $cached = file_get_contents( CACHIFY_CACHE_DIR . DIRECTORY_SEPARATOR . 'example.org/test2/index.html' ); + self::assertStringStartsWith( + 'Test 2

Test Content #2.

+ +', $cached ); + + // Delete the first item. + Cachify_HDD::delete_item( '965b4abf2414e45036ab90c9d3f8dbc7', 'http://example.org/testme/' ); + self::assertFalse( is_file( CACHIFY_CACHE_DIR . DIRECTORY_SEPARATOR . 'example.org/testme/index.html' ), 'first item was not deleted' ); + self::assertTrue( is_file( CACHIFY_CACHE_DIR . DIRECTORY_SEPARATOR . 'example.org/test2/index.html' ), 'second item should still be present' ); + + // Clear the cache. + Cachify_HDD::clear_cache(); + self::assertFalse( is_dir( CACHIFY_CACHE_DIR . DIRECTORY_SEPARATOR . 'example.org/test2' ) ); + self::assertFalse( Cachify_HDD::get_item() ); + } +} diff --git a/tests/test-cachify-memcached.php b/tests/test-cachify-memcached.php new file mode 100644 index 00000000..84cc0b58 --- /dev/null +++ b/tests/test-cachify-memcached.php @@ -0,0 +1,34 @@ + 10, + 'test_2' => 20, + ); + } + ); + + // Call flush registration. + Cachify::register_flush_cache_hooks(); + + // Verify that the filter has been called. + self::assertNotNull( $original_capture, 'Filter not called' ); + self::assertEquals( 12, count( $original_capture ), 'Unexpected number of default hooks' ); + self::assertEmpty( + array_filter( + $original_capture, + function( $v ) { + return 10 !== $v; + } + ), + 'All default filters should have priority 10' + ); + + // Verify that the action has been hooked with given priority. + self::assertEquals( + 10, + has_action( 'test_1', array( Cachify::class, 'flush_total_cache' ) ), + 'Flush action not hooked as expected' + ); + self::assertEquals( + 20, + has_action( 'test_2', array( Cachify::class, 'flush_total_cache' ) ), + 'Flush action not hooked as expected' + ); + } + + /** + * Test registration of scripts. + */ + public function test_register_scripts() { + Cachify::register_scripts(); + self::assertTrue( wp_script_is( 'cachify-admin-bar-flush', 'registered' ) ); + $script = wp_scripts()->registered['cachify-admin-bar-flush']; + self::assertStringEndsWith( + '/js/admin-bar-flush.min.js', + $script->src, + 'unexpected script source' + ); + } + + /** + * Test registration of styles. + */ + public function test_register_styles() { + Cachify::register_styles(); + self::assertTrue( wp_style_is( 'cachify-dashboard', 'registered' ) ); + self::assertTrue( wp_style_is( 'cachify-admin-bar-flush', 'registered' ) ); + + $style = wp_styles()->registered['cachify-dashboard']; + self::assertStringEndsWith( + '/css/dashboard.min.css', + $style->src, + 'unexpected dashboard style source' + ); + + $style = wp_styles()->registered['cachify-admin-bar-flush']; + self::assertStringEndsWith( + '/css/admin-bar-flush.min.css', + $style->src, + 'unexpected admin bar style source' + ); + } + + /** + * Test single site plugin activation. + */ + public function test_on_activation() { + self::assertFalse( get_option( 'cachify' ), 'Cachify option should not be initialized initially' ); + Cachify::on_activation(); + self::assertEquals( array() , get_option( 'cachify' ), 'Cachify option not initialized' ); + } +}