diff --git a/bin/run-wpcli b/bin/run-wpcli new file mode 100755 index 0000000..7175378 --- /dev/null +++ b/bin/run-wpcli @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +# Usage: bin/run-wpcli [WORDPRESS_VERSION] [PHP_VERSION] [COMMAND] +# Example: bin/run-wpcli 67 82 "tiny optimize --attachments=123,456" +# Example: bin/run-wpcli 67 82 "tiny optimize" + + +CONFIG_FILE="config/wp-version.conf" +WORDPRESS_VERSION_ENV="${1:-$WORDPRESS_VERSION}" +PHP_VERSION_ENV="${2:-$PHP_VERSION}" + +WORDPRESS_PORT="80${WORDPRESS_VERSION_ENV}" +WP_IMAGE_KEY="${WORDPRESS_VERSION_ENV}_${PHP_VERSION_ENV}" +WP_IMAGE=$(grep "^${WP_IMAGE_KEY}=" "$CONFIG_FILE" | cut -d'=' -f2) + +COMMAND=${3:-"tiny --help"} + +export WP_IMAGE +export COMPOSE_PROJECT_NAME="tinify_${WORDPRESS_VERSION_ENV}_${PHP_VERSION_ENV}" +export WORDPRESS_PORT + +docker compose -f config/docker-compose.yml run --rm wpcli wp $COMMAND \ No newline at end of file diff --git a/src/class-tiny-cli.php b/src/class-tiny-cli.php new file mode 100644 index 0000000..7f94814 --- /dev/null +++ b/src/class-tiny-cli.php @@ -0,0 +1,151 @@ +tiny_settings = $settings; + } + + /** + * Optimize will process images + * + * [--attachments=] + * : A comma separated list of attachment IDs to process. If omitted + * will optimize all uncompressed attachments + * + * + * ## EXAMPLES + * + * optimize specific attachments + * wp tiny optimize --attachments=532,603,705 + * + * optimize all unprocessed images + * wp tiny optimize + * + * + * @param array $args + * @param array $assoc_args + * @return void + */ + public function optimize( $args, $assoc_args ) { + $attachments = isset( $assoc_args['attachments'] ) ? + array_map( 'trim', explode( ',', $assoc_args['attachments'] ) ) : + array(); + + if ( empty( $attachments ) ) { + $attachments = $this->get_unoptimized_attachments(); + } + + if ( empty( $attachments ) ) { + WP_CLI::success( 'No images found that need optimization.' ); + return; + } + + $total = count( $attachments ); + WP_CLI::log( 'Optimizing ' . $total . ' images.' ); + + $progress = WP_CLI\Utils\make_progress_bar( 'Optimizing images', $total ); + $optimized = 0; + foreach ( $attachments as $attachment_id ) { + $attachment_id = intval( $attachment_id ); + + if ( ! $this->is_valid_attachment( $attachment_id ) ) { + WP_CLI::warning( 'skipping - invalid attachment: ' . $attachment_id ); + $progress->tick(); + continue; + } + + try { + $result = $this->optimize_attachment( $attachment_id ); + if ( isset( $result['success'] ) && $result['success'] > 0 ) { + $optimized++; + } + } catch ( Exception $e ) { + WP_CLI::warning( + 'skipping - error: ' . + $e->getMessage() . + ' (ID: ' . + $attachment_id . + ')' + ); + } + + $progress->tick(); + } + + $progress->finish(); + WP_CLI::success( 'Done! Optimized ' . $optimized . ' of ' . $total . ' images.' ); + } + + private function get_unoptimized_attachments() { + $stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->tiny_settings ); + + if ( empty( $stats['available-for-optimization'] ) ) { + return array(); + } + + $ids = array(); + foreach ( $stats['available-for-optimization'] as $item ) { + if ( isset( $item['ID'] ) ) { + $ids[] = $item['ID']; + } + } + return $ids; + } + + /** + * Will process an attachment for optimization + * + * @return array{ success: int, failed: int } + */ + private function optimize_attachment( $attachment_id ) { + $tiny_image = new Tiny_Image( $this->tiny_settings, $attachment_id ); + return $tiny_image->compress(); + } + + private function is_valid_attachment( $attachment_id ) { + $mime_type = get_post_mime_type( $attachment_id ); + if ( ! $mime_type || strpos( $mime_type, 'image/' ) !== 0 ) { + return false; + } + + $supported_types = array( 'image/jpeg', 'image/png', 'image/webp' ); + if ( ! in_array( $mime_type, $supported_types, true ) ) { + return false; + } + + return true; + } +} diff --git a/src/class-tiny-plugin.php b/src/class-tiny-plugin.php index 7be7512..ce6f839 100644 --- a/src/class-tiny-plugin.php +++ b/src/class-tiny-plugin.php @@ -71,6 +71,10 @@ public function init() { } } + public function cli_init() { + Tiny_CLI::register_command( $this->settings ); + } + public function ajax_init() { add_filter( 'wp_ajax_tiny_async_optimize_upload_new_media', $this->get_method( 'compress_on_upload' ) diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index ee54e7d..6e70295 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -50,6 +50,13 @@ public function xmlrpc_init() { } } + public function cli_init() { + try { + $this->init_compressor(); + } catch ( Tiny_Exception $e ) { + } + } + public function ajax_init() { try { $this->init_compressor(); diff --git a/src/class-tiny-wp-base.php b/src/class-tiny-wp-base.php index f37c651..f19ec6c 100644 --- a/src/class-tiny-wp-base.php +++ b/src/class-tiny-wp-base.php @@ -49,6 +49,10 @@ protected function doing_ajax_request() { return defined( 'DOING_AJAX' ) && DOING_AJAX; } + protected function is_cli() { + return defined( 'WP_CLI' ) && WP_CLI; + } + protected static function get_prefixed_name( $name ) { return self::PREFIX . $name; } @@ -65,6 +69,10 @@ public function __construct() { add_action( 'admin_init', $this->get_method( 'admin_init' ) ); add_action( 'admin_menu', $this->get_method( 'admin_menu' ) ); } + + if ( self::is_cli() ) { + add_action( 'cli_init', $this->get_method( 'cli_init' ) ); + } } protected function get_method( $name ) { @@ -100,4 +108,7 @@ public function admin_menu() { public function rest_init() { } + + public function cli_init() { + } } diff --git a/test/helpers/wordpress-cli.php b/test/helpers/wordpress-cli.php new file mode 100644 index 0000000..27c2802 --- /dev/null +++ b/test/helpers/wordpress-cli.php @@ -0,0 +1,29 @@ +wp->stub('get_post_mime_type', function ($i) { + return 'image/png'; + }); + $this->wp->stub('wp_get_attachment_metadata', function ($i) { + return array( + 'width' => 1256, + 'height' => 1256, + 'file' => '2025/07/test.png', + 'sizes' => array( + 'thumbnail' => array( + 'file' => 'test-150x150.png', + 'width' => 150, + 'height' => 150, + 'mime-type' => 'image/png' + ) + ), + ); + }); + + $virtual_test_image = array( + 'path' => '2025/07', + 'images' => array( + array( + 'size' => 137856, + 'file' => 'test.png', + ), + array( + 'size' => 37856, + 'file' => 'test-150x150.jpg', + ), + ) + ); + $this->wp->createImagesFromJSON($virtual_test_image); + + $settings = new Tiny_Settings(); + $mockCompressor = $this->createMock(Tiny_Compress::class); + + $expected = array( + 'file' => "vfs://root/wp-content/uploads/2025/07/test.png", + 'resize' => false, + 'preserve' => array(), + 'convert_opts' => array( + 'convert' => false, + 'convert_to' => array( + 'image/avif', + 'image/webp' + ) + ), + ); + $mockCompressor->expects($this->once()) + ->method('compress_file') + ->with( + $expected['file'], + $expected['resize'], + $expected['preserve'], + $expected['convert_opts'] + ); + $settings->set_compressor($mockCompressor); + + $command = new Tiny_Command($settings); + + $command->optimize(array(), array( + "attachments" => '4030', + )); + } + + public function test_will_compress_all_uncompressed_attachments_if_none_given() + { + // mock db + if (!defined('ARRAY_A')) { + define('ARRAY_A', 'ARRAY_A'); + } + global $wpdb; + $wpdb = $this->getMockBuilder(stdClass::class) + ->addMethods(['get_results']) + ->getMock(); + + $wpdb->posts = 'wp_posts'; + $wpdb->postmeta = 'wp_postmeta'; + + $mock_results = array( + array( + 'ID' => 1, + 'post_title' => 'Test Image', + 'meta_value' => serialize(array( + 'width' => 1200, + 'height' => 800, + 'file' => '2025/07/test.png', + 'sizes' => array() + )), + 'unique_attachment_name' => '2025/07/test.png', + 'tiny_meta_value' => '' + ) + ); + + $wpdb->method('get_results') + ->willReturn($mock_results); + + // create mock image + $virtual_test_image = array( + 'path' => '2025/07', + 'images' => array( + array( + 'size' => 137856, + 'file' => 'test.png', + ), + ) + ); + $this->wp->createImagesFromJSON($virtual_test_image); + + // mock wp_get_attachment_metadata + $this->wp->stub('wp_get_attachment_metadata', function ($i) { + return array( + 'width' => 1256, + 'height' => 1256, + 'file' => '2025/07/test.png', + 'sizes' => array(), + ); + }); + + // mock get_post_mime_type + $this->wp->stub('get_post_mime_type', function ($i) { + return 'image/png'; + }); + + // mock compressor + $settings = new Tiny_Settings(); + $mockCompressor = $this->createMock(Tiny_Compress::class); + $settings->set_compressor($mockCompressor); + + // create assertion + $mockCompressor->expects($this->once()) + ->method('compress_file'); + + // invoke test + $command = new Tiny_Command($settings); + $command->optimize(array(), array()); + } +} diff --git a/test/unit/TinyPluginTest.php b/test/unit/TinyPluginTest.php index fd654bc..890b9a4 100644 --- a/test/unit/TinyPluginTest.php +++ b/test/unit/TinyPluginTest.php @@ -1,41 +1,44 @@ subject = new Tiny_Plugin(); $this->subject->init(); - $this->compressor = $this->getMockBuilder( 'TestCompressor' ) - ->setMethods( array( 'compress_file' ) ) - ->getMock(); - $this->subject->set_compressor( $this->compressor ); + $this->compressor = $this->getMockBuilder('TestCompressor') + ->setMethods(array('compress_file')) + ->getMock(); + $this->subject->set_compressor($this->compressor); - $this->wp->addOption( 'tinypng_api_key', 'test123' ); - $this->wp->addOption( 'tinypng_sizes[0]', 'on' ); - $this->wp->addOption( 'tinypng_sizes[large]', 'on' ); - $this->wp->addOption( 'tinypng_sizes[post-thumbnail]', 'on' ); + $this->wp->addOption('tinypng_api_key', 'test123'); + $this->wp->addOption('tinypng_sizes[0]', 'on'); + $this->wp->addOption('tinypng_sizes[large]', 'on'); + $this->wp->addOption('tinypng_sizes[post-thumbnail]', 'on'); - $this->wp->addImageSize( 'post-thumbnail', array( 'width' => 825, 'height' => 510 ) ); + $this->wp->addImageSize('post-thumbnail', array('width' => 825, 'height' => 510)); $this->wp->createImages(); } - public function success_compress( $file ) { - if ( preg_match( '#[^-]+-([^.]+)[.](png|jpe?g)$#', basename( $file ), $match ) ) { + public function success_compress($file) + { + if (preg_match('#[^-]+-([^.]+)[.](png|jpe?g)$#', basename($file), $match)) { $key = $match[1]; } else { $key = null; } - $input = filesize( $file ); - switch ( $key ) { + $input = filesize($file); + switch ($key) { case 'thumbnail': $output = 81; $width = '150'; @@ -61,174 +64,206 @@ public function success_compress( $file ) { $width = '4000'; $height = '3000'; } - $this->vfs->getChild( vfsStream::path( $file ) )->truncate( $output ); - return array( 'input' => array( 'size' => $input ), 'output' => array( 'size' => $output, 'width' => $width, 'height' => $height ) ); + $this->vfs->getChild(vfsStream::path($file))->truncate($output); + return array('input' => array('size' => $input), 'output' => array('size' => $output, 'width' => $width, 'height' => $height)); } - public function test_init_should_add_filters() { + public function test_init_should_add_filters() + { $this->assertEquals(array( - array( 'jpeg_quality', array( 'Tiny_Plugin', 'jpeg_quality' ) ), - array( 'wp_editor_set_quality', array( 'Tiny_Plugin', 'jpeg_quality' ) ), - array( 'wp_generate_attachment_metadata', array( $this->subject, 'process_attachment' ), 10, 2 ), - ), $this->wp->getCalls( 'add_filter' )); + array('jpeg_quality', array('Tiny_Plugin', 'jpeg_quality')), + array('wp_editor_set_quality', array('Tiny_Plugin', 'jpeg_quality')), + array('wp_generate_attachment_metadata', array($this->subject, 'process_attachment'), 10, 2), + ), $this->wp->getCalls('add_filter')); } - public function test_compress_should_call_do_action() { - $this->wp->stub( 'get_post_mime_type', function( $i ) { return "image/png"; } ); - $this->compressor->expects( $this->exactly( 3 ) )->method( 'compress_file' )->withConsecutive( - array( $this->equalTo( 'vfs://root/wp-content/uploads/14/01/test.png' ) ), - array( $this->equalTo( 'vfs://root/wp-content/uploads/14/01/test-large.png' ) ), - array( $this->equalTo( 'vfs://root/wp-content/uploads/14/01/test-post-thumbnail.png' ) ) - )->will( $this->returnCallback( array( $this, 'success_compress' ) ) ); - $this->subject->blocking_compress_on_upload( $this->wp->getTestMetadata(), 1 ); + public function test_compress_should_call_do_action() + { + $this->wp->stub('get_post_mime_type', function ($i) { + return "image/png"; + }); + $this->compressor->expects($this->exactly(3))->method('compress_file')->withConsecutive( + array($this->equalTo('vfs://root/wp-content/uploads/14/01/test.png')), + array($this->equalTo('vfs://root/wp-content/uploads/14/01/test-large.png')), + array($this->equalTo('vfs://root/wp-content/uploads/14/01/test-post-thumbnail.png')) + )->will($this->returnCallback(array($this, 'success_compress'))); + $this->subject->blocking_compress_on_upload($this->wp->getTestMetadata(), 1); $do_action_calls = array(); - foreach ($this->wp->getCalls( 'do_action' ) as $action) { + foreach ($this->wp->getCalls('do_action') as $action) { array_push($do_action_calls, $action[0]); } - $this->assertEquals('tiny_image_after_compression', $do_action_calls[sizeof($do_action_calls)-1]); + $this->assertEquals('tiny_image_after_compression', $do_action_calls[sizeof($do_action_calls) - 1]); } - public function test_compress_should_respect_settings() { - $this->wp->stub( 'get_post_mime_type', function( $i ) { return "image/png"; } ); - $this->compressor->expects( $this->exactly( 3 ) )->method( 'compress_file' )->withConsecutive( - array( $this->equalTo( 'vfs://root/wp-content/uploads/14/01/test.png' ) ), - array( $this->equalTo( 'vfs://root/wp-content/uploads/14/01/test-large.png' ) ), - array( $this->equalTo( 'vfs://root/wp-content/uploads/14/01/test-post-thumbnail.png' ) ) - )->will( $this->returnCallback( array( $this, 'success_compress' ) ) ); - $this->subject->blocking_compress_on_upload( $this->wp->getTestMetadata(), 1 ); + public function test_compress_should_respect_settings() + { + $this->wp->stub('get_post_mime_type', function ($i) { + return "image/png"; + }); + $this->compressor->expects($this->exactly(3))->method('compress_file')->withConsecutive( + array($this->equalTo('vfs://root/wp-content/uploads/14/01/test.png')), + array($this->equalTo('vfs://root/wp-content/uploads/14/01/test-large.png')), + array($this->equalTo('vfs://root/wp-content/uploads/14/01/test-post-thumbnail.png')) + )->will($this->returnCallback(array($this, 'success_compress'))); + $this->subject->blocking_compress_on_upload($this->wp->getTestMetadata(), 1); } - public function test_compress_should_not_compress_twice() { - $this->wp->stub( 'get_post_mime_type', function( $i ) { return "image/png"; } ); + public function test_compress_should_not_compress_twice() + { + $this->wp->stub('get_post_mime_type', function ($i) { + return "image/png"; + }); $testmeta = $this->wp->getTestMetadata(); - $tiny_image = new Tiny_Image( new Tiny_Settings(), 1, $testmeta ); + $tiny_image = new Tiny_Image(new Tiny_Settings(), 1, $testmeta); $tiny_image->get_image_size()->add_tiny_meta_start(); - $tiny_image->get_image_size()->add_tiny_meta( self::success_compress( 'vfs://root/wp-content/uploads/14/01/test.png' ) ); - $tiny_image->get_image_size( 'large' )->add_tiny_meta_start(); - $tiny_image->get_image_size( 'large' )->add_tiny_meta( self::success_compress( 'vfs://root/wp-content/uploads/14/01/test-large.png' ) ); + $tiny_image->get_image_size()->add_tiny_meta(self::success_compress('vfs://root/wp-content/uploads/14/01/test.png')); + $tiny_image->get_image_size('large')->add_tiny_meta_start(); + $tiny_image->get_image_size('large')->add_tiny_meta(self::success_compress('vfs://root/wp-content/uploads/14/01/test-large.png')); $tiny_image->update_tiny_post_meta(); - $this->compressor->expects( $this->once() )->method( 'compress_file' )->withConsecutive( - array( $this->equalTo( 'vfs://root/wp-content/uploads/14/01/test-post-thumbnail.png' ) ) - )->will( $this->returnCallback( array( $this, 'success_compress' ) ) ); - $this->subject->blocking_compress_on_upload( $testmeta, 1 ); + $this->compressor->expects($this->once())->method('compress_file')->withConsecutive( + array($this->equalTo('vfs://root/wp-content/uploads/14/01/test-post-thumbnail.png')) + )->will($this->returnCallback(array($this, 'success_compress'))); + $this->subject->blocking_compress_on_upload($testmeta, 1); } - public function test_compress_when_file_changed() { - $this->wp->stub( 'get_post_mime_type', function( $i ) { return "image/png"; } ); + public function test_compress_when_file_changed() + { + $this->wp->stub('get_post_mime_type', function ($i) { + return "image/png"; + }); $testmeta = $this->wp->getTestMetadata(); - $tiny_image = new Tiny_Image( new Tiny_Settings(), 1, $testmeta ); + $tiny_image = new Tiny_Image(new Tiny_Settings(), 1, $testmeta); $tiny_image->get_image_size()->add_tiny_meta_start(); - $tiny_image->get_image_size()->add_tiny_meta( self::success_compress( 'vfs://root/wp-content/uploads/14/01/test.png' ) ); - $tiny_image->get_image_size( 'large' )->add_tiny_meta_start(); - $tiny_image->get_image_size( 'large' )->add_tiny_meta( self::success_compress( 'vfs://root/wp-content/uploads/14/01/test-large.png' ) ); - $tiny_image->get_image_size( 'post-thumbnail' )->add_tiny_meta_start(); - $tiny_image->get_image_size( 'post-thumbnail' )->add_tiny_meta( self::success_compress( 'vfs://root/wp-content/uploads/14/01/test-post-thumbnail.png' ) ); + $tiny_image->get_image_size()->add_tiny_meta(self::success_compress('vfs://root/wp-content/uploads/14/01/test.png')); + $tiny_image->get_image_size('large')->add_tiny_meta_start(); + $tiny_image->get_image_size('large')->add_tiny_meta(self::success_compress('vfs://root/wp-content/uploads/14/01/test-large.png')); + $tiny_image->get_image_size('post-thumbnail')->add_tiny_meta_start(); + $tiny_image->get_image_size('post-thumbnail')->add_tiny_meta(self::success_compress('vfs://root/wp-content/uploads/14/01/test-post-thumbnail.png')); $tiny_image->update_tiny_post_meta(); - $this->vfs->getChild( 'wp-content/uploads/14/01/test-large.png' )->truncate( 100000 ); + $this->vfs->getChild('wp-content/uploads/14/01/test-large.png')->truncate(100000); - $this->compressor->expects( $this->once() )->method( 'compress_file' )->withConsecutive( - array( $this->equalTo( 'vfs://root/wp-content/uploads/14/01/test-large.png' ) ) - )->will( $this->returnCallback( array( $this, 'success_compress' ) ) ); - $this->subject->blocking_compress_on_upload( $testmeta, 1 ); + $this->compressor->expects($this->once())->method('compress_file')->withConsecutive( + array($this->equalTo('vfs://root/wp-content/uploads/14/01/test-large.png')) + )->will($this->returnCallback(array($this, 'success_compress'))); + $this->subject->blocking_compress_on_upload($testmeta, 1); } - public function test_compress_should_update_metadata() { - $this->wp->stub( 'get_post_mime_type', function( $i ) { return "image/png"; } ); - $this->compressor->expects( $this->exactly( 3 ) )->method( 'compress_file' )->will( - $this->returnCallback( array( $this, 'success_compress' ) ) + public function test_compress_should_update_metadata() + { + $this->wp->stub('get_post_mime_type', function ($i) { + return "image/png"; + }); + $this->compressor->expects($this->exactly(3))->method('compress_file')->will( + $this->returnCallback(array($this, 'success_compress')) ); - $this->subject->blocking_compress_on_upload( $this->wp->getTestMetadata(), 1 ); + $this->subject->blocking_compress_on_upload($this->wp->getTestMetadata(), 1); - $tiny_metadata = $this->wp->getMetadata( 1, Tiny_Config::META_KEY, true ); - foreach ( $tiny_metadata as $key => $values ) { - if ( ! empty( $values ) ) { - $this->assertBetween( -1, + 1, $values['end'] - time() ); - unset( $tiny_metadata[ $key ]['end'] ); - unset( $tiny_metadata[ $key ]['start'] ); + $tiny_metadata = $this->wp->getMetadata(1, Tiny_Config::META_KEY, true); + foreach ($tiny_metadata as $key => $values) { + if (! empty($values)) { + $this->assertBetween(-1, +1, $values['end'] - time()); + unset($tiny_metadata[$key]['end']); + unset($tiny_metadata[$key]['start']); } } $this->assertEquals(array( - 0 => array( 'input' => array( 'size' => 12345 ), 'output' => array( 'size' => 10000, 'width' => 4000, 'height' => 3000 ) ), + 0 => array('input' => array('size' => 12345), 'output' => array('size' => 10000, 'width' => 4000, 'height' => 3000)), 'thumbnail' => array(), 'medium' => array(), - 'large' => array( 'input' => array( 'size' => 10000 ), 'output' => array( 'size' => 6789, 'width' => 1024, 'height' => 1024 ) ), - 'post-thumbnail' => array( 'input' => array( 'size' => 1234 ), 'output' => array( 'size' => 1000, 'width' => 800, 'height' => 500 ) ), + 'large' => array('input' => array('size' => 10000), 'output' => array('size' => 6789, 'width' => 1024, 'height' => 1024)), + 'post-thumbnail' => array('input' => array('size' => 1234), 'output' => array('size' => 1000, 'width' => 800, 'height' => 500)), ), $tiny_metadata); } - public function test_should_handle_compress_exceptions() { - $this->wp->stub( 'get_post_mime_type', function( $i ) { return "image/jpeg"; } ); + public function test_should_handle_compress_exceptions() + { + $this->wp->stub('get_post_mime_type', function ($i) { + return "image/jpeg"; + }); - $this->compressor->expects( $this->exactly( 3 ) )->method( 'compress_file' )->will( - $this->throwException( new Tiny_Exception( 'Does not appear to be a PNG or JPEG file', 'BadSignature' ) ) + $this->compressor->expects($this->exactly(3))->method('compress_file')->will( + $this->throwException(new Tiny_Exception('Does not appear to be a PNG or JPEG file', 'BadSignature')) ); - $this->subject->blocking_compress_on_upload( $this->wp->getTestMetadata(), 1 ); + $this->subject->blocking_compress_on_upload($this->wp->getTestMetadata(), 1); - $tiny_metadata = $this->wp->getMetadata( 1, Tiny_Config::META_KEY, true ); - foreach ( $tiny_metadata as $key => $values ) { - if ( ! empty( $values ) ) { - $this->assertEquals( time(), $values['timestamp'], 2 ); - unset( $tiny_metadata[ $key ]['timestamp'] ); + $tiny_metadata = $this->wp->getMetadata(1, Tiny_Config::META_KEY, true); + foreach ($tiny_metadata as $key => $values) { + if (! empty($values)) { + $this->assertEquals(time(), $values['timestamp'], 2); + unset($tiny_metadata[$key]['timestamp']); } } $this->assertEquals(array( - 0 => array( 'error' => 'BadSignature', 'message' => 'Does not appear to be a PNG or JPEG file' ), + 0 => array('error' => 'BadSignature', 'message' => 'Does not appear to be a PNG or JPEG file'), 'thumbnail' => array(), 'medium' => array(), - 'large' => array( 'error' => 'BadSignature', 'message' => 'Does not appear to be a PNG or JPEG file' ), - 'post-thumbnail' => array( 'error' => 'BadSignature', 'message' => 'Does not appear to be a PNG or JPEG file' ), + 'large' => array('error' => 'BadSignature', 'message' => 'Does not appear to be a PNG or JPEG file'), + 'post-thumbnail' => array('error' => 'BadSignature', 'message' => 'Does not appear to be a PNG or JPEG file'), ), $tiny_metadata); } - public function test_should_return_if_no_compressor() { - $this->subject->set_compressor( null ); - $this->wp->stub( 'get_post_mime_type', function( $i ) { return "image/png"; } ); - $this->compressor->expects( $this->never() )->method( 'compress_file' ); + public function test_should_return_if_no_compressor() + { + $this->subject->set_compressor(null); + $this->wp->stub('get_post_mime_type', function ($i) { + return "image/png"; + }); + $this->compressor->expects($this->never())->method('compress_file'); - $this->subject->blocking_compress_on_upload( $this->wp->getTestMetadata(), 1 ); + $this->subject->blocking_compress_on_upload($this->wp->getTestMetadata(), 1); } - public function test_should_return_if_no_image() { - $this->wp->stub( 'get_post_mime_type', function( $i ) { return "video/webm"; } ); - $this->compressor->expects( $this->never() )->method( 'compress_file' ); + public function test_should_return_if_no_image() + { + $this->wp->stub('get_post_mime_type', function ($i) { + return "video/webm"; + }); + $this->compressor->expects($this->never())->method('compress_file'); - $this->subject->blocking_compress_on_upload( $this->wp->getTestMetadata(), 1 ); + $this->subject->blocking_compress_on_upload($this->wp->getTestMetadata(), 1); } - public function test_wrong_metadata_should_not_show_warnings() { - $this->wp->stub( 'get_post_mime_type', function( $i ) { return "image/png"; } ); - $this->compressor->expects( $this->exactly( 1 ) )->method( 'compress_file' )->will( - $this->returnCallback( array( $this, 'success_compress' ) ) + public function test_wrong_metadata_should_not_show_warnings() + { + $this->wp->stub('get_post_mime_type', function ($i) { + return "image/png"; + }); + $this->compressor->expects($this->exactly(1))->method('compress_file')->will( + $this->returnCallback(array($this, 'success_compress')) ); $testmeta = $this->wp->getTestMetadata(); $testmeta['sizes'] = 0; - $this->subject->blocking_compress_on_upload( $testmeta, 1 ); + $this->subject->blocking_compress_on_upload($testmeta, 1); } - public function test_wrong_metadata_should_save_tiny_metadata() { - $this->wp->stub( 'get_post_mime_type', function( $i ) { return "image/png"; } ); - $this->compressor->expects( $this->exactly( 1 ) )->method( 'compress_file' )->will( - $this->returnCallback( array( $this, 'success_compress' ) ) + public function test_wrong_metadata_should_save_tiny_metadata() + { + $this->wp->stub('get_post_mime_type', function ($i) { + return "image/png"; + }); + $this->compressor->expects($this->exactly(1))->method('compress_file')->will( + $this->returnCallback(array($this, 'success_compress')) ); $testmeta = $this->wp->getTestMetadata(); $testmeta['sizes'] = 0; - $this->subject->blocking_compress_on_upload( $testmeta, 1 ); - $this->assertEquals( 2, count( $this->wp->getCalls( 'update_post_meta' ) ) ); + $this->subject->blocking_compress_on_upload($testmeta, 1); + $this->assertEquals(2, count($this->wp->getCalls('update_post_meta'))); } - public function test_get_bulk_cost() { + public function test_get_bulk_cost() + { $virtual_compressed_image = array( 'path' => '2015/09', 'images' => array( @@ -239,7 +274,7 @@ public function test_get_bulk_cost() { ) ); $this->wp->createImagesFromJSON($virtual_compressed_image); - + $wpdb_results = array( array( 'ID' => 1, @@ -261,7 +296,7 @@ public function test_get_bulk_cost() { $free_limit, ); - $this->assertEquals($cost, 0.01, 0.0001, 'one compression is $0,009, rounded to 0.01', ); + $this->assertEquals($cost, 0.01, 0.0001, 'one compression is $0,009, rounded to 0.01',); } public function test_when_image_is_uncompressed_and_conversion_enabled_cost_two_credits() { @@ -333,7 +368,8 @@ public function test_when_image_is_uncompressed_and_conversion_enabled_cost_two_ * * @return void */ - public function test_when_files_is_compressed_will_only_cost_1_credit() { + public function test_when_files_is_compressed_will_only_cost_1_credit() + { $this->wp->addOption('tinypng_convert_format', array( 'convert' => 'on' diff --git a/test/unit/TinyTestCase.php b/test/unit/TinyTestCase.php index 8e1c26a..dab0ea4 100644 --- a/test/unit/TinyTestCase.php +++ b/test/unit/TinyTestCase.php @@ -3,6 +3,7 @@ require_once dirname( __FILE__ ) . '/../helpers/mock-http-stream-wrapper.php'; require_once dirname( __FILE__ ) . '/../helpers/mock-tinify-client.php'; require_once dirname( __FILE__ ) . '/../helpers/wordpress.php'; +require_once dirname( __FILE__ ) . '/../helpers/wordpress-cli.php'; require_once dirname( __FILE__ ) . '/../../src/config/class-tiny-config.php'; require_once 'vendor/autoload.php'; diff --git a/test/unit/TinyWpBaseTest.php b/test/unit/TinyWpBaseTest.php index 20423c1..c560886 100644 --- a/test/unit/TinyWpBaseTest.php +++ b/test/unit/TinyWpBaseTest.php @@ -1,26 +1,43 @@ subject = new Tiny_Test_Base(); } - public function test_should_add_init_hooks() { - $this->assertEquals(array( - array( 'init', array( $this->subject, 'init' ) ), - array( 'rest_api_init', array( $this->subject, 'rest_init' ) ), - array( 'admin_init', array( $this->subject, 'admin_init' ) ), - array( 'admin_menu', array( $this->subject, 'admin_menu' ) ), + public function test_should_add_init_hooks() + { + $this->assertEquals( + array( + array('init', array($this->subject, 'init')), + array('rest_api_init', array($this->subject, 'rest_init')), + array('admin_init', array($this->subject, 'admin_init')), + array('admin_menu', array($this->subject, 'admin_menu')), + ), + $this->wp->getCalls('add_action') + ); + } + public function will_hook_into_cli_init_when_cli_is_available() + { + if (!defined('WP_CLI')) { + define('WP_CLI', WP_CLI); + } + $this->assertEquals( + array( + array('cli_init', array($this->subject, 'cli_init')), ), - $this->wp->getCalls( 'add_action' ) + $this->wp->getCalls('add_action') ); + + define('WP_CLI', false); } } diff --git a/tiny-compress-images.php b/tiny-compress-images.php index 4ed84a2..ddd4b47 100644 --- a/tiny-compress-images.php +++ b/tiny-compress-images.php @@ -21,6 +21,7 @@ require dirname( __FILE__ ) . '/src/class-tiny-settings.php'; require dirname( __FILE__ ) . '/src/class-tiny-plugin.php'; require dirname( __FILE__ ) . '/src/class-tiny-notices.php'; +require dirname( __FILE__ ) . '/src/class-tiny-cli.php'; require dirname( __FILE__ ) . '/src/class-tiny-picture.php'; require dirname( __FILE__ ) . '/src/compatibility/wpml/class-tiny-wpml.php'; require dirname( __FILE__ ) . '/src/compatibility/as3cf/class-tiny-as3cf.php';