From 122ceac35e8a45ae957be2b4296e10c0360bfe85 Mon Sep 17 00:00:00 2001 From: Lukas Gaechter Date: Sun, 12 Jan 2020 21:44:16 +0100 Subject: [PATCH 01/87] Update Timber Object Getter function names in Twig --- lib/Twig.php | 64 +++++++++----- tests/test-timber-twig-objects.php | 131 +++++++++++++++++++++++++++-- 2 files changed, 167 insertions(+), 28 deletions(-) diff --git a/lib/Twig.php b/lib/Twig.php index b671c8686..1ceae9033 100644 --- a/lib/Twig.php +++ b/lib/Twig.php @@ -54,50 +54,72 @@ public function add_timber_functions( $twig ) { * Timber object functions. */ - $twig->addFunction(new TwigFunction('Post', function( $post_id, $PostClass = 'Timber\Post' ) { - return self::maybe_convert_array( $post_id, $PostClass ); - } ) ); + $twig->addFunction( new TwigFunction( 'get_post', [ Timber::class, 'get_post' ] ) ); + $twig->addFunction( new TwigFunction( 'get_posts', [ Timber::class, 'get_posts' ] ) ); + $twig->addFunction( new TwigFunction( 'get_term', [ Timber::class, 'get_term' ] ) ); + $twig->addFunction( new TwigFunction( 'get_terms', [ Timber::class, 'get_terms' ] ) ); - $twig->addFunction( new TwigFunction( 'PostQuery', function( $args ) { - return new PostQuery( $args ); - } ) ); + // @TODO: Enable this when factories are merged into 2.0. + // $twig->addFunction( new TwigFunction( 'get_user', [ Timber::class, 'get_user' ] ) ); - $twig->addFunction(new TwigFunction('Image', function( $post_id, $ImageClass = 'Timber\Image' ) { - return self::maybe_convert_array( $post_id, $ImageClass ); - } ) ); - $twig->addFunction(new TwigFunction('Term', array($this, 'handle_term_object'))); - $twig->addFunction(new TwigFunction('User', [Timber::class, 'get_user'] ) ); - $twig->addFunction( new TwigFunction( 'Attachment', function( $post_id, $AttachmentClass = 'Timber\Attachment' ) { - return self::maybe_convert_array( $post_id, $AttachmentClass ); - } ) ); + // @TODO: Enable this when factories are merged into 2.0. + // $twig->addFunction( new TwigFunction( 'get_users', [ Timber::class, 'get_users' ] ); /** * Deprecated Timber object functions. */ + + $twig->addFunction(new TwigFunction('Post', function( $post_id, $PostClass = 'Timber\Post' ) { + Helper::deprecated( '{{ Post() }}', '{{ get_post() }} or {{ get_posts() }}', '2.0.0' ); + return self::maybe_convert_array( $post_id, $PostClass ); + } ) ); $twig->addFunction( new TwigFunction( 'TimberPost', function( $post_id, $PostClass = 'Timber\Post' ) { - Helper::deprecated( '{{ TimberPost() }}', '{{ Post() }}', '2.0.0' ); + Helper::deprecated( '{{ TimberPost() }}', '{{ get_post() }} or {{ get_posts() }}', '2.0.0' ); return self::maybe_convert_array( $post_id, $PostClass ); } ) ); + $twig->addFunction(new TwigFunction('Image', function( $post_id, $ImageClass = 'Timber\Image' ) { + Helper::deprecated( '{{ Image() }}', '{{ get_post() }} or {{ get_posts() }}', '2.0.0' ); + return self::maybe_convert_array( $post_id, $ImageClass ); + } ) ); $twig->addFunction( new TwigFunction( 'TimberImage', function( $post_id = false, $ImageClass = 'Timber\Image' ) { - Helper::deprecated( '{{ TimberImage() }}', '{{ Image() }}', '2.0.0' ); + Helper::deprecated( '{{ TimberImage() }}', '{{ get_post() }} or {{ get_posts() }}', '2.0.0' ); return self::maybe_convert_array( $post_id, $ImageClass ); } ) ); + $twig->addFunction( new TwigFunction( + 'Term', + function( $term_id, $taxonomy = '', $TermClass = 'Timber\Term' ) { + Helper::deprecated( '{{ Term() }}', '{{ get_term() }} or {{ get_terms() }}', '2.0.0' ); + return self::handle_term_object( $term_id, $taxonomy, $TermClass ); + } + ) ); $twig->addFunction( new TwigFunction( 'TimberTerm', function( $term_id, $taxonomy = '', $TermClass = 'Timber\Term' ) { - Helper::deprecated( '{{ TimberTerm() }}', '{{ Term() }}', '2.0.0' ); + Helper::deprecated( '{{ TimberTerm() }}', '{{ get_term() }} or {{ get_terms() }}', '2.0.0' ); return self::handle_term_object($term_id, $taxonomy, $TermClass); } ) ); + $twig->addFunction(new TwigFunction('User', function( $post_id, $UserClass = 'Timber\User' ) { + Helper::deprecated( '{{ User() }}', '{{ get_user() }} or {{ get_users() }}', '2.0.0' ); + return self::maybe_convert_array( $post_id, $UserClass ); + } ) ); + $twig->addFunction( new TwigFunction( + 'TimberUser', + function( $user_id, $UserClass = 'Timber\User' ) { + Helper::deprecated( '{{ TimberUser() }}', '{{ User() }}', '2.0.0' ); + return self::maybe_convert_array($user_id, $UserClass); + } + ) ); + /* bloginfo and translate */ $twig->addFunction(new TwigFunction('bloginfo', 'bloginfo')); $twig->addFunction(new TwigFunction('__', '__')); @@ -224,7 +246,7 @@ public function add_timber_filters( $twig ) { /** * @deprecated since 1.13 (to be removed in 2.0). Use Twig's native filter filter instead - * @todo remove this in 2.x so that filter merely passes to Twig's filter without any + * @todo remove this in 2.x so that filter merely passes to Twig's filter without any * modification * @ticket #1594 #2120 */ @@ -237,8 +259,8 @@ public function add_timber_filters( $twig ) { /** * Date and Time filters. - * - * @todo copy this formatting to other functions + * + * @todo copy this formatting to other functions */ $twig->addFilter(new TwigFilter( 'date', @@ -336,7 +358,7 @@ public function add_timber_escapers( $twig ) { /** * Overwrite Twig defaults. * - * Makes Twig compatible with how WordPress handles dates, timezones and perhaps other items in + * Makes Twig compatible with how WordPress handles dates, timezones and perhaps other items in * the future * * @since 2.0.0 diff --git a/tests/test-timber-twig-objects.php b/tests/test-timber-twig-objects.php index 4d268b246..2cd6962b7 100644 --- a/tests/test-timber-twig-objects.php +++ b/tests/test-timber-twig-objects.php @@ -20,6 +20,9 @@ function testTimberImageInTwig() { $this->assertEquals('http://example.org/wp-content/uploads/'.date('Y').'/'.date('m').'/arch.jpg', $compiled); } + /** + * @expectedDeprecated {{ Image() }} + */ function testImageInTwig() { $iid = TestTimberImage::get_attachment(); $str = '{{Image('.$iid.').src}}'; @@ -27,6 +30,16 @@ function testImageInTwig() { $this->assertEquals('http://example.org/wp-content/uploads/'.date('Y').'/'.date('m').'/arch.jpg', $compiled); } + function testImageWithGetPostInTwig() { + $iid = TestTimberImage::get_attachment(); + $str = '{{ get_post('.$iid.').src }}'; + $compiled = Timber::compile_string($str); + $this->assertEquals('http://example.org/wp-content/uploads/'.date('Y').'/'.date('m').'/arch.jpg', $compiled); + } + + /** + * @expectedDeprecated {{ Image() }} + */ function testImagesInTwig() { $images = array(); $images[] = TestTimberImage::get_attachment( 0, 'arch.jpg' ); @@ -36,6 +49,15 @@ function testImagesInTwig() { $this->assertEquals('http://example.org/wp-content/uploads/'.date('Y').'/'.date('m').'/arch.jpghttp://example.org/wp-content/uploads/'.date('Y').'/'.date('m').'/city-museum.jpg', $compiled); } + function testImagesWithGetPostsInTwig() { + $images = array(); + $images[] = TestTimberImage::get_attachment( 0, 'arch.jpg' ); + $images[] = TestTimberImage::get_attachment( 0, 'city-museum.jpg' ); + $str = '{% for image in get_posts(images) %}{{image.src}}{% endfor %}'; + $compiled = Timber::compile_string($str, array('images' => $images)); + $this->assertEquals('http://example.org/wp-content/uploads/'.date('Y').'/'.date('m').'/arch.jpghttp://example.org/wp-content/uploads/'.date('Y').'/'.date('m').'/city-museum.jpg', $compiled); + } + /** * @expectedDeprecated {{ TimberImage() }} */ @@ -48,6 +70,9 @@ function testTimberImagesInTwig() { $this->assertEquals('http://example.org/wp-content/uploads/'.date('Y').'/'.date('m').'/arch.jpghttp://example.org/wp-content/uploads/'.date('Y').'/'.date('m').'/city-museum.jpg', $compiled); } + /** + * @expectedDeprecated {{ Image() }} + */ function testTimberImageInTwigToString() { $iid = TestTimberImage::get_attachment(); $str = '{{Image('.$iid.')}}'; @@ -55,6 +80,16 @@ function testTimberImageInTwigToString() { $this->assertEquals('http://example.org/wp-content/uploads/'.date('Y').'/'.date('m').'/arch.jpg', $compiled); } + function testTimberImageWithGetPostInTwigToString() { + $iid = TestTimberImage::get_attachment(); + $str = '{{ get_post(' . $iid . ') }}'; + $compiled = Timber::compile_string( $str ); + $this->assertEquals( + 'http://example.org/wp-content/uploads/' . date( 'Y' ) . '/' . date( 'm' ) . '/arch.jpg', + $compiled + ); + } + /** * @expectedDeprecated {{ TimberPost() }} */ @@ -64,12 +99,21 @@ function testTimberPostInTwig(){ $this->assertEquals('Foo', Timber::compile_string($str)); } + /** + * @expectedDeprecated {{ Post() }} + */ function testPostInTwig(){ $pid = $this->factory->post->create(array('post_title' => 'Foo')); $str = '{{Post('.$pid.').title}}'; $this->assertEquals('Foo', Timber::compile_string($str)); } + function testGetPostInTwig() { + $pid = $this->factory->post->create( [ 'post_title' => 'Foo' ] ); + $str = '{{ get_post(' . $pid . ').title }}'; + $this->assertEquals( 'Foo', Timber::compile_string( $str ) ); + } + /** * @expectedDeprecated {{ TimberPost() }} */ @@ -80,6 +124,9 @@ function testTimberPostsInTwig(){ $this->assertEquals('FooBar', Timber::compile_string($str, array('pids' => $pids))); } + /** + * @expectedDeprecated {{ Post() }} + */ function testPostsInTwig(){ $pids[] = $this->factory->post->create(array('post_title' => 'Foo')); $pids[] = $this->factory->post->create(array('post_title' => 'Bar')); @@ -87,22 +134,45 @@ function testPostsInTwig(){ $this->assertEquals('FooBar', Timber::compile_string($str, array('pids' => $pids))); } - function testPostQueryWithStringInTwig(){ + function testGetPostsInTwig() { + $pids[] = $this->factory->post->create( [ 'post_title' => 'Foo' ] ); + $pids[] = $this->factory->post->create( [ 'post_title' => 'Bar' ] ); + $str = '{% for post in get_posts(pids) %}{{post.title}}{% endfor %}'; + $this->assertEquals( 'FooBar', Timber::compile_string( $str, [ 'pids' => $pids ] ) ); + } + + /** + * @expectedIncorrectUsage Timber::get_posts() + */ + function testGetPostsWithQueryStringInTwig(){ $pids[] = $this->factory->post->create( array( 'post_title' => 'Foo' ) ); $pids[] = $this->factory->post->create( array( 'post_title' => 'Bar' ) ); - $str = "{% for post in PostQuery({ query: 'post_type=post&posts_per_page=-1&order=ASC'}) %}{{ post.title }}{% endfor %}"; + $str = "{% for post in get_posts('post_type=post&posts_per_page=-1&order=ASC') %}{{ post.title }}{% endfor %}"; $this->assertEquals( 'FooBar', Timber::compile_string( $str, array( 'pids' => $pids ) ) ); } - function testPostQueryWithArgsInTwig(){ - $pids[] = $this->factory->post->create( array( 'post_title' => 'Foo' ) ); - $pids[] = $this->factory->post->create( array( 'post_title' => 'Bar' ) ); - $str = "{% for post in PostQuery({ query: { post_type: 'post', posts_per_page: -1, order: 'ASC'} }) %}{{ post.title }}{% endfor %}"; + function testGetPostsWithArgsInTwig() { + $pids[] = $this->factory->post->create( [ 'post_title' => 'Foo' ] ); + $pids[] = $this->factory->post->create( [ 'post_title' => 'Bar' ] ); + $str = "{% for post in get_posts({ post_type: 'post', posts_per_page: -1, order: 'ASC'}) %}{{ post.title }}{% endfor %}"; - $this->assertEquals( 'FooBar', Timber::compile_string( $str, array( 'pids' => $pids ) ) ); + $this->assertEquals( 'FooBar', Timber::compile_string( $str, [ 'pids' => $pids ] ) ); + } + + /** + * @expectedDeprecated {{ TimberUser() }} + */ + function testTimberUserInTwig(){ + $uid = $this->factory->user->create(array('display_name' => 'Pete Karl')); + $template = '{{ TimberUser('.$uid.').name }}'; + $str = Timber::compile_string($template); + $this->assertEquals('Pete Karl', $str); } + /** + * @expectedDeprecated {{ User() }} + */ function testUsersInTwig(){ $uids[] = $this->factory->user->create(array('display_name' => 'Mark Watabe')); $uids[] = $this->factory->user->create(array('display_name' => 'Austin Tzou')); @@ -110,12 +180,41 @@ function testUsersInTwig(){ $this->assertEquals('Mark Watabe Austin Tzou', trim(Timber::compile_string($str, array('uids' => $uids)))); } + function testGetUsersInTwig() { + $uids[] = $this->factory->user->create( [ 'display_name' => 'Mark Watabe' ] ); + $uids[] = $this->factory->user->create( [ 'display_name' => 'Austin Tzou' ] ); + $str = '{% for user in get_users(uids) %}{{ user.name }} {% endfor %}'; + $this->assertEquals( + 'Mark Watabe Austin Tzou', + trim( Timber::compile_string( $str, [ 'uids' => $uids ] ) ) + ); + } + + /** + * @expectedDeprecated {{ User() }} + */ function testUserInTwig(){ $uid = $this->factory->user->create(array('display_name' => 'Nathan Hass')); $str = '{{User('.$uid.').name}}'; $this->assertEquals('Nathan Hass', Timber::compile_string($str)); } + function testGetUserInTwig() { + $uid = $this->factory->user->create( [ 'display_name' => 'Nathan Hass' ] ); + $str = '{{ get_user(' . $uid . ').name }}'; + $this->assertEquals( 'Nathan Hass', Timber::compile_string( $str ) ); + } + + /** + * @expectedDeprecated {{ TimberUser() }} + */ + function testTimberUsersInTwig() { + $uids[] = $this->factory->user->create(array('display_name' => 'Estelle Getty')); + $uids[] = $this->factory->user->create(array('display_name' => 'Bea Arthur')); + $str = '{% for user in TimberUser(uids) %}{{user.name}} {% endfor %}'; + $this->assertEquals('Estelle Getty Bea Arthur', trim(Timber::compile_string($str, array('uids' => $uids)))); + } + /** * @expectedDeprecated {{ TimberTerm() }} */ @@ -125,12 +224,21 @@ function testTimberTermInTwig(){ $this->assertEquals('Golden Girls', Timber::compile_string($str, array('tid' => $tid))); } + /** + * @expectedDeprecated {{ Term() }} + */ function testTermInTwig(){ $tid = $this->factory->term->create(array('name' => 'Mythbusters')); $str = '{{Term(tid).title}}'; $this->assertEquals('Mythbusters', Timber::compile_string($str, array('tid' => $tid))); } + function testGetTermInTwig() { + $tid = $this->factory->term->create( [ 'name' => 'Mythbusters' ] ); + $str = '{{ get_term(tid).title }}'; + $this->assertEquals( 'Mythbusters', Timber::compile_string( $str, [ 'tid' => $tid ] ) ); + } + /** * @expectedDeprecated {{ TimberTerm() }} */ @@ -141,6 +249,9 @@ function testTimberTermsInTwig(){ $this->assertEquals('Foods Cars ', Timber::compile_string($str, array('tids' => $tids))); } + /** + * @expectedDeprecated {{ Term() }} + */ function testTermsInTwig(){ $tids[] = $this->factory->term->create(array('name' => 'Animals')); $tids[] = $this->factory->term->create(array('name' => 'Germans')); @@ -148,4 +259,10 @@ function testTermsInTwig(){ $this->assertEquals('Animals Germans ', Timber::compile_string($str, array('tids' => $tids))); } + function testGetTermsInTwig() { + $tids[] = $this->factory->term->create( [ 'name' => 'Animals' ] ); + $tids[] = $this->factory->term->create( [ 'name' => 'Germans' ] ); + $str = '{% for term in get_terms(tids) %}{{term.title}} {% endfor %}'; + $this->assertEquals( 'Animals Germans ', Timber::compile_string( $str, [ 'tids' => $tids ] ) ); + } } From 5f9189beb1bcd6bbb4824706869a541b8f028b43 Mon Sep 17 00:00:00 2001 From: Lukas Gaechter Date: Sun, 12 Jan 2020 22:02:08 +0100 Subject: [PATCH 02/87] Add Twig functions for getting comments --- lib/Twig.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Twig.php b/lib/Twig.php index 1ceae9033..93ad78417 100644 --- a/lib/Twig.php +++ b/lib/Twig.php @@ -59,11 +59,11 @@ public function add_timber_functions( $twig ) { $twig->addFunction( new TwigFunction( 'get_term', [ Timber::class, 'get_term' ] ) ); $twig->addFunction( new TwigFunction( 'get_terms', [ Timber::class, 'get_terms' ] ) ); - // @TODO: Enable this when factories are merged into 2.0. + // @TODO: Enable these when factories are merged into 2.0. // $twig->addFunction( new TwigFunction( 'get_user', [ Timber::class, 'get_user' ] ) ); - - // @TODO: Enable this when factories are merged into 2.0. // $twig->addFunction( new TwigFunction( 'get_users', [ Timber::class, 'get_users' ] ); + // $twig->addFunction( new TwigFunction( 'get_comment', [ Timber::class, 'get_comment' ] ); + // $twig->addFunction( new TwigFunction( 'get_comments', [ Timber::class, 'get_comments' ] ); /** * Deprecated Timber object functions. From d28fd539dd7dd4094a3eb40c8853676434aed72b Mon Sep 17 00:00:00 2001 From: Lukas Gaechter Date: Sun, 12 Jan 2020 22:02:19 +0100 Subject: [PATCH 03/87] Update Upgrade Guide --- docs/upgrade-guides/2.0.md | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/docs/upgrade-guides/2.0.md b/docs/upgrade-guides/2.0.md index b27e7a886..f95e17415 100644 --- a/docs/upgrade-guides/2.0.md +++ b/docs/upgrade-guides/2.0.md @@ -50,14 +50,6 @@ Namespaced class names were already introduced in Timber version 1.0. Up until n A special case is the class alias `Timber` for the `Timber\Timber` class. We decided to keep it, because it’s more convenient to write `Timber::render()` instead of `Timber\Timber::render()`. -### Twig - -The same goes for Timber classes in Twig. We realized there’s no need to have a «Timber» prefix. We can directly use `Post`, `Image`, `Term` and `User`. The following functions are now deprecated: - -- `{{ TimberPost() }}` – use `{{ Post() }}` instead -- `{{ TimberImage() }}` – use `{{ Image() }}` instead -- `{{ TimberTerm() }}` – use `{{ Term() }}` instead -- `{{ TimberUser() }}` – use `{{ User() }}` instead ### Twig classes @@ -133,6 +125,30 @@ In short: ## Twig +### Update function names + +In Twig, you could use functions that were called the same as classes to convert objects or IDs of objects into Timber object. To have the same names as in Timber’s public API, we’ve added the following functions. + +- `{{ get_post() }}` +- `{{ get_posts() }}` +- `{{ get_term() }}` +- `{{ get_terms() }}` +- `{{ get_user() }}` +- `{{ get_users() }}` +- `{{ get_comment() }}` +- `{{ get_comments() }}` + +The following functions are now deprecated: + +- `{{ TimberPost() }}` – use `{{ get_post() }}` or `{{ get_posts() }}` instead +- `{{ Post() }}` – use `{{ get_post() }}` or `{{ get_posts() }}` instead +- `{{ TimberTerm() }}` – use `{{ get_term() }}` or `{{ get_terms() }}` instead +- `{{ Term() }}` – use `{{ get_term() }}` or `{{ get_terms() }}` instead +- `{{ TimberImage() }}` – use `{{ get_post() }}` or `{{ get_posts() }}` instead +- `{{ Image() }}` – use `{{ get_post() }}` or `{{ get_posts() }}` instead +- `{{ TimberUser() }}` – use `{{ get_user() }}` or `{{ get_users() }}` instead +- `{{ User() }}` – use `{{ get_user() }}` or `{{ get_users() }}` instead + ### Namespaced Twig locations You can now use namespaced Twig locations. Read more about this in the [Template Locations Guide](https://timber.github.io/docs/guides/template-locations/#register-your-own-namespaces). @@ -250,7 +266,7 @@ Up until now, there was only a representation for WordPress image attachments in - The `Timber\Image` class now extends the `Timber\Attachment` class. All your code should already be compatible with this change. But in the future, you might want to use the new `Timber\Attachment` class if you work with an attachment that is not an image. - We’ve added new methods for `Timber\Attachment`. See the section below (@todo: Add anchor link) -- We’ve added a new Twig function `Attachment()`. (@todo: Add link to documentation) +- To get attachments from attachment IDs in Twig, you can use `{{ get_post(attachment_id) }}`. (@todo: Add link to documentation) ## Deprecated functions and variables From 7d02bb44297ef155a1842d3370e726627c857fd0 Mon Sep 17 00:00:00 2001 From: Lukas Gaechter Date: Wed, 26 Feb 2020 21:03:23 +0100 Subject: [PATCH 04/87] Use get_image() instead of Image() in Twig --- docs/guides/acf-cookbook.md | 10 +++++----- docs/guides/cookbook-images.md | 2 +- docs/guides/posts.md | 4 ++-- docs/integrations/advanced-custom-fields.md | 14 +++++++------- docs/upgrade-guides/2.0.md | 2 +- lib/Attachment.php | 2 +- lib/Image.php | 2 +- lib/Twig.php | 11 +++++++++-- tests/test-timber-attachment.php | 10 +++++----- tests/test-timber-image.php | 12 ++++++------ 10 files changed, 38 insertions(+), 31 deletions(-) diff --git a/docs/guides/acf-cookbook.md b/docs/guides/acf-cookbook.md index f9d7eca61..954abcba6 100644 --- a/docs/guides/acf-cookbook.md +++ b/docs/guides/acf-cookbook.md @@ -27,7 +27,7 @@ You can retrieve an image from a custom field, then use it in a Twig template. T ### The quick way (for most situations) ```twig - + ``` ### The long way (for some special situations) @@ -60,7 +60,7 @@ You can now use all the above functions to transform your custom images in the s ```twig {% for image in post.meta('gallery') %} - + {% endfor %} ``` @@ -92,7 +92,7 @@ You can access repeater fields within twig files:

{{ item.name }}

{{ item.info }}
- +
{% endfor %} @@ -148,8 +148,8 @@ Similar to repeaters, get the field by the name of the flexible content field: ```twig {% for media_item in post.meta('media_set') %} {% if media_item.acf_fc_layout == 'image_set' %} - -

{{ Image(media_item.image).caption }}

+ +

{{ get_image(media_item.image).caption }}

{% elseif media_item.acf_fc_layout == 'video_set' %} diff --git a/docs/guides/cookbook-images.md b/docs/guides/cookbook-images.md index 32ffec391..0c4e618a4 100644 --- a/docs/guides/cookbook-images.md +++ b/docs/guides/cookbook-images.md @@ -105,7 +105,7 @@ When setting up your custom fields you’ll want to save the `image_id` to the f ### The quick way (for most situations) ```twig - + ``` ### The long way (for some special situations) diff --git a/docs/guides/posts.md b/docs/guides/posts.md index 5041adf8d..3a089d9c6 100644 --- a/docs/guides/posts.md +++ b/docs/guides/posts.md @@ -44,7 +44,7 @@ You can convert post IDs to post objects in Twig using the `Post()` function. This is especially helpful if you only have the image ID and want to convert it to an image: ```twig - + ``` It also works if you have an array of post IDs that you want to convert to `Timber\Post` objects. @@ -180,4 +180,4 @@ In the back, the query will not count the number of found rows. This can result ## Using posts or post collections in the context -Timber will automatically set the `post` or `posts` variable for you in the context depending on the template file you’re using. Read more about this in the [Context Guide](https://timber.github.io/docs/guides/context/#template-contexts). \ No newline at end of file +Timber will automatically set the `post` or `posts` variable for you in the context depending on the template file you’re using. Read more about this in the [Context Guide](https://timber.github.io/docs/guides/context/#template-contexts). diff --git a/docs/integrations/advanced-custom-fields.md b/docs/integrations/advanced-custom-fields.md index 3ffc233f0..b1b08c60a 100644 --- a/docs/integrations/advanced-custom-fields.md +++ b/docs/integrations/advanced-custom-fields.md @@ -70,7 +70,7 @@ You can retrieve an image from a custom field, then use it in a Twig template. T ### The quick way (for most situations) ```twig - + ``` ### The long way (for some special situations) @@ -107,7 +107,7 @@ You can now use all the above functions to transform your custom images in the s ```twig {% for image in post.meta('gallery') %} - + {% endfor %} ``` @@ -142,7 +142,7 @@ You can access repeater fields within Twig files:

{{ item.name }}

{{ item.info }}
- +
{% endfor %} @@ -198,8 +198,8 @@ Similar to repeaters, get the field by the name of the flexible content field: ```twig {% for media_item in post.meta('media_set') %} {% if media_item.acf_fc_layout == 'image_set' %} - -

{{ Image(media_item.image).caption }}

+ +

{{ get_image(media_item.image).caption }}

{% elseif media_item.acf_fc_layout == 'video_set' %} @@ -216,8 +216,8 @@ Similar to nested repeaters, you should only call the `meta` method once when yo {% for media_item in post.meta('media_set') %} {% if media_item.acf_fc_layout == 'image_set' %} {% for image_item in media_item.image_set %} - -

{{ Image(image_item.image).caption }}

+ +

{{ get_image(image_item.image).caption }}

{% endfor %} {% endif %} diff --git a/docs/upgrade-guides/2.0.md b/docs/upgrade-guides/2.0.md index ace9bdac6..e2a9f35e2 100644 --- a/docs/upgrade-guides/2.0.md +++ b/docs/upgrade-guides/2.0.md @@ -149,7 +149,7 @@ The following functions are now deprecated: - `{{ TimberTerm() }}` – use `{{ get_term() }}` or `{{ get_terms() }}` instead - `{{ Term() }}` – use `{{ get_term() }}` or `{{ get_terms() }}` instead - `{{ TimberImage() }}` – use `{{ get_post() }}` or `{{ get_posts() }}` instead -- `{{ Image() }}` – use `{{ get_post() }}` or `{{ get_posts() }}` instead +- `{{ Image() }}` – use `{{ get_image() }}`, `{{ get_images() }}`, `{{ get_attachment() }}` or `{{ get_attachments() }}` instead - `{{ TimberUser() }}` – use `{{ get_user() }}` or `{{ get_users() }}` instead - `{{ User() }}` – use `{{ get_user() }}` or `{{ get_users() }}` instead diff --git a/lib/Attachment.php b/lib/Attachment.php index 466ea75dd..2a1975c84 100644 --- a/lib/Attachment.php +++ b/lib/Attachment.php @@ -408,7 +408,7 @@ public function path() { * @api * @example * ```twig - * + * * ``` * ```html * diff --git a/lib/Image.php b/lib/Image.php index 879f5df77..af56e5652 100644 --- a/lib/Image.php +++ b/lib/Image.php @@ -28,7 +28,7 @@ * * * Another way to initialize images as Timber\Image objects, but within Twig * * ``` diff --git a/lib/Twig.php b/lib/Twig.php index 310325918..c89621313 100644 --- a/lib/Twig.php +++ b/lib/Twig.php @@ -54,8 +54,15 @@ public function add_timber_functions( $twig ) { * Timber object functions. */ + // Posts $twig->addFunction( new TwigFunction( 'get_post', [ Timber::class, 'get_post' ] ) ); $twig->addFunction( new TwigFunction( 'get_posts', [ Timber::class, 'get_posts' ] ) ); + $twig->addFunction( new TwigFunction( 'get_attachment', [ Timber::class, 'get_post' ] ) ); + $twig->addFunction( new TwigFunction( 'get_attachments', [ Timber::class, 'get_posts' ] ) ); + $twig->addFunction( new TwigFunction( 'get_image', [ Timber::class, 'get_post' ] ) ); + $twig->addFunction( new TwigFunction( 'get_images', [ Timber::class, 'get_posts' ] ) ); + + // Terms $twig->addFunction( new TwigFunction( 'get_term', [ Timber::class, 'get_term' ] ) ); $twig->addFunction( new TwigFunction( 'get_terms', [ Timber::class, 'get_terms' ] ) ); @@ -82,7 +89,7 @@ function( $post_id, $PostClass = 'Timber\Post' ) { ) ); $twig->addFunction(new TwigFunction('Image', function( $post_id, $ImageClass = 'Timber\Image' ) { - Helper::deprecated( '{{ Image() }}', '{{ get_post() }} or {{ get_posts() }}', '2.0.0' ); + Helper::deprecated( '{{ Image() }}', '{{ get_image() }}, {{ get_images() }}, {{ get_attachment() }} or {{ get_attachments() }}', '2.0.0' ); return self::maybe_convert_array( $post_id, $ImageClass ); } ) ); $twig->addFunction( new TwigFunction( @@ -514,7 +521,7 @@ public function intl_date( $date, $format = null ) { */ public static function time_ago( $from, $to = null, $format_past = '%s ago', $format_future = '%s from now' ) { Helper::deprecated( 'time_ago', 'DateTimeHelper::time_ago', '2.0.0' ); - + return DateTimeHelper::time_ago( $from, $to, $format_past, $format_future ); } diff --git a/tests/test-timber-attachment.php b/tests/test-timber-attachment.php index b22fe02b6..d786baf48 100644 --- a/tests/test-timber-attachment.php +++ b/tests/test-timber-attachment.php @@ -92,7 +92,7 @@ function testTimberAttachmentSrc() { $iid = self::get_attachment(); $attachment = new Timber\Attachment($iid); $post = get_post($iid); - $str = '{{ Attachment(post).src }}'; + $str = '{{ get_attachment(post).src }}'; $result = Timber::compile_string( $str, array('post' => $post) ); $this->assertEquals($attachment->src(), $result); } @@ -101,7 +101,7 @@ function testTimberAttachmentSrc() { function testAttachmentSrc() { $pid = $this->factory->post->create(); $iid = self::get_attachment($pid, 'dummy-pdf.pdf'); - $str = '{{ Attachment(post).src }}'; + $str = '{{ get_attachment(post).src }}'; $result = Timber::compile_string( $str, array('post' => $iid) ); $this->assertEquals('http://example.org/wp-content/uploads/'.date('Y/m').'/dummy-pdf.pdf', $result); } @@ -109,7 +109,7 @@ function testAttachmentSrc() { function testFileSize() { $pid = $this->factory->post->create(); $iid = self::get_attachment( $pid, 'dummy-pdf.pdf' ); - $str = '{{ Attachment(post).size }}'; + $str = '{{ get_attachment(post).size }}'; $result = Timber::compile_string( $str, array( 'post' => $iid ) ); $this->assertEquals('16 KB', $result); } @@ -117,7 +117,7 @@ function testFileSize() { function testFileSizeRaw() { $pid = $this->factory->post->create(); $iid = self::get_attachment( $pid, 'dummy-pdf.pdf' ); - $str = '{{ Attachment(post).size_raw }}'; + $str = '{{ get_attachment(post).size_raw }}'; $result = Timber::compile_string( $str, array( 'post' => $iid ) ); $this->assertEquals('16555', $result); } @@ -125,7 +125,7 @@ function testFileSizeRaw() { function testFileExtension() { $pid = $this->factory->post->create(); $iid = self::get_attachment( $pid, 'dummy-pdf.pdf' ); - $str = '{{ Attachment(post).extension }}'; + $str = '{{ get_attachment(post).extension }}'; $result = Timber::compile_string( $str, array( 'post' => $iid ) ); $this->assertEquals('PDF', $result); } diff --git a/tests/test-timber-image.php b/tests/test-timber-image.php index 63210c169..2c84cd213 100644 --- a/tests/test-timber-image.php +++ b/tests/test-timber-image.php @@ -43,7 +43,7 @@ function testTimberImageSrc() { $iid = self::get_attachment(); $image = new Timber\Image($iid); $post = get_post($iid); - $str = '{{ Image(post).src }}'; + $str = '{{ get_image(post).src }}'; $result = Timber::compile_string( $str, array('post' => $post) ); $this->assertEquals($image->src(), $result); } @@ -718,7 +718,7 @@ function testImageWidthWithFilter() { $photo = $this->copyTestAttachment(); $photo = Timber\URLHelper::get_rel_path($photo); update_post_meta($pid, 'custom_photo', '/'.$photo); - $str = '{{ Image(post.custom_photo).width }}'; + $str = '{{ get_image(post.custom_photo).width }}'; $post = Timber::get_post($pid); $rendered = Timber::compile_string( $str, array('post' => $post) ); $this->assertEquals( 1500, $rendered ); @@ -893,7 +893,7 @@ function testTimberImageFromPost() { $image = $post->thumbnail(); $post = get_post($post->ID); - $str = '{{ Image(post).src }}'; + $str = '{{ get_image(post).src }}'; $result = Timber::compile_string( $str, array('post' => $post) ); $this->assertEquals($image->src(), $result); @@ -902,7 +902,7 @@ function testTimberImageFromPost() { function testTimberImageFromTimberImage() { $post = $this->get_post_with_image(); $image = $post->thumbnail(); - $str = '{{ Image(post).src }}'; + $str = '{{ get_image(post).src }}'; $post = new Timber\Image($image); $result = Timber::compile_string( $str, array('post' => $post) ); $this->assertEquals($image->src(), $result); @@ -911,7 +911,7 @@ function testTimberImageFromTimberImage() { function testTimberImageFromTimberImageID() { $post = $this->get_post_with_image(); $image = $post->thumbnail(); - $str = '{{ Image(post).src }}'; + $str = '{{ get_image(post).src }}'; $post = new Timber\Image($image->ID); $result = Timber::compile_string( $str, array('post' => $post) ); $this->assertEquals($image->src(), $result); @@ -921,7 +921,7 @@ function testTimberImageFromImageID() { $post = $this->get_post_with_image(); $image = $post->thumbnail(); $post = $image->ID; - $str = '{{ Image(post).src }}'; + $str = '{{ get_image(post).src }}'; $result = Timber::compile_string( $str, array('post' => $post) ); $this->assertEquals($image->src(), $result); } From a96abb01a188cdd8a9af2f62180658a7356c1434 Mon Sep 17 00:00:00 2001 From: Lukas Gaechter Date: Wed, 26 Feb 2020 21:50:20 +0100 Subject: [PATCH 05/87] Update missing function names --- docs/guides/posts.md | 4 ++-- docs/guides/terms.md | 6 +++--- tests/test-timber-image.php | 4 ++-- tests/test-timber-term.php | 2 +- tests/test-timber-twig-objects.php | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/guides/posts.md b/docs/guides/posts.md index 3a089d9c6..192f77019 100644 --- a/docs/guides/posts.md +++ b/docs/guides/posts.md @@ -38,7 +38,7 @@ Here’s a Twig template that received the post above in a `$post` variable. You can convert post IDs to post objects in Twig using the `Post()` function. ```twig -{% set post = Post(post_id) %} +{% set post = get_post(post_id) %} ``` This is especially helpful if you only have the image ID and want to convert it to an image: @@ -50,7 +50,7 @@ This is especially helpful if you only have the image ID and want to convert it It also works if you have an array of post IDs that you want to convert to `Timber\Post` objects. ```twig -{% for post in Post(post_ids) %} +{% for post in get_posts(post_ids) %} ``` ## Invalid posts diff --git a/docs/guides/terms.md b/docs/guides/terms.md index 2ec92d5d0..875a94e2c 100644 --- a/docs/guides/terms.md +++ b/docs/guides/terms.md @@ -21,13 +21,13 @@ What you get in return is a [`Timber\Term`](https://timber.github.io/docs/refere You can convert terms IDs to term objects in Twig using the `Term()` function. ```twig -{% set term = Term(term_id) %} +{% set term = get_term(term_id) %} ``` It also works if you have an array of terms IDs that you want to convert to `Timber\Term` objects. ```twig -{% for term in Term(term_ids) %} +{% for term in get_terms(term_ids) %} ``` ## Invalid terms @@ -146,4 +146,4 @@ Or you can use a for-loop: We make use of the `loop` variable in Twig to either display an *and* or a comma. -See how we end the opening tag of the for-loop with `-%}` and start the closing tag with `{%-`? These are [Whitespace Controls](https://twig.symfony.com/doc/2.x/templates.html#whitespace-control) and can come in quite handy. Here, we use them to remove all the superfluous markup whitespace we don’t need. \ No newline at end of file +See how we end the opening tag of the for-loop with `-%}` and start the closing tag with `{%-`? These are [Whitespace Controls](https://twig.symfony.com/doc/2.x/templates.html#whitespace-control) and can come in quite handy. Here, we use them to remove all the superfluous markup whitespace we don’t need. diff --git a/tests/test-timber-image.php b/tests/test-timber-image.php index 2c84cd213..b1dc04603 100644 --- a/tests/test-timber-image.php +++ b/tests/test-timber-image.php @@ -63,7 +63,7 @@ function testWithOutputBuffer() { function testReplacedImage() { $pid = $this->factory->post->create(array('post_type' => 'post')); $attach_id = self::get_attachment($pid, 'arch.jpg'); - $template = '{{Image(img).src|resize(200, 200)}}'; + $template = '{{ get_image(img).src|resize(200, 200) }}'; $str = Timber::compile_string($template, array('img' => $attach_id)); $resized_one = Timber\ImageHelper::get_server_location($str); sleep(1); @@ -85,7 +85,7 @@ function testReplacedImage() { function testResizedReplacedImage() { $pid = $this->factory->post->create(array('post_type' => 'post')); $attach_id = self::get_attachment($pid, 'arch.jpg'); - $template = '{{Image(img).src|resize(200, 200)}}'; + $template = '{{ get_image(img).src|resize(200, 200) }}'; $str = Timber::compile_string($template, array('img' => $attach_id)); $new_id = self::get_attachment($pid, 'pizza.jpg'); self::replace_attachment($attach_id, $new_id); diff --git a/tests/test-timber-term.php b/tests/test-timber-term.php index a7dcaacdc..6cdbcc1fb 100644 --- a/tests/test-timber-term.php +++ b/tests/test-timber-term.php @@ -25,7 +25,7 @@ function testGetTerm() { // @todo #2087 get this to work w/o $taxonomy param $term = Timber::get_term($term_id, ''); $this->assertEquals('Zong', $term->title()); - $template = '{% set zp_term = Term("'.$term->ID.'", "arts") %}{{ zp_term.name }}'; + $template = '{% set zp_term = get_term("'.$term->ID.'", "arts") %}{{ zp_term.name }}'; $string = Timber::compile_string($template); $this->assertEquals('Zong', $string); } diff --git a/tests/test-timber-twig-objects.php b/tests/test-timber-twig-objects.php index 2cd6962b7..fb466eb61 100644 --- a/tests/test-timber-twig-objects.php +++ b/tests/test-timber-twig-objects.php @@ -25,7 +25,7 @@ function testTimberImageInTwig() { */ function testImageInTwig() { $iid = TestTimberImage::get_attachment(); - $str = '{{Image('.$iid.').src}}'; + $str = '{{ get_image('.$iid.').src }}'; $compiled = Timber::compile_string($str); $this->assertEquals('http://example.org/wp-content/uploads/'.date('Y').'/'.date('m').'/arch.jpg', $compiled); } @@ -75,7 +75,7 @@ function testTimberImagesInTwig() { */ function testTimberImageInTwigToString() { $iid = TestTimberImage::get_attachment(); - $str = '{{Image('.$iid.')}}'; + $str = '{{ get_image('.$iid.') }}'; $compiled = Timber::compile_string($str); $this->assertEquals('http://example.org/wp-content/uploads/'.date('Y').'/'.date('m').'/arch.jpg', $compiled); } From 48dee964c42d766b3268fd3935da120acf258768 Mon Sep 17 00:00:00 2001 From: Lukas Gaechter Date: Wed, 26 Feb 2020 21:50:38 +0100 Subject: [PATCH 06/87] Enable functions for users and comments --- lib/Twig.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/Twig.php b/lib/Twig.php index c89621313..9d4805c6d 100644 --- a/lib/Twig.php +++ b/lib/Twig.php @@ -66,11 +66,13 @@ public function add_timber_functions( $twig ) { $twig->addFunction( new TwigFunction( 'get_term', [ Timber::class, 'get_term' ] ) ); $twig->addFunction( new TwigFunction( 'get_terms', [ Timber::class, 'get_terms' ] ) ); - // @TODO: Enable these when factories are merged into 2.0. - // $twig->addFunction( new TwigFunction( 'get_user', [ Timber::class, 'get_user' ] ) ); - // $twig->addFunction( new TwigFunction( 'get_users', [ Timber::class, 'get_users' ] ); - // $twig->addFunction( new TwigFunction( 'get_comment', [ Timber::class, 'get_comment' ] ); - // $twig->addFunction( new TwigFunction( 'get_comments', [ Timber::class, 'get_comments' ] ); + // Users + $twig->addFunction( new TwigFunction( 'get_user', [ Timber::class, 'get_user' ] ) ); + $twig->addFunction( new TwigFunction( 'get_users', [ Timber::class, 'get_users' ] ) ); + + // Comments + $twig->addFunction( new TwigFunction( 'get_comment', [ Timber::class, 'get_comment' ] ) ); + $twig->addFunction( new TwigFunction( 'get_comments', [ Timber::class, 'get_comments' ] ) ); /** * Deprecated Timber object functions. From 37144bd062454ce225dfe3358233959b9eee967c Mon Sep 17 00:00:00 2001 From: Lukas Gaechter Date: Sat, 6 Jun 2020 13:27:58 +0200 Subject: [PATCH 07/87] Delete unused process_term_args() function --- lib/Twig.php | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/lib/Twig.php b/lib/Twig.php index f8087fd57..4657ac7ec 100644 --- a/lib/Twig.php +++ b/lib/Twig.php @@ -163,25 +163,6 @@ public static function maybe_convert_array( $post_id, $class ) { return new $class( $post_id ); } - /** - * Process the arguments for handle_term_object to determine what arguments the user is sending - * @since 1.5.1 - * @author @jarednova - * @param string $maybe_taxonomy probably a taxonomy, but it could be a Timber\Term subclass - * @param string $TermClass a string for the Timber\Term subclass - * @return array of processed arguments - */ - protected static function process_term_args( $maybe_taxonomy, $TermClass ) { - // A user could be sending a TermClass in the first arg, let's test for that ... - if ( class_exists($maybe_taxonomy) ) { - $tc = new $maybe_taxonomy; - if ( is_subclass_of($tc, 'Timber\Term') ) { - return array('taxonomy' => '', 'TermClass' => $maybe_taxonomy); - } - } - return array('taxonomy' => $maybe_taxonomy, 'TermClass' => $TermClass); - } - /** * Adds filters to Twig. * From fc99acee0915e4ccc6eeae41f69ce3cbbf788133 Mon Sep 17 00:00:00 2001 From: Lukas Gaechter Date: Sat, 6 Jun 2020 13:34:57 +0200 Subject: [PATCH 08/87] Update documentation with updates from master branch --- docs/v2/guides/cookbook-images.md | 4 +++- docs/v2/integrations/advanced-custom-fields.md | 17 +++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/v2/guides/cookbook-images.md b/docs/v2/guides/cookbook-images.md index df608a353..fa712bab9 100644 --- a/docs/v2/guides/cookbook-images.md +++ b/docs/v2/guides/cookbook-images.md @@ -102,7 +102,9 @@ When setting up your custom fields you’ll want to save the `image_id` to the f ### The quick way (for most situations) ```twig - +{% set image = get_image(post.hero_image) %} + +{{ image.alt }} ``` ### The long way (for some special situations) diff --git a/docs/v2/integrations/advanced-custom-fields.md b/docs/v2/integrations/advanced-custom-fields.md index 54d509538..f29c38178 100644 --- a/docs/v2/integrations/advanced-custom-fields.md +++ b/docs/v2/integrations/advanced-custom-fields.md @@ -124,6 +124,19 @@ or * * * +## Relationship field + +The post data returned from a relationship field will not contain the Timber methods needed for easy handling inside of your Twig file. To get these, you’ll need to convert them into proper `Timber\Post` objects using `get_posts()`: + +```twig +{% for item in get_posts(post.relationship_field) %} + {{ item.title }} + {# Do something with item #} +{% endfor %} +``` + +* * * + ## Repeater Field You can access repeater fields within Twig files: @@ -261,13 +274,13 @@ add_filter( 'timber/context', 'global_timber_context' ); /** * Filters global context. - * + * * @param array $context An array of existing context variables. * @return mixed */ function global_timber_context( $context ) { $context['options'] = get_fields( 'option' ); - + return $context; } ``` From b8dbbdb739a4dcec26ac4afdfc8ac4453f4cec64 Mon Sep 17 00:00:00 2001 From: Iain MacDonald Date: Thu, 6 Aug 2020 19:03:40 +0800 Subject: [PATCH 09/87] Better control over Pagination stops I had the case where I needed to hide the last pages of pagination (the very oldest posts). I found the `end_step` (not documented anywhere) controlled how many pages are shown at either end of the pagination range. Additionally I was not able to set this to zero to hide the pages completely. My proposal is to allow zero pages to be shown at the ends of the list. Also to enable different values for the start and end. The start value defaults to the same as the end value for backwards compatibility. --- lib/Pagination.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/Pagination.php b/lib/Pagination.php index c4eb48477..c70baa1fa 100644 --- a/lib/Pagination.php +++ b/lib/Pagination.php @@ -114,6 +114,7 @@ public static function paginate_links( $args = array() ) { 'prev_next' => false, 'prev_text' => __('« Previous'), 'next_text' => __('Next »'), + 'start_size' => 1, 'end_size' => 1, 'mid_size' => 2, 'type' => 'array', @@ -130,7 +131,8 @@ public static function paginate_links( $args = array() ) { return array(); } $args['current'] = (int) $args['current']; - $args['end_size'] = 0 < (int) $args['end_size'] ? (int) $args['end_size'] : 1; // Out of bounds? Make it the default. + $args['end_size'] = 0 <= (int) $args['end_size'] ? (int) $args['end_size'] : 1; // Out of bounds? Make it the default. + $args['start_size'] = 0 <= (int) $args['start_size'] ? (int) $args['start_size'] : $args['end_size']; // Default to end_size for backwards compat $args['mid_size'] = 0 <= (int) $args['mid_size'] ? (int) $args['mid_size'] : 2; $args['add_args'] = is_array($args['add_args']) ? $args['add_args'] : false; $page_links = array(); @@ -147,7 +149,7 @@ public static function paginate_links( $args = array() ) { ); $dots = true; } else { - if ( $args['show_all'] || ($n <= $args['end_size'] || ($args['current'] && $n >= $args['current'] - $args['mid_size'] && $n <= $args['current'] + $args['mid_size']) || $n > $args['total'] - $args['end_size']) ) { + if ( $args['show_all'] || ($n <= $args['start_size'] || ($args['current'] && $n >= $args['current'] - $args['mid_size'] && $n <= $args['current'] + $args['mid_size']) || $n > $args['total'] - $args['end_size']) ) { $link = str_replace('%_%', 1 == $n ? '' : $args['format'], $args['base']); $link = str_replace('%#%', $n, $link); From 99f0e9879dc2fb4f0355982744f81625bc1d7a6b Mon Sep 17 00:00:00 2001 From: Iain MacDonald Date: Sat, 8 Aug 2020 23:17:59 +0800 Subject: [PATCH 10/87] Add tests for Pagination End Limits --- lib/Pagination.php | 8 +++--- tests/test-timber-pagination.php | 45 ++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/lib/Pagination.php b/lib/Pagination.php index c70baa1fa..930371d48 100644 --- a/lib/Pagination.php +++ b/lib/Pagination.php @@ -84,10 +84,10 @@ protected function init( $prefs = array(), $wp_query = null ) { } // set next and prev using pages array generated by paginate links - if ( isset($current) && isset($this->pages[$current + 1]) ) { + if ( isset($current) && isset($this->pages[$current + 1]) && isset($this->pages[$current + 1]['link']) ) { $this->next = array('link' => $this->pages[$current + 1]['link'], 'class' => 'page-numbers next'); } - if ( isset($current) && isset($this->pages[$current - 1]) ) { + if ( isset($current) && isset($this->pages[$current - 1]) && isset($this->pages[$current - 1]['link']) ) { $this->prev = array('link' => $this->pages[$current - 1]['link'], 'class' => 'page-numbers prev'); } if ( $paged < 2 ) { @@ -114,7 +114,7 @@ public static function paginate_links( $args = array() ) { 'prev_next' => false, 'prev_text' => __('« Previous'), 'next_text' => __('Next »'), - 'start_size' => 1, + 'start_size' => -1, 'end_size' => 1, 'mid_size' => 2, 'type' => 'array', @@ -136,7 +136,7 @@ public static function paginate_links( $args = array() ) { $args['mid_size'] = 0 <= (int) $args['mid_size'] ? (int) $args['mid_size'] : 2; $args['add_args'] = is_array($args['add_args']) ? $args['add_args'] : false; $page_links = array(); - $dots = false; + $dots = true; for ( $n = 1; $n <= $args['total']; $n++ ) { $n_display = number_format_i18n($n); if ( $n == $args['current'] ) { diff --git a/tests/test-timber-pagination.php b/tests/test-timber-pagination.php index 54dc143b6..b249b6971 100644 --- a/tests/test-timber-pagination.php +++ b/tests/test-timber-pagination.php @@ -412,7 +412,48 @@ function test1459Pagintion() { $pagination = $data['posts']->pagination(); $this->assertEquals('http://example.org/my_cpt/page/3/', $pagination->pages[2]['link']); } - - + + /** + * @ticket #2302 + */ + function testPaginationEndLimits() { + $pids = $this->factory->post->create_many( 150 ); + // Test defaults (mid = 2, end = 1, start = end) + $posts = new Timber\PostQuery(array('post_type' => 'post', 'paged' => 13, 'posts_per_page' => 5)); + $pagination = $posts->pagination(array('show_all' => false)); + $this->assertEquals( 11, count( $pagination->pages ) ); + // Test mid_size + $posts = new Timber\PostQuery(array('post_type' => 'post', 'paged' => 13, 'posts_per_page' => 5)); + $pagination = $posts->pagination(array('show_all' => false, 'mid_size' => 1)); + $this->assertEquals( 7, count( $pagination->pages ) ); + // Test mid_size = 0 + $posts = new Timber\PostQuery(array('post_type' => 'post', 'paged' => 13, 'posts_per_page' => 5)); + $pagination = $posts->pagination(array('show_all' => false, 'mid_size' => 0)); + $this->assertEquals( 5, count( $pagination->pages ) ); + // Test end_size + $posts = new Timber\PostQuery(array('post_type' => 'post', 'paged' => 13, 'posts_per_page' => 5)); + $pagination = $posts->pagination(array('show_all' => false, 'end_size' => 2)); + $this->assertEquals( 13, count( $pagination->pages ) ); + // Test end_size = 0 + $posts = new Timber\PostQuery(array('post_type' => 'post', 'paged' => 13, 'posts_per_page' => 5)); + $pagination = $posts->pagination(array('show_all' => false, 'end_size' => 0)); + $this->assertEquals( 9, count( $pagination->pages ) ); + // Test start_size + $posts = new Timber\PostQuery(array('post_type' => 'post', 'paged' => 13, 'posts_per_page' => 5)); + $pagination = $posts->pagination(array('show_all' => false, 'start_size' => 2)); + $this->assertEquals( 12, count( $pagination->pages ) ); + // Test start_size = 0 + $posts = new Timber\PostQuery(array('post_type' => 'post', 'paged' => 13, 'posts_per_page' => 5)); + $pagination = $posts->pagination(array('show_all' => false, 'start_size' => 0)); + $this->assertEquals( 10, count( $pagination->pages ) ); + // Test start_size, end_size + $posts = new Timber\PostQuery(array('post_type' => 'post', 'paged' => 13, 'posts_per_page' => 5)); + $pagination = $posts->pagination(array('show_all' => false, 'start_size' => 2, 'end_size' => 3)); + $this->assertEquals( 14, count( $pagination->pages ) ); + // Test start_size, end_size = 0 + $posts = new Timber\PostQuery(array('post_type' => 'post', 'paged' => 13, 'posts_per_page' => 5)); + $pagination = $posts->pagination(array('show_all' => false, 'start_size' => 2, 'end_size' => 0)); + $this->assertEquals( 11, count( $pagination->pages ) ); + } } From 3a675a9d38de92147ebceb9fdd2771cdc3730e75 Mon Sep 17 00:00:00 2001 From: Lukas Gaechter Date: Mon, 10 Aug 2020 21:04:25 +0200 Subject: [PATCH 11/87] Update name to learn-timber-theme --- docs/v2/getting-started/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/v2/getting-started/introduction.md b/docs/v2/getting-started/introduction.md index a847cd38e..c7e5c858a 100644 --- a/docs/v2/getting-started/introduction.md +++ b/docs/v2/getting-started/introduction.md @@ -10,7 +10,7 @@ Let’s get familiar with some of the concepts of Timber and Twig. If you want to start from scratch, you can use the following command. Run it from the **wp-content/themes** folder of your WordPress installation. ```bash -composer create-project timber/getting-started-theme getting-started-theme +composer create-project timber/learn-timber-theme learn-timber-theme ``` And now … From e60c6274696e4df1f6a51c8e7ac8671646ba380b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Sch=C3=B6ldstr=C3=B6m?= Date: Fri, 14 Aug 2020 12:29:41 -0300 Subject: [PATCH 12/87] fix #2216: delete sideloaded image tmp files --- lib/ImageHelper.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ImageHelper.php b/lib/ImageHelper.php index cc2461d48..6279822d7 100644 --- a/lib/ImageHelper.php +++ b/lib/ImageHelper.php @@ -378,14 +378,15 @@ public static function sideload_image( $file ) { $file_array = array(); $file_array['name'] = PathHelper::basename($matches[0]); $file_array['tmp_name'] = $tmp; - // If error storing temporarily, unlink + // If error storing temporarily, do not use if ( is_wp_error($tmp) ) { - @unlink($file_array['tmp_name']); $file_array['tmp_name'] = ''; } // do the validation and storage stuff $locinfo = PathHelper::pathinfo($loc); $file = wp_upload_bits($locinfo['basename'], null, file_get_contents($file_array['tmp_name'])); + // delete tmp file + @unlink($file_array['tmp_name']); return $file['url']; } From 91675ac0da36750f91bc7f1ed0489096b3d939ba Mon Sep 17 00:00:00 2001 From: Jared Novack Date: Sun, 16 Aug 2020 19:49:25 -0400 Subject: [PATCH 13/87] Update changelog and version numbers for 1.18.0 --- bin/timber.php | 2 +- lib/Timber.php | 2 +- readme.txt | 12 +++++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/bin/timber.php b/bin/timber.php index 94ea64b46..737c50cb9 100644 --- a/bin/timber.php +++ b/bin/timber.php @@ -4,7 +4,7 @@ Description: The WordPress Timber Library allows you to write themes using the power of Twig templates. Plugin URI: https://upstatement.com/timber Author: Jared Novack + Upstatement -Version: 1.17.0 +Version: 1.18.0 Author URI: http://upstatement.com/ */ // we look for Composer files first in the plugins dir. diff --git a/lib/Timber.php b/lib/Timber.php index 87fc4687a..6beff8f1e 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -35,7 +35,7 @@ */ class Timber { - public static $version = '1.17.0'; + public static $version = '1.18.0'; public static $locations; public static $dirname = 'views'; public static $twig_cache = false; diff --git a/readme.txt b/readme.txt index d2040f190..b4ac9445d 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ Contributors: jarednova Tags: template engine, templates, twig Requires at least: 4.9.8 Tested up to: 5.4.2 -Stable tag: 1.17.0 +Stable tag: 1.18.0 Requires PHP: 5.6 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -38,6 +38,16 @@ _Twig is the template language powering Timber; if you need a little background **Fixes and improvements** += 1.18.0 = + +**Changes for Theme Developers** + +* Improves control over pagination stops #2302 (thanks @IJMacD) + +**Fixes and improvements** + +* Fixes an error with array_filter and later versions of Twig + = 1.17.0 = **Changes for Theme Developers** From af8245669fcf1a0162bf100fe5b9e710453f5ba6 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Fri, 21 Aug 2020 16:17:15 -0700 Subject: [PATCH 14/87] #2093 transition away from array arg to PostQuery::__construct() --- lib/PostQuery.php | 41 +++++++++++++++------------ lib/Timber.php | 2 +- tests/test-timber-context.php | 7 +++-- tests/test-timber-pagination.php | 30 +++++++------------- tests/test-timber-post-collection.php | 3 +- tests/test-timber-post-getter.php | 4 +-- tests/test-timber.php | 2 +- 7 files changed, 44 insertions(+), 45 deletions(-) diff --git a/lib/PostQuery.php b/lib/PostQuery.php index 83cf5269d..0e4d6596d 100644 --- a/lib/PostQuery.php +++ b/lib/PostQuery.php @@ -106,25 +106,30 @@ class PostQuery extends ArrayObject implements PostCollectionInterface, JsonSeri * for the current template. Default `false`. * } */ - public function __construct( $args = array() ) { - // Backwards compatibility. - if ( ! empty( $args ) && ! isset( $args['query'] ) ) { - $args = array( - 'query' => $args, - ); - - Helper::deprecated( - 'Passing query arguments directly to PostQuery', - 'Put your query in an array with a "query" key', - '2.0.0' - ); - } + public function __construct( $args = null ) { + // @todo remove these if/else clauses completely and deal directly w/ WP_Query + if (is_array($args)) { + // Backwards compatibility. + if ( ! empty( $args ) && ! isset( $args['query'] ) ) { + $args = array( + 'query' => $args, + ); + + Helper::deprecated( + 'Passing query arguments directly to PostQuery', + 'Put your query in an array with a "query" key', + '2.0.0' + ); + } - $args = wp_parse_args( $args, array( - 'query' => false, - 'merge_default' => false, - 'post_class' => '\Timber\Post', - ) ); + $args = wp_parse_args( $args, array( + 'query' => false, + 'merge_default' => false, + 'post_class' => '\Timber\Post', + ) ); + } else { + $args = ['query' => ($args ?? new WP_Query())]; + } if ($args['query'] instanceof WP_Query) { // @todo this is the new happy path diff --git a/lib/Timber.php b/lib/Timber.php index 2abab3bbf..9398c7a69 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -635,7 +635,7 @@ public static function context() { $post = ( new Post() )->setup(); $context['post'] = $post; } elseif ( is_archive() || is_home() ) { - $context['posts'] = new PostQuery(); + $context['posts'] = new PostQuery($GLOBALS['wp_query']); } return $context; diff --git a/tests/test-timber-context.php b/tests/test-timber-context.php index e60800c99..3efd1f5da 100644 --- a/tests/test-timber-context.php +++ b/tests/test-timber-context.php @@ -2,9 +2,10 @@ use Timber\Timber; use Timber\Post; +use Timber\PostQuery; /** - * @group called-post-constructor + * @group post-collections */ class TestTimberContext extends Timber_UnitTestCase { /** @@ -47,8 +48,8 @@ function testPostsContextSimple() { $context = Timber::context(); $this->assertArrayNotHasKey( 'post', $context ); - $this->assertInstanceOf( 'Timber\PostQuery', $context['posts'] ); - $this->assertCount( 3, $context['posts']->get_posts() ); + $this->assertInstanceOf( PostQuery::class, $context['posts'] ); + $this->assertCount( 3, $context['posts'] ); } function testIfSetupFunctionIsRunInSingularTemplates() { diff --git a/tests/test-timber-pagination.php b/tests/test-timber-pagination.php index f41321c7c..422a9ed9b 100644 --- a/tests/test-timber-pagination.php +++ b/tests/test-timber-pagination.php @@ -123,7 +123,7 @@ function testDoubleEncodedPaginationUrl() { query_posts('post_type=portfolio&paged=3'); $link = Timber::compile_string("{{ posts.pagination.next.link|e('esc_url') }}", array( - 'posts' => new Timber\PostQuery(), + 'posts' => new Timber\PostQuery($GLOBALS['wp_query']), ) ); $this->assertEquals('http://example.org/portfolio/page/4/?wx9umscriptalert(1)/script%_253eaq86s=1', $link); } @@ -135,7 +135,7 @@ function testDoubleEncodedPaginationUrlWithEscHTML() { query_posts('post_type=portfolio&paged=3'); $link = Timber::compile_string("{{ posts.pagination.next.link|e('esc_html') }}", array( - 'posts' => new Timber\PostQuery(), + 'posts' => new Timber\PostQuery($GLOBALS['wp_query']), ) ); $this->assertEquals('http://example.org/portfolio/page/4/?wx9umscriptalert(1)/script%_253eaq86s=1', $link); } @@ -288,7 +288,7 @@ function testCollectionPaginationSearch() { $this->setPermalinkStructure(''); $posts = $this->factory->post->create_many( 55 ); $this->go_to( home_url( '?s=post' ) ); - $posts = new Timber\PostQuery(); + $posts = new Timber\PostQuery($GLOBALS['wp_query']); $pagination = $posts->pagination(); $this->assertEquals( home_url().esc_url('/?paged=5&s=post'), $pagination->pages[4]['link'] ); } @@ -296,9 +296,7 @@ function testCollectionPaginationSearch() { function testCollectionPaginationOnLaterPage() { $pids = $this->factory->post->create_many( 55, array( 'post_type' => 'portfolio' ) ); $this->go_to( home_url( '/portfolio/page/3' ) ); - $posts = new Timber\PostQuery( array( - 'query' => 'post_type=portfolio&paged=3' - ) ); + $posts = new Timber\PostQuery( new WP_Query('post_type=portfolio&paged=3') ); $pagination = $posts->pagination(); $this->assertEquals(6, count($pagination->pages)); } @@ -306,9 +304,7 @@ function testCollectionPaginationOnLaterPage() { function testCollectionPaginationWithSize() { $this->setPermalinkStructure('/%postname%/'); $pids = $this->factory->post->create_many( 99, array( 'post_type' => 'portfolio' ) ); - $posts = new Timber\PostQuery( array( - 'query' => 'post_type=portfolio&posts_per_page=20', - ) ); + $posts = new Timber\PostQuery( new WP_Query('post_type=portfolio&posts_per_page=20') ); $pagination = $posts->pagination(); $this->assertEquals(5, count($pagination->pages)); } @@ -318,9 +314,7 @@ function testCollectionPaginationSearchPrettyWithPostname() { $posts = $this->factory->post->create_many( 55 ); $archive = home_url('?s=post'); $this->go_to( $archive ); - $posts = new Timber\PostQuery( array( - 'query' => 's=post' - ) ); + $posts = new Timber\PostQuery( new WP_Query('s=post') ); $pagination = $posts->pagination(); $this->assertEquals( 'http://example.org/page/5/?s=post', $pagination->pages[4]['link'] ); } @@ -330,9 +324,7 @@ function testCollectionPaginationSearchPrettyWithPostnameNext() { $posts = $this->factory->post->create_many( 55 ); $archive = home_url( '?s=post' ); $this->go_to( $archive ); - $posts = new Timber\PostQuery( array( - 'query' => 's=post' - ) ); + $posts = new Timber\PostQuery( new WP_Query('s=post') ); $pagination = $posts->pagination(); $this->assertEquals( 'http://example.org/page/2/?s=post', $pagination->next['link'] ); } @@ -343,7 +335,7 @@ function testCollectionPaginationQueryVars() { $this->setPermalinkStructure('/%postname%/'); $posts = $this->factory->post->create_many( 55 ); $this->go_to( home_url('?myvar=value') ); - $posts = new Timber\PostQuery(); + $posts = new Timber\PostQuery($GLOBALS['wp_query']); $pagination = $posts->pagination(); $this->assertEquals( 'http://example.org/page/2/?myvar=value', $pagination->next['link'] ); } @@ -364,7 +356,7 @@ function testCollectionPaginationSearchPretty() { $posts = $this->factory->post->create_many( 55 ); $archive = home_url( '?s=post' ); $this->go_to( $archive ); - $posts = new Timber\PostQuery(); + $posts = new Timber\PostQuery($GLOBALS['wp_query']); $pagination = $posts->pagination(); $this->assertEquals( 'http://example.org/page/5/?s=post', $pagination->pages[4]['link'] ); } @@ -372,7 +364,7 @@ function testCollectionPaginationSearchPretty() { function testCollectionPaginationNextUsesBaseAndFormatArgs() { $posts = $this->factory->post->create_many( 55 ); $this->go_to( home_url( '/' ) ); - $posts = new Timber\PostQuery(); + $posts = new Timber\PostQuery($GLOBALS['wp_query']); $pagination = $posts->pagination( array( 'base' => '/apricot/%_%', 'format' => 'page/%#%' ) ); $this->assertEquals( '/apricot/page/2/', $pagination->next['link'] ); } @@ -402,7 +394,7 @@ function testCollectionPaginationPrevUsesBaseAndFormatArgsPage() { function testCollectionPaginationWithMoreThan10Pages() { $posts = $this->factory->post->create_many( 150 ); $this->go_to( home_url( '/page/13' ) ); - $posts = new Timber\PostQuery(); + $posts = new Timber\PostQuery($GLOBALS['wp_query']); $expected_next_link = user_trailingslashit('http://example.org/page/14/'); $pagination = $posts->pagination(); $this->assertEquals( $expected_next_link, $pagination->next['link'] ); diff --git a/tests/test-timber-post-collection.php b/tests/test-timber-post-collection.php index 1752a1e59..79304eafe 100644 --- a/tests/test-timber-post-collection.php +++ b/tests/test-timber-post-collection.php @@ -42,13 +42,14 @@ function testCollectionWithWP_PostArray() { } function testPaginationOnLaterPage() { + $this->markTestIncomplete(); $this->setPermalinkStructure('/%postname%/'); register_post_type( 'portfolio' ); $pids = $this->factory->post->create_many( 55, array( 'post_type' => 'portfolio' ) ); // @todo what is this testing? Still passes with this line commented out... // $this->go_to( home_url( '/portfolio/page/3' ) ); query_posts('post_type=portfolio&paged=3'); - $posts = new Timber\PostQuery(); + $posts = new Timber\PostQuery($GLOBALS['wp_query']); $pagination = $posts->pagination(); $this->assertEquals(6, count($pagination->pages)); } diff --git a/tests/test-timber-post-getter.php b/tests/test-timber-post-getter.php index 206fd15a4..6f7ed4f39 100644 --- a/tests/test-timber-post-getter.php +++ b/tests/test-timber-post-getter.php @@ -374,9 +374,9 @@ function testGetPostsInLoop() { function testGetPostsFromLoop() { $posts = $this->factory->post->create_many( 15 ); $this->go_to( '/' ); - $posts = new Timber\PostQuery(); + $posts = new Timber\PostQuery($GLOBALS['wp_query']); $this->assertEquals( 10, count( $posts ) ); - $pc = new Timber\PostQuery(); + $pc = new Timber\PostQuery($GLOBALS['wp_query']); $this->assertEquals( 10, count( $pc ) ); } diff --git a/tests/test-timber.php b/tests/test-timber.php index 901e302a2..ca45d0b99 100644 --- a/tests/test-timber.php +++ b/tests/test-timber.php @@ -6,7 +6,7 @@ * @group posts-api * @group terms-api * @group users-api - * @group called-post-constructor + * @group post-collections */ class TestTimberMainClass extends Timber_UnitTestCase { From 2b7850a1e88a2f2db246322593c511a9f0295ccf Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Fri, 21 Aug 2020 17:38:55 -0700 Subject: [PATCH 15/87] #2093 refactor or skip a bunch of transitioning tests --- lib/PostQuery.php | 2 +- tests/test-timber-helper.php | 11 +- tests/test-timber-pagination.php | 81 +++++++-------- tests/test-timber-post-array-object.php | 22 +--- tests/test-timber-post-collection.php | 127 ++++++------------------ tests/test-timber-post-getter.php | 2 +- tests/test-timber-post-iterator.php | 19 ++-- tests/test-timber-static.php | 72 +++++++------- tests/test-timber.php | 107 ++++++++------------ 9 files changed, 163 insertions(+), 280 deletions(-) diff --git a/lib/PostQuery.php b/lib/PostQuery.php index 0e4d6596d..435b288bb 100644 --- a/lib/PostQuery.php +++ b/lib/PostQuery.php @@ -128,7 +128,7 @@ public function __construct( $args = null ) { 'post_class' => '\Timber\Post', ) ); } else { - $args = ['query' => ($args ?? new WP_Query())]; + $args = ['query' => $args]; } if ($args['query'] instanceof WP_Query) { diff --git a/tests/test-timber-helper.php b/tests/test-timber-helper.php index 033d72eec..138a7fde6 100644 --- a/tests/test-timber-helper.php +++ b/tests/test-timber-helper.php @@ -1,5 +1,7 @@ factory->post->create(array('post_title' => 'Stringer Bell', 'post_content' => 'Idris Elba')); $posts[] = $this->factory->post->create(array('post_title' => 'Snoop', 'post_content' => 'Felicia Pearson')); $posts[] = $this->factory->post->create(array('post_title' => 'Cheese', 'post_content' => 'Method Man')); - $posts = new Timber\PostQuery( array( - 'query' => $posts, - ) ); - $template = '{% for post in posts | filter({post_content: "Method Man" - })%}{{ post.title }}{% endfor %}'; + $posts = new PostArrayObject( $posts ); + $template = '{% for post in posts | filter({post_content: "Method Man"})%}{{ post.title }}{% endfor %}'; $str = Timber::compile_string($template, array('posts' => $posts)); $this->assertEquals('Cheese', trim($str)); } diff --git a/tests/test-timber-pagination.php b/tests/test-timber-pagination.php index 422a9ed9b..afc6a20a4 100644 --- a/tests/test-timber-pagination.php +++ b/tests/test-timber-pagination.php @@ -55,11 +55,9 @@ function testPaginationWithPostQuery() { $this->go_to( home_url( '/' ) ); // @todo once the Posts API uses Factories, simplify this to Timber::get_posts([...]) - $query = new PostQuery([ - 'query' => new WP_Query([ - 'post_type' => 'portfolio', - ]), - ]); + $query = new PostQuery(new WP_Query([ + 'post_type' => 'portfolio', + ])); $this->assertCount(6, $query->pagination()->pages); } @@ -123,7 +121,7 @@ function testDoubleEncodedPaginationUrl() { query_posts('post_type=portfolio&paged=3'); $link = Timber::compile_string("{{ posts.pagination.next.link|e('esc_url') }}", array( - 'posts' => new Timber\PostQuery($GLOBALS['wp_query']), + 'posts' => new PostQuery($GLOBALS['wp_query']), ) ); $this->assertEquals('http://example.org/portfolio/page/4/?wx9umscriptalert(1)/script%_253eaq86s=1', $link); } @@ -135,7 +133,7 @@ function testDoubleEncodedPaginationUrlWithEscHTML() { query_posts('post_type=portfolio&paged=3'); $link = Timber::compile_string("{{ posts.pagination.next.link|e('esc_html') }}", array( - 'posts' => new Timber\PostQuery($GLOBALS['wp_query']), + 'posts' => new PostQuery($GLOBALS['wp_query']), ) ); $this->assertEquals('http://example.org/portfolio/page/4/?wx9umscriptalert(1)/script%_253eaq86s=1', $link); } @@ -231,7 +229,7 @@ function testPaginationInCategory() { } $this->go_to( home_url( '/category/news' ) ); query_posts('category_name=news'); - $post_objects = new Timber\PostQuery( array( + $post_objects = new PostQuery( array( 'query' => false, ) ); $pagination = $post_objects->pagination(); @@ -275,7 +273,7 @@ function testPaginationWithMoreThan10Pages() { function testPostsCollectionPagination() { $pids = $this->factory->post->create_many( 13 ); - $posts = new Timber\PostQuery( array( + $posts = new PostQuery( array( 'query' => array( 'post_type' => 'post' ) @@ -288,7 +286,7 @@ function testCollectionPaginationSearch() { $this->setPermalinkStructure(''); $posts = $this->factory->post->create_many( 55 ); $this->go_to( home_url( '?s=post' ) ); - $posts = new Timber\PostQuery($GLOBALS['wp_query']); + $posts = new PostQuery($GLOBALS['wp_query']); $pagination = $posts->pagination(); $this->assertEquals( home_url().esc_url('/?paged=5&s=post'), $pagination->pages[4]['link'] ); } @@ -296,7 +294,7 @@ function testCollectionPaginationSearch() { function testCollectionPaginationOnLaterPage() { $pids = $this->factory->post->create_many( 55, array( 'post_type' => 'portfolio' ) ); $this->go_to( home_url( '/portfolio/page/3' ) ); - $posts = new Timber\PostQuery( new WP_Query('post_type=portfolio&paged=3') ); + $posts = new PostQuery( new WP_Query('post_type=portfolio&paged=3') ); $pagination = $posts->pagination(); $this->assertEquals(6, count($pagination->pages)); } @@ -304,7 +302,7 @@ function testCollectionPaginationOnLaterPage() { function testCollectionPaginationWithSize() { $this->setPermalinkStructure('/%postname%/'); $pids = $this->factory->post->create_many( 99, array( 'post_type' => 'portfolio' ) ); - $posts = new Timber\PostQuery( new WP_Query('post_type=portfolio&posts_per_page=20') ); + $posts = new PostQuery( new WP_Query('post_type=portfolio&posts_per_page=20') ); $pagination = $posts->pagination(); $this->assertEquals(5, count($pagination->pages)); } @@ -314,7 +312,7 @@ function testCollectionPaginationSearchPrettyWithPostname() { $posts = $this->factory->post->create_many( 55 ); $archive = home_url('?s=post'); $this->go_to( $archive ); - $posts = new Timber\PostQuery( new WP_Query('s=post') ); + $posts = new PostQuery( new WP_Query('s=post') ); $pagination = $posts->pagination(); $this->assertEquals( 'http://example.org/page/5/?s=post', $pagination->pages[4]['link'] ); } @@ -324,7 +322,7 @@ function testCollectionPaginationSearchPrettyWithPostnameNext() { $posts = $this->factory->post->create_many( 55 ); $archive = home_url( '?s=post' ); $this->go_to( $archive ); - $posts = new Timber\PostQuery( new WP_Query('s=post') ); + $posts = new PostQuery( new WP_Query('s=post') ); $pagination = $posts->pagination(); $this->assertEquals( 'http://example.org/page/2/?s=post', $pagination->next['link'] ); } @@ -335,7 +333,7 @@ function testCollectionPaginationQueryVars() { $this->setPermalinkStructure('/%postname%/'); $posts = $this->factory->post->create_many( 55 ); $this->go_to( home_url('?myvar=value') ); - $posts = new Timber\PostQuery($GLOBALS['wp_query']); + $posts = new PostQuery($GLOBALS['wp_query']); $pagination = $posts->pagination(); $this->assertEquals( 'http://example.org/page/2/?myvar=value', $pagination->next['link'] ); } @@ -344,49 +342,51 @@ function testCollectionPaginationSearchPrettyWithPostnamePrev() { $posts = $this->factory->post->create_many( 55 ); $archive = home_url( 'page/4/?s=post' ); $this->go_to( $archive ); - $posts = new Timber\PostQuery( array( - 'query' => 's=post&paged=4' - ) ); + $posts = new PostQuery( new WP_Query('s=post&paged=4') ); $pagination = $posts->pagination(); $this->assertEquals( 'http://example.org/page/3/?s=post', $pagination->prev['link'] ); } function testCollectionPaginationSearchPretty() { + $this->markTestSkipped(); $this->setPermalinkStructure( '/blog/%year%/%monthnum%/%postname%/' ); $posts = $this->factory->post->create_many( 55 ); $archive = home_url( '?s=post' ); $this->go_to( $archive ); - $posts = new Timber\PostQuery($GLOBALS['wp_query']); + $posts = Timber::get_posts(); $pagination = $posts->pagination(); $this->assertEquals( 'http://example.org/page/5/?s=post', $pagination->pages[4]['link'] ); } function testCollectionPaginationNextUsesBaseAndFormatArgs() { + $this->markTestSkipped(); $posts = $this->factory->post->create_many( 55 ); $this->go_to( home_url( '/' ) ); - $posts = new Timber\PostQuery($GLOBALS['wp_query']); + $posts = Timber::get_posts(); $pagination = $posts->pagination( array( 'base' => '/apricot/%_%', 'format' => 'page/%#%' ) ); $this->assertEquals( '/apricot/page/2/', $pagination->next['link'] ); } function testCollectionPaginationPrevUsesBaseAndFormatArgs() { + $this->markTestSkipped(); for($i=0; $i<30; $i++) { $this->factory->post->create(array('post_title' => 'post'.$i, 'post_date' => '2014-02-'.$i)); } - $posts = new Timber\PostQuery( array( - 'query' => 'paged=3' - ) ); + $posts = Timber::get_posts([ + 'paged' => 3, + ]); $pagination = $posts->pagination( array( 'base' => '/apricot/%_%', 'format' => '?pagination=%#%' ) ); $this->assertEquals( '/apricot/?pagination=2', $pagination->prev['link'] ); } function testCollectionPaginationPrevUsesBaseAndFormatArgsPage() { + $this->markTestSkipped(); for($i=0; $i<30; $i++) { $this->factory->post->create(array('post_title' => 'post'.$i, 'post_date' => '2014-02-'.$i)); } - $posts = new Timber\PostQuery( array( - 'query' => 'paged=3' - ) ); + $posts = Timber::get_posts([ + 'posts' => 3, + ]); $pagination = $posts->pagination( array( 'base' => '/apricot/%_%', 'format' => '?page=%#%' ) ); $this->assertEquals( '/apricot/?page=2', $pagination->prev['link'] ); } @@ -394,7 +394,7 @@ function testCollectionPaginationPrevUsesBaseAndFormatArgsPage() { function testCollectionPaginationWithMoreThan10Pages() { $posts = $this->factory->post->create_many( 150 ); $this->go_to( home_url( '/page/13' ) ); - $posts = new Timber\PostQuery($GLOBALS['wp_query']); + $posts = new PostQuery($GLOBALS['wp_query']); $expected_next_link = user_trailingslashit('http://example.org/page/14/'); $pagination = $posts->pagination(); $this->assertEquals( $expected_next_link, $pagination->next['link'] ); @@ -404,19 +404,12 @@ function testPostCollectionPaginationForMultiplePostTypes() { register_post_type( 'recipe' ); $pids = $this->factory->post->create_many( 43, array( 'post_type' => 'recipe' ) ); - $recipes = new Timber\PostQuery(array( - 'query' => array( - 'post_type' => 'recipe' - ), - ) ); + $recipes = new PostQuery( new WP_Query('post_type=recipe') ); $pagination = $recipes->pagination(); $this->assertEquals( 5, count( $pagination->pages ) ); $pids = $this->factory->post->create_many( 13 ); - $posts = new Timber\PostQuery( array( - 'query' => array( - 'post_type' => 'post' - ), - ) ); + + $posts = new PostQuery( new WP_Query('post_type=post') ); $pagination = $posts->pagination(); $this->assertEquals( 2, count( $pagination->pages ) ); @@ -426,9 +419,9 @@ function testPostCollectionPaginationForMultiplePostTypes() { /** * @ticket #2123 - * @expectedDeprecated Passing query arguments directly to PostQuery */ function testLittlePaginationCateogry() { + $this->markTestSkipped(); $this->setPermalinkStructure('/%postname%/'); // setup $posts = $this->factory->post->create_many( 3, array( 'post_type' => 'post' ) ); @@ -441,7 +434,7 @@ function testLittlePaginationCateogry() { $category_slug = 'zonk'; $paged = 1; $context = Timber::context(); - $context['posts'] = new Timber\PostQuery([ + $context['posts'] = Timber::get_posts([ 'posts_per_page' => 3, 'orderby' => 'date', 'order' => 'DESC', @@ -454,9 +447,9 @@ function testLittlePaginationCateogry() { /** * @ticket #1459 - * @expectedDeprecated Passing query arguments directly to PostQuery */ function test1459Pagintion() { + $this->markTestSkipped(); $this->setPermalinkStructure('/%year%/%postname%/'); global $paged; register_post_type('my_cpt', array('public' => true, 'has_archive' => true)); @@ -465,10 +458,10 @@ function test1459Pagintion() { $paged = 1; } $this->go_to( home_url( 'my_cpt' ) ); - $data['posts'] = new \Timber\PostQuery(['post_type' => 'my_cpt', 'posts_per_page' => 4, 'paged' => $paged]); - wp_reset_query(); // for good measure - $pagination = $data['posts']->pagination(); - $this->assertEquals('http://example.org/my_cpt/page/3/', $pagination->pages[2]['link']); + $data['posts'] = Timber::get_posts(['post_type' => 'my_cpt', 'posts_per_page' => 4, 'paged' => $paged]); + wp_reset_query(); // for good measure + $pagination = $data['posts']->pagination(); + $this->assertEquals('http://example.org/my_cpt/page/3/', $pagination->pages[2]['link']); } diff --git a/tests/test-timber-post-array-object.php b/tests/test-timber-post-array-object.php index dc050ba1e..b6bc315f6 100644 --- a/tests/test-timber-post-array-object.php +++ b/tests/test-timber-post-array-object.php @@ -30,30 +30,12 @@ function testEmpty() { function testCount() { $this->factory->post->create_many( 20 ); - $query = new Timber\PostQuery([ - 'query' => [ - 'post_type' => 'post', - 'posts_per_page' => -1, - ], - ]); - $coll = new PostArrayObject($query->to_array()); + $coll = new PostArrayObject(get_posts('post_type=post&posts_per_page=-1')); $this->assertCount(20, $coll); - } - - function testPagination() { - $this->factory->post->create_many( 20 ); - $query = new Timber\PostQuery([ - 'query' => [ - 'post_type' => 'post', - ], - ]); - - $coll = new PostArrayObject($query->to_array()); - $this->assertNull($coll->pagination()); - } + } function testLazyInstantiation() { // For performance reasons, we don't want to instantiate every Timber\Post instance diff --git a/tests/test-timber-post-collection.php b/tests/test-timber-post-collection.php index 79304eafe..3562b9d14 100644 --- a/tests/test-timber-post-collection.php +++ b/tests/test-timber-post-collection.php @@ -1,6 +1,7 @@ factory->post->create_many(10); - $pc = new Timber\PostQuery( array( - 'query' => 'post_type=post&numberposts=6', - ) ); + $pc = new PostQuery( new WP_Query('post_type=post&posts_per_page=6') ); $this->assertEquals(6, count($pc)); } @@ -34,9 +33,7 @@ function testCollectionWithWP_PostArray() { $cat = $this->factory->term->create(array('name' => 'Things', 'taxonomy' => 'category')); $pids = $this->factory->post->create_many(4, array('category' => $cat)); $posts = get_posts( array('post_category' => array($cat), 'posts_per_page' => 3) ); - $pc = new Timber\PostQuery( array( - 'query' => $posts - ) ); + $pc = new PostArrayObject( $posts ); $pagination = $pc->pagination(); $this->assertNull($pagination); } @@ -49,7 +46,7 @@ function testPaginationOnLaterPage() { // @todo what is this testing? Still passes with this line commented out... // $this->go_to( home_url( '/portfolio/page/3' ) ); query_posts('post_type=portfolio&paged=3'); - $posts = new Timber\PostQuery($GLOBALS['wp_query']); + $posts = new PostQuery($GLOBALS['wp_query']); $pagination = $posts->pagination(); $this->assertEquals(6, count($pagination->pages)); } @@ -59,81 +56,33 @@ function testBasicCollectionWithPagination() { $page = $this->factory->post->create(array('post_title' => 'Test', 'post_type' => 'page')); $this->go_to('/'); query_posts(array('post_type=post')); - $pc = new Timber\PostQuery( array( - 'query' => 'post_type=post', - ) ); + $pc = new PostQuery( new WP_Query('post_type=post') ); $str = Timber::compile('assets/collection-pagination.twig', array('posts' => $pc)); $str = preg_replace('/\s+/', ' ', $str); $this->assertEquals('

POST

POST

POST

POST

POST

POST

POST

POST

POST

POST

', trim($str)); } - /** - * @expectedDeprecated Passing query arguments directly to PostQuery - */ - function testFoundPostsDeprecated() { + function testFoundPosts() { $this->factory->post->create_many( 20 ); - $query = new Timber\PostQuery( [ - 'post_type' => 'post', - ] ); + $query = new PostQuery( new WP_Query('post_type=post') ); $this->assertCount( 10, $query ); $this->assertEquals( 20, $query->found_posts ); } - /** - * @expectedDeprecated Passing query arguments directly to PostQuery - */ function testFoundPostsInQueryWithNoFoundRows() { $this->factory->post->create_many( 20 ); - $query = new Timber\PostQuery( [ + $query = new PostQuery( new WP_Query( [ 'post_type' => 'post', 'no_found_rows' => true, - ] ); + ] ) ); $this->assertCount( 10, $query ); $this->assertEquals( 0, $query->found_posts ); } - /** - * @expectedDeprecated Passing query arguments directly to PostQuery - */ - function testFoundPostsInCollection() { - $this->factory->post->create_many( 20 ); - - $posts = ( new Timber\PostQuery( [ - 'post_type' => 'post', - ] ) )->to_array(); - - $collection = new Timber\PostQuery( $posts ); - - $this->assertCount( 10, $collection ); - $this->assertEquals( null, $collection->found_posts ); - } - - /** - * @expectedDeprecated Passing query arguments directly to PostQuery - */ - function testFoundPostsInCollectionWithNoFoundRows() { - $this->factory->post->create_many( 20 ); - - $posts = ( new Timber\PostQuery( [ - 'post_type' => 'post', - 'no_found_rows' => true, - ] ) )->to_array(); - - $collection = new Timber\PostQuery( $posts ); - - $this->assertCount( 10, $collection ); - $this->assertEquals( null, $collection->found_posts ); - } - - - /* - * PostCollectionInterface tests - */ - function testTheLoop(){ foreach (range(1, 3) as $i) { $this->factory->post->create( array( @@ -147,9 +96,7 @@ function testTheLoop(){ $results = Timber::compile_string( '{% for p in posts %}{{fn("get_the_title")}}{% endfor %}', [ - 'posts' => new PostQuery([ - 'query' => $wp_query, - ]), + 'posts' => new PostQuery($wp_query), ] ); @@ -166,9 +113,7 @@ function testTwigLoopVar() { // internals over time. $compiled = Timber::compile_string( "{% for p in posts %}\n{{loop|json_encode}}\n{% endfor %}\n", array( - 'posts' => new PostQuery([ - 'query' => $wp_query, - ]), + 'posts' => new PostQuery($wp_query), ) ); // Get each iteration as an object (each should have its own line). @@ -198,18 +143,14 @@ function testPostCount() { // We should be able to call count(...) directly on our collection, by virtue // of it implementing the Countable interface. - $this->assertCount(8, new PostQuery([ - 'query' => new WP_Query('post_type=post'), - ])); + $this->assertCount(8, new PostQuery(new WP_Query('post_type=post'))); } - function testFoundPosts() { + function testFoundPostsWithPostsPerPage() { $this->factory->post->create_many( 10 ); // @todo once the Posts API uses Factories, simplify this to Timber::get_posts([...]) - $query = new PostQuery([ - 'query' => new WP_Query('post_type=post&posts_per_page=3'), - ]); + $query = new PostQuery(new WP_Query('post_type=post&posts_per_page=3')); $this->assertCount(3, $query); $this->assertEquals(10, $query->found_posts); @@ -231,9 +172,7 @@ function testArrayAccess() { ]); // @todo once the Posts API uses Factories, simplify this to Timber::get_posts([...]) - $query = new PostQuery([ - 'query' => new WP_Query('post_type=post'), - ]); + $query = new PostQuery(new WP_Query('post_type=post')); $this->assertEquals('Post 0', $query[0]->title()); $this->assertEquals('Post 1', $query[1]->title()); @@ -263,11 +202,9 @@ function testIterationWithClassMaps() { ]; }); - $query = new PostQuery([ - 'query' => new WP_Query([ - 'post_type' => ['post', 'page', 'custom'] - ]), - ]); + $query = new PostQuery(new WP_Query([ + 'post_type' => ['post', 'page', 'custom'] + ])); $expected = [ CollectionTestCustom::class, @@ -311,11 +248,9 @@ function testLazyInstantiation() { 'post_type' => 'page', ]); - $query = new PostQuery([ - 'query' => new WP_Query([ - 'post_type' => ['post', 'page'], - ]), - ]); + $query = new PostQuery(new WP_Query([ + 'post_type' => ['post', 'page'], + ])); // No posts should have been instantiated yet. $this->assertEquals([ @@ -366,11 +301,9 @@ function testRealize() { 'post_type' => 'page', ]); - $query = new PostQuery([ - 'query' => new WP_Query([ - 'post_type' => ['post', 'page'], - ]), - ]); + $query = new PostQuery(new WP_Query([ + 'post_type' => ['post', 'page'], + ])); // Eagerly instantiate all Posts. $query->realize(); @@ -413,11 +346,9 @@ public function testToArray() { ]; }); - $query = new PostQuery([ - 'query' => new WP_Query([ - 'post_type' => ['post', 'page', 'custom'] - ]), - ]); + $query = new PostQuery( new WP_Query([ + 'post_type' => ['post', 'page', 'custom'] + ])); $arr = $query->to_array(); @@ -441,9 +372,7 @@ public function testJsonSerialize() { ]; }); - $query = new PostQuery([ - 'query' => new WP_Query('post_type=funke'), - ]); + $query = new PostQuery(new WP_Query('post_type=funke')); $this->assertEquals([ [ diff --git a/tests/test-timber-post-getter.php b/tests/test-timber-post-getter.php index 6f7ed4f39..160d0a12a 100644 --- a/tests/test-timber-post-getter.php +++ b/tests/test-timber-post-getter.php @@ -362,7 +362,7 @@ function testGetPostsInLoop() { if ( have_posts() ) { while ( have_posts() ) { the_post(); - $posts = new Timber\PostQuery(); + $posts = new Timber\PostQuery($GLOBALS['wp_query']); } } $end = microtime( true ); diff --git a/tests/test-timber-post-iterator.php b/tests/test-timber-post-iterator.php index 7a8b541b9..dd3a7dc72 100644 --- a/tests/test-timber-post-iterator.php +++ b/tests/test-timber-post-iterator.php @@ -1,5 +1,8 @@ factory->post->create_many(3, [ 'post_title' => 'My Post', ]); - $posts = new Timber\PostQuery( array( - 'query' => $pids - ) ); + $posts = new Timber\PostArrayObject( $pids ); $this->collector = []; @@ -34,9 +35,7 @@ function testLoopEndAfterLastItem() { function testSetupMethodCalled() { $pids = $this->factory->post->create_many(3); - $posts = new Timber\PostQuery( array( - 'query' => $pids - ) ); + $posts = new Timber\PostArrayObject( $pids ); // Make sure $wp_query is set up. $this->go_to( get_permalink( get_option( 'page_for_posts' ) ) ); @@ -56,9 +55,7 @@ function testSetupMethodCalled() { */ function testResetPostDataAfterLastItem() { $pids = $this->factory->post->create_many(3); - $posts = new Timber\PostQuery( array( - 'query' => $pids - ) ); + $posts = new Timber\PostArrayObject( $pids ); // Make sure $wp_query is set up. $this->go_to( get_permalink( get_option( 'page_for_posts' ) ) ); @@ -80,9 +77,7 @@ function testResetPostDataAfterLastItem() { */ function testInTheLoopAfterLastItem() { $pids = $this->factory->post->create_many(3); - $posts = new Timber\PostQuery( array( - 'query' => $pids - ) ); + $posts = new Timber\PostArrayObject( $pids ); // Make sure $wp_query is set up. $this->go_to( get_permalink( get_option( 'page_for_posts' ) ) ); diff --git a/tests/test-timber-static.php b/tests/test-timber-static.php index 55fdb0e5a..97699ba0d 100644 --- a/tests/test-timber-static.php +++ b/tests/test-timber-static.php @@ -63,39 +63,43 @@ function testStaticPostPage() { $this->assertEquals('Timmy', $first_post->title()); } - function testOtherPostOnStaticPostPage() { - $page_id = $this->factory->post->create(array('post_title' => 'Gobbles', 'post_type' => 'page')); - update_option('page_for_posts', $page_id); - $post_id = $this->factory->post->create(array('post_title' => 'My Real post', 'post_type' => 'post')); - $this->go_to(home_url('/?p='.$page_id)); - $post = Timber::get_post($post_id); - $this->assertEquals($post_id, $post->ID); - // @todo #2094 factories - $page = new Timber\Post(); - $this->assertEquals($page_id, $page->ID); - } - - - function testRegularStaticPage() { - $page_id = $this->factory->post->create(array('post_title' => 'Mister Slave', 'post_type' => 'page')); - $children = $this->factory->post->create_many(10, array('post_title' => 'Timmy')); - $this->go_to(home_url('/?p='.$page_id)); - $posts = Timber::get_posts(); - $this->assertEquals(0, count($posts)); - // @todo #2094 factories - $page = new Timber\Post(); - $this->assertEquals($page_id, $page->ID); - } - - function testRegularStaticPageFlipped() { - $page_id = $this->factory->post->create(array('post_title' => 'Mister Slave', 'post_type' => 'page')); - $children = $this->factory->post->create_many(10, array('post_title' => 'Timmy')); - $this->go_to(home_url('/?p='.$page_id)); - // @todo #2094 factories - $page = new Timber\Post(); - $this->assertEquals($page_id, $page->ID); - $posts = Timber::get_posts(); - $this->assertEquals(0, count($posts)); - } + function testOtherPostOnStaticPostPage() { + $page_id = $this->factory->post->create(array('post_title' => 'Gobbles', 'post_type' => 'page')); + update_option('page_for_posts', $page_id); + $post_id = $this->factory->post->create(array('post_title' => 'My Real post', 'post_type' => 'post')); + $this->go_to(home_url('/?p='.$page_id)); + + $post = Timber::get_post($post_id); + $this->assertEquals($post_id, $post->ID); + } + + + function testRegularStaticPage() { + // @todo what exactly is this testing? + $this->markTestSkipped(); + $page_id = $this->factory->post->create(array('post_title' => 'Mister Slave', 'post_type' => 'page')); + $children = $this->factory->post->create_many(10, array('post_title' => 'Timmy')); + $this->go_to(home_url('/?p='.$page_id)); + + $posts = Timber::get_posts(); + $this->assertCount(0, $posts); + + $page = Timber::get_post(); + $this->assertEquals($page_id, $page->ID); + } + + function testRegularStaticPageFlipped() { + // @todo what exactly is this testing? + $this->markTestSkipped(); + $page_id = $this->factory->post->create(array('post_title' => 'Mister Slave', 'post_type' => 'page')); + $children = $this->factory->post->create_many(10, array('post_title' => 'Timmy')); + $this->go_to(home_url('/?p='.$page_id)); + + $page = Timber::get_post(); + $this->assertEquals($page_id, $page->ID); + + $posts = Timber::get_posts(); + $this->assertCount(0, $posts); + } } diff --git a/tests/test-timber.php b/tests/test-timber.php index ca45d0b99..6090be8b7 100644 --- a/tests/test-timber.php +++ b/tests/test-timber.php @@ -1,6 +1,7 @@ markTestSkipped(); $pid = $this->factory->post->create(); - $posts = new Timber\PostQuery( array( - 'query' => array( - 'post_type' => 'post' - ), - 'post_class' => 'TimberAlert', - ) ); - $this->assertEquals('TimberAlert', get_class($posts[0])); + + $this->add_filter_temporarily('timber/post/classmap', function() { + return [ + 'post' => TimberAlert::class, + ]; + }); + + $query = [ + 'post_type' => 'post', + ]; + + $posts = Timber::get_posts($query); + $this->assertInstanceOf(TimberAlert::class, $posts[0]); $this->assertEquals($pid, $posts[0]->ID); - $post = Timber::get_post(array('post_type' => 'post'), 'TimberAlert'); - $this->assertEquals('TimberAlert', get_class($post)); + + $post = Timber::get_post($query); + $this->assertInstanceOf(TimberAlert::class, $post); $this->assertEquals($pid, $post->ID); } @@ -195,74 +203,36 @@ function testGetPostWithCustomPostTypeNotPublic() { $this->assertEquals($pid, $post->ID); } - function testGetPostsQueryString(){ - $this->factory->post->create(); - $this->factory->post->create(); - $posts = new Timber\PostQuery( array( - 'query' => 'post_type=post' - ) ); - $this->assertGreaterThan(1, count($posts)); - } - function testGetPostsQueryArray(){ + $this->markTestSkipped(); $this->factory->post->create(); - $query = array('post_type' => 'post'); - $posts = new Timber\PostQuery( array( - 'query' => $query - ) ); - $this->assertEquals('Timber\Post', get_class($posts[0])); + $posts = Timber::get_posts([ + 'post_type' => 'post', + ]); + $this->assertInstanceOf(Post::class, $posts[0]); } function testGetPostsFromSlug(){ $post_id = $this->factory->post->create(array('post_name' => 'mycoolpost')); $post = Timber::get_post('mycoolpost'); $this->assertEquals($post_id, $post->ID); - - $post = Timber::get_post('mycoolpost'); - $this->assertEquals($post_id, $post->ID); - } - - function testGetPostsQueryStringClassName(){ - $this->factory->post->create(); - $this->factory->post->create(); - $posts = new Timber\PostQuery( array( - 'query' => 'post_type=post' - ) ); - $post = $posts[0]; - $this->assertEquals('Timber\Post', get_class($post)); } function testGetPostsFromArrayOfIds(){ $this->markTestSkipped(); - $pids = array(); - $pids[] = $this->factory->post->create(); - $pids[] = $this->factory->post->create(); - $pids[] = $this->factory->post->create(); - $posts = new Timber\PostQuery( array( - 'query' => $pids, - ) ); - $this->assertEquals('Timber\Post', get_class($posts[0])); - } + $pids = [ + $this->factory->post->create(), + $this->factory->post->create(), + $this->factory->post->create(), + ]; + $posts = Timber::get_posts($pids); - function testGetPostsArrayCount(){ - $pids = array(); - $pids[] = $this->factory->post->create(); - $pids[] = $this->factory->post->create(); - $pids[] = $this->factory->post->create(); - $posts = new Timber\PostQuery( array( - 'query' => $pids - ) ); - $this->assertEquals(3, count($posts)); - } + $this->assertCount(3, $posts); + $this->assertInstanceOf(PostArrayObject::class, $posts); - function testGetPostsCollection() { - $pids = array(); - $pids[] = $this->factory->post->create(); - $pids[] = $this->factory->post->create(); - $pids[] = $this->factory->post->create(); - $posts = new Timber\PostCollection($pids); - $this->assertEquals(3, count($posts)); - $this->assertEquals('Timber\PostCollection', get_class($posts)); + foreach ($posts as $post) { + $this->assertInstanceOf(Post::class, $post); + } } function testUserInContextAnon() { @@ -441,4 +411,15 @@ function testGettingWithCategoryList() { ) )); } + /** + * @group wp_query_hacks + */ + function testNumberpostsFix() { + $this->markTestSkipped('@todo restore support for numberposts fix from QueryIterator::fix_number_posts_wp_quirk'); + $pids = $this->factory->post->create_many(10); + // @todo call Timber::get_posts() + $pc = new PostQuery( new WP_Query('post_type=post&numberposts=6') ); + $this->assertEquals(6, count($pc)); + } + } From e1a5037cf5aef3d1d0aaad9803c8ee9436fba4ee Mon Sep 17 00:00:00 2001 From: Nicolas Lemoine Date: Mon, 24 Aug 2020 15:54:50 +0200 Subject: [PATCH 16/87] #2301 Keep Twig native `filter` parity --- lib/Helper.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/Helper.php b/lib/Helper.php index 326e192b7..383c2dc3f 100644 --- a/lib/Helper.php +++ b/lib/Helper.php @@ -174,7 +174,7 @@ public static function ob_function( $function, $args = array(null) ) { /** * @codeCoverageIgnore * @deprecated since 1.3.0 - * + * * @param mixed $function_name String or array( $class( string|object ), $function_name ). * @param array $defaults Optional. * @param bool $return_output_buffer Optional. Return function output instead of return value. Default false. @@ -441,7 +441,12 @@ public static function filter_array( $list, $arrow, $operator = 'AND' ) { return self::wp_list_filter( $list, $arrow, $operator ); } - return array_filter( $list, $arrow, \ARRAY_FILTER_USE_BOTH ); + if ( is_array( $list ) ) { + return array_filter( $list, $arrow, \ARRAY_FILTER_USE_BOTH ); + } + + // the IteratorIterator wrapping is needed as some internal PHP classes are \Traversable but do not implement \Iterator + return new \CallbackFilterIterator( new \IteratorIterator($array), $arrow ); } /** From 59310defbee356fb9f508ad064b8d389c1b3a0ea Mon Sep 17 00:00:00 2001 From: Nicolas Lemoine Date: Mon, 24 Aug 2020 16:37:30 +0200 Subject: [PATCH 17/87] Fix variable name --- lib/Helper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Helper.php b/lib/Helper.php index 383c2dc3f..81d8c3794 100644 --- a/lib/Helper.php +++ b/lib/Helper.php @@ -446,7 +446,7 @@ public static function filter_array( $list, $arrow, $operator = 'AND' ) { } // the IteratorIterator wrapping is needed as some internal PHP classes are \Traversable but do not implement \Iterator - return new \CallbackFilterIterator( new \IteratorIterator($array), $arrow ); + return new \CallbackFilterIterator( new \IteratorIterator( $list ), $arrow ); } /** From e96381721433a135f47268eb27926eeedef8837f Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Tue, 25 Aug 2020 11:36:26 -0700 Subject: [PATCH 18/87] #2093 migrate some PostGetter tests --- tests/Timber_UnitTestCase.php | 6 + tests/test-timber-post-collection.php | 12 +- tests/test-timber-post-getter.php | 85 ++------ tests/test-timber.php | 274 ++++++++++++++++++++------ 4 files changed, 246 insertions(+), 131 deletions(-) diff --git a/tests/Timber_UnitTestCase.php b/tests/Timber_UnitTestCase.php index 80c27ef8d..cd0ef585d 100644 --- a/tests/Timber_UnitTestCase.php +++ b/tests/Timber_UnitTestCase.php @@ -215,6 +215,12 @@ protected function add_filter_temporarily(string $filter, callable $callback, in }; } + protected function register_post_classmap_temporarily(array $classmap) { + $this->add_filter_temporarily('timber/post/classmap', function(array $current) use ($classmap) { + return array_merge($current, $classmap); + }); + } + /** * Add the given nav_menu_item post IDs to the given menu. * @param int $menu_id the term_id of the menu to add to. diff --git a/tests/test-timber-post-collection.php b/tests/test-timber-post-collection.php index 3562b9d14..bcfec7acc 100644 --- a/tests/test-timber-post-collection.php +++ b/tests/test-timber-post-collection.php @@ -194,13 +194,11 @@ function testIterationWithClassMaps() { 'post_type' => 'post', ]); - $this->add_filter_temporarily('timber/post/classmap', function() { - return [ - 'post' => CollectionTestPost::class, - 'page' => CollectionTestPage::class, - 'custom' => CollectionTestCustom::class, - ]; - }); + $this->register_post_classmap_temporarily([ + 'post' => CollectionTestPost::class, + 'page' => CollectionTestPage::class, + 'custom' => CollectionTestCustom::class, + ]); $query = new PostQuery(new WP_Query([ 'post_type' => ['post', 'page', 'custom'] diff --git a/tests/test-timber-post-getter.php b/tests/test-timber-post-getter.php index 160d0a12a..5cc2ace3e 100644 --- a/tests/test-timber-post-getter.php +++ b/tests/test-timber-post-getter.php @@ -2,7 +2,7 @@ /** * @group posts-api - * @group called-post-constructor + * @group timber */ class TestTimberPostGetter extends Timber_UnitTestCase { @@ -11,68 +11,6 @@ function setUp() { delete_option('sticky_posts'); parent::setUp(); } - /** - * @group wp_query_hacks - */ - function testGettingWithCatAndOtherStuff() { - $pids = $this->factory->post->create_many(6); - $cat = $this->factory->term->create(array('name' => 'Something', 'taxonomy' => 'category')); - $cat_post = $this->factory->post->create(array('post_title' => 'Germany', 'post_category' => array($cat)) ); - $cat_post = $this->factory->post->create(array('post_title' => 'France', 'post_category' => array($cat)) ); - $cat_post = $this->factory->post->create(array('post_title' => 'England', 'post_category' => array($cat)) ); - $args = array( - 'post_type' => 'post', - 'posts_per_page' => 2, - 'post_status' => 'publish', - 'cat' => $cat - ); - $posts = new Timber\PostQuery( array( - 'query' => $args, - ) ); - $this->assertEquals(2, count($posts)); - } - - /** - * @group wp_query_hacks - */ - function testGettingWithCategoryAndOtherStuff() { - $pids = $this->factory->post->create_many(6); - $cat = $this->factory->term->create(array('name' => 'Something', 'taxonomy' => 'category')); - $cat_post = $this->factory->post->create(array('post_title' => 'Germany', 'post_category' => array($cat)) ); - $cat_post = $this->factory->post->create(array('post_title' => 'France', 'post_category' => array($cat)) ); - $cat_post = $this->factory->post->create(array('post_title' => 'England', 'post_category' => array($cat)) ); - $args = array( - 'post_type' => 'post', - 'posts_per_page' => 2, - 'post_status' => 'publish', - 'category' => $cat - ); - $posts = new Timber\PostQuery( array( - 'query' => $args - ) ); - $this->assertEquals(2, count($posts)); - } - - /** - * @group wp_query_hacks - */ - function testGettingWithCat() { - $cat = $this->factory->term->create(array('name' => 'News', 'taxonomy' => 'category')); - - $pids = $this->factory->post->create_many(6); - $cats = $this->factory->post->create_many(3, array('post_category' => array($cat)) ); - $cat_post = $this->factory->post->create(array('post_category' => array($cat)) ); - - $cat_post = Timber::get_post($cat_post); - $this->assertEquals('News', $cat_post->category()->title()); - - $posts = new Timber\PostQuery( array( - 'query' => array( - 'cat' => $cat, - ), - ) ); - $this->assertEquals(4, count($posts)); - } /** * @group wp_query_hacks @@ -151,6 +89,7 @@ function testGettingArrayWithSticky(){ } function testStickyAgainstGetPosts() { + $this->markTestSkipped('@todo this behavior is being deprecated'); $first = $this->factory->post->create(array('post_date' => '2015-04-23 15:13:52')); $sticky_id = $this->factory->post->create(array('post_date' => '2015-04-21 15:13:52')); $last = $this->factory->post->create(array('post_date' => '2015-04-24 15:13:52')); @@ -163,29 +102,36 @@ function testStickyAgainstGetPosts() { } function testStickyAgainstTwoSuccessiveLookups() { + $this->markTestSkipped('@todo this behavior is being deprecated'); $first = $this->factory->post->create(array('post_date' => '2015-04-23 15:13:52')); $sticky_id = $this->factory->post->create(array('post_date' => '2015-04-21 15:13:52')); $last = $this->factory->post->create(array('post_date' => '2015-04-24 15:13:52')); update_option('sticky_posts', array($sticky_id)); add_filter( 'timber/get_posts/mirror_wp_get_posts', '__return_true' ); + $posts = Timber::get_posts('post_type=post'); $this->assertEquals($last, $posts[0]->ID); + $posts = new Timber\PostQuery(array('query' => 'post_type=post')); $this->assertEquals($sticky_id, $posts[0]->ID); } function testStickyAgainstQuery() { - $pids = $this->factory->post->create(array('post_date' => '2015-04-23 15:13:52')); + $this->factory->post->create(array('post_date' => '2015-04-23 15:13:52')); $sticky_id = $this->factory->post->create(array('post_date' => '2015-04-21 15:13:52')); - $pids = $this->factory->post->create(array('post_date' => '2015-04-24 15:13:52')); + $this->factory->post->create(array('post_date' => '2015-04-24 15:13:52')); + update_option('sticky_posts', array($sticky_id)); - $posts = new Timber\PostQuery(array('query' => 'post_type=post')); + + $posts = Timber::get_posts([ + 'post_type' => 'post', + ]); $this->assertEquals($sticky_id, $posts[0]->ID); + $posts = new WP_Query('post_type=post'); $this->assertEquals($sticky_id, $posts->posts[0]->ID); } - // @todo adapt this to new Class Map API and move to test-timber.php function testGetPostsWithClassMap() { $this->markTestSkipped(); register_post_type('portfolio', array('public' => true)); @@ -203,7 +149,6 @@ function testGetPostsWithClassMap() { $this->assertEquals( 'TimberPortfolio', get_class($posts[1]) ); } - // @todo adapt this to new Class Map API and move to test-timber.php function testGetPostWithClassMap() { $this->markTestSkipped(); register_post_type('portfolio', array('public' => true)); @@ -303,6 +248,7 @@ function testNumberPostsBig() { * @group wp_query_hacks */ function testNumberPostsAll() { + $this->markTestSkipped(); $pids = $this->factory->post->create_many( 17 ); $query = 'post_type=post&numberposts=-1'; $posts = new Timber\PostQuery( array( @@ -313,6 +259,7 @@ function testNumberPostsAll() { } function testPostsPerPage() { + $this->markTestSkipped(); $pids = $this->factory->post->create_many( 15 ); $query = 'post_type=post&posts_per_page=7'; $posts = new Timber\PostQuery( array( @@ -322,6 +269,7 @@ function testPostsPerPage() { } function testPostsPerPageAll() { + $this->markTestSkipped(); $pids = $this->factory->post->create_many( 23 ); $query = 'post_type=post&posts_per_page=-1'; $posts = new Timber\PostQuery( array( @@ -331,6 +279,7 @@ function testPostsPerPageAll() { } function testPostsPerPageBig() { + $this->markTestSkipped(); $pids = $this->factory->post->create_many( 15 ); $query = 'post_type=post&posts_per_page=15'; $posts = new Timber\PostQuery( array( diff --git a/tests/test-timber.php b/tests/test-timber.php index 6090be8b7..4673d6b6f 100644 --- a/tests/test-timber.php +++ b/tests/test-timber.php @@ -8,6 +8,7 @@ * @group terms-api * @group users-api * @group post-collections + * @group timber */ class TestTimberMainClass extends Timber_UnitTestCase { @@ -163,11 +164,9 @@ function testGetPostByQueryArray() { $this->markTestSkipped(); $pid = $this->factory->post->create(); - $this->add_filter_temporarily('timber/post/classmap', function() { - return [ - 'post' => TimberAlert::class, - ]; - }); + $this->register_post_classmap_temporarily([ + 'post' => TimberAlert::class, + ]); $query = [ 'post_type' => 'post', @@ -261,7 +260,53 @@ function testQueryPostsInContext(){ $this->assertInstanceOf( Timber\PostQuery::class, $context['posts'] ); } - /* Terms */ + function testGetPostsWithClassMap() { + $this->markTestSkipped(); + register_post_type('portfolio', array('public' => true)); + register_post_type('alert', array('public' => true)); + $this->factory->post->create(array('post_type' => 'portfolio', 'post_title' => 'A portfolio item', 'post_date' => '2015-04-23 15:13:52')); + $this->factory->post->create(array('post_type' => 'alert', 'post_title' => 'An alert', 'post_date' => '2015-06-23 15:13:52')); + + $this->register_post_classmap_temporarily([ + 'alert' => TimberAlert::class, + 'portfolio' => TimberPortfolio::class, + ]); + + $posts = Timber::get_posts([ + 'post_type' => 'any', + ]); + + $this->assertInstanceOf( TimberAlert::class, $posts[0] ); + $this->assertInstanceOf( TimberPortfolio::class, $posts[1] ); + } + + function testGetPostWithClassMap() { + $this->markTestSkipped(); + register_post_type('portfolio', array('public' => true)); + register_post_type('alert', array('public' => true)); + $post_id_portfolio = $this->factory->post->create(array('post_type' => 'portfolio', 'post_title' => 'A portfolio item', 'post_date' => '2015-04-23 15:13:52')); + $post_id_alert = $this->factory->post->create(array('post_type' => 'alert', 'post_title' => 'An alert', 'post_date' => '2015-06-23 15:13:52')); + + $this->register_post_classmap_temporarily([ + 'alert' => TimberAlert::class, + 'portfolio' => TimberPortfolio::class, + ]); + + $portfolio = Timber::get_post($post_id_portfolio); + $alert = Timber::get_post($post_id_alert); + + $this->assertInstanceOf( TimberPortfolio::class, $portfolio ); + $this->assertEquals( $post_id_portfolio, $portfolio->ID ); + + $this->assertInstanceOf( TimberAlert::class, $alert ); + $this->assertEquals( $post_id_alert, $alert->ID ); + } + + + + /* Terms API */ + + function testGetTerm(){ // @todo #2087 $this->markTestSkipped(); @@ -305,51 +350,55 @@ function testGetTerms(){ } - /* Previews */ - function testGetPostPreview(){ - $editor_user_id = $this->factory->user->create( array( 'role' => 'editor' ) ); - wp_set_current_user( $editor_user_id ); - - $post_id = $this->factory->post->create( array( 'post_author' => $editor_user_id, 'post_content' => "OLD CONTENT HERE" ) ); - _wp_put_post_revision( array( 'ID' => $post_id, 'post_content' => 'New Stuff Goes here'), true ); - - $_GET['preview'] = true; - $_GET['preview_id'] = $post_id; - - $the_post = Timber::get_post( $post_id ); - $this->assertEquals( 'New Stuff Goes here', $the_post->post_content ); - } - - function testTimberRenderString() { - $pid = $this->factory->post->create(array('post_title' => 'Zoogats')); - $post = Timber::get_post($pid); - ob_start(); - Timber::render_string('

{{post.title}}

', array('post' => $post)); - $data = ob_get_contents(); - ob_end_clean(); - $this->assertEquals('

Zoogats

', trim($data)); - } - - function testTimberRender() { - $pid = $this->factory->post->create(array('post_title' => 'Foobar')); - $post = Timber::get_post($pid); - ob_start(); - Timber::render('assets/single-post.twig', array('post' => $post)); - $data = ob_get_contents(); - ob_end_clean(); - $this->assertEquals('

Foobar

', trim($data)); - } - - function testTimberGetCallingScriptFile() { - $calling_file = LocationManager::get_calling_script_file(); - $file = getcwd().'/tests/test-timber.php'; - $this->assertEquals($calling_file, $file); - } - - function testCompileNull() { - $str = Timber::compile('assets/single-course.twig', null); - $this->assertEquals('I am single course', $str); - } + + + /* Previews */ + + + function testGetPostPreview(){ + $editor_user_id = $this->factory->user->create( array( 'role' => 'editor' ) ); + wp_set_current_user( $editor_user_id ); + + $post_id = $this->factory->post->create( array( 'post_author' => $editor_user_id, 'post_content' => "OLD CONTENT HERE" ) ); + _wp_put_post_revision( array( 'ID' => $post_id, 'post_content' => 'New Stuff Goes here'), true ); + + $_GET['preview'] = true; + $_GET['preview_id'] = $post_id; + + $the_post = Timber::get_post( $post_id ); + $this->assertEquals( 'New Stuff Goes here', $the_post->post_content ); + } + + function testTimberRenderString() { + $pid = $this->factory->post->create(array('post_title' => 'Zoogats')); + $post = Timber::get_post($pid); + ob_start(); + Timber::render_string('

{{post.title}}

', array('post' => $post)); + $data = ob_get_contents(); + ob_end_clean(); + $this->assertEquals('

Zoogats

', trim($data)); + } + + function testTimberRender() { + $pid = $this->factory->post->create(array('post_title' => 'Foobar')); + $post = Timber::get_post($pid); + ob_start(); + Timber::render('assets/single-post.twig', array('post' => $post)); + $data = ob_get_contents(); + ob_end_clean(); + $this->assertEquals('

Foobar

', trim($data)); + } + + function testTimberGetCallingScriptFile() { + $calling_file = LocationManager::get_calling_script_file(); + $file = getcwd().'/tests/test-timber.php'; + $this->assertEquals($calling_file, $file); + } + + function testCompileNull() { + $str = Timber::compile('assets/single-course.twig', null); + $this->assertEquals('I am single course', $str); + } /** * @ticket 1660 @@ -415,11 +464,124 @@ function testGettingWithCategoryList() { * @group wp_query_hacks */ function testNumberpostsFix() { - $this->markTestSkipped('@todo restore support for numberposts fix from QueryIterator::fix_number_posts_wp_quirk'); - $pids = $this->factory->post->create_many(10); - // @todo call Timber::get_posts() - $pc = new PostQuery( new WP_Query('post_type=post&numberposts=6') ); - $this->assertEquals(6, count($pc)); + // $this->markTestSkipped('@todo restore support for numberposts fix from QueryIterator::fix_number_posts_wp_quirk'); + $this->factory->post->create_many(10); + + $posts = Timber::get_posts( [ + 'post_type' => 'post', + 'numberposts' => 6, + ] ); + $this->assertCount(6, $posts); + } + + /** + * @group wp_query_hacks + */ + function testNumberPostsAll() { + $this->markTestSkipped(); + $pids = $this->factory->post->create_many( 17 ); + $query = 'post_type=post&numberposts=-1'; + $posts = Timber::get_posts( [ + 'post_type' => 'post', + 'numberposts' => 17, + ] ); + $this->assertEquals(17, count($posts)); + + } + + function testPostsPerPage() { + $pids = $this->factory->post->create_many( 15 ); + + $posts = Timber::get_posts( [ + 'post_type' => 'post', + 'posts_per_page' => 7, + ] ); + + $this->assertCount(7, $posts); + } + + function testPostsPerPageAll() { + $pids = $this->factory->post->create_many( 23 ); + + $posts = Timber::get_posts( [ + 'post_type' => 'post', + 'posts_per_page' => -1, + ] ); + + $this->assertCount(23, $posts); + } + + function testPostsPerPageBig() { + $pids = $this->factory->post->create_many( 15 ); + + $posts = Timber::get_posts( [ + 'post_type' => 'post', + 'posts_per_page' => 15, + ] ); + + $this->assertCount(15, $posts); + } + + /** + * @group wp_query_hacks + */ + function testGettingWithCatAndOtherStuff() { + $pids = $this->factory->post->create_many(6); + $cat = $this->factory->term->create(array('name' => 'Something', 'taxonomy' => 'category')); + + $this->factory->post->create(array('post_title' => 'Germany', 'post_category' => array($cat)) ); + $this->factory->post->create(array('post_title' => 'France', 'post_category' => array($cat)) ); + $this->factory->post->create(array('post_title' => 'England', 'post_category' => array($cat)) ); + + $posts = Timber::get_posts([ + 'post_type' => 'post', + 'posts_per_page' => 2, + 'post_status' => 'publish', + 'cat' => $cat + ]); + + $this->assertEquals(2, count($posts)); + } + + /** + * @group wp_query_hacks + */ + function testGettingWithCategoryAndOtherStuff() { + $pids = $this->factory->post->create_many(6); + $cat = $this->factory->term->create(array('name' => 'Something', 'taxonomy' => 'category')); + + $this->factory->post->create(array('post_title' => 'Germany', 'post_category' => array($cat)) ); + $this->factory->post->create(array('post_title' => 'France', 'post_category' => array($cat)) ); + $this->factory->post->create(array('post_title' => 'England', 'post_category' => array($cat)) ); + + $posts = Timber::get_posts([ + 'post_type' => 'post', + 'posts_per_page' => 2, + 'post_status' => 'publish', + 'category' => $cat + ]); + + $this->assertCount(2, $posts); + } + + /** + * @group wp_query_hacks + */ + function testGettingWithCat() { + $cat = $this->factory->term->create(array('name' => 'News', 'taxonomy' => 'category')); + + $pids = $this->factory->post->create_many(6); + $cats = $this->factory->post->create_many(3, array('post_category' => array($cat)) ); + $cat_post = $this->factory->post->create(array('post_category' => array($cat)) ); + + $cat_post = Timber::get_post($cat_post); + $this->assertEquals('News', $cat_post->category()->title()); + + $posts = Timber::get_posts([ + 'cat' => $cat, + ]); + + $this->assertCount(4, $posts); } } From e3d4ff3c0b443a52cc4857c7e382740f34f93378 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Tue, 25 Aug 2020 11:55:39 -0700 Subject: [PATCH 19/87] #2093 deprecate ::query_post[s]() --- lib/Timber.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Timber.php b/lib/Timber.php index 9398c7a69..cdf442c5b 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -6,6 +6,7 @@ use Timber\Factory\MenuFactory; use Timber\Factory\TermFactory; use Timber\Factory\UserFactory; +use Timber\Helper; /** * Class Timber @@ -264,6 +265,7 @@ public static function get_post_by( $type, $search_value, $args = array() ) { * @return Post|array|bool|null */ public static function query_post( $query = false, $PostClass = 'Timber\Post' ) { + Helper::deprecated('Timber\Timber::query_post()', 'Timber\Timber::get_post()', '2.0.0'); return PostGetter::query_post($query, $PostClass); } @@ -279,6 +281,7 @@ public static function query_post( $query = false, $PostClass = 'Timber\Post' ) * @return PostCollection */ public static function query_posts( $query = false, $PostClass = 'Timber\Post' ) { + Helper::deprecated('Timber\Timber::query_posts()', 'Timber\Timber::get_posts()', '2.0.0'); return PostGetter::query_posts($query, $PostClass); } From 3fa4618e61be364e2c5c788abac3723ac4fbf3a1 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Tue, 25 Aug 2020 14:17:13 -0700 Subject: [PATCH 20/87] #2093 migrate more PostGetter tests and skip temporarily failing Timber tests --- tests/test-timber-post-getter.php | 61 ++++++-- tests/test-timber-post.php | 7 +- tests/test-timber.php | 227 +++++++++++++++++++++++++++++- 3 files changed, 277 insertions(+), 18 deletions(-) diff --git a/tests/test-timber-post-getter.php b/tests/test-timber-post-getter.php index 5cc2ace3e..0e2a514c5 100644 --- a/tests/test-timber-post-getter.php +++ b/tests/test-timber-post-getter.php @@ -2,7 +2,6 @@ /** * @group posts-api - * @group timber */ class TestTimberPostGetter extends Timber_UnitTestCase { @@ -16,6 +15,7 @@ function setUp() { * @group wp_query_hacks */ function testGettingWithCatList() { + $this->markTestSkipped('moved to test-timber'); $cat = array(); $cat[] = $this->factory->term->create(array('name' => 'News', 'taxonomy' => 'category')); $cat[] = $this->factory->term->create(array('name' => 'Local', 'taxonomy' => 'category')); @@ -36,6 +36,7 @@ function testGettingWithCatList() { * @group wp_query_hacks */ function testGettingWithCategory() { + $this->markTestSkipped('moved to test-timber'); $cat = $this->factory->term->create(array('name' => 'News', 'taxonomy' => 'category')); $pids = $this->factory->post->create_many(6); $cats = $this->factory->post->create_many(3, array('post_category' => array($cat)) ); @@ -56,6 +57,10 @@ function testGettingWithCategory() { * @group wp_query_hacks */ function testGettingWithCategoryList() { + // We don't really need to test this AND 'category' => [...] + // since they're not really alternate code paths as far as Timber is concerned. + // That is, only WP itself is concerned with the distinction. + $this->markTestSkipped('removed'); $cat = array(); $cat[] = $this->factory->term->create(array('name' => 'News', 'taxonomy' => 'category')); $cat[] = $this->factory->term->create(array('name' => 'Local', 'taxonomy' => 'category')); @@ -73,6 +78,7 @@ function testGettingWithCategoryList() { } function testGettingArrayWithSticky(){ + $this->markTestSkipped('moved to TestTimberMainClass::testFromArrayWithSticky'); $pids = $this->factory->post->create_many(6); $sticky_id = $this->factory->post->create(); $sticky = array($sticky_id, $pids[0]); @@ -89,7 +95,7 @@ function testGettingArrayWithSticky(){ } function testStickyAgainstGetPosts() { - $this->markTestSkipped('@todo this behavior is being deprecated'); + $this->markTestSkipped('@todo this behavior is being removed'); $first = $this->factory->post->create(array('post_date' => '2015-04-23 15:13:52')); $sticky_id = $this->factory->post->create(array('post_date' => '2015-04-21 15:13:52')); $last = $this->factory->post->create(array('post_date' => '2015-04-24 15:13:52')); @@ -102,7 +108,7 @@ function testStickyAgainstGetPosts() { } function testStickyAgainstTwoSuccessiveLookups() { - $this->markTestSkipped('@todo this behavior is being deprecated'); + $this->markTestSkipped('@todo this behavior is being removed'); $first = $this->factory->post->create(array('post_date' => '2015-04-23 15:13:52')); $sticky_id = $this->factory->post->create(array('post_date' => '2015-04-21 15:13:52')); $last = $this->factory->post->create(array('post_date' => '2015-04-24 15:13:52')); @@ -117,6 +123,7 @@ function testStickyAgainstTwoSuccessiveLookups() { } function testStickyAgainstQuery() { + $this->markTestSkipped('moved to test-timber'); $this->factory->post->create(array('post_date' => '2015-04-23 15:13:52')); $sticky_id = $this->factory->post->create(array('post_date' => '2015-04-21 15:13:52')); $this->factory->post->create(array('post_date' => '2015-04-24 15:13:52')); @@ -133,7 +140,7 @@ function testStickyAgainstQuery() { } function testGetPostsWithClassMap() { - $this->markTestSkipped(); + $this->markTestSkipped('moved to test-timber'); register_post_type('portfolio', array('public' => true)); register_post_type('alert', array('public' => true)); $this->factory->post->create(array('post_type' => 'portfolio', 'post_title' => 'A portfolio item', 'post_date' => '2015-04-23 15:13:52')); @@ -150,7 +157,7 @@ function testGetPostsWithClassMap() { } function testGetPostWithClassMap() { - $this->markTestSkipped(); + $this->markTestSkipped('moved to test-timber'); register_post_type('portfolio', array('public' => true)); $post_id_portfolio = $this->factory->post->create(array('post_type' => 'portfolio', 'post_title' => 'A portfolio item', 'post_date' => '2015-04-23 15:13:52')); $post_id_alert = $this->factory->post->create(array('post_type' => 'alert', 'post_title' => 'An alert', 'post_date' => '2015-06-23 15:13:52')); @@ -175,8 +182,7 @@ function testGetPostWithClassMap() { } function testGettingEmptyArray(){ - // @todo do we even want to support this? - $this->markTestSkipped(); + $this->markTestSkipped('moved to test-timber'); $pids = $this->factory->post->create_many( 15 ); $posts = new Timber\PostQuery( array( 'query' => array() @@ -185,8 +191,7 @@ function testGettingEmptyArray(){ } function testGettingWithFalse(){ - // @todo do we even want to support this? - $this->markTestSkipped(); + $this->markTestSkipped('moved to test-timber'); $pids = $this->factory->post->create_many( 15 ); $posts = new Timber\PostQuery( array( 'query' => false @@ -195,6 +200,7 @@ function testGettingWithFalse(){ } function testGetAttachment() { + $this->markTestSkipped('moved to test-timber'); $upload_dir = wp_upload_dir(); $post_id = $this->factory->post->create(); $filename = TestTimberImage::copyTestAttachment( 'flag.png' ); @@ -225,6 +231,7 @@ function testGetAttachment() { } function testNumberPosts() { + $this->markTestSkipped('moved to test-timber'); $pids = $this->factory->post->create_many( 15 ); $query = 'post_type=post&numberposts=7'; $posts = new Timber\PostQuery( array( @@ -235,6 +242,7 @@ function testNumberPosts() { } function testNumberPostsBig() { + $this->markTestSkipped('moved to test-timber'); $pids = $this->factory->post->create_many( 15 ); $query = 'post_type=post&numberposts=15'; $posts = new Timber\PostQuery( array( @@ -248,7 +256,7 @@ function testNumberPostsBig() { * @group wp_query_hacks */ function testNumberPostsAll() { - $this->markTestSkipped(); + $this->markTestSkipped('moved to test-timber'); $pids = $this->factory->post->create_many( 17 ); $query = 'post_type=post&numberposts=-1'; $posts = new Timber\PostQuery( array( @@ -259,7 +267,7 @@ function testNumberPostsAll() { } function testPostsPerPage() { - $this->markTestSkipped(); + $this->markTestSkipped('moved to test-timber'); $pids = $this->factory->post->create_many( 15 ); $query = 'post_type=post&posts_per_page=7'; $posts = new Timber\PostQuery( array( @@ -269,7 +277,7 @@ function testPostsPerPage() { } function testPostsPerPageAll() { - $this->markTestSkipped(); + $this->markTestSkipped('moved to test-timber'); $pids = $this->factory->post->create_many( 23 ); $query = 'post_type=post&posts_per_page=-1'; $posts = new Timber\PostQuery( array( @@ -279,7 +287,7 @@ function testPostsPerPageAll() { } function testPostsPerPageBig() { - $this->markTestSkipped(); + $this->markTestSkipped('moved to test-timber'); $pids = $this->factory->post->create_many( 15 ); $query = 'post_type=post&posts_per_page=15'; $posts = new Timber\PostQuery( array( @@ -288,7 +296,11 @@ function testPostsPerPageBig() { $this->assertEquals(15, count($posts)); } + /** + * @expectedDeprecated Timber\Timber::query_post() + */ function testQueryPost() { + $this->markTestSkipped('moved to test-timber and deprecated'); $posts = $this->factory->post->create_many( 6 ); $post = Timber::get_post( $posts[3] ); $this->go_to( home_url( '/?p='.$posts[2] ) ); @@ -297,7 +309,11 @@ function testQueryPost() { $this->assertEquals( get_the_ID(), $post->ID ); } + /** + * @expectedDeprecated Timber\Timber::query_post() + */ function testBlankQueryPost() { + $this->markTestSkipped('moved to test-timber and deprecated'); $pid = $this->factory->post->create( ); $this->go_to( home_url( '/?p='.$pid ) ); $post = Timber::query_post(); @@ -305,6 +321,7 @@ function testBlankQueryPost() { } function testGetPostsInLoop() { + $this->markTestSkipped('@todo what are we actually testing here? The Loop? Performance?'); $posts = $this->factory->post->create_many( 55 ); $this->go_to( '/' ); $start = microtime( true ); @@ -321,6 +338,7 @@ function testGetPostsInLoop() { } function testGetPostsFromLoop() { + $this->markTestSkipped('moved to TestTimberMainClass::testGetPostsDefault()'); $posts = $this->factory->post->create_many( 15 ); $this->go_to( '/' ); $posts = new Timber\PostQuery($GLOBALS['wp_query']); @@ -330,6 +348,7 @@ function testGetPostsFromLoop() { } function testGetPostsFromArray() { + $this->markTestSkipped('moved to test-timber'); $pids = $this->factory->post->create_many( 15 ); $posts = new Timber\PostQuery( array( 'query' => $pids @@ -339,6 +358,7 @@ function testGetPostsFromArray() { } function testGetPostWithSlug() { + $this->markTestSkipped('removed'); $post = $this->factory->post->create( array( 'post_name' => 'silly-post' ) ); $posts = new Timber\PostQuery( array( 'query' => 'silly-post' @@ -348,6 +368,7 @@ function testGetPostWithSlug() { } function testCustomPostTypeAndClass() { + $this->markTestSkipped('redundant'); register_post_type('job'); $jobs = $this->factory->post->create_many( 10, array('post_type' => 'job')); $jobPosts = new Timber\PostQuery( array( @@ -359,6 +380,7 @@ function testCustomPostTypeAndClass() { } function testCustomPostTypeAndClassOnSinglePage() { + $this->markTestSkipped('moved to test-timber'); register_post_type('job'); $post_id = $this->factory->post->create( array( 'post_type' => 'job' ) ); $post = Timber::get_post($post_id); @@ -373,16 +395,19 @@ function testCustomPostTypeAndClassOnSinglePage() { } function testStringWithPostClass() { + $this->markTestSkipped('removed'); $yes = \Timber\PostGetter::is_post_class_or_class_map('job'); $this->assertTrue($yes); } function testStringWithPostClassBogus() { + $this->markTestSkipped('removed'); $no = \Timber\PostGetter::is_post_class_or_class_map('pants'); $this->assertFalse($no); } function testNotATimberPost() { + $this->markTestSkipped('removed'); self::enable_error_log(false); $post_id = $this->factory->post->create( array( 'post_type' => 'state' ) ); $use = \Timber\PostGetter::get_post_class('state', 'MyState'); @@ -393,6 +418,7 @@ function testNotATimberPost() { } function testPostTypeReturnAgainstArgType() { + $this->markTestSkipped('removed in favor of Class Maps'); register_post_type('person'); $jobs = $this->factory->post->create_many( 4, array('post_type' => 'person')); $personPostsArray = new Timber\PostQuery( array( @@ -413,6 +439,7 @@ function testPostTypeReturnAgainstArgType() { * Make sure that the_post action is called when we loop over a collection of posts. */ function testThePostHook() { + $this->markTestSkipped('moved to test-timber'); add_action( 'the_post', function( $post ) { add_filter( 'touched_the_post_action', '__return_true' ); } ); @@ -427,6 +454,7 @@ function testThePostHook() { } function testChangeArgumentInDefaultQuery() { + $this->markTestSkipped('moved to test-timber'); update_option( 'show_on_front', 'posts' ); $post_ids = $this->factory->post->create_many( 3, array( 'post_type' => 'post' ) ); $this->go_to( '/' ); @@ -438,7 +466,7 @@ function testChangeArgumentInDefaultQuery() { 'merge_default' => true, ) ); - $posts = $posts->get_posts(); + $posts = $posts->to_array(); $this->assertEquals( $posts[0]->ID, $post_ids[1] ); } @@ -447,6 +475,7 @@ function testChangeArgumentInDefaultQuery() { * @expectedDeprecated Passing query arguments directly to PostQuery */ function testDeprecatedPostQueryArguments() { + $this->markTestSkipped('removed'); update_option( 'show_on_front', 'posts' ); $post_ids = $this->factory->post->create_many( 3, array( 'post_type' => 'post' ) ); $this->go_to( '/' ); @@ -460,6 +489,8 @@ function testDeprecatedPostQueryArguments() { } function testGettingPostsWithStickiesReturnsCorrectAmountOfPosts(){ + $this->markTestSkipped('@todo this behavior is being removed'); + $post_ids = $this->factory->post->create_many(20); //Set some posts as sticky, outside of the first ten posts @@ -484,10 +515,12 @@ function testGettingPostsWithStickiesReturnsCorrectAmountOfPosts(){ function testOrderOfPostsIn() { + $this->markTestSkipped('@todo I don\'t think this test is really improving coverage?'); $pids = $this->factory->post->create_many(30); shuffle($pids); $first_pids = array_slice($pids, 0, 5); $query = array('post__in' => $first_pids, 'orderby' => 'post__in'); + $timber_posts = Timber::get_posts($query); $timber_ids = array_map(function($post) { return $post->ID; diff --git a/tests/test-timber-post.php b/tests/test-timber-post.php index be3fcd588..2be85e343 100644 --- a/tests/test-timber-post.php +++ b/tests/test-timber-post.php @@ -79,10 +79,11 @@ function testPostOnSingle(){ } function testPostOnSingleQuery(){ - $post_id = $this->factory->post->create(); + $this->markTestSkipped('@todo fix Timber::get_post()'); + $this->factory->post->create(); $this->go_to(home_url('/?p='.$post_id)); $post_id = $this->factory->post->create(); - $post = Timber::query_post($post_id); + $post = Timber::get_post($post_id); $this->assertEquals($post_id, $post->ID); $this->assertEquals($post_id, get_the_ID()); } @@ -90,7 +91,7 @@ function testPostOnSingleQuery(){ function testPostOnSingleQueryNoParams(){ $post_id = $this->factory->post->create(); $this->go_to(home_url('/?p='.$post_id)); - $post = Timber::query_post(); + $post = Timber::get_post(); $this->assertEquals($post_id, $post->ID); $this->assertEquals($post_id, get_the_ID()); } diff --git a/tests/test-timber.php b/tests/test-timber.php index 4673d6b6f..60b23a89e 100644 --- a/tests/test-timber.php +++ b/tests/test-timber.php @@ -8,7 +8,6 @@ * @group terms-api * @group users-api * @group post-collections - * @group timber */ class TestTimberMainClass extends Timber_UnitTestCase { @@ -522,6 +521,43 @@ function testPostsPerPageBig() { $this->assertCount(15, $posts); } + /** + * @expectedDeprecated Timber\Timber::query_post() + */ + function testQueryPost() { + $posts = $this->factory->post->create_many( 6 ); + $post = Timber::get_post( $posts[3] ); + $this->go_to( home_url( '/?p='.$posts[2] ) ); + $this->assertNotEquals( get_the_ID(), $post->ID ); + $post = Timber::query_post( $posts[3] ); + $this->assertEquals( get_the_ID(), $post->ID ); + } + + /** + * @expectedDeprecated Timber\Timber::query_post() + */ + function testBlankQueryPost() { + $pid = $this->factory->post->create( ); + $this->go_to( home_url( '/?p='.$pid ) ); + $post = Timber::query_post(); + $this->assertEquals( $pid, $post->ID ); + } + + function testGetPostsWithMergeDefault() { + $this->markTestSkipped('@todo fix merge_default option'); + update_option( 'show_on_front', 'posts' ); + $post_ids = $this->factory->post->create_many( 3, array( 'post_type' => 'post' ) ); + $this->go_to( '/' ); + + $posts = Timber::get_posts( [ + 'post__in' => [$post_ids[1]], + ], [ + 'merge_default' => true, + ] ); + + $this->assertEquals( $posts[0]->ID, $post_ids[1] ); + } + /** * @group wp_query_hacks */ @@ -584,4 +620,193 @@ function testGettingWithCat() { $this->assertCount(4, $posts); } + function testGettingEmptyArray(){ + $this->markTestSkipped('@todo switch to PostFactory in ::get_posts()'); + $this->factory->post->create_many( 15 ); + + $this->assertEquals([], Timber::get_posts([])); + } + + function testFromFalse(){ + $this->markTestSkipped('@todo switch to PostFactory in ::get_posts()'); + $pids = $this->factory->post->create_many( 15 ); + + $this->assertFalse(Timber::get_posts(false)); + } + + function testFromArray() { + // Create 15 posts to query by ID directly. + $pids = $this->factory->post->create_many(15); + + // Query for our 15 posts. + $result_ids = array_map(function($p) { return $p->ID; }, Timber::get_posts($pids)); + + // Resulting IDs should match exactly. + $this->assertEquals($pids, $result_ids); + } + + function testFromArrayWithSticky(){ + // Create 6 posts to query by ID directly. + $pids = $this->factory->post->create_many(6); + + // Make one of the 6 sticky, along with a new one that will not be queried. + update_option('sticky_posts', [$pids[0], $this->factory->post->create()]); + + // Query for our 6 posts. + $result_ids = array_map(function($p) { return $p->ID; }, Timber::get_posts($pids)); + + // Resulting IDs should not include the extra sticky ID. + $this->assertEquals($pids, $result_ids); + } + + function testStickyAgainstQuery() { + // Set up some posts. Make the second one sticky. + $ids = [ + $this->factory->post->create(array('post_date' => '2015-04-23 15:13:52')), + $this->factory->post->create(array('post_date' => '2015-04-21 15:13:52')), + $this->factory->post->create(array('post_date' => '2015-04-24 15:13:52')), + ]; + $sticky_id = $ids[1]; + update_option('sticky_posts', array($sticky_id)); + + $posts = Timber::get_posts( [ + 'post_type' => 'post', + ] ); + $this->assertEquals($sticky_id, $posts[0]->ID); + + $query = new WP_Query('post_type=post'); + $this->assertEquals($sticky_id, $query->posts[0]->ID); + } + + function testGetPostsInLoop() { + $this->markTestSkipped('@todo fix Timber::get_post()'); + $posts = $this->factory->post->create_many( 55 ); + $this->go_to( '/' ); + + if ( have_posts() ) { + while ( have_posts() ) { + the_post(); + $this->assertInstanceOf(Post::class, Timber::get_post()); + } + } + } + + function testFromSlug() { + $this->markTestSkipped('@todo fix Timber::get_post()'); + $this->factory->post->create( array( 'post_name' => 'silly-post' ) ); + + $post = Timber::get_post( 'silly-post' ); + + $this->assertEquals( 'silly-post', $post->slug ); + } + + /** + * @todo will this behavior change? + */ + function testCustomPostTypeOsnSinglePage() { + register_post_type('job'); + + // Set up the global query context for a single job post. + $post_id = $this->factory->post->create( array( 'post_type' => 'job' ) ); + $post = Timber::get_post($post_id); + $this->go_to('?p='.$post->ID); + + // Create more jobs. + $this->factory->post->create_many( 10, array('post_type' => 'job')); + + $jobs = Timber::get_posts([ + 'post_type' => 'job', + ]); + + $this->assertCount(10, $jobs); + } + + /** + * Make sure that the_post action is called when we loop over a collection of posts. + */ + function testThePostHook() { + $this->markTestSkipped('@todo fix Timber::get_posts()'); + + // Tally up the times that the_post action is called. + $the_post_count = 0; + add_action( 'the_post', function( $post ) use (&$the_post_count) { + $the_post_count++; + } ); + + $this->factory->post->create_many( 3 ); + + foreach ( Timber::get_posts() as $post ) { + // whatever + } + + $this->assertEquals(3, $the_post_count); + } + + function testChangeArgumentInDefaultQuery() { + $this->markTestIncomplete('@todo we need to come up with a stronger test because this passes with or without merge_default'); + update_option( 'show_on_front', 'posts' ); + $post_ids = $this->factory->post->create_many( 3, array( 'post_type' => 'post' ) ); + $this->go_to( '/' ); + + $posts = new Timber\PostQuery( array( + 'query' => array( + 'post__in' => array( $post_ids[1] ), + ), + // 'merge_default' => true, + ) ); + + $posts = $posts->to_array(); + + $this->assertEquals( $posts[0]->ID, $post_ids[1] ); + } + + function testGetAttachment() { + $this->markTestSkipped('@todo seems like a lot of what gets tested here is core WP file mgmt. Is that what we want?'); + + // Create an attachment and a post to attach it to. + $upload_dir = wp_upload_dir(); + $post_id = $this->factory->post->create(); + $filename = TestTimberImage::copyTestAttachment( 'flag.png' ); + $destination_url = str_replace( ABSPATH, 'http://'.$_SERVER['HTTP_HOST'].'/', $filename ); + $wp_filetype = wp_check_filetype( basename( $filename ), null ); + $attachment = array( + 'post_mime_type' => $wp_filetype['type'], + 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ), + 'post_content' => '', + 'post_status' => 'inherit' + ); + $attach_id = wp_insert_attachment( $attachment, $filename, $post_id ); + add_post_meta( $post_id, '_thumbnail_id', $attach_id, true ); + + $data = [ + 'post' => Timber::get_post($post_id), + 'size' => ['width' => 100, 'height' => 50], + 'crop' => 'default', + ]; + + Timber::compile( 'assets/thumb-test.twig', $data ); + $exists = file_exists( $filename ); + $this->assertTrue( $exists ); + $resized_path = $upload_dir['path'].'/flag-'.$data['size']['width'].'x'.$data['size']['height'].'-c-'.$data['crop'].'.png'; + $exists = file_exists( $resized_path ); + $this->assertTrue( file_exists() ); + + $attachments = Timber::get_posts( [ + 'post_type' => 'attachment', + 'post_status' => 'inherit', + ] ); + $this->assertGreaterThan(0, count($attachments)); + } + + function testGetPostsDefault() { + $this->factory->post->create_many( 15 ); + $this->go_to( '/' ); + + $this->assertCount( 10, Timber::get_posts() ); + } + + /* + * @todo add more test coverage here... + */ + } From aed937a72b0b3b81af9fd562848d20a576912fa4 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Tue, 25 Aug 2020 15:49:10 -0700 Subject: [PATCH 21/87] update a few comments --- lib/PostQuery.php | 1 + lib/Timber.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/PostQuery.php b/lib/PostQuery.php index 435b288bb..c649b410b 100644 --- a/lib/PostQuery.php +++ b/lib/PostQuery.php @@ -63,6 +63,7 @@ class PostQuery extends ArrayObject implements PostCollectionInterface, JsonSeri * the arguments that can be used for the `$query` parameter. * * @api + * @todo update these docs * @example * ```php * // Get posts from default query diff --git a/lib/Timber.php b/lib/Timber.php index cdf442c5b..f823834b4 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -257,7 +257,7 @@ public static function get_post_by( $type, $search_value, $args = array() ) { * Query post. * * @api - * @deprecated since 2.0.0 Use `new Timber\Post()` instead. + * @deprecated since 2.0.0 Use `Timber::get_post()` instead. * * @param mixed $query * @param string $PostClass @@ -273,7 +273,7 @@ public static function query_post( $query = false, $PostClass = 'Timber\Post' ) * Query posts. * * @api - * @deprecated since 2.0.0 Use `new Timber\PostQuery()` instead. + * @deprecated since 2.0.0 Use `Timber::get_posts()` instead. * * @param mixed $query * @param string $PostClass From b1e7fa5d13e9eaa22696bc0a19b28934d2896af0 Mon Sep 17 00:00:00 2001 From: Jared Novack Date: Tue, 25 Aug 2020 20:20:23 -0400 Subject: [PATCH 22/87] Update changelog and version numbers for 1.18.1 --- bin/timber.php | 2 +- lib/Timber.php | 2 +- readme.txt | 8 +++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/bin/timber.php b/bin/timber.php index 737c50cb9..ef6402ef1 100644 --- a/bin/timber.php +++ b/bin/timber.php @@ -4,7 +4,7 @@ Description: The WordPress Timber Library allows you to write themes using the power of Twig templates. Plugin URI: https://upstatement.com/timber Author: Jared Novack + Upstatement -Version: 1.18.0 +Version: 1.18.1 Author URI: http://upstatement.com/ */ // we look for Composer files first in the plugins dir. diff --git a/lib/Timber.php b/lib/Timber.php index 6beff8f1e..ab3a57b28 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -35,7 +35,7 @@ */ class Timber { - public static $version = '1.18.0'; + public static $version = '1.18.1'; public static $locations; public static $dirname = 'views'; public static $twig_cache = false; diff --git a/readme.txt b/readme.txt index b4ac9445d..b92421e18 100644 --- a/readme.txt +++ b/readme.txt @@ -38,6 +38,12 @@ _Twig is the template language powering Timber; if you need a little background **Fixes and improvements** += 1.18.1 = + +**Fixes and improvements** + +* Corrects an issue where #2305 tested for arrays but not other Iterables (like `Timber\PostCollection`s) #2314 (thanks @nlemoine) + = 1.18.0 = **Changes for Theme Developers** @@ -46,7 +52,7 @@ _Twig is the template language powering Timber; if you need a little background **Fixes and improvements** -* Fixes an error with array_filter and later versions of Twig +* Fixes an error with array_filter and later versions of Twig #2305 = 1.17.0 = From 2b9098f56d01ebea6bc25f3cae93977214382907 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Tue, 25 Aug 2020 17:39:08 -0700 Subject: [PATCH 23/87] #2093 switch Posts API over to Factories!!! --- lib/Timber.php | 55 +++++++++------- tests/test-timber-context.php | 4 +- tests/test-timber.php | 115 +++++++++++++++++++--------------- 3 files changed, 98 insertions(+), 76 deletions(-) diff --git a/lib/Timber.php b/lib/Timber.php index f823834b4..9658d7d7d 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -4,9 +4,11 @@ use Timber\Factory\CommentFactory; use Timber\Factory\MenuFactory; +use Timber\Factory\PostFactory; use Timber\Factory\TermFactory; use Timber\Factory\UserFactory; use Timber\Helper; +use Timber\PostCollectionInterface; /** * Class Timber @@ -135,32 +137,40 @@ class_alias( 'Timber\Timber', 'Timber' ); * @api * @deprecated since 2.0.0 Use `new Timber\Post()` instead. * - * @param mixed $query Optional. Post ID or query (as query string or an array of - * arguments for WP_Query). If a query is provided, only the - * first post of the result will be returned. Default false. - * @param string|array $PostClass Optional. Class to use to wrap the returned post object. - * Default 'Timber\Post'. + * @param mixed $query Optional. Post ID or query (as an array of arguments for WP_Query). + * If a query is provided, only the first post of the result will be + * returned. Default false. + * @param array $options Optional associative array of options. Defaults to an empty array. * * @return \Timber\Post|bool Timber\Post object if a post was found, false if no post was * found. */ - public static function get_post( $query = false, $PostClass = 'Timber\Post' ) { - return PostGetter::get_post($query, $PostClass); + public static function get_post( $query = false, array $options = [] ) { + $factory = new PostFactory(); + + // Default to the global query. + $result = $factory->from($query ?: $GLOBALS['wp_query']); + + // If we got a Collection, return the first Post. + return ($result instanceof PostCollectionInterface) ? $result[0] : $result; } /** * Get posts. * * @api - * @deprecated since 2.0.0 Use `new Timber\PostQuery()` instead. * - * @param mixed $query - * @param string|array $PostClass + * @todo improve this docblock + * @param mixed $query + * @param array $options * * @return array|bool|null */ - public static function get_posts( $query = false, $PostClass = 'Timber\Post', $return_collection = false ) { - return PostGetter::get_posts($query, $PostClass, $return_collection); + public static function get_posts( $query = false, array $options = [] ) { + $factory = new PostFactory(); + + // Default to the global query. + return $factory->from($query ?: $GLOBALS['wp_query']); } /** @@ -259,14 +269,14 @@ public static function get_post_by( $type, $search_value, $args = array() ) { * @api * @deprecated since 2.0.0 Use `Timber::get_post()` instead. * - * @param mixed $query - * @param string $PostClass + * @param mixed $query + * @param array $options * * @return Post|array|bool|null */ - public static function query_post( $query = false, $PostClass = 'Timber\Post' ) { + public static function query_post( $query = false, array $options = [] ) { Helper::deprecated('Timber\Timber::query_post()', 'Timber\Timber::get_post()', '2.0.0'); - return PostGetter::query_post($query, $PostClass); + return self::get_post($query, $options); } /** @@ -275,14 +285,14 @@ public static function query_post( $query = false, $PostClass = 'Timber\Post' ) * @api * @deprecated since 2.0.0 Use `Timber::get_posts()` instead. * - * @param mixed $query - * @param string $PostClass + * @param mixed $query + * @param array $options * * @return PostCollection */ - public static function query_posts( $query = false, $PostClass = 'Timber\Post' ) { + public static function query_posts( $query = false, array $options = [] ) { Helper::deprecated('Timber\Timber::query_posts()', 'Timber\Timber::get_posts()', '2.0.0'); - return PostGetter::query_posts($query, $PostClass); + return self::get_posts($query, $options); } /* Term Retrieval @@ -635,10 +645,9 @@ public static function context() { $context = self::context_global(); if ( is_singular() ) { - $post = ( new Post() )->setup(); - $context['post'] = $post; + $context['post'] = Timber::get_post()->setup(); } elseif ( is_archive() || is_home() ) { - $context['posts'] = new PostQuery($GLOBALS['wp_query']); + $context['posts'] = Timber::get_posts(); } return $context; diff --git a/tests/test-timber-context.php b/tests/test-timber-context.php index 3efd1f5da..e6d9e7366 100644 --- a/tests/test-timber-context.php +++ b/tests/test-timber-context.php @@ -5,6 +5,7 @@ use Timber\PostQuery; /** + * @group posts-api * @group post-collections */ class TestTimberContext extends Timber_UnitTestCase { @@ -12,12 +13,11 @@ class TestTimberContext extends Timber_UnitTestCase { * This throws an infite loop if memorization isn't working */ function testContextLoop() { - add_filter( 'timber/context', function( $context ) { + $this->add_filter_temporarily( 'timber/context', function( $context ) { $context = Timber::context(); $context['zebra'] = 'silly horse'; return $context; - } ); $context = Timber::context(); diff --git a/tests/test-timber.php b/tests/test-timber.php index 60b23a89e..151fc8964 100644 --- a/tests/test-timber.php +++ b/tests/test-timber.php @@ -181,24 +181,31 @@ function testGetPostByQueryArray() { } function testGetPostWithCustomPostType() { - register_post_type('event', array('public' => true)); - $pid = $this->factory->post->create(array('post_type' => 'event')); - $post = new TimberAlert($pid); - $this->assertEquals('TimberAlert', get_class($post)); - $this->assertEquals($pid, $post->ID); - $this->assertEquals('event', $post->post_type); - $post = Timber::get_post($pid, 'TimberAlert'); - $this->assertEquals('TimberAlert', get_class($post)); - $this->assertEquals($pid, $post->ID); - $this->assertEquals('event', $post->post_type); + register_post_type('event', [ + 'public' => true, + ]); + + $event_id = $this->factory->post->create([ + 'post_type' => 'event' + ]); + $this->register_post_classmap_temporarily([ + 'event' => TimberAlert::class, + ]); + + $this->assertInstanceOf(TimberAlert::class, Timber::get_post($event_id)); } function testGetPostWithCustomPostTypeNotPublic() { - register_post_type('event', array('public' => false)); + register_post_type('event', [ + 'public' => false + ]); $pid = $this->factory->post->create(array('post_type' => 'event')); - $post = Timber::get_post($pid, 'TimberAlert'); - $this->assertEquals('TimberAlert', get_class($post)); - $this->assertEquals($pid, $post->ID); + + $this->register_post_classmap_temporarily([ + 'event' => TimberAlert::class, + ]); + + $this->assertInstanceOf(TimberAlert::class, Timber::get_post($pid)); } function testGetPostsQueryArray(){ @@ -211,6 +218,7 @@ function testGetPostsQueryArray(){ } function testGetPostsFromSlug(){ + $this->markTestSkipped('@todo this behavior is being removed?'); $post_id = $this->factory->post->create(array('post_name' => 'mycoolpost')); $post = Timber::get_post('mycoolpost'); $this->assertEquals($post_id, $post->ID); @@ -254,8 +262,9 @@ function testUserInContextLoggedIn() { function testQueryPostsInContext(){ $pids = $this->factory->post->create_many(20); $this->go_to('/'); + $context = Timber::context(); - $this->assertArrayHasKey( 'posts', $context ); + $this->assertInstanceOf( Timber\PostQuery::class, $context['posts'] ); } @@ -280,25 +289,18 @@ function testGetPostsWithClassMap() { } function testGetPostWithClassMap() { - $this->markTestSkipped(); register_post_type('portfolio', array('public' => true)); register_post_type('alert', array('public' => true)); - $post_id_portfolio = $this->factory->post->create(array('post_type' => 'portfolio', 'post_title' => 'A portfolio item', 'post_date' => '2015-04-23 15:13:52')); - $post_id_alert = $this->factory->post->create(array('post_type' => 'alert', 'post_title' => 'An alert', 'post_date' => '2015-06-23 15:13:52')); + $portfolio_id = $this->factory->post->create(array('post_type' => 'portfolio', 'post_title' => 'A portfolio item', 'post_date' => '2015-04-23 15:13:52')); + $alert_id = $this->factory->post->create(array('post_type' => 'alert', 'post_title' => 'An alert', 'post_date' => '2015-06-23 15:13:52')); $this->register_post_classmap_temporarily([ 'alert' => TimberAlert::class, 'portfolio' => TimberPortfolio::class, ]); - $portfolio = Timber::get_post($post_id_portfolio); - $alert = Timber::get_post($post_id_alert); - - $this->assertInstanceOf( TimberPortfolio::class, $portfolio ); - $this->assertEquals( $post_id_portfolio, $portfolio->ID ); - - $this->assertInstanceOf( TimberAlert::class, $alert ); - $this->assertEquals( $post_id_alert, $alert->ID ); + $this->assertInstanceOf( TimberPortfolio::class, Timber::get_post($portfolio_id) ); + $this->assertInstanceOf( TimberAlert::class, Timber::get_post($alert_id) ); } @@ -355,37 +357,38 @@ function testGetTerms(){ function testGetPostPreview(){ - $editor_user_id = $this->factory->user->create( array( 'role' => 'editor' ) ); - wp_set_current_user( $editor_user_id ); + $this->markTestSkipped('@todo restore preview stuff from PostCollection::maybe_set_preview()'); + $editor_user_id = $this->factory->user->create( array( 'role' => 'editor' ) ); + wp_set_current_user( $editor_user_id ); - $post_id = $this->factory->post->create( array( 'post_author' => $editor_user_id, 'post_content' => "OLD CONTENT HERE" ) ); - _wp_put_post_revision( array( 'ID' => $post_id, 'post_content' => 'New Stuff Goes here'), true ); + $post_id = $this->factory->post->create( array( 'post_author' => $editor_user_id, 'post_content' => "OLD CONTENT HERE" ) ); + _wp_put_post_revision( array( 'ID' => $post_id, 'post_content' => 'New Stuff Goes here'), true ); - $_GET['preview'] = true; - $_GET['preview_id'] = $post_id; + $_GET['preview'] = true; + $_GET['preview_id'] = $post_id; - $the_post = Timber::get_post( $post_id ); - $this->assertEquals( 'New Stuff Goes here', $the_post->post_content ); + $the_post = Timber::get_post( $post_id ); + $this->assertEquals( 'New Stuff Goes here', $the_post->post_content ); } function testTimberRenderString() { $pid = $this->factory->post->create(array('post_title' => 'Zoogats')); - $post = Timber::get_post($pid); - ob_start(); - Timber::render_string('

{{post.title}}

', array('post' => $post)); - $data = ob_get_contents(); - ob_end_clean(); - $this->assertEquals('

Zoogats

', trim($data)); + $post = Timber::get_post($pid); + ob_start(); + Timber::render_string('

{{post.title}}

', array('post' => $post)); + $data = ob_get_contents(); + ob_end_clean(); + $this->assertEquals('

Zoogats

', trim($data)); } function testTimberRender() { $pid = $this->factory->post->create(array('post_title' => 'Foobar')); - $post = Timber::get_post($pid); - ob_start(); - Timber::render('assets/single-post.twig', array('post' => $post)); - $data = ob_get_contents(); - ob_end_clean(); - $this->assertEquals('

Foobar

', trim($data)); + $post = Timber::get_post($pid); + ob_start(); + Timber::render('assets/single-post.twig', array('post' => $post)); + $data = ob_get_contents(); + ob_end_clean(); + $this->assertEquals('

Foobar

', trim($data)); } function testTimberGetCallingScriptFile() { @@ -404,8 +407,12 @@ function testCompileNull() { */ function testDoubleInstantiationOfSubclass() { $post_id = $this->factory->post->create( array( 'post_type' => 'person' ) ); - $post = Timber::get_post($post_id, 'Person'); - $this->assertEquals('Person', get_class($post)); + + $this->register_post_classmap_temporarily([ + 'person' => Person::class, + ]); + + $this->assertInstanceOf(Person::class, Timber::get_post($post_id)); } /** @@ -413,6 +420,7 @@ function testDoubleInstantiationOfSubclass() { */ function testDoubleInstantiationOfTimberPostClass() { $post_id = $this->factory->post->create( array( 'post_type' => 'post' ) ); + // Unlike above, do NOT register a special Class Map. $post = Timber::get_post($post_id); $this->assertEquals('Timber\Post', get_class($post)); } @@ -421,6 +429,7 @@ function testDoubleInstantiationOfTimberPostClass() { * @group wp_query_hacks */ function testGettingWithCategory() { + $this->markTestSkipped('@todo fix cat/category hack'); // Create several irrelevant posts that should NOT show up in our query. $this->factory->post->create_many(6); @@ -440,6 +449,7 @@ function testGettingWithCategory() { * @group wp_query_hacks */ function testGettingWithCategoryList() { + $this->markTestSkipped('@todo fix cat/category hack'); // Create several irrelevant posts that should NOT show up in our query. $this->factory->post->create_many(6); @@ -463,7 +473,7 @@ function testGettingWithCategoryList() { * @group wp_query_hacks */ function testNumberpostsFix() { - // $this->markTestSkipped('@todo restore support for numberposts fix from QueryIterator::fix_number_posts_wp_quirk'); + $this->markTestSkipped('@todo restore support for numberposts fix from QueryIterator::fix_number_posts_wp_quirk'); $this->factory->post->create_many(10); $posts = Timber::get_posts( [ @@ -525,6 +535,9 @@ function testPostsPerPageBig() { * @expectedDeprecated Timber\Timber::query_post() */ function testQueryPost() { + // The old PostGetter::query_post() method calls ::current() on the Collection + // it gets back from ::query_posts(). Is that what we want here? + $this->markTestSkipped('@todo remove?'); $posts = $this->factory->post->create_many( 6 ); $post = Timber::get_post( $posts[3] ); $this->go_to( home_url( '/?p='.$posts[2] ) ); @@ -639,7 +652,7 @@ function testFromArray() { $pids = $this->factory->post->create_many(15); // Query for our 15 posts. - $result_ids = array_map(function($p) { return $p->ID; }, Timber::get_posts($pids)); + $result_ids = array_map(function($p) { return $p->ID; }, Timber::get_posts($pids)->to_array()); // Resulting IDs should match exactly. $this->assertEquals($pids, $result_ids); @@ -653,7 +666,7 @@ function testFromArrayWithSticky(){ update_option('sticky_posts', [$pids[0], $this->factory->post->create()]); // Query for our 6 posts. - $result_ids = array_map(function($p) { return $p->ID; }, Timber::get_posts($pids)); + $result_ids = array_map(function($p) { return $p->ID; }, Timber::get_posts($pids)->to_array()); // Resulting IDs should not include the extra sticky ID. $this->assertEquals($pids, $result_ids); From 8f1b9f1424c959df7b35d86eb1b1f2b806b2c663 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Tue, 25 Aug 2020 18:12:36 -0700 Subject: [PATCH 24/87] #2093 restore and refactor some skipped tests Also remove a test for behavior we no longer support. --- lib/Timber.php | 2 -- tests/test-timber.php | 69 +++++++++++++++++++++---------------------- 2 files changed, 34 insertions(+), 37 deletions(-) diff --git a/lib/Timber.php b/lib/Timber.php index 9658d7d7d..52c3e6ce7 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -135,8 +135,6 @@ class_alias( 'Timber\Timber', 'Timber' ); * Get a post by post ID or query (as a query string or an array of arguments). * * @api - * @deprecated since 2.0.0 Use `new Timber\Post()` instead. - * * @param mixed $query Optional. Post ID or query (as an array of arguments for WP_Query). * If a query is provided, only the first post of the result will be * returned. Default false. diff --git a/tests/test-timber.php b/tests/test-timber.php index 151fc8964..7ccb440b7 100644 --- a/tests/test-timber.php +++ b/tests/test-timber.php @@ -2,6 +2,7 @@ use Timber\LocationManager; use Timber\Post; +use Timber\PostArrayObject; /** * @group posts-api @@ -22,14 +23,6 @@ function testGetPostNumeric(){ $this->assertEquals('Timber\Post', get_class($post)); } - // @todo are we dropping support for ::get_post("string") ? - function testGetPostString(){ - $this->markTestSkipped(); - $this->factory->post->create(); - $post = Timber::get_post('post_type=post'); - $this->assertEquals('Timber\Post', get_class($post)); - } - function testGetPostBySlug(){ $this->factory->post->create( [ 'post_name' => 'kill-bill' ] ); @@ -147,37 +140,42 @@ function testGetPostByTitleForNonexistentPost(){ $this->assertEquals( null, $post ); } - function testGetPostByPostObject() { - $this->markTestSkipped(); + function testGetPostFromPostObject() { $pid = $this->factory->post->create(); $wp_post = get_post($pid); - $post = new TimberAlert($wp_post); - $this->assertEquals('TimberAlert', get_class($post)); - $this->assertEquals($pid, $post->ID); - $post = Timber::get_post($wp_post, 'TimberAlert'); - $this->assertEquals('TimberAlert', get_class($post)); - $this->assertEquals($pid, $post->ID); + + $this->register_post_classmap_temporarily([ + 'post' => TimberAlert::class, + ]); + + $post = Timber::get_post($wp_post); + $this->assertInstanceOf(TimberAlert::class, $post); } - function testGetPostByQueryArray() { - $this->markTestSkipped(); + function testGetPostFromQueryArray() { $pid = $this->factory->post->create(); $this->register_post_classmap_temporarily([ 'post' => TimberAlert::class, ]); - $query = [ + $this->assertInstanceOf(TimberAlert::class, Timber::get_post([ 'post_type' => 'post', - ]; + ])); + } - $posts = Timber::get_posts($query); - $this->assertInstanceOf(TimberAlert::class, $posts[0]); - $this->assertEquals($pid, $posts[0]->ID); + function testGetPostsFromQueryArray() { + $pid = $this->factory->post->create(); - $post = Timber::get_post($query); - $this->assertInstanceOf(TimberAlert::class, $post); - $this->assertEquals($pid, $post->ID); + $this->register_post_classmap_temporarily([ + 'post' => TimberAlert::class, + ]); + + $posts = Timber::get_posts([ + 'post_type' => 'post', + ]); + + $this->assertInstanceOf(TimberAlert::class, $posts[0]); } function testGetPostWithCustomPostType() { @@ -208,12 +206,13 @@ function testGetPostWithCustomPostTypeNotPublic() { $this->assertInstanceOf(TimberAlert::class, Timber::get_post($pid)); } - function testGetPostsQueryArray(){ - $this->markTestSkipped(); + function testGetPostsQueryArrayDefault(){ $this->factory->post->create(); + $posts = Timber::get_posts([ 'post_type' => 'post', ]); + $this->assertInstanceOf(Post::class, $posts[0]); } @@ -225,7 +224,6 @@ function testGetPostsFromSlug(){ } function testGetPostsFromArrayOfIds(){ - $this->markTestSkipped(); $pids = [ $this->factory->post->create(), $this->factory->post->create(), @@ -235,7 +233,6 @@ function testGetPostsFromArrayOfIds(){ $this->assertCount(3, $posts); $this->assertInstanceOf(PostArrayObject::class, $posts); - foreach ($posts as $post) { $this->assertInstanceOf(Post::class, $post); } @@ -269,7 +266,6 @@ function testQueryPostsInContext(){ } function testGetPostsWithClassMap() { - $this->markTestSkipped(); register_post_type('portfolio', array('public' => true)); register_post_type('alert', array('public' => true)); $this->factory->post->create(array('post_type' => 'portfolio', 'post_title' => 'A portfolio item', 'post_date' => '2015-04-23 15:13:52')); @@ -634,14 +630,18 @@ function testGettingWithCat() { } function testGettingEmptyArray(){ - $this->markTestSkipped('@todo switch to PostFactory in ::get_posts()'); $this->factory->post->create_many( 15 ); - $this->assertEquals([], Timber::get_posts([])); + $collection = Timber::get_posts([]); + + $this->assertEmpty($collection); + $this->assertEquals([], $collection->to_array()); } function testFromFalse(){ - $this->markTestSkipped('@todo switch to PostFactory in ::get_posts()'); + // We don't actually test this directly in TestTimberPostGetter::testGettingWithFalse(); + // that test directly instantiates a collection. + $this->markTestSkipped('@todo what should this be?'); $pids = $this->factory->post->create_many( 15 ); $this->assertFalse(Timber::get_posts(false)); @@ -692,7 +692,6 @@ function testStickyAgainstQuery() { } function testGetPostsInLoop() { - $this->markTestSkipped('@todo fix Timber::get_post()'); $posts = $this->factory->post->create_many( 55 ); $this->go_to( '/' ); From 0f5782268ad698d8179c543028be21a0ce313a66 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Tue, 25 Aug 2020 19:25:39 -0700 Subject: [PATCH 25/87] #2093 restore cat(egory) query fix --- lib/Timber.php | 11 ++++++++ tests/test-timber.php | 63 +++++++++++++------------------------------ 2 files changed, 30 insertions(+), 44 deletions(-) diff --git a/lib/Timber.php b/lib/Timber.php index 52c3e6ce7..c67abe202 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -2,6 +2,8 @@ namespace Timber; +use WP_Query; + use Timber\Factory\CommentFactory; use Timber\Factory\MenuFactory; use Timber\Factory\PostFactory; @@ -116,6 +118,15 @@ protected static function init() { Admin::init(); new Integrations(); + // @todo find a more permanent home for this stuff, maybe in a QueryHelper class? + add_filter('pre_get_posts', function(WP_Query $query) { + $cat = $query->query['category'] ?? null; + if ( $cat && !isset($query->query['cat']) ) { + unset($query->query['category']); + $query->set('cat', $cat); + } + }); + /** * Make an alias for the Timber class. * diff --git a/tests/test-timber.php b/tests/test-timber.php index 7ccb440b7..498a9d7cc 100644 --- a/tests/test-timber.php +++ b/tests/test-timber.php @@ -421,50 +421,6 @@ function testDoubleInstantiationOfTimberPostClass() { $this->assertEquals('Timber\Post', get_class($post)); } - /** - * @group wp_query_hacks - */ - function testGettingWithCategory() { - $this->markTestSkipped('@todo fix cat/category hack'); - // Create several irrelevant posts that should NOT show up in our query. - $this->factory->post->create_many(6); - - $cat = $this->factory->term->create(array('name' => 'News', 'taxonomy' => 'category')); - $cats = $this->factory->post->create_many(3, array('post_category' => array($cat)) ); - $cat_post = $this->factory->post->create(array('post_category' => array($cat)) ); - - $cat_post = Timber::get_post($cat_post); - $this->assertEquals('News', $cat_post->category()->title()); - - $this->assertCount(4, Timber\Timber::get_posts( array( - 'category' => $cat, - ) )); - } - - /** - * @group wp_query_hacks - */ - function testGettingWithCategoryList() { - $this->markTestSkipped('@todo fix cat/category hack'); - // Create several irrelevant posts that should NOT show up in our query. - $this->factory->post->create_many(6); - - // Create a list of categories and get their IDs. - $cats = [ - $this->factory->term->create(array('name' => 'News', 'taxonomy' => 'category')), - $this->factory->term->create(array('name' => 'Local', 'taxonomy' => 'category')), - ]; - - // Create three posts with a combination of relevant categories. - $this->factory->post->create(array('post_category' => array($cats[0])) ); - $this->factory->post->create(array('post_category' => array($cats[1])) ); - $this->factory->post->create(array('post_category' => $cats) ); - - $this->assertCount(3, Timber\Timber::get_posts( array( - 'category' => $cats, - ) )); - } - /** * @group wp_query_hacks */ @@ -527,6 +483,25 @@ function testPostsPerPageBig() { $this->assertCount(15, $posts); } + /** + * @group wp_query_hacks + */ + function testGetPostsWithCategoryFix() { + // Create several irrelevant posts that should NOT show up in our query. + $this->factory->post->create_many(6); + + $cat = $this->factory->term->create(array('name' => 'News', 'taxonomy' => 'category')); + $cats = $this->factory->post->create_many(3, array('post_category' => array($cat)) ); + $cat_post = $this->factory->post->create(array('post_category' => array($cat)) ); + + $cat_post = Timber::get_post($cat_post); + $this->assertEquals('News', $cat_post->category()->title()); + + $this->assertCount(4, Timber\Timber::get_posts( array( + 'category' => $cat, + ) )); + } + /** * @expectedDeprecated Timber\Timber::query_post() */ From a2c9dda1c4400d572a20abe2598e1d19400f95e7 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Tue, 25 Aug 2020 19:40:19 -0700 Subject: [PATCH 26/87] #2093 remove tests for ::get_post[s]("post-slug") Use ::get_post_by("slug", "post-slug") instead. --- tests/test-timber.php | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tests/test-timber.php b/tests/test-timber.php index 498a9d7cc..386230254 100644 --- a/tests/test-timber.php +++ b/tests/test-timber.php @@ -216,13 +216,6 @@ function testGetPostsQueryArrayDefault(){ $this->assertInstanceOf(Post::class, $posts[0]); } - function testGetPostsFromSlug(){ - $this->markTestSkipped('@todo this behavior is being removed?'); - $post_id = $this->factory->post->create(array('post_name' => 'mycoolpost')); - $post = Timber::get_post('mycoolpost'); - $this->assertEquals($post_id, $post->ID); - } - function testGetPostsFromArrayOfIds(){ $pids = [ $this->factory->post->create(), @@ -678,15 +671,6 @@ function testGetPostsInLoop() { } } - function testFromSlug() { - $this->markTestSkipped('@todo fix Timber::get_post()'); - $this->factory->post->create( array( 'post_name' => 'silly-post' ) ); - - $post = Timber::get_post( 'silly-post' ); - - $this->assertEquals( 'silly-post', $post->slug ); - } - /** * @todo will this behavior change? */ From 97ccbf1e8cb22577f486b2ed95f23cbb01a66bc2 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Tue, 25 Aug 2020 19:45:24 -0700 Subject: [PATCH 27/87] #2093 restore numberposts/posts_per_page helper code --- lib/Timber.php | 7 +++++++ tests/test-timber.php | 2 -- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/Timber.php b/lib/Timber.php index c67abe202..12d5ba987 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -127,6 +127,13 @@ protected static function init() { } }); + add_filter('pre_get_posts', function(WP_Query $query) { + $count = $query->query['numberposts'] ?? null; + if ( $count && !isset($query->query['posts_per_page']) ) { + $query->set('posts_per_page', $count); + } + }); + /** * Make an alias for the Timber class. * diff --git a/tests/test-timber.php b/tests/test-timber.php index 386230254..20fbc4c17 100644 --- a/tests/test-timber.php +++ b/tests/test-timber.php @@ -418,7 +418,6 @@ function testDoubleInstantiationOfTimberPostClass() { * @group wp_query_hacks */ function testNumberpostsFix() { - $this->markTestSkipped('@todo restore support for numberposts fix from QueryIterator::fix_number_posts_wp_quirk'); $this->factory->post->create_many(10); $posts = Timber::get_posts( [ @@ -432,7 +431,6 @@ function testNumberpostsFix() { * @group wp_query_hacks */ function testNumberPostsAll() { - $this->markTestSkipped(); $pids = $this->factory->post->create_many( 17 ); $query = 'post_type=post&numberposts=-1'; $posts = Timber::get_posts( [ From 6923e014cf34829e8670580be60d1b969b999945 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Tue, 25 Aug 2020 20:12:03 -0700 Subject: [PATCH 28/87] #2093 restore preview helper code --- lib/Post.php | 2 +- lib/Timber.php | 23 +++++++++++++++++++++++ tests/test-timber.php | 18 ++++++++++++++---- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/lib/Post.php b/lib/Post.php index 9154cd4df..2a643f7e9 100644 --- a/lib/Post.php +++ b/lib/Post.php @@ -396,7 +396,7 @@ protected function init( $pid = null ) { if ( is_numeric($pid) ) { $this->ID = $pid; } - $post_info = $this->get_info($pid); + $post_info = apply_filters('timber/post/import_data', $this->get_info($pid)); $this->import($post_info); } diff --git a/lib/Timber.php b/lib/Timber.php index 12d5ba987..e3db3c0c3 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -134,6 +134,29 @@ protected static function init() { } }); + add_filter('timber/post/import_data', function($data) { + if ( isset($_GET['preview']) && isset($_GET['preview_id']) ) { + $preview = wp_get_post_autosave($_GET['preview_id']); + if ( is_object($preview) ) { + + $preview = sanitize_post($preview); + + $data->post_content = $preview->post_content; + $data->post_title = $preview->post_title; + $data->post_excerpt = $preview->post_excerpt; + + // @todo I think we can safely delete this? + // It was included in the old PostCollection method but not defined anywhere, + // so I think it was always just falling into a magic __call() and doing nothing. + // $post->import_custom($preview_id); + + add_filter('get_the_terms', '_wp_preview_terms_filter', 10, 3); + } + } + + return $data; + }); + /** * Make an alias for the Timber class. * diff --git a/tests/test-timber.php b/tests/test-timber.php index 20fbc4c17..ff9e6b857 100644 --- a/tests/test-timber.php +++ b/tests/test-timber.php @@ -346,18 +346,28 @@ function testGetTerms(){ function testGetPostPreview(){ - $this->markTestSkipped('@todo restore preview stuff from PostCollection::maybe_set_preview()'); $editor_user_id = $this->factory->user->create( array( 'role' => 'editor' ) ); wp_set_current_user( $editor_user_id ); $post_id = $this->factory->post->create( array( 'post_author' => $editor_user_id, 'post_content' => "OLD CONTENT HERE" ) ); - _wp_put_post_revision( array( 'ID' => $post_id, 'post_content' => 'New Stuff Goes here'), true ); + _wp_put_post_revision([ + 'ID' => $post_id, + 'post_title' => 'Revised Title', + 'post_content' => 'New Stuff Goes here', + 'post_excerpt' => 'New and improved!', + ], true ); $_GET['preview'] = true; $_GET['preview_id'] = $post_id; - $the_post = Timber::get_post( $post_id ); - $this->assertEquals( 'New Stuff Goes here', $the_post->post_content ); + $post = Timber::get_post( $post_id ); + + $this->assertEquals( 'Revised Title', $post->post_title ); + $this->assertEquals( 'New Stuff Goes here', $post->post_content ); + $this->assertEquals( 'New and improved!', $post->post_excerpt ); + + unset($_GET['preview']); + unset($_GET['preview_id']); } function testTimberRenderString() { From fadc7abbc413f9167b0322ef6f460b52023a087b Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Tue, 25 Aug 2020 21:21:39 -0700 Subject: [PATCH 29/87] #2093 fix ::get_post() bug when no posts match --- lib/Timber.php | 6 +++++- tests/test-timber-post.php | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/Timber.php b/lib/Timber.php index e3db3c0c3..b15e63ff5 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -191,7 +191,11 @@ public static function get_post( $query = false, array $options = [] ) { $result = $factory->from($query ?: $GLOBALS['wp_query']); // If we got a Collection, return the first Post. - return ($result instanceof PostCollectionInterface) ? $result[0] : $result; + if ($result instanceof PostCollectionInterface) { + return $result[0] ?? false; + } + + return $result; } /** diff --git a/tests/test-timber-post.php b/tests/test-timber-post.php index 2be85e343..d7a0d4c53 100644 --- a/tests/test-timber-post.php +++ b/tests/test-timber-post.php @@ -10,6 +10,10 @@ */ class TestTimberPost extends Timber_UnitTestCase { + function testGetPostWithNoPosts() { + $this->assertFalse(Timber::get_post()); + } + function testPostObject(){ $post_id = $this->factory->post->create(); $post = Timber::get_post($post_id); From d73dda5672a5696826c4bfe8fb10840e00fc5009 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Tue, 25 Aug 2020 22:18:38 -0700 Subject: [PATCH 30/87] #2093 fix ::get_post() when singular query has already run --- lib/Timber.php | 10 +++++++++- tests/test-timber-revisions.php | 14 +++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/Timber.php b/lib/Timber.php index b15e63ff5..feac83c01 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -3,6 +3,7 @@ namespace Timber; use WP_Query; +use WP_Post; use Timber\Factory\CommentFactory; use Timber\Factory\MenuFactory; @@ -187,8 +188,15 @@ class_alias( 'Timber\Timber', 'Timber' ); public static function get_post( $query = false, array $options = [] ) { $factory = new PostFactory(); + global $wp_query; + + // Has WP already queried and found a post? + if ($query === false && ($wp_query->queried_object instanceof WP_Post)) { + $query = $wp_query->queried_object; + } + // Default to the global query. - $result = $factory->from($query ?: $GLOBALS['wp_query']); + $result = $factory->from($query ?: $wp_query); // If we got a Collection, return the first Post. if ($result instanceof PostCollectionInterface) { diff --git a/tests/test-timber-revisions.php b/tests/test-timber-revisions.php index e6805ffa0..1ff142c2a 100644 --- a/tests/test-timber-revisions.php +++ b/tests/test-timber-revisions.php @@ -1,7 +1,7 @@ assertEquals('I am revised', trim(strip_tags($revision->content())) ); @@ -114,8 +113,7 @@ function testPreviewClass() { $wp_query->queried_object = get_post($post_id); $_GET['preview'] = true; $_GET['preview_nonce'] = wp_create_nonce('post_preview_' . $post_id); - // @todo #2094 factories - $post = new Timber\Post(); + $post = Timber::get_post(); $this->assertEquals( $original_post->class(), $post->class() ); } @@ -207,8 +205,7 @@ function testPreviewContent(){ $wp_query->queried_object = get_post($post_id); $_GET['preview'] = true; $_GET['preview_nonce'] = wp_create_nonce('post_preview_' . $post_id); - // @todo #2094 factories - $post = new Timber\Post(); + $post = Timber::get_post(); $this->assertEquals( $quote . 'Yes', trim(strip_tags($post->content())) ); } @@ -246,8 +243,7 @@ function testMultiPreviewRevisions(){ $wp_query->queried_object = get_post($post_id); $_GET['preview'] = true; $_GET['preview_nonce'] = wp_create_nonce('post_preview_' . $post_id); - // @todo #2094 factories - $post = new Timber\Post(); + $post = Timber::get_post(); $this->assertEquals('I am the one', trim(strip_tags($post->content())) ); } From fe484c77dd383462c0175e98e8f77d0f1307390f Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Tue, 25 Aug 2020 22:20:26 -0700 Subject: [PATCH 31/87] #2094 replace a bunch of direct instantiations --- lib/Attachment.php | 16 +++++++--------- lib/Core.php | 2 +- lib/Post.php | 7 +------ tests/test-timber-attachment.php | 12 ++++++++---- tests/test-timber-helper.php | 2 +- tests/test-timber-image-retina.php | 4 +++- tests/test-timber-image.php | 13 +++++++------ tests/test-timber-integration-acf.php | 7 ++----- tests/test-timber-integrations-coauthors.php | 8 +++++--- tests/test-timber-integrations.php | 3 +-- tests/test-timber-pages.php | 5 ++--- tests/test-timber-post-preview-object.php | 14 +++++++------- tests/test-timber-post-terms.php | 2 +- tests/test-timber-post.php | 5 +++-- tests/test-timber-static.php | 5 ++--- tests/test-timber-user.php | 4 +--- 16 files changed, 52 insertions(+), 57 deletions(-) diff --git a/lib/Attachment.php b/lib/Attachment.php index 466ea75dd..3e5bf9e99 100644 --- a/lib/Attachment.php +++ b/lib/Attachment.php @@ -2,6 +2,8 @@ namespace Timber; +use Timber\Factory\PostFactory; + /** * Class Attachment * @@ -121,15 +123,9 @@ class Attachment extends Post implements CoreInterface { * Creates a new `Timber\Attachment` object. * * @api - * @example - * ```php - * // You can pass it an ID number - * $myImage = new Timber\Attachment(552); - * - * // Or send it a URL to an image - * $myImage = new Timber\Attachment( 'http://google.com/logo.jpg' ); - * ``` + * @internal * + * @todo make this protected * @param int|mixed $attachment An attachment ID, a `Timber\Post`, a `WP_Post` object, an ACF * image array, a path (absolute or relative) or an URL. */ @@ -534,7 +530,9 @@ public function parent() { return false; } - return new $this->PostClass( $this->post_parent ); + $factory = new PostFactory(); + + return $factory->from( $this->post_parent ); } /** diff --git a/lib/Core.php b/lib/Core.php index 3946d823c..ebcb61cfc 100644 --- a/lib/Core.php +++ b/lib/Core.php @@ -117,7 +117,7 @@ public function __get( $field ) { * @example * ```php * $data = array( 'airplane' => '757-200', 'flight' => '5316' ); - * $post = new Timber\Post(); + * $post = Timber::get_post(); * $post->import(data); * * echo $post->airplane; // 757-200 diff --git a/lib/Post.php b/lib/Post.php index 2a643f7e9..63075767a 100644 --- a/lib/Post.php +++ b/lib/Post.php @@ -173,12 +173,7 @@ class Post extends Core implements CoreInterface, MetaInterface, DatedInterface, * If you send the constructor nothing it will try to figure out the current post id based on * being inside The_Loop. * - * @api - * @example - * ```php - * $post = new Timber\Post(); - * $other_post = new Timber\Post($random_post_id); - * ``` + * @internal * * @param mixed $pid */ diff --git a/tests/test-timber-attachment.php b/tests/test-timber-attachment.php index b22fe02b6..1b92b626d 100644 --- a/tests/test-timber-attachment.php +++ b/tests/test-timber-attachment.php @@ -1,5 +1,9 @@ post_name.'/'; $links[] = 'http://example.org/?attachment_id='.$image->ID; @@ -19,7 +23,7 @@ function testAttachmentLink() { function testAttachmentInitWithWP_Post() { $aid = self::get_attachment(); $wp_post = get_post($aid); - $attach = new Timber\Attachment($wp_post); + $attach = Timber::get_post($wp_post); $this->assertEquals($wp_post->ID, $attach->id); } @@ -53,7 +57,7 @@ function testInitFromID() { $filename = self::copyTestAttachment( 'arch.jpg' ); $attachment = array( 'post_title' => 'The Arch', 'post_content' => '' ); $iid = wp_insert_attachment( $attachment, $filename, $pid ); - $attachment = new Timber\Attachment( $iid ); + $attachment = Timber::get_post( $iid ); $this->assertEquals( 'The Arch', $attachment->title() ); } @@ -90,7 +94,7 @@ function testPathInfo() { function testTimberAttachmentSrc() { $iid = self::get_attachment(); - $attachment = new Timber\Attachment($iid); + $attachment = Timber::get_post($iid); $post = get_post($iid); $str = '{{ Attachment(post).src }}'; $result = Timber::compile_string( $str, array('post' => $post) ); diff --git a/tests/test-timber-helper.php b/tests/test-timber-helper.php index 138a7fde6..cf3aa1d77 100644 --- a/tests/test-timber-helper.php +++ b/tests/test-timber-helper.php @@ -323,7 +323,7 @@ function testDoingItWrong() { $post_id = $this->factory->post->create(); $posts = Timber::get_posts(); update_post_meta($post_id, '_thumbnail_id', '707'); - $post = new Timber\Post($post_id); + $post = Timber::get_post($post_id); $thumbnail_id = $post->_thumbnail_id; } diff --git a/tests/test-timber-image-retina.php b/tests/test-timber-image-retina.php index 65305ee17..98372ae49 100644 --- a/tests/test-timber-image-retina.php +++ b/tests/test-timber-image-retina.php @@ -1,7 +1,9 @@ factory->post->create(); $iid = self::get_attachment( $pid ); add_post_meta( $pid, '_thumbnail_id', $iid, true ); - add_post_meta( $iid, '_wp_attachment_metadata', wp_generate_attachment_metadata($iid, get_attached_file($iid)), true ); + add_post_meta( $iid, '_wp_attachment_metadata', wp_generate_attachment_metadata($iid, get_attached_file($iid)), true ); $post = Timber::get_post($pid); return $post; } @@ -41,7 +42,7 @@ function testInitFromRelativePath() { function testTimberImageSrc() { $iid = self::get_attachment(); - $image = new Timber\Image($iid); + $image = Timber::get_post($iid); $post = get_post($iid); $str = '{{ Image(post).src }}'; $result = Timber::compile_string( $str, array('post' => $post) ); @@ -612,7 +613,7 @@ function testImageDeletionByAttachmentLocation() { $this->assertFileExists( $resized_500_file ); $this->assertFileExists( $resized_520_file ); //Now delete the "parent" image - $post = new Timber\Image( $attach_id ); + $post = Timber::get_post( $attach_id ); Timber\ImageHelper::delete_generated_files( $post->file_loc ); //Have the children been deleted as well? $this->assertFileNotExists( $resized_520_file ); @@ -909,7 +910,7 @@ function testTimberImageFromTimberImage() { $post = $this->get_post_with_image(); $image = $post->thumbnail(); $str = '{{ Image(post).src }}'; - $post = new Timber\Image($image); + $post = Timber::get_post($image); $result = Timber::compile_string( $str, array('post' => $post) ); $this->assertEquals($image->src(), $result); } @@ -918,7 +919,7 @@ function testTimberImageFromTimberImageID() { $post = $this->get_post_with_image(); $image = $post->thumbnail(); $str = '{{ Image(post).src }}'; - $post = new Timber\Image($image->ID); + $post = Timber::get_post($image->ID); $result = Timber::compile_string( $str, array('post' => $post) ); $this->assertEquals($image->src(), $result); } diff --git a/tests/test-timber-integration-acf.php b/tests/test-timber-integration-acf.php index 26afa47f9..8f8700e90 100644 --- a/tests/test-timber-integration-acf.php +++ b/tests/test-timber-integration-acf.php @@ -5,11 +5,8 @@ /** * @group users-api * @group comments-api - * @group called-post-constructor - * @group called-term-constructor * @group integrations - * @todo #2094 replace direct Timber\User instantiations - * @todo #2094 replace direct Timber\Comment instantiations + * @group posts-api */ class TestTimberIntegrationACF extends Timber_UnitTestCase { function testACFInit() { @@ -169,7 +166,7 @@ function testACFContentField() { update_field( 'content', 'I am custom content', $pid ); update_field( '_content', 'I am also custom content', $pid ); $str = '{{ post.content }}'; - $post = new Timber\Post( $pid ); + $post = Timber::get_post( $pid ); $str = Timber::compile_string( $str, array( 'post' => $post ) ); $this->assertEquals( '

Cool content bro!

', trim($str) ); } diff --git a/tests/test-timber-integrations-coauthors.php b/tests/test-timber-integrations-coauthors.php index 6efa7730d..d13d14359 100644 --- a/tests/test-timber-integrations-coauthors.php +++ b/tests/test-timber-integrations-coauthors.php @@ -1,8 +1,7 @@ assertInstanceOf('Timber\Integrations\CoAuthorsPlusUser', $author); } + /** + * @group attachments + */ function testGuestAuthorAvatar(){ $pid = $this->factory->post->create(); $post = Timber::get_post($pid); @@ -198,7 +200,7 @@ function testGuestAuthorAvatar(){ ) ); $attach_id = self::attach_featured_image($guest_id, 'avt-1.jpg'); - $image = new Timber\Image(array('ID' => $attach_id)); + $image = Timber::get_post($attach_id); global $coauthors_plus; $coauthors_plus->add_coauthors($pid, array($user_login)); diff --git a/tests/test-timber-integrations.php b/tests/test-timber-integrations.php index dab74bb2d..e66391915 100644 --- a/tests/test-timber-integrations.php +++ b/tests/test-timber-integrations.php @@ -18,8 +18,7 @@ function testIntegrationClasses() { function testWPPostConvert() { $pid = $this->factory->post->create(); $wp_post = get_post( $pid ); - // @todo #2094 factories - $post = new Timber\Post(); + $post = Timber::get_post(); $timber_post = $post->convert( $wp_post ); $this->assertTrue( $timber_post instanceof Timber\Post ); } diff --git a/tests/test-timber-pages.php b/tests/test-timber-pages.php index 74379b9f6..dcb686ef3 100644 --- a/tests/test-timber-pages.php +++ b/tests/test-timber-pages.php @@ -1,8 +1,8 @@ go_to($cat->path()); $term = Timber::get_term(); $this->assertEquals($category_id, $term->ID); - $post = new Timber\Post(); - $this->assertEquals(0, $post->ID); + $this->assertFalse(Timber::get_post()); } diff --git a/tests/test-timber-post-preview-object.php b/tests/test-timber-post-preview-object.php index e537a5a41..143c0b6db 100644 --- a/tests/test-timber-post-preview-object.php +++ b/tests/test-timber-post-preview-object.php @@ -1,7 +1,7 @@ factory->post->create(array( 'post_excerpt' => $this->gettysburg, )); - $post = new Timber\Post($post_id); + $post = Timber::get_post($post_id); $excerpt = $post->excerpt(array( 'words' => 4, 'force' => true, @@ -47,7 +47,7 @@ public function testExcerptConstructorWithChars() { $post_id = $this->factory->post->create(array( 'post_excerpt' => $this->gettysburg, )); - $post = new Timber\Post($post_id); + $post = Timber::get_post($post_id); $excerpt = $post->excerpt(array( 'chars' => 20, 'force' => true, @@ -62,7 +62,7 @@ public function testExcerptConstructorWithEnd() { $post_id = $this->factory->post->create(array( 'post_excerpt' => $this->gettysburg, )); - $post = new Timber\Post($post_id); + $post = Timber::get_post($post_id); $excerpt = $post->excerpt(array( 'chars' => 20, 'force' => true, @@ -81,7 +81,7 @@ public function testExcerptConstructorWithHtml() { . ' STRONG ' . $this->gettysburg, )); - $post = new Timber\Post($post_id); + $post = Timber::get_post($post_id); $excerpt = $post->excerpt(array( 'chars' => 26, 'read_more' => false, @@ -99,7 +99,7 @@ public function testExcerptConstructorStrippingSomeTags() { . ' STRONG ' . $this->gettysburg, )); - $post = new Timber\Post($post_id); + $post = Timber::get_post($post_id); $excerpt = $post->excerpt(array( 'words' => 5, 'read_more' => false, @@ -118,7 +118,7 @@ public function testExcerptConstructorWithReadMore() { $post_id = $this->factory->post->create(array( 'post_excerpt' => $this->gettysburg, )); - $post = new Timber\Post($post_id); + $post = Timber::get_post($post_id); $readmore = 'read more! if you dare...'; $excerpt = $post->excerpt(array( 'chars' => 20, diff --git a/tests/test-timber-post-terms.php b/tests/test-timber-post-terms.php index bf999e6b6..e68acee9e 100644 --- a/tests/test-timber-post-terms.php +++ b/tests/test-timber-post-terms.php @@ -87,7 +87,7 @@ function testPostTermOrder() { $car = Timber::get_term($tid); } wp_set_object_terms($pid, $cars, 'cars', false); - $post = new Timber\Post($pid); + $post = Timber::get_post($pid); $template = "{% for term_item in post.terms({query : {taxonomy: 'cars', orderby: 'term_id', order: 'ASC'}}) %}{{ term_item.name }} {% endfor %}"; $str = Timber::compile_string($template, array('post' => $post)); $this->assertEquals('Honda Civic Toyota Corolla Toyota Camry Dodge Intrepid ', $str); diff --git a/tests/test-timber-post.php b/tests/test-timber-post.php index d7a0d4c53..3b1f55f40 100644 --- a/tests/test-timber-post.php +++ b/tests/test-timber-post.php @@ -23,7 +23,7 @@ function testPostObject(){ function testIDDataType() { $uid = $this->factory->post->create(array('title' => 'Air Force Once')); - $post = new Timber\Post($uid); + $post = Timber::get_post($uid); $this->assertEquals('integer', gettype($post->id)); $this->assertEquals('integer', gettype($post->ID)); } @@ -45,6 +45,7 @@ function testNameMethod() { } function testGetImage() { + $this->markTestSkipped('@todo how to handle Image instances in Class Map?'); $post_id = $this->factory->post->create(array('post_title' => 'St. Louis History')); $filename = TestTimberImage::copyTestAttachment( 'arch.jpg' ); $attachment = array( 'post_title' => 'The Arch', 'post_content' => '' ); @@ -52,7 +53,7 @@ function testGetImage() { update_post_meta($post_id, 'landmark', $iid); $post = Timber::get_post($post_id); $image = $post->meta('landmark'); - $image = new Timber\Image($image); + $image = Timber::get_post($image); $this->assertEquals('The Arch', $image->title()); } diff --git a/tests/test-timber-static.php b/tests/test-timber-static.php index 97699ba0d..20b5a8fab 100644 --- a/tests/test-timber-static.php +++ b/tests/test-timber-static.php @@ -35,9 +35,8 @@ function testPageAsStaticFront() { update_option('page_on_front', $page_id); $this->go_to(home_url('/')); global $wp_query; - $wp_query->queried_object_id = $page_id; - // @todo #2094 factories - $page = new Timber\Post(); + $wp_query->queried_object = get_post($page_id); + $page = Timber::get_post(); $this->assertEquals($page_id, $page->ID); } diff --git a/tests/test-timber-user.php b/tests/test-timber-user.php index c19a5cf69..d84b1758f 100644 --- a/tests/test-timber-user.php +++ b/tests/test-timber-user.php @@ -2,8 +2,6 @@ /** * @group users-api - * @group called-post-constructor - * @todo #2094 replace direct Timber\User instantiations */ class TestTimberUser extends Timber_UnitTestCase { @@ -34,7 +32,7 @@ function testPostWithBlankUser() { , 'post_content' => 'is fine, I guess' , 'post_status' => 'publish' ]); - $post = new Timber\Post($post_id); + $post = Timber::get_post($post_id); $template = '{{ post.title }} by {{ post.author }}'; $str = Timber::compile_string($template, array('post' => $post)); $this->assertEquals('Baseball by', trim($str)); From 3e90f28acf17f572dcdf7e08e43997560540af18 Mon Sep 17 00:00:00 2001 From: Jared Novack Date: Wed, 26 Aug 2020 14:14:22 -0400 Subject: [PATCH 32/87] Add image sideloaded test --- tests/test-timber-image-helper.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/test-timber-image-helper.php b/tests/test-timber-image-helper.php index 1a2b3760c..e50e0ce93 100644 --- a/tests/test-timber-image-helper.php +++ b/tests/test-timber-image-helper.php @@ -72,6 +72,22 @@ function testCustomWordPressDirectoryStructure($template, $size) { $exists = file_exists( $resized_path ); $this->assertTrue( $exists ); } + + function testDeleteSideloadedFile() { + $filename = 'acGwPDj4_400x400'; + $img = Timber\ImageHelper::sideload_image('https://pbs.twimg.com/profile_images/768086933310476288/'.$filename.'.jpg'); + $files = scandir('/tmp'); + $matches = false; + foreach ($files as $file) { + $substr = substr($file, 0, strlen($filename)); + echo $substr."\n"; + if ( $substr == $filename ) { + $matches = true; + } + } + $this->assertFalse($matches); + } + /** * @doesNotPerformAssertions */ From 3db0232fcca90b073e4ce01f6eeeb1e4f5a6badb Mon Sep 17 00:00:00 2001 From: Jared Novack Date: Wed, 26 Aug 2020 19:03:15 -0400 Subject: [PATCH 33/87] Update theming.md --- docs/getting-started/theming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/theming.md b/docs/getting-started/theming.md index 6a3c9d955..e51862426 100755 --- a/docs/getting-started/theming.md +++ b/docs/getting-started/theming.md @@ -10,7 +10,7 @@ menu: Let’s start with your single post. Find this file: ``` -wp-content/themes/{timber-starter-theme}/templates/single.twig +wp-content/themes/{timber-starter-theme}/views/single.twig ``` Brilliant! Open it up. From 3fabc800f33e85c3e3de15be62d0f43e2f1f2426 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Thu, 27 Aug 2020 16:21:38 -0700 Subject: [PATCH 34/87] #2093 port over changes from #2145 --- lib/Helper.php | 5 ++- lib/Timber.php | 99 ++++++++++++++++++++++++++++++++++++++----- tests/test-timber.php | 78 +++++++++++++++++++++++++++++++++- 3 files changed, 169 insertions(+), 13 deletions(-) diff --git a/lib/Helper.php b/lib/Helper.php index 4646eb0f4..af81a046a 100644 --- a/lib/Helper.php +++ b/lib/Helper.php @@ -237,8 +237,9 @@ public static function ob_function( $function, $args = array(null) ) { } /** + * Output a value (string, array, object, etc.) to the error log * - * + * @api * @param mixed $arg that you want to error_log * @return void */ @@ -387,7 +388,7 @@ public static function deprecated( $function, $replacement, $version ) { /** * Filters whether to trigger an error for deprecated functions. * - * @since 2.5.0 + * @since WordPress 2.5.0 * * @param bool $trigger Whether to trigger the error for deprecated functions. Default true. */ diff --git a/lib/Timber.php b/lib/Timber.php index feac83c01..02137abaa 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -174,9 +174,32 @@ class_alias( 'Timber\Timber', 'Timber' ); ================================ */ /** - * Get a post by post ID or query (as a query string or an array of arguments). + * Get a Timber Post from a post ID, WP_Post object, a WP_Query object, or an associative + * array of arguments for WP_Query::__construct(). + * + * By default, Timber will use the `Timber\Post` class to create a new post object. To control + * which class is instantiated for your Post object, use [Class Maps](https://timber.github.io/docs/v2/guides/class-maps/) * * @api + * @example + * ```php + * // Using a post ID. + * $post = Timber::get_post( 75 ); + * + * // Using a WP_Post object. + * $wp_post = get_post( 123 ); + * $post = Timber::get_post( $wp_post ); + * + * // Using a WP_Query argument array + * $post = Timber::get_post( [ + * 'post_type' => 'page', + * ] ); + * + * // Use currently queried post. Same as using get_the_ID() as a parameter. + * $post = Timber::get_post(); + * ``` + * @see https://developer.wordpress.org/reference/classes/wp_query/__construct/ + * * @param mixed $query Optional. Post ID or query (as an array of arguments for WP_Query). * If a query is provided, only the first post of the result will be * returned. Default false. @@ -185,7 +208,25 @@ class_alias( 'Timber\Timber', 'Timber' ); * @return \Timber\Post|bool Timber\Post object if a post was found, false if no post was * found. */ - public static function get_post( $query = false, array $options = [] ) { + public static function get_post( $query = false, $options = [] ) { + if ( is_string( $query ) && ! is_numeric( $query ) ) { + Helper::doing_it_wrong( + 'Timber::get_post()', + 'Getting a post by post slug or post name was removed from Timber::get_post() in Timber 2.0. Use Timber::get_post_by() instead.', + '2.0.0' + ); + } + + if ( is_string( $options ) ) { + Helper::doing_it_wrong( + 'Timber::get_post()', + 'The $PostClass parameter for passing in the post class to use in Timber::get_posts() was replaced with an $options array in Timber 2.0. To customize which class to instantiate for your post, use Class Maps instead: https://timber.github.io/docs/v2/guides/class-maps/', + '2.0.0' + ); + + $options = []; + } + $factory = new PostFactory(); global $wp_query; @@ -217,7 +258,42 @@ public static function get_post( $query = false, array $options = [] ) { * * @return array|bool|null */ - public static function get_posts( $query = false, array $options = [] ) { + public static function get_posts( $query = false, $options = [] ) { + if ( is_string( $query ) ) { + Helper::doing_it_wrong( + 'Timber::get_posts()', + "Querying posts by using a query string was removed in Timber 2.0. Pass in the query string as an options array instead. For example, change Timber::get_posts( 'post_type=portfolio&posts_per_page=3') to Timber::get_posts( [ 'post_type' => 'portfolio', 'posts_per_page' => 3 ] ). Learn more: https://timber.github.io/docs/v2/reference/timber-timber/#get_posts", + '2.0.0' + ); + + $query = new WP_Query( $query ); + } + + if ( is_string( $options ) ) { + Helper::doing_it_wrong( + 'Timber::get_posts()', + 'The $PostClass parameter for passing in the post class to use in Timber::get_posts() was replaced with an $options array in Timber 2.0. To customize which class to instantiate for your post, use Class Maps instead: https://timber.github.io/docs/v2/guides/class-maps/', + '2.0.0' + ); + $options = []; + } + + if ( 3 === func_num_args() ) { + Helper::doing_it_wrong( + 'Timber::get_posts()', + 'The $return_collection parameter to control whether a post collection is returned in Timber::get_posts() was removed in Timber 2.0.', + '2.0.0' + ); + } + + /** + * @todo Define all default $options. + * @todo Actually apply options. + */ + $options = wp_parse_args( $options, [ + 'merge_default' => false, + ] ); + $factory = new PostFactory(); // Default to the global query. @@ -230,10 +306,11 @@ public static function get_posts( $query = false, array $options = [] ) { * @api * @since 2.0.0 * @example - * ``` - * $post = Timber::get_post_by( 'slug', 'about-us' ); - * ``` * ```php + * // By slug + * $post = Timber::get_post_by( 'slug', 'about-us' ); + * + * // By title * $post = Timber::get_post_by( 'title', 'About us' ); * ``` * @@ -245,9 +322,9 @@ public static function get_posts( $query = false, array $options = [] ) { * @param array $args { * Optional. An array of arguments to configure what is returned. * - * @type string|array $post_type Optional. What WordPress post type to limit the + * @type string|array $post_type Optional. What WordPress post type to limit the * results to. Defaults to 'any' - * @type string $order_by Optional. The field to sort by. Defaults to + * @type string $order_by Optional. The field to sort by. Defaults to * 'post_date' * @type string $order Optional. The sort to apply. Defaults to ASC * @@ -326,7 +403,8 @@ public static function get_post_by( $type, $search_value, $args = array() ) { * @return Post|array|bool|null */ public static function query_post( $query = false, array $options = [] ) { - Helper::deprecated('Timber\Timber::query_post()', 'Timber\Timber::get_post()', '2.0.0'); + Helper::deprecated('Timber::query_post()', 'Timber::get_post()', '2.0.0'); + return self::get_post($query, $options); } @@ -342,7 +420,8 @@ public static function query_post( $query = false, array $options = [] ) { * @return PostCollection */ public static function query_posts( $query = false, array $options = [] ) { - Helper::deprecated('Timber\Timber::query_posts()', 'Timber\Timber::get_posts()', '2.0.0'); + Helper::deprecated('Timber::query_posts()', 'Timber::get_posts()', '2.0.0'); + return self::get_posts($query, $options); } diff --git a/tests/test-timber.php b/tests/test-timber.php index ff9e6b857..dd435a3e8 100644 --- a/tests/test-timber.php +++ b/tests/test-timber.php @@ -519,7 +519,7 @@ function testQueryPost() { } /** - * @expectedDeprecated Timber\Timber::query_post() + * @expectedDeprecated Timber::query_post() */ function testBlankQueryPost() { $pid = $this->factory->post->create( ); @@ -784,6 +784,82 @@ function testGetPostsDefault() { $this->assertCount( 10, Timber::get_posts() ); } + /** + * @expectedIncorrectUsage Timber::get_post() + */ + function testDeprecatedGetPostFromSlug(){ + $post_id = $this->factory->post->create( [ 'post_name' => 'mycoolpost' ] ); + $this->assertFalse( Timber::get_post( 'mycoolpost' ) ); + } + + /** + * @expectedIncorrectUsage Timber::get_post() + */ + function testDeprecatedPostClassParameterForGetPost() { + $post_id = $this->factory->post->create(); + $post = Timber\Timber::get_post( $post_id, 'Deprecated class name param' ); + + $this->assertInstanceOf( Post::class, $post ); + } + + /** + * @expectedIncorrectUsage Timber::get_posts() + */ + function testDeprecatedPostClassParameterForGetPosts() { + $this->factory->post->create_many( 2 ); + + $posts = Timber\Timber::get_posts([ + 'post_type' => 'post' + ], 'Deprecated class name param' ); + + $this->assertInstanceOf( Post::class, $posts[0] ); + } + + /** + * @expectedIncorrectUsage Timber::get_posts() + */ + function testDeprecatedQueryStringsForGetPosts() { + $this->factory->post->create_many( 2 ); + + $posts = Timber\Timber::get_posts( 'post_type=post' ); + $this->assertCount( 2, $posts ); + } + + /** + * @expectedIncorrectUsage Timber::get_posts() + */ + function testDeprecatedReturnCollectionParameterInGetPosts() { + $this->factory->post->create_many( 2 ); + + $posts = Timber\Timber::get_posts( + [ 'post_type' => 'post' ], + 'Timber\Post', + true + ); + + $this->assertEquals( 'Timber\Post', get_class( $posts[0] ) ); + } + + /** + * @expectedDeprecated Timber::query_post() + */ + function testDeprecatedQueryPost() { + $post_id = $this->factory->post->create( [ 'post_type' => 'post' ] ); + $post = Timber\Timber::query_post( $post_id ); + + $this->assertEquals( $post->ID, $post_id ); + } + + /** + * @expectedDeprecated Timber::query_posts() + */ + function testDeprecatedQueryPosts() { + $post_ids = $this->factory->post->create_many( 3, [ 'post_type' => 'post' ] ); + $posts = Timber\Timber::query_posts( [ 'post_type' => 'post' ] ); + + $this->assertEquals( $posts[0]->ID, $post_ids[0] ); + } + /* * @todo add more test coverage here... */ From a823abf613ac2e49c49d00223365f7e31527aeb6 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Thu, 27 Aug 2020 16:34:26 -0700 Subject: [PATCH 35/87] #2093 fix a couple broken tests Assuming the post ID check failed because post_date was the same across posts --- tests/test-timber-pagination.php | 6 ++++-- tests/test-timber.php | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test-timber-pagination.php b/tests/test-timber-pagination.php index afc6a20a4..febcebb5f 100644 --- a/tests/test-timber-pagination.php +++ b/tests/test-timber-pagination.php @@ -40,13 +40,15 @@ function testPaginationWithGetPosts() { $pids = $this->factory->post->create_many( 33 ); $pids = $this->factory->post->create_many( 55, array( 'post_type' => 'portfolio' ) ); $this->go_to( home_url( '/' ) ); - Timber::get_posts('post_type=portfolio'); + Timber::get_posts([ + 'post_type' => 'portfolio' + ]); $pagination = Timber::get_pagination(); global $timber; $timber->active_query = false; unset($timber->active_query); - $this->assertEquals(4, count($pagination['pages'])); + $this->assertCount(4, $pagination['pages']); } function testPaginationWithPostQuery() { diff --git a/tests/test-timber.php b/tests/test-timber.php index dd435a3e8..8334a83d0 100644 --- a/tests/test-timber.php +++ b/tests/test-timber.php @@ -857,7 +857,7 @@ function testDeprecatedQueryPosts() { $post_ids = $this->factory->post->create_many( 3, [ 'post_type' => 'post' ] ); $posts = Timber\Timber::query_posts( [ 'post_type' => 'post' ] ); - $this->assertEquals( $posts[0]->ID, $post_ids[0] ); + $this->assertCount( 3, $posts ); } /* From 6003e17c426425d1a7e2c4d1d407992c2704184d Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Thu, 27 Aug 2020 16:56:01 -0700 Subject: [PATCH 36/87] #2093 fix Post::convert() --- lib/Post.php | 9 +-------- tests/test-timber-integrations.php | 7 ++++--- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/lib/Post.php b/lib/Post.php index 63075767a..2ad24d5b2 100644 --- a/lib/Post.php +++ b/lib/Post.php @@ -1859,14 +1859,7 @@ public function convert( $data ) { if ( is_object($data) ) { $data = Helper::convert_wp_object($data); } else if ( is_array($data) ) { - $func = __FUNCTION__; - foreach ( $data as &$ele ) { - if ( is_array($ele) ) { - $ele = $this->$func($ele); - } else if ( is_object($ele) ) { - $ele = Helper::convert_wp_object($ele); - } - } + $data = array_map([$this, 'convert'], $data); } return $data; } diff --git a/tests/test-timber-integrations.php b/tests/test-timber-integrations.php index e66391915..56f63b501 100644 --- a/tests/test-timber-integrations.php +++ b/tests/test-timber-integrations.php @@ -1,6 +1,7 @@ factory->post->create(); $wp_post = get_post( $pid ); - $post = Timber::get_post(); - $timber_post = $post->convert( $wp_post ); - $this->assertTrue( $timber_post instanceof Timber\Post ); + $post = Timber::get_post( $pid ); + + $this->assertInstanceOf( Post::class, $post->convert($wp_post) ); } function testWPCLIClearCacheTimber(){ From c48af0fc071bd100e95492f4b0bb4b8bc15b21f0 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Fri, 28 Aug 2020 20:08:48 +0000 Subject: [PATCH 37/87] #2093 overhaul Term::posts() --- lib/Term.php | 134 ++++++++------ tests/test-timber-term.php | 345 +++++++++++++++++++++++-------------- 2 files changed, 301 insertions(+), 178 deletions(-) diff --git a/lib/Term.php b/lib/Term.php index 4546dc1db..9b188b824 100644 --- a/lib/Term.php +++ b/lib/Term.php @@ -2,6 +2,7 @@ namespace Timber; +use WP_Query; use WP_Term; /** @@ -555,11 +556,27 @@ public function path() { * * @api * @example + * Query the default posts_per_page for this Term: + * + * ```twig + *

Recent posts in {{ term.name }}

+ * + *
    + * {% for post in term.posts() %} + *
  • + * {{ post.title }} + *
  • + * {% endfor %} + *
+ * ``` + * + * Query exactly 3 Posts from this Term: + * * ```twig *

Recent posts in {{ term.name }}

* *
    - * {% for post in term.posts(3, 'post') %} + * {% for post in term.posts(3) %} *
  • * {{ post.title }} *
  • @@ -586,61 +603,74 @@ public function path() { * ``` * * @param int|array $numberposts_or_args Optional. Either the number of posts or an array of - * arguments for the post query that this method is going. - * to perform. Default `10`. - * @param string $post_type_or_class Optional. Either the post type to get or the name of - * post class to use for the returned posts. Default - * `any`. - * @param string $post_class Optional. The name of the post class to use for the - * returned posts. Default `Timber\Post`. + * arguments for the post query to be performed. + * Default is an empty array, the equivalent of: + * ```php + * [ + * 'posts_per_page' => get_option('posts_per_page'), + * 'post_type' => 'any', + * 'tax_query' => [ ...tax query for this Term... ] + * ] + * ``` + * Note that this *used* to be + * @param string $post_type_or_class Deprecated. Before Timber 2.x this was a post_type to be + * used for querying posts OR the Timber\Post subclass to + * instantiate for each post returned. As of Timber 2.0.0, + * specify `post_type` in the `$query` array argument. To + * specify the class, use Class Maps. + * @see https://timber.github.io/docs/v2/guides/posts/ + * @see https://timber.github.io/docs/v2/guides/class-maps/ * @return \Timber\PostQuery - * @todo implement this via Timber::get_posts() instead */ - public function posts( $numberposts_or_args = 10, $post_type_or_class = 'any', $post_class = '' ) { - if ( !strlen($post_class) ) { - $post_class = $this->PostClass; + public function posts( $query = [], $post_type_or_class = null ) { + if ( is_string($query) ) { + Helper::doing_it_wrong( + 'Passing a query string to Term::posts()', + 'Pass a query array instead: e.g. `"posts_per_page=3"` should be replaced with `["posts_per_page" => 3]`', + '2.0.0' + ); + + return false; } - $default_tax_query = array(array( - 'field' => 'id', - 'terms' => $this->ID, - 'taxonomy' => $this->taxonomy, - )); - if ( is_string($numberposts_or_args) && strstr($numberposts_or_args, '=') ) { - $args = $numberposts_or_args; - $new_args = array(); - parse_str($args, $new_args); - $args = $new_args; - $args['tax_query'] = $default_tax_query; - if ( !isset($args['post_type']) ) { - $args['post_type'] = 'any'; - } - if ( class_exists($post_type_or_class) ) { - $post_class = $post_type_or_class; - } - } else if ( is_array($numberposts_or_args) ) { - //they sent us an array already baked - $args = $numberposts_or_args; - if ( !isset($args['tax_query']) ) { - $args['tax_query'] = $default_tax_query; - } - if ( class_exists($post_type_or_class) ) { - $post_class = $post_type_or_class; - } - if ( !isset($args['post_type']) ) { - $args['post_type'] = 'any'; - } - } else { - $args = array( - 'numberposts_or_args' => $numberposts_or_args, - 'tax_query' => $default_tax_query, - 'post_type' => $post_type_or_class + + if ( is_int($query) ) { + $query = [ + 'posts_per_page' => $query, + 'post_type' => 'any', + ]; + } + + if ( isset($post_type_or_class) ) { + Helper::deprecated( + 'Passing post_type_or_class', + 'Pass post_type as part of the $query argument. For specifying class, use Class Maps: https://timber.github.io/docs/v2/guides/class-maps/', + '2.0.0' ); + + // Honor the non-deprecated posts_per_page param over the deprecated second arg. + $query['post_type'] = $query['post_type'] ?? $post_type_or_class; } - return new PostQuery( array( - 'query' => $args, - 'post_class' => $post_class, - ) ); + if ( func_num_args() > 2 ) { + Helper::doing_it_wrong( + 'Passing a post class', + 'Use Class Maps instead: https://timber.github.io/docs/v2/guides/class-maps/', + '2.0.0' + ); + } + + $tax_query = [ + [ + 'field' => 'id', + 'terms' => $this->ID, + 'taxonomy' => $this->taxonomy, + ], + ]; + + // Merge a clause for this Term into any user-specified tax_query clauses. + $query['tax_query'] = array_merge($query['tax_query'] ?? [], $tax_query); + + return Timber::get_posts( $query ); } @@ -663,13 +693,11 @@ public function title() { * @deprecated 2.0.0 use `{{ term.posts }}` instead * * @param int $numberposts - * @param string $post_type - * @param string $PostClass * @return array|bool|null */ public function get_posts( $numberposts = 10, $post_type = 'any', $PostClass = '' ) { Helper::deprecated('{{ term.get_posts }}', '{{ term.posts }}', '2.0.0'); - return $this->posts($numberposts, $post_type, $PostClass); + return $this->posts($numberposts); } /** diff --git a/tests/test-timber-term.php b/tests/test-timber-term.php index c0dea5ebf..0c07556bb 100644 --- a/tests/test-timber-term.php +++ b/tests/test-timber-term.php @@ -1,5 +1,9 @@ assertFalse(strstr($term->path(), 'http://')); } - function testGetPostsWithPostTypesString() { - register_post_type('portfolio', array('taxonomies' => array('post_tag'), 'public' => true)); - $term_id = $this->factory->term->create(array('name' => 'Zong')); - $posts = $this->factory->post->create_many(3, array('post_type' => 'post', 'tags_input' => 'zong') ); - $posts = $this->factory->post->create_many(5, array('post_type' => 'portfolio', 'tags_input' => 'zong') ); - $term = Timber::get_term($term_id); - $posts_gotten = $term->posts('posts_per_page=4'); - $this->assertEquals(4, count($posts_gotten)); - $posts_gotten = $term->posts(array('posts_per_page' => 7)); - $this->assertEquals(7, count($posts_gotten)); - } - function testPosts() { + /* + * Term::posts() tests + */ + + function testPostsDefault() { register_post_type('portfolio', array('taxonomies' => array('arts'), 'public' => true)); - register_taxonomy('arts', array('portfolio')); + register_taxonomy('arts', array('portfolio', 'post')); - // create a term, and some posts to assign it to + // Create a term, and some posts to assign it to. $term_id = $this->factory->term->create(array('name' => 'Zong', 'taxonomy' => 'arts')); - $posts = $this->factory->post->create_many(5, array('post_type' => 'portfolio' )); + + // Create 12 posts total. + // NOTE: Neither post_type has enough to satisfy the assertion below on its own, + // but together they should exceed the default posts_per_page and we should get + // exactly posts_per_page (10) back. + $posts = array_merge( + $this->factory->post->create_many(5), + $this->factory->post->create_many(7, ['post_type' => 'portfolio']) + ); // assign the term to each of our new posts - foreach($posts as $post_id) { + foreach ($posts as $post_id) { wp_set_object_terms($post_id, $term_id, 'arts', true); } + $other_id = $this->factory->term->create(array('name' => 'Other', 'taxonomy' => 'arts')); + $other_posts = $this->factory->post->create_many(10); + foreach ($other_posts as $id) { + wp_set_object_terms($id, $other_id, 'arts', true); + } + $term = Timber::get_term($term_id); - $this->assertEquals(5, count($term->posts())); + // Expect the default posts_per_page, with posts of all types. + $this->assertCount(10, $term->posts()); + // Passing an empty array should behave exactly the same. + $this->assertCount(10, $term->posts([])); } - /** - * @expectedDeprecated {{ term.get_posts }} - */ - function testGetPostsOld() { - $term_id = $this->factory->term->create(); - $posts = array(); - $posts[] = $this->factory->post->create(); - $posts[] = $this->factory->post->create(); - $posts[] = $this->factory->post->create(); - foreach($posts as $post_id){ - wp_set_object_terms($post_id, $term_id, 'post_tag', true); - } - $term = Timber::get_term($term_id); - $gotten_posts = $term->get_posts(); - $this->assertEquals(count($posts), count($gotten_posts)); - } + function testPostsDefaultPostType() { + register_post_type('portfolio', array('taxonomies' => array('arts'), 'public' => true)); + register_taxonomy('arts', array('portfolio', 'post')); - function testGetPostsAsPageOld() { - $term_id = $this->factory->term->create(); - $posts = array(); - $posts[] = $this->factory->post->create(); - $posts[] = $this->factory->post->create(); - $posts[] = $this->factory->post->create(); - foreach($posts as $post_id){ - set_post_type($post_id, 'page'); - wp_set_object_terms($post_id, $term_id, 'post_tag', true); + // Create a term, and some posts to assign it to. + $term_id = $this->factory->term->create(array('name' => 'Zong', 'taxonomy' => 'arts')); + + // Create 12 posts total. + // NOTE: Neither post_type has enough to satisfy the assertion below on its own, + // but together they should exceed the 8 we ask for so we should get exactly 8 back. + // This is because, according to the docs, post_type defaults to "any" when using + // tax_query. + // https://developer.wordpress.org/reference/classes/WP_Query/parse_query/ + $posts = array_merge( + $this->factory->post->create_many(5), + $this->factory->post->create_many(7, ['post_type' => 'portfolio']) + ); + + // assign the term to each of our new posts + foreach ($posts as $post_id) { + wp_set_object_terms($post_id, $term_id, 'arts', true); } + $term = Timber::get_term($term_id); - $gotten_posts = $term->posts(count($posts), 'page'); - $this->assertEquals(count($posts), count($gotten_posts)); - $gotten_posts = $term->posts(count($posts), 'any'); - $this->assertEquals(count($posts), count($gotten_posts)); - $gotten_posts = $term->posts(count($posts), 'post'); - $this->assertEquals(0, count($gotten_posts)); + + // Expect exactly the count we asked for. + $this->assertCount(8, $term->posts([ + 'posts_per_page' => 8, + ])); } - /** - * @expectedDeprecated {{ term.get_posts }} - */ - function testGetPostsNew() { - $this->markTestSkipped('@todo reimplement Term::posts() using ::get_posts()'); - require_once('php/timber-post-subclass.php'); - $term_id = $this->factory->term->create(); - $posts = array(); - $posts[] = $this->factory->post->create(); - $posts[] = $this->factory->post->create(); - $posts[] = $this->factory->post->create(); - foreach($posts as $post_id){ - set_post_type($post_id, 'page'); - wp_set_object_terms($post_id, $term_id, 'post_tag', true); + function testPostsWithPostTypeQuery() { + register_post_type('portfolio', array('taxonomies' => array('arts'), 'public' => true)); + register_taxonomy('arts', array('portfolio', 'post')); + + // Create a term, and some posts to assign it to. + $term_id = $this->factory->term->create(array('name' => 'Zong', 'taxonomy' => 'arts')); + + // Create 12 posts total. But we should only get 7 back below even though posts_per_page + // defaults to 10, because we limit by post_type. + $posts = array_merge( + $this->factory->post->create_many(5), + $this->factory->post->create_many(7, ['post_type' => 'portfolio']) + ); + + // assign the term to each of our new posts + foreach($posts as $post_id) { + wp_set_object_terms($post_id, $term_id, 'arts', true); } - $term = Timber::get_term($term_id); - $gotten_posts = $term->get_posts('post_type=page'); - $this->assertEquals(count($posts), count($gotten_posts)); - $gotten_posts = $term->get_posts('post_type=page', 'TimberPostSubclass'); - $this->assertEquals(count($posts), count($gotten_posts)); - $this->assertInstanceOf( 'TimberPostSubclass', $gotten_posts[0] ); + $term = Timber::get_term($term_id); - $gotten_posts = $term->get_posts(array('post_type' => 'page'), 'TimberPostSubclass'); - $this->assertInstanceOf( 'TimberPostSubclass', $gotten_posts[0] ); - $this->assertEquals(count($posts), count($gotten_posts)); + // Expect the default posts_per_page, with posts of all types. + $this->assertCount(7, $term->posts([ + 'post_type' => 'portfolio', + ])); } - function testPostsWithCustomPostType() { - $term_id = $this->factory->term->create(); - $posts = array(); - $posts[] = $this->factory->post->create(); - $posts[] = $this->factory->post->create(); - $posts[] = $this->factory->post->create(); + function testPostsWithTaxQuery() { + register_post_type('portfolio', array('taxonomies' => array('arts'), 'public' => true)); + register_taxonomy('arts', array('portfolio', 'post')); + + // Create a term, and some posts to assign it to. + $term_id = $this->factory->term->create(['taxonomy' => 'arts']); + + // Create 12 posts total. + // NOTE: Neither post_type has enough to satisfy the assertion below on its own, + // but together they should exceed the 8 we ask for so we should get exactly 8 back. + // This is because, according to the docs, post_type defaults to "any" when using + // tax_query. + // https://developer.wordpress.org/reference/classes/WP_Query/parse_query/ + $posts = array_merge( + $this->factory->post->create_many(5), + $this->factory->post->create_many(7, ['post_type' => 'portfolio']) + ); - foreach ( $posts as $post_id ) { - set_post_type( $post_id, 'page' ); - wp_set_object_terms( $post_id, $term_id, 'post_tag', true ); + // assign the term to each of our new posts + foreach ($posts as $post_id) { + wp_set_object_terms($post_id, $term_id, 'arts', true); } - $term = Timber::get_term( $term_id ); + // Tag one post and one portfolio with a special crafts term, too. + register_taxonomy('crafts', array('portfolio', 'post')); + $craft_id = $this->factory->term->create(['taxonomy' => 'crafts']); + wp_set_object_terms($posts[0], $craft_id, 'crafts', true); + wp_set_object_terms($posts[5], $craft_id, 'crafts', true); - $term_posts = $term->posts( [ - 'posts_per_page' => 2, - 'orderby' => 'menu_order', - ], 'page' ); + $term = Timber::get_term($term_id); - $this->assertEquals( 'Timber\Post', get_class( $term_posts[0] ) ); - $this->assertEquals( 'page', $term_posts[0]->post_type ); - $this->assertEquals( 2, count( $term_posts ) ); + // Expect the intersection of arts & crafts. + $this->assertCount(2, $term->posts([ + 'tax_query' => [ + [ + 'field' => 'id', + 'terms' => $craft_id, + 'taxonomy' => 'crafts', + ] + ], + ])); } - function testPostsWithCustomPostTypeAndCustomClass() { - require_once 'php/timber-post-subclass.php'; + /** + * @expectedIncorrectUsage Passing a query string to Term::posts() + */ + function testGetPostsWithQueryString() { + register_post_type('portfolio', array('taxonomies' => array('post_tag'), 'public' => true)); + $term_id = $this->factory->term->create(array('name' => 'Zong')); + $this->factory->post->create_many(3, array('post_type' => 'post', 'tags_input' => 'zong') ); + $this->factory->post->create_many(5, array('post_type' => 'portfolio', 'tags_input' => 'zong') ); - $term_id = $this->factory->term->create(); - $posts = array(); - $posts[] = $this->factory->post->create(); - $posts[] = $this->factory->post->create(); - $posts[] = $this->factory->post->create(); + // Count is mismatched because string-based queries default to a post_type of "post". + $term = Timber::get_term($term_id); + $this->assertFalse($term->posts('posts_per_page=8')); + } - foreach ( $posts as $post_id ) { - set_post_type( $post_id, 'page' ); - wp_set_object_terms( $post_id, $term_id, 'post_tag', true ); - } + /** + * @expectedDeprecated Passing post_type_or_class + * This test *partially* honors the logic described in + * https://github.com/timber/timber/issues/799#issuecomment-192445207, + * although that behavior is not deprecated. + */ + function testGetPostsWithPostTypeArg() { + register_post_type('portfolio', array('taxonomies' => array('post_tag'), 'public' => true)); + $term_id = $this->factory->term->create(array('name' => 'Zong')); + $this->factory->post->create_many(3, array('post_type' => 'post', 'tags_input' => 'zong') ); + $this->factory->post->create_many(5, array('post_type' => 'portfolio', 'tags_input' => 'zong') ); - $term = Timber::get_term( $term_id ); + $term = Timber::get_term($term_id); + $this->assertCount(3, $term->posts([ + 'orderby' => 'menu_order', + ], 'post')); + } - $term_posts = $term->posts( [ - 'posts_per_page' => 2, - 'orderby' => 'menu_order', - ], 'page', 'TimberPostSubclass' ); + /** + * @expectedIncorrectUsage Passing a post class + */ + function testGetPostsWithPostClassArg() { + register_post_type('portfolio', array('taxonomies' => array('post_tag'), 'public' => true)); + $term_id = $this->factory->term->create(array('name' => 'Zong')); + $this->factory->post->create_many(3, array('post_type' => 'post', 'tags_input' => 'zong') ); + $this->factory->post->create_many(5, array('post_type' => 'portfolio', 'tags_input' => 'zong') ); - $this->markTestSkipped('@todo reimplement Term::posts() using ::get_posts()'); - $this->assertInstanceOf( 'TimberPostSubclass', $term_posts[0] ); - $this->assertEquals( 'page', $term_posts[0]->post_type ); - $this->assertEquals( 2, count( $term_posts ) ); + $term = Timber::get_term($term_id); + $this->assertCount(3, $term->posts([ + 'orderby' => 'menu_order', + ], null, 'INCORRECT')); } /** - * This test uses the logic described in https://github.com/timber/timber/issues/799#issuecomment-192445207. + * @expectedDeprecated {{ term.get_posts }} */ - function testPostsWithCustomPostTypePageAndCustomClass() { - require_once 'php/timber-post-subclass.php'; - require_once 'php/timber-post-subclass-page.php'; + function testGetPostsDeprecated() { + $term_id = $this->factory->term->create(['name' => 'Rad']); + $posts = $this->factory->post->create_many(3, [ + 'tags_input' => 'rad', + ]); + $term = Timber::get_term($term_id); - $term_id = $this->factory->term->create(); - $posts = array(); - $posts[] = $this->factory->post->create(); - $posts[] = $this->factory->post->create(); - $posts[] = $this->factory->post->create(); + $this->assertCount(3, $term->get_posts()); + } - foreach ( $posts as $post_id ) { - set_post_type( $post_id, 'page' ); + function testPostsWithPostCount() { + $term_id = $this->factory->term->create(); + // Assign some pages to our post_tag Term. + $page_ids = $this->factory->post->create_many(3, [ + 'post_type' => 'page', + 'post_date' => '2020-01-01', + ]); + // Create some posts too. + $post_ids = $this->factory->post->create_many(3, [ + 'post_date' => '2019-01-01', + ]); + // Tag all posts. + foreach ( array_merge($page_ids, $post_ids) as $post_id ) { wp_set_object_terms( $post_id, $term_id, 'post_tag', true ); } + $this->register_post_classmap_temporarily([ + 'page' => TermTestPage::class, + ]); + + // Get the first four posts from this term. + $term_posts = Timber::get_term( $term_id )->posts( 4 ); + + $this->assertCount( 4, $term_posts ); + + // Pages should come first due to later publish dates. + $this->assertInstanceOf( TermTestPage::class, $term_posts[0] ); + $this->assertInstanceOf( TermTestPage::class, $term_posts[1] ); + $this->assertInstanceOf( TermTestPage::class, $term_posts[2] ); + $this->assertInstanceOf( Post::class, $term_posts[3] ); + } + + function testPostsWithExtraQueryArgs() { + $term_id = $this->factory->term->create(['name' => 'Rad']); + + $posts = [ + $this->factory->post->create([ + 'post_title' => 'Earlier', + 'post_date' => '2020-01-01', + 'tags_input' => 'rad', + ]), + $this->factory->post->create([ + 'post_title' => 'Later', + 'post_date' => '2020-03-01', + 'tags_input' => 'rad', + ]), + $this->factory->post->create([ + 'post_title' => 'Much Later', + 'post_date' => '2020-08-01', + 'tags_input' => 'rad', + ]), + ]; + $term = Timber::get_term( $term_id ); $term_posts = $term->posts( [ 'posts_per_page' => 2, - 'orderby' => 'menu_order', - ], 'page', 'TimberPostSubclass' ); + 'orderby' => 'post_date', + 'order' => 'ASC' + ] ); - $this->markTestSkipped('@todo reimplement Term::posts() using ::get_posts()'); - $this->assertInstanceOf( 'page', $term_posts[0] ); - $this->assertEquals( 'page', $term_posts[0]->post_type ); - $this->assertEquals( 2, count( $term_posts ) ); + $this->assertCount( 2, $term_posts ); + $this->assertEquals( 'Earlier', $term_posts[0]->title() ); + $this->assertEquals( 'Later', $term_posts[1]->title() ); } function testTermChildren() { From 97459f8a635f49fb3019e09ce71f2097f4ee6f32 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Fri, 28 Aug 2020 20:13:30 +0000 Subject: [PATCH 38/87] #2093 prevent users from overriding term clause via Term::posts() --- lib/Term.php | 2 ++ tests/test-timber-term.php | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/Term.php b/lib/Term.php index 9b188b824..0761327fd 100644 --- a/lib/Term.php +++ b/lib/Term.php @@ -660,6 +660,8 @@ public function posts( $query = [], $post_type_or_class = null ) { } $tax_query = [ + // Force a tax_query constraint on this term. + 'relation' => 'AND', [ 'field' => 'id', 'terms' => $this->ID, diff --git a/tests/test-timber-term.php b/tests/test-timber-term.php index 0c07556bb..758ccc0c7 100644 --- a/tests/test-timber-term.php +++ b/tests/test-timber-term.php @@ -236,7 +236,10 @@ function testPostsWithTaxQuery() { 'field' => 'id', 'terms' => $craft_id, 'taxonomy' => 'crafts', - ] + ], + // This should get overridden; we don't want users to be able to + // override the Term we're querying for. + 'relation' => 'OR', ], ])); } From 9ce2d5d53113c967ee9cb4c5d77ccbcc3f16f6cb Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Fri, 28 Aug 2020 15:01:21 -0700 Subject: [PATCH 39/87] #2093 implement default Class Map callback for attachments Distinguish between Images (more specific) and generic Attachment post objects. --- lib/Factory/PostFactory.php | 60 +++++++++++------ tests/TimberAttachment_UnitTestCase.php | 2 +- tests/test-timber-attachment.php | 88 ++++++++++++++++++++++++- 3 files changed, 126 insertions(+), 24 deletions(-) diff --git a/lib/Factory/PostFactory.php b/lib/Factory/PostFactory.php index 72b7fd869..fd156ccf2 100644 --- a/lib/Factory/PostFactory.php +++ b/lib/Factory/PostFactory.php @@ -4,6 +4,8 @@ use Timber\Attachment; use Timber\CoreInterface; +use Timber\Image; +use Timber\PathHelper; use Timber\Post; use Timber\PostArrayObject; use Timber\PostQuery; @@ -39,15 +41,15 @@ public function from($params) { return false; } - protected function from_id(int $id) { + protected function from_id(int $id) { $wp_post = get_post($id); if (!$wp_post) { return false; } - return $this->build($wp_post); - } + return $this->build($wp_post); + } protected function from_post_object(object $obj) : CoreInterface { if ($obj instanceof CoreInterface) { @@ -71,31 +73,49 @@ protected function from_wp_query(WP_Query $query) : Iterable { } protected function get_post_class(WP_Post $post) : string { - // Get the user-configured Class Map - $map = apply_filters( 'timber/post/classmap', [ - 'post' => Post::class, - 'page' => Post::class, - // @todo special logic for attachments? - 'attachment' => Attachment::class, - ] ); + // Get the user-configured Class Map + $map = apply_filters( 'timber/post/classmap', [ + 'post' => Post::class, + 'page' => Post::class, + // Apply special logic for attachments. + 'attachment' => function(WP_Post $attachment) { + return $this->is_image($attachment) ? Image::class : Attachment::class; + }, + ] ); $class = $map[$post->post_type] ?? null; - // If class is a callable, call it to get the actual class name - if (is_callable($class)) { - $class = $class($post); - } + // If class is a callable, call it to get the actual class name + if (is_callable($class)) { + $class = $class($post); + } - // If we don't have a post class by now, fallback on the default class - return $class ?? Post::class; + // If we don't have a post class by now, fallback on the default class + return $class ?? Post::class; } - protected function build(WP_Post $post) : CoreInterface { + protected function is_image(WP_Post $post) { + $src = wp_get_attachment_url( $post->ID ); + $check = wp_check_filetype( PathHelper::basename( $src ) ); + + $extensions = apply_filters( 'timber/post/image_extensions', [ + 'jpg', + 'jpeg', + 'jpe', + 'gif', + 'png', + 'webp', + ] ); + + return in_array( $check['ext'], $extensions ); + } + + protected function build(WP_Post $post) : CoreInterface { $class = $this->get_post_class($post); - // @todo make Core constructors protected, call Post::build() here - return new $class($post); - } + // @todo make Core constructors protected, call Post::build() here + return new $class($post); + } protected function is_numeric_array($arr) { if ( ! is_array($arr) ) { diff --git a/tests/TimberAttachment_UnitTestCase.php b/tests/TimberAttachment_UnitTestCase.php index 04c4d0532..b3f584d81 100644 --- a/tests/TimberAttachment_UnitTestCase.php +++ b/tests/TimberAttachment_UnitTestCase.php @@ -84,7 +84,7 @@ public static function get_attachment( $pid = 0, $file = 'arch.jpg' ) { public static function get_timber_attachment_object($file = 'cropper.png') { $iid = self::get_attachment(0, $file); - return new Timber\Image($iid); + return Timber::get_post( $iid ); } } diff --git a/tests/test-timber-attachment.php b/tests/test-timber-attachment.php index 1b92b626d..b388292e2 100644 --- a/tests/test-timber-attachment.php +++ b/tests/test-timber-attachment.php @@ -1,14 +1,89 @@ add_filter_temporarily('upload_mimes', function($types) { + return array_merge($types, [ + 'webp' => 'image/webp', + ]); + }); + + // Create 7 attachment posts with different extensions. + $pids = $this->factory->post->create_many(7, [ + 'post_type' => 'attachment', + ]); + $attachment_ids = array_map([self::class, 'get_attachment'], $pids, [ + 'hebrew.jpg', + 'jarednova.jpeg', + 'robocop.gif', + 'flag.png', + 'mountains.webp', + 'dummy-pdf.pdf', + 'white-castle.tif', + ]); + + // Instantiate our various attachment posts. + $attachments = array_map([Timber::class, 'get_post'], $attachment_ids); + + $this->assertInstanceOf(Image::class, $attachments[0]); // hebrew.jpg + $this->assertInstanceOf(Image::class, $attachments[1]); // jarednova.jpeg + $this->assertInstanceOf(Image::class, $attachments[2]); // robocop.gif + $this->assertInstanceOf(Image::class, $attachments[3]); // flag.png + $this->assertInstanceOf(Image::class, $attachments[4]); // mountains.webp + + // PDFs and TIFs should be returned as Attachments but NOT images. + $this->assertEquals(Attachment::class, get_class($attachments[5])); + $this->assertEquals(Attachment::class, get_class($attachments[6])); + } + + function testAttachmentWithExtentionFilter() { + // Add support for "uploading" WEBP images. + $this->add_filter_temporarily('upload_mimes', function($types) { + return array_merge($types, [ + 'webp' => 'image/webp', + ]); + }); + + // Create 7 attachment posts with different extensions. + $pids = $this->factory->post->create_many(7, [ + 'post_type' => 'attachment', + ]); + $attachment_ids = array_map([self::class, 'get_attachment'], $pids, [ + 'hebrew.jpg', + 'jarednova.jpeg', + 'robocop.gif', + 'flag.png', + 'mountains.webp', + 'dummy-pdf.pdf', + 'white-castle.tif', + ]); + + $this->add_filter_temporarily('timber/post/image_extensions', function() { + // ONLY these extensions should be considered images. + return ['webp', 'pdf', 'tif']; + }); + + // Instantiate our various attachment posts. + $attachments = array_map([Timber::class, 'get_post'], $attachment_ids); + + $this->assertEquals(Attachment::class, get_class($attachments[0])); // hebrew.jpg + $this->assertEquals(Attachment::class, get_class($attachments[1])); // jarednova.jpeg + $this->assertEquals(Attachment::class, get_class($attachments[2])); // robocop.gif + $this->assertEquals(Attachment::class, get_class($attachments[3])); // flag.png + $this->assertEquals(Image::class, get_class($attachments[4])); // mountains.webp + $this->assertEquals(Image::class, get_class($attachments[5])); // dummy-pdf.pdf + $this->assertEquals(Image::class, get_class($attachments[6])); // white-castle.tif + } function testAttachmentLink() { self::setPermalinkStructure(); @@ -28,6 +103,7 @@ function testAttachmentInitWithWP_Post() { } function testAttachmentArray() { + $this->markTestSkipped('@todo drop support for this'); $post_id = $this->factory->post->create(); $filename = self::copyTestAttachment('arch.jpg'); $wp_filetype = wp_check_filetype( basename( $filename ), null ); @@ -46,6 +122,7 @@ function testAttachmentArray() { } function testAttachmentPath() { + $this->markTestSkipped('@todo Image::from_file'); $filename = self::copyTestAttachment( 'arch.jpg' ); $image = new Timber\Image( $filename ); $this->assertStringStartsWith('/wp-content', $image->path()); @@ -62,6 +139,7 @@ function testInitFromID() { } function testInitFromFilePath() { + $this->markTestSkipped('@todo Image::from_file'); $attachment_file = self::copyTestAttachment(); $attachment = new Timber\Attachment( $attachment_file ); $size = $attachment->size_raw(); @@ -69,6 +147,7 @@ function testInitFromFilePath() { } function testInitFromRelativePath() { + $this->markTestSkipped('@todo Image::from_file'); $filename = self::copyTestAttachment( 'arch.jpg' ); $path = str_replace(ABSPATH, '/', $filename); $attachment = new Timber\Attachment( $path ); @@ -77,6 +156,7 @@ function testInitFromRelativePath() { } function testInitFromURL() { + $this->markTestSkipped('@todo Image::from_url'); $destination_path = self::copyTestAttachment(); $destination_path = Timber\URLHelper::get_rel_path( $destination_path ); $destination_url = 'http://'.$_SERVER['HTTP_HOST'].$destination_path; @@ -86,6 +166,7 @@ function testInitFromURL() { } function testPathInfo() { + $this->markTestSkipped('@todo Image::from_file'); $filename = self::copyTestAttachment( 'arch.jpg' ); $image = new Timber\Attachment( $filename ); $path_parts = $image->get_pathinfo(); @@ -124,6 +205,7 @@ function testFileSizeRaw() { $str = '{{ Attachment(post).size_raw }}'; $result = Timber::compile_string( $str, array( 'post' => $iid ) ); $this->assertEquals('16555', $result); + $this->assertFalse(Timber::get_post($iid)->is_image()); } function testFileExtension() { From b5f9ee8a92c2bdf43e8199952b99f36b76591ece Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Fri, 28 Aug 2020 15:22:23 -0700 Subject: [PATCH 40/87] #2093 backport webp extension and image ext. filter to Image::is_image() --- lib/Image.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/Image.php b/lib/Image.php index 879f5df77..7a7dfcc6f 100644 --- a/lib/Image.php +++ b/lib/Image.php @@ -408,7 +408,15 @@ public function img_sizes( $size = "full" ) { protected function is_image() { $src = wp_get_attachment_url( $this->ID ); $check = wp_check_filetype( PathHelper::basename( $src ), null ); - $image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png' ); + $image_exts = apply_filters( 'timber/post/image_extensions', [ + 'jpg', + 'jpeg', + 'jpe', + 'gif', + 'png', + 'webp', + ] ); + return in_array( $check['ext'], $image_exts ); } From 560575c4341bbb2122d69a1c2b3327e388a7cdd2 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Fri, 28 Aug 2020 16:23:37 -0700 Subject: [PATCH 41/87] #2094 replace direct Attachment/Image instantiations --- lib/Image.php | 12 ++---------- tests/test-timber-attachment.php | 22 +++++++++++++++------- tests/test-timber-image-path-helper.php | 2 +- tests/test-timber-image-retina.php | 25 +++++++++++++++---------- tests/test-timber-image.php | 17 ++++++++--------- tests/test-timber-post.php | 2 +- tests/test-timber-wp-vip.php | 10 ++++------ 7 files changed, 46 insertions(+), 44 deletions(-) diff --git a/lib/Image.php b/lib/Image.php index 7a7dfcc6f..0b1a03995 100644 --- a/lib/Image.php +++ b/lib/Image.php @@ -15,7 +15,7 @@ * // Lets say you have an alternate large 'cover image' for your post * // stored in a custom field which returns an image ID. * $cover_image_id = $context['post']->cover_image; - * $context['cover_image'] = new Timber\Image($cover_image_id); + * $context['cover_image'] = Timber::get_post($cover_image_id); * Timber::render('single.twig', $context); * ``` * @@ -81,15 +81,7 @@ class Image extends Attachment { protected $dimensions; /** - * Creates a new Timber\Image object - * @example - * ```php - * // You can pass it an ID number - * $myImage = new Timber\Image(552); - * - * //Or send it a URL to an image - * $myImage = new Timber\Image('http://google.com/logo.jpg'); - * ``` + * @internal * @param bool|int|string $iid */ public function __construct( $iid ) { diff --git a/tests/test-timber-attachment.php b/tests/test-timber-attachment.php index b388292e2..a78898cf3 100644 --- a/tests/test-timber-attachment.php +++ b/tests/test-timber-attachment.php @@ -103,7 +103,7 @@ function testAttachmentInitWithWP_Post() { } function testAttachmentArray() { - $this->markTestSkipped('@todo drop support for this'); + $this->markTestSkipped('@todo drop support for this?'); $post_id = $this->factory->post->create(); $filename = self::copyTestAttachment('arch.jpg'); $wp_filetype = wp_check_filetype( basename( $filename ), null ); @@ -122,9 +122,17 @@ function testAttachmentArray() { } function testAttachmentPath() { - $this->markTestSkipped('@todo Image::from_file'); + $this->markTestSkipped('@todo ::from_file'); + $filename = self::copyTestAttachment( 'arch.jpg' ); + $image = Attachment::from_file( $filename ); + $this->assertStringStartsWith('/wp-content', $image->path()); + $this->assertStringEndsWith('.jpg', $image->path()); + } + + function testAttachmentFromUrl() { + $this->markTestSkipped('@todo ::from_url'); $filename = self::copyTestAttachment( 'arch.jpg' ); - $image = new Timber\Image( $filename ); + $image = Attachment::from_url( $filename ); $this->assertStringStartsWith('/wp-content', $image->path()); $this->assertStringEndsWith('.jpg', $image->path()); } @@ -141,7 +149,7 @@ function testInitFromID() { function testInitFromFilePath() { $this->markTestSkipped('@todo Image::from_file'); $attachment_file = self::copyTestAttachment(); - $attachment = new Timber\Attachment( $attachment_file ); + $attachment = Attachment::from_file( $attachment_file ); $size = $attachment->size_raw(); $this->assertEquals( 154752, $size ); } @@ -150,7 +158,7 @@ function testInitFromRelativePath() { $this->markTestSkipped('@todo Image::from_file'); $filename = self::copyTestAttachment( 'arch.jpg' ); $path = str_replace(ABSPATH, '/', $filename); - $attachment = new Timber\Attachment( $path ); + $attachment = Attachment::from_file( $path ); $size = $attachment->size_raw(); $this->assertEquals( 154752, $size ); } @@ -160,7 +168,7 @@ function testInitFromURL() { $destination_path = self::copyTestAttachment(); $destination_path = Timber\URLHelper::get_rel_path( $destination_path ); $destination_url = 'http://'.$_SERVER['HTTP_HOST'].$destination_path; - $image = new Timber\Attachment( $destination_url ); + $image = Attachment::from_url( $destination_url ); $this->assertEquals( $destination_url, $image->src() ); $this->assertEquals( $destination_url, (string)$image ); } @@ -168,7 +176,7 @@ function testInitFromURL() { function testPathInfo() { $this->markTestSkipped('@todo Image::from_file'); $filename = self::copyTestAttachment( 'arch.jpg' ); - $image = new Timber\Attachment( $filename ); + $image = Attachment::from_file( $filename ); $path_parts = $image->get_pathinfo(); $this->assertEquals('jpg', $path_parts['extension']); } diff --git a/tests/test-timber-image-path-helper.php b/tests/test-timber-image-path-helper.php index 13b0be8aa..4e83e30ea 100644 --- a/tests/test-timber-image-path-helper.php +++ b/tests/test-timber-image-path-helper.php @@ -27,7 +27,7 @@ function testImagePathStartsWithSpecialChar() { if (!is_int($file_id)) { error_log(print_r($file_id, true)); } - $image = new Timber\Image($file_id); + $image = Timber::get_post($file_id); $str = ''; $result = Timber::compile_string($str, array('image' => $image)); $upload_dir = wp_upload_dir(); diff --git a/tests/test-timber-image-retina.php b/tests/test-timber-image-retina.php index 98372ae49..45240ac4b 100644 --- a/tests/test-timber-image-retina.php +++ b/tests/test-timber-image-retina.php @@ -8,20 +8,23 @@ class TestTimberImageRetina extends Timber_UnitTestCase { function testImageRetina() { + $this->markTestSkipped('@todo ::from_url'); $file = TestTimberImage::copyTestAttachment(); $ret = Timber\ImageHelper::retina_resize($file, 2); - $image = new Timber\Image( $ret ); + $image = Attachment::from_url( $ret ); $this->assertEquals( 3000, $image->width() ); } function testImageBiggerRetina() { + $this->markTestSkipped('@todo ::from_url'); $file = TestTimberImage::copyTestAttachment(); $ret = Timber\ImageHelper::retina_resize($file, 3); - $image = new Timber\Image( $ret ); + $image = Attachment::from_url( $ret ); $this->assertEquals( 4500, $image->width() ); } function testImageRetinaFilter() { + $this->markTestSkipped('@todo ::from_url'); $filename = TestTimberImage::copyTestAttachment( 'eastern.jpg' ); $wp_filetype = wp_check_filetype( basename( $filename ), null ); $post_id = $this->factory->post->create( array( 'post_title' => 'Thing One' ) ); @@ -33,17 +36,18 @@ function testImageRetinaFilter() { ); $attach_id = wp_insert_attachment( $attachment, $filename, $post_id ); add_post_meta( $post_id, '_thumbnail_id', $attach_id, true ); - $data = array(); - $post = Timber::get_post( $post_id ); - $data['post'] = $post; - $str = '{{post.thumbnail.src|retina}}'; - $compiled = Timber::compile_string($str, $data); + + $compiled = Timber::compile_string('{{post.thumbnail.src|retina}}', [ + 'post' => Timber::get_post($post_id), + ]); + $img = Attachment::from_url($compiled); + $this->assertContains('@2x', $compiled); - $img = new Timber\Image($compiled); $this->assertEquals(500, $img->width()); } function testImageRetinaFloatFilter() { + $this->markTestSkipped('@todo ::from_url'); $filename = TestTimberImage::copyTestAttachment( 'eastern.jpg' ); $wp_filetype = wp_check_filetype( basename( $filename ), null ); $post_id = $this->factory->post->create( array( 'post_title' => 'Thing One' ) ); @@ -61,11 +65,12 @@ function testImageRetinaFloatFilter() { $str = '{{post.thumbnail.src|retina(1.5)}}'; $compiled = Timber::compile_string($str, $data); $this->assertContains('@1.5x', $compiled); - $img = new Timber\Image($compiled); + $img = Attachment::from_url($compiled); $this->assertEquals(375, $img->width()); } function testImageResizeRetinaFilter() { + $this->markTestSkipped('@todo ::from_url'); $filename = TestTimberImage::copyTestAttachment( 'eastern.jpg' ); $wp_filetype = wp_check_filetype( basename( $filename ), null ); $post_id = $this->factory->post->create(); @@ -81,7 +86,7 @@ function testImageResizeRetinaFilter() { $data['post'] = Timber::get_post( $post_id ); $str = '{{post.thumbnail.src|resize(100, 50)|retina(3)}}'; $compiled = Timber::compile_string($str, $data); - $img = new Timber\Image($compiled); + $img = Attachment::from_url($compiled); $this->assertContains('@3x', $compiled); $this->assertEquals(300, $img->width()); } diff --git a/tests/test-timber-image.php b/tests/test-timber-image.php index 0b11b086e..97b1da4eb 100644 --- a/tests/test-timber-image.php +++ b/tests/test-timber-image.php @@ -21,21 +21,19 @@ public function get_post_with_image() { return $post; } -/* ---------------- - * Tests - ---------------- */ - function testInitFromFilePath() { + $this->markTestSkipped('@todo ::from_file'); $attachment_file = self::copyTestAttachment(); - $image = new Timber\Image( $attachment_file ); + $image = Attachment::from_file( $attachment_file ); $size = $image->width(); $this->assertEquals( 1500, $size ); } function testInitFromRelativePath() { + $this->markTestSkipped('@todo ::from_file'); $filename = self::copyTestAttachment( 'arch.jpg' ); $path = str_replace(ABSPATH, '/', $filename); - $image = new Timber\Image( $path ); + $image = Attachment::from_file( $path ); $width = $image->width(); $this->assertEquals( 1500, $width ); } @@ -821,7 +819,7 @@ function testImageSizeWithWPNameUsingNative(){ if (!is_int($file_id)) { error_log(print_r($file_id, true)); } - $image = new Timber\Image($file_id); + $image = Timber::get_post($file_id); $str = ''; $result = Timber::compile_string($str, array('image' => $image)); $upload_dir = wp_upload_dir(); @@ -839,7 +837,7 @@ function testImageSizeWithWPNameUsingNativeGif(){ if (!is_int($file_id)) { error_log(print_r($file_id, true)); } - $image = new Timber\Image($file_id); + $image = Timber::get_post($file_id); $str = ''; $result = Timber::compile_string($str, array('image' => $image)); $upload_dir = wp_upload_dir(); @@ -884,8 +882,9 @@ function testResizeGif() { } function testImageNoParent() { + $this->markTestSkipped('@todo ::from_file'); $filename = self::copyTestAttachment( 'arch.jpg' ); - $image = new Timber\Image( $filename ); + $image = Attachment::from_file( $filename ); $this->assertFalse($image->parent()); } diff --git a/tests/test-timber-post.php b/tests/test-timber-post.php index 3b1f55f40..3d6e50106 100644 --- a/tests/test-timber-post.php +++ b/tests/test-timber-post.php @@ -70,7 +70,7 @@ function testFalseParent() { $attachment = array( 'post_title' => 'The Arch', 'post_content' => '' ); $iid = wp_insert_attachment( $attachment, $filename, $pid ); update_post_meta( $iid, 'architect', 'Eero Saarinen' ); - $image = new Timber\Image( $iid ); + $image = Timber::get_post( $iid ); $parent = $image->parent(); $this->assertEquals($pid, $parent->ID); $this->assertFalse($parent->parent()); diff --git a/tests/test-timber-wp-vip.php b/tests/test-timber-wp-vip.php index 40cc22c34..93b1541e3 100644 --- a/tests/test-timber-wp-vip.php +++ b/tests/test-timber-wp-vip.php @@ -1,5 +1,8 @@ '; $result = Timber::compile_string($str, array('image' => $image)); $upload_dir = wp_upload_dir(); @@ -59,9 +62,4 @@ function testImageSrcThumbnail() { remove_filter( 'timber/allow_fs_write', '__return_false' ); } - - - - - } \ No newline at end of file From 90f4808e530f1d8e4df289ed81b80563266040e6 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Fri, 28 Aug 2020 17:09:47 -0700 Subject: [PATCH 42/87] #2093 restore skipped Post test --- tests/test-timber-post.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/test-timber-post.php b/tests/test-timber-post.php index 3d6e50106..7f8345348 100644 --- a/tests/test-timber-post.php +++ b/tests/test-timber-post.php @@ -84,13 +84,12 @@ function testPostOnSingle(){ } function testPostOnSingleQuery(){ - $this->markTestSkipped('@todo fix Timber::get_post()'); $this->factory->post->create(); - $this->go_to(home_url('/?p='.$post_id)); $post_id = $this->factory->post->create(); + $this->go_to(home_url('/?p='.$post_id)); + $post = Timber::get_post($post_id); $this->assertEquals($post_id, $post->ID); - $this->assertEquals($post_id, get_the_ID()); } function testPostOnSingleQueryNoParams(){ From 40c411e7ccc778b07bed8e9d73d08e7aed9aa434 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Fri, 28 Aug 2020 17:52:06 -0700 Subject: [PATCH 43/87] #2093 implement Post::build() --- lib/Attachment.php | 15 +-------- lib/Factory/PostFactory.php | 3 +- lib/Image.php | 8 ----- lib/Post.php | 54 +++++------------------------- tests/test-timber-helper.php | 9 +++-- tests/test-timber-twig-objects.php | 1 + 6 files changed, 19 insertions(+), 71 deletions(-) diff --git a/lib/Attachment.php b/lib/Attachment.php index 3e5bf9e99..7d64c9ea0 100644 --- a/lib/Attachment.php +++ b/lib/Attachment.php @@ -119,20 +119,6 @@ class Attachment extends Post implements CoreInterface { */ public $caption; - /** - * Creates a new `Timber\Attachment` object. - * - * @api - * @internal - * - * @todo make this protected - * @param int|mixed $attachment An attachment ID, a `Timber\Post`, a `WP_Post` object, an ACF - * image array, a path (absolute or relative) or an URL. - */ - public function __construct( $attachment ) { - $this->init( $attachment ); - } - /** * Gets the src for an attachment. * @@ -152,6 +138,7 @@ public function __toString() { * @param int|mixed $iid An attachment identifier. */ public function init( $iid = null ) { + // @todo extract important logic out into ::from_url(), ::from_file() $iid = $this->determine_id( $iid ); /** diff --git a/lib/Factory/PostFactory.php b/lib/Factory/PostFactory.php index fd156ccf2..cfdc3f568 100644 --- a/lib/Factory/PostFactory.php +++ b/lib/Factory/PostFactory.php @@ -113,8 +113,7 @@ protected function is_image(WP_Post $post) { protected function build(WP_Post $post) : CoreInterface { $class = $this->get_post_class($post); - // @todo make Core constructors protected, call Post::build() here - return new $class($post); + return $class::build($post); } protected function is_numeric_array($arr) { diff --git a/lib/Image.php b/lib/Image.php index 0b1a03995..3fa35182f 100644 --- a/lib/Image.php +++ b/lib/Image.php @@ -80,14 +80,6 @@ class Image extends Attachment { */ protected $dimensions; - /** - * @internal - * @param bool|int|string $iid - */ - public function __construct( $iid ) { - $this->init($iid); - } - /** * @return string the src of the file */ diff --git a/lib/Post.php b/lib/Post.php index 2ad24d5b2..570e0c59b 100644 --- a/lib/Post.php +++ b/lib/Post.php @@ -169,17 +169,22 @@ class Post extends Core implements CoreInterface, MetaInterface, DatedInterface, */ protected $__type; + public static function build( WP_Post $wp_post ) { + $post = new static( $wp_post ); + + return $post; + } + /** * If you send the constructor nothing it will try to figure out the current post id based on * being inside The_Loop. * * @internal * - * @param mixed $pid + * @param WP_Post $wp_post */ - public function __construct( $pid = null ) { - $pid = $this->determine_id($pid); - $this->init($pid); + public function __construct( $wp_post ) { + $this->init($wp_post); } /** @@ -289,47 +294,6 @@ protected static function is_previewing() { } } - /** - * tries to figure out what post you want to get if not explictly defined (or if it is, allows it to be passed through) - * @internal - * @param mixed a value to test against - * @return int|null the numberic id we should be using for this post object, null when there's no ID (ex: 404 page) - */ - protected function determine_id( $pid ) { - global $wp_query; - if ( $pid === null && - isset($wp_query->queried_object_id) - && $wp_query->queried_object_id - && isset($wp_query->queried_object) - && is_object($wp_query->queried_object) - && get_class($wp_query->queried_object) == 'WP_Post' - ) { - $pid = $wp_query->queried_object_id; - } else if ( $pid === null && $wp_query->is_home && isset($wp_query->queried_object_id) && $wp_query->queried_object_id ) { - //hack for static page as home page - $pid = $wp_query->queried_object_id; - } else if ( $pid === null ) { - $gtid = false; - $maybe_post = get_post(); - if ( isset($maybe_post->ID) ) { - $gtid = true; - } - if ( $gtid ) { - $pid = get_the_ID(); - } - if ( !$pid ) { - global $wp_query; - if ( isset($wp_query->query['p']) ) { - $pid = $wp_query->query['p']; - } - } - } - if ( $pid === null && ($pid_from_loop = PostGetter::loop_to_id()) ) { - $pid = $pid_from_loop; - } - return $pid; - } - /** * Outputs the title of the post if you do something like `

    {{post}}

    ` * diff --git a/tests/test-timber-helper.php b/tests/test-timber-helper.php index cf3aa1d77..c032a65f9 100644 --- a/tests/test-timber-helper.php +++ b/tests/test-timber-helper.php @@ -1,5 +1,7 @@ register_post_classmap_temporarily([ + 'post' => TimberPostSubclass::class, + ]); + + $tps = Timber::get_post($this->factory->post->create()); $jimmy = new stdClass(); $jimmy->name = 'Jimmy'; $pumpkins = array($tps, $jimmy); diff --git a/tests/test-timber-twig-objects.php b/tests/test-timber-twig-objects.php index fe271b8ef..21433b7de 100644 --- a/tests/test-timber-twig-objects.php +++ b/tests/test-timber-twig-objects.php @@ -7,6 +7,7 @@ * @group terms-api * @group users-api * @group comments-api + * @group twig */ class TestTimberTwigObjects extends Timber_UnitTestCase { From d92c7a215b3cf2a0b3afb132ea240d19e79d4b5a Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Fri, 28 Aug 2020 19:26:56 -0700 Subject: [PATCH 44/87] #2093 simplify Post() Twig helper --- lib/Twig.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/Twig.php b/lib/Twig.php index c4aca52af..2b9d6c4e0 100644 --- a/lib/Twig.php +++ b/lib/Twig.php @@ -48,9 +48,7 @@ public function add_timber_functions( $twig ) { * Timber object functions. */ - $twig->addFunction(new TwigFunction('Post', function( $post_id, $PostClass = 'Timber\Post' ) { - return self::maybe_convert_array( $post_id, $PostClass ); - } ) ); + $twig->addFunction(new TwigFunction('Post', [Timber::class, 'get_post'] ) ); $twig->addFunction( new TwigFunction( 'PostQuery', function( $args ) { return new PostQuery( $args ); From 3d9400ae423fd1c1c3a957f55ce0d5bc24f1647b Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Fri, 28 Aug 2020 22:44:36 -0700 Subject: [PATCH 45/87] #2093 switch Twig Post API to use PostFactory --- lib/Twig.php | 52 +++++++++++++------------------------ tests/test-timber-image.php | 3 +-- 2 files changed, 19 insertions(+), 36 deletions(-) diff --git a/lib/Twig.php b/lib/Twig.php index 2b9d6c4e0..9097950fe 100644 --- a/lib/Twig.php +++ b/lib/Twig.php @@ -7,6 +7,9 @@ use Twig\TwigFunction; use Twig\TwigFilter; +use Timber\Factory\PostFactory; +use Timber\Image; + /** * Class Twig */ @@ -48,37 +51,42 @@ public function add_timber_functions( $twig ) { * Timber object functions. */ - $twig->addFunction(new TwigFunction('Post', [Timber::class, 'get_post'] ) ); + $factory = new PostFactory(); + + $twig->addFunction(new TwigFunction('Post', [$factory, 'from'] ) ); $twig->addFunction( new TwigFunction( 'PostQuery', function( $args ) { return new PostQuery( $args ); } ) ); - $twig->addFunction(new TwigFunction('Image', function( $post_id, $ImageClass = 'Timber\Image' ) { - return self::maybe_convert_array( $post_id, $ImageClass ); + $twig->addFunction(new TwigFunction('Image', function( $ident ) use ( $factory ) { + if ( is_string( $ident ) ) { + // TODO Image::from_file(); + return new Image( $ident ); + } + + return $factory->from( $ident ); } ) ); $twig->addFunction(new TwigFunction('Term', [Timber::class, 'get_term'])); $twig->addFunction(new TwigFunction('User', [Timber::class, 'get_user'] ) ); - $twig->addFunction( new TwigFunction( 'Attachment', function( $post_id, $AttachmentClass = 'Timber\Attachment' ) { - return self::maybe_convert_array( $post_id, $AttachmentClass ); - } ) ); + $twig->addFunction( new TwigFunction( 'Attachment', [$factory, 'from'] ) ); /** * Deprecated Timber object functions. */ $twig->addFunction( new TwigFunction( 'TimberPost', - function( $post_id, $PostClass = 'Timber\Post' ) { + function( $ident ) use ( $factory ) { Helper::deprecated( '{{ TimberPost() }}', '{{ Post() }}', '2.0.0' ); - return self::maybe_convert_array( $post_id, $PostClass ); + return $factory->from( $ident ); } ) ); $twig->addFunction( new TwigFunction( 'TimberImage', - function( $post_id = false, $ImageClass = 'Timber\Image' ) { + function( $post_id = false ) use ( $factory ) { Helper::deprecated( '{{ TimberImage() }}', '{{ Image() }}', '2.0.0' ); - return self::maybe_convert_array( $post_id, $ImageClass ); + return $factory->from( $post_id ); } ) ); @@ -98,30 +106,6 @@ function( $post_id = false, $ImageClass = 'Timber\Image' ) { return $twig; } - /** - * Converts input to Timber object(s) - * - * @internal - * @since 2.0.0 - * - * @param mixed $post_id A post ID, object or something else that the Timber object class - * constructor an read. - * @param string $class The class to use to convert the input. - * - * @return mixed An object or array of objects. - */ - public static function maybe_convert_array( $post_id, $class ) { - if ( is_array( $post_id ) && ! Helper::is_array_assoc( $post_id ) ) { - foreach ( $post_id as &$id ) { - $id = new $class( $id ); - } - - return $post_id; - } - - return new $class( $post_id ); - } - /** * Process the arguments for handle_term_object to determine what arguments the user is sending * @since 1.5.1 diff --git a/tests/test-timber-image.php b/tests/test-timber-image.php index 97b1da4eb..62a729305 100644 --- a/tests/test-timber-image.php +++ b/tests/test-timber-image.php @@ -729,8 +729,6 @@ function testImageWidthWithFilter() { $this->assertEquals( 1500, $rendered ); } - - function testResizeNamed() { add_image_size('timber-testResizeNamed', $width = 600, $height = 400, $crop = true); $data = array(); @@ -895,6 +893,7 @@ function testImageParent() { } function testTimberImageFromPost() { + $this->markTestSkipped('@todo can we still support this use-case?'); $post = $this->get_post_with_image(); $image = $post->thumbnail(); $post = get_post($post->ID); From f67b31ecdcddc0ac359b1d58c932987766b97f23 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Mon, 31 Aug 2020 14:26:01 -0700 Subject: [PATCH 46/87] typo --- lib/Term.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Term.php b/lib/Term.php index 0761327fd..d598b6e14 100644 --- a/lib/Term.php +++ b/lib/Term.php @@ -612,7 +612,6 @@ public function path() { * 'tax_query' => [ ...tax query for this Term... ] * ] * ``` - * Note that this *used* to be * @param string $post_type_or_class Deprecated. Before Timber 2.x this was a post_type to be * used for querying posts OR the Timber\Post subclass to * instantiate for each post returned. As of Timber 2.0.0, From 5eec8f724af03d032f87270379f422ca5b9c74fb Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Mon, 31 Aug 2020 14:34:00 -0700 Subject: [PATCH 47/87] Revert "#2093 switch Twig Post API to use PostFactory" This reverts commit 3d9400ae423fd1c1c3a957f55ce0d5bc24f1647b. --- lib/Twig.php | 52 ++++++++++++++++++++++++------------- tests/test-timber-image.php | 3 ++- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/lib/Twig.php b/lib/Twig.php index 9097950fe..2b9d6c4e0 100644 --- a/lib/Twig.php +++ b/lib/Twig.php @@ -7,9 +7,6 @@ use Twig\TwigFunction; use Twig\TwigFilter; -use Timber\Factory\PostFactory; -use Timber\Image; - /** * Class Twig */ @@ -51,42 +48,37 @@ public function add_timber_functions( $twig ) { * Timber object functions. */ - $factory = new PostFactory(); - - $twig->addFunction(new TwigFunction('Post', [$factory, 'from'] ) ); + $twig->addFunction(new TwigFunction('Post', [Timber::class, 'get_post'] ) ); $twig->addFunction( new TwigFunction( 'PostQuery', function( $args ) { return new PostQuery( $args ); } ) ); - $twig->addFunction(new TwigFunction('Image', function( $ident ) use ( $factory ) { - if ( is_string( $ident ) ) { - // TODO Image::from_file(); - return new Image( $ident ); - } - - return $factory->from( $ident ); + $twig->addFunction(new TwigFunction('Image', function( $post_id, $ImageClass = 'Timber\Image' ) { + return self::maybe_convert_array( $post_id, $ImageClass ); } ) ); $twig->addFunction(new TwigFunction('Term', [Timber::class, 'get_term'])); $twig->addFunction(new TwigFunction('User', [Timber::class, 'get_user'] ) ); - $twig->addFunction( new TwigFunction( 'Attachment', [$factory, 'from'] ) ); + $twig->addFunction( new TwigFunction( 'Attachment', function( $post_id, $AttachmentClass = 'Timber\Attachment' ) { + return self::maybe_convert_array( $post_id, $AttachmentClass ); + } ) ); /** * Deprecated Timber object functions. */ $twig->addFunction( new TwigFunction( 'TimberPost', - function( $ident ) use ( $factory ) { + function( $post_id, $PostClass = 'Timber\Post' ) { Helper::deprecated( '{{ TimberPost() }}', '{{ Post() }}', '2.0.0' ); - return $factory->from( $ident ); + return self::maybe_convert_array( $post_id, $PostClass ); } ) ); $twig->addFunction( new TwigFunction( 'TimberImage', - function( $post_id = false ) use ( $factory ) { + function( $post_id = false, $ImageClass = 'Timber\Image' ) { Helper::deprecated( '{{ TimberImage() }}', '{{ Image() }}', '2.0.0' ); - return $factory->from( $post_id ); + return self::maybe_convert_array( $post_id, $ImageClass ); } ) ); @@ -106,6 +98,30 @@ function( $post_id = false ) use ( $factory ) { return $twig; } + /** + * Converts input to Timber object(s) + * + * @internal + * @since 2.0.0 + * + * @param mixed $post_id A post ID, object or something else that the Timber object class + * constructor an read. + * @param string $class The class to use to convert the input. + * + * @return mixed An object or array of objects. + */ + public static function maybe_convert_array( $post_id, $class ) { + if ( is_array( $post_id ) && ! Helper::is_array_assoc( $post_id ) ) { + foreach ( $post_id as &$id ) { + $id = new $class( $id ); + } + + return $post_id; + } + + return new $class( $post_id ); + } + /** * Process the arguments for handle_term_object to determine what arguments the user is sending * @since 1.5.1 diff --git a/tests/test-timber-image.php b/tests/test-timber-image.php index 62a729305..97b1da4eb 100644 --- a/tests/test-timber-image.php +++ b/tests/test-timber-image.php @@ -729,6 +729,8 @@ function testImageWidthWithFilter() { $this->assertEquals( 1500, $rendered ); } + + function testResizeNamed() { add_image_size('timber-testResizeNamed', $width = 600, $height = 400, $crop = true); $data = array(); @@ -893,7 +895,6 @@ function testImageParent() { } function testTimberImageFromPost() { - $this->markTestSkipped('@todo can we still support this use-case?'); $post = $this->get_post_with_image(); $image = $post->thumbnail(); $post = get_post($post->ID); From 7842a95d104657015f830f8be5afee035ea4e663 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Mon, 31 Aug 2020 14:34:09 -0700 Subject: [PATCH 48/87] Revert "#2093 simplify Post() Twig helper" This reverts commit d92c7a215b3cf2a0b3afb132ea240d19e79d4b5a. --- lib/Twig.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Twig.php b/lib/Twig.php index 2b9d6c4e0..c4aca52af 100644 --- a/lib/Twig.php +++ b/lib/Twig.php @@ -48,7 +48,9 @@ public function add_timber_functions( $twig ) { * Timber object functions. */ - $twig->addFunction(new TwigFunction('Post', [Timber::class, 'get_post'] ) ); + $twig->addFunction(new TwigFunction('Post', function( $post_id, $PostClass = 'Timber\Post' ) { + return self::maybe_convert_array( $post_id, $PostClass ); + } ) ); $twig->addFunction( new TwigFunction( 'PostQuery', function( $args ) { return new PostQuery( $args ); From 02c2233b4587f342224ce03a2bd94356a606099e Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Wed, 2 Sep 2020 17:56:25 -0700 Subject: [PATCH 49/87] #2093 implement Timber::get_attachment_by() --- lib/Timber.php | 45 +++++++++++++++++++++++ tests/test-timber-attachment.php | 61 ++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/lib/Timber.php b/lib/Timber.php index 02137abaa..73be48ee2 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -12,6 +12,7 @@ use Timber\Factory\UserFactory; use Timber\Helper; use Timber\PostCollectionInterface; +use Timber\URLHelper; /** * Class Timber @@ -425,6 +426,50 @@ public static function query_posts( $query = false, array $options = [] ) { return self::get_posts($query, $options); } + /** + * Get an Attachment by its URL or absolute file path. Honors the `timber/post/image_extensions` + * filter, returning a Timber\Image if the found attachment is identified as an image. + * Also honors Class Maps. + * + * @api + * @since 2.0.0 + * @example + * ```php + * // By URL + * $attachment = Timber::get_attachment_by( 'url', 'https://example.com/uploads/2020/09/cat.gif' ); + * + * // By filepath + * $attachment = Timber::get_attachment_by( 'path', '/path/to/wp-content/uploads/2020/09/cat.gif' ); + * + * // Try to handle either case + * $mystery_string = some_function(); + * $attachment = Timber::get_attachment_by( $mystery_string ); + * ``` + * @param string $field_or_ident can be "url", "path", an attachment URL, or the absolute + * path of an attachment file. If "url" or "path" is given, a second arg is required. + * @param string $ident an attachment URL or absolute path. + * @return \Timber\Attachment|false + */ + public static function get_attachment_by( string $field_or_ident, string $ident = '' ) { + if ($field_or_ident === 'url') { + $id = attachment_url_to_postid($ident); + + return $id ? (new PostFactory())->from($id) : false; + } + + if ($field_or_ident === 'path') { + return self::get_attachment_by('url', URLHelper::file_system_to_url($ident)); + } + + if (empty($ident)) { + $field = URLHelper::starts_with($field_or_ident, ABSPATH) ? 'path' : 'url'; + + return self::get_attachment_by($field, $field_or_ident); + } + + return false; + } + /* Term Retrieval ================================ */ diff --git a/tests/test-timber-attachment.php b/tests/test-timber-attachment.php index a78898cf3..e7e960ebc 100644 --- a/tests/test-timber-attachment.php +++ b/tests/test-timber-attachment.php @@ -3,6 +3,7 @@ use Timber\Attachment; use Timber\Image; use Timber\Timber; +use Timber\URLHelper; /** * @group posts-api @@ -10,6 +11,66 @@ */ class TestTimberAttachment extends TimberAttachment_UnitTestCase { + /** + * + */ + function testGetAttachment() { + $this->markTestSkipped(); + $pid = $this->factory->post->create(); + $iid = self::get_attachment( $pid, 'dummy-pdf.pdf' ); + $file = URLHelper::file_system_to_url(Timber::get_post($iid)->file_loc); + echo ABSPATH; + $attachment = Timber::get_attachment($file); + + $this->assertEquals('dummy-pdf.pdf', basename($attachment->src())); + } + + function testGetAttachmentByUrl() { + $pid = $this->factory->post->create(); + $iid = self::get_attachment( $pid, 'dummy-pdf.pdf' ); + $url = Timber::get_post($iid)->src(); + + $attachment = Timber::get_attachment_by('url', $url); + + $this->assertInstanceOf(Attachment::class, $attachment); + $this->assertEquals('dummy-pdf.pdf', basename($attachment->src())); + } + + function testGetAttachmentByPath() { + $pid = $this->factory->post->create(); + $iid = self::get_attachment( $pid, 'dummy-pdf.pdf' ); + $path = URLHelper::url_to_file_system( Timber::get_post($iid)->src() ); + + $attachment = Timber::get_attachment_by('path', $path); + + $this->assertInstanceOf(Attachment::class, $attachment); + $this->assertEquals('dummy-pdf.pdf', basename($attachment->src())); + } + + function testGetAttachmentBy() { + $pid = $this->factory->post->create(); + $iid = self::get_attachment( $pid, 'dummy-pdf.pdf' ); + $url = Timber::get_post($iid)->src(); + $path = URLHelper::url_to_file_system( $url ); + + $this->assertInstanceOf(Attachment::class, Timber::get_attachment_by($url)); + $this->assertInstanceOf(Attachment::class, Timber::get_attachment_by($path)); + } + + function testGetImageByUrl() { + $pid = $this->factory->post->create(); + $iid = self::get_attachment( $pid, 'jarednova.jpeg' ); + $url = Timber::get_post($iid)->src(); + + $this->assertInstanceOf(Image::class, Timber::get_attachment_by($url)); + } + + function testGetAttachmentByUrlNonsense() { + $this->assertFalse(Timber::get_attachment_by('url', 'life finds a way')); + $this->assertFalse(Timber::get_attachment_by('path', 'must go faster')); + $this->assertFalse(Timber::get_attachment_by('you two, dig up, dig up dinosaurs')); + } + function testAttachmentByExtension() { // Add support for "uploading" WEBP images. $this->add_filter_temporarily('upload_mimes', function($types) { From 60d914c1c94c336d14516ceb181f23cbb68beaf2 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Wed, 2 Sep 2020 18:56:07 -0700 Subject: [PATCH 50/87] #2093 flag passing only "url"/"path" as incorrect NOTE: For some reason the tests are erroring out even though they are tagged with @expectedIncorrectUsage... --- lib/Timber.php | 20 ++++++++++++++++++++ tests/test-timber-attachment.php | 14 ++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/lib/Timber.php b/lib/Timber.php index 73be48ee2..e982358fd 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -452,12 +452,32 @@ public static function query_posts( $query = false, array $options = [] ) { */ public static function get_attachment_by( string $field_or_ident, string $ident = '' ) { if ($field_or_ident === 'url') { + if (empty($ident)) { + Helper::doing_it_wrong( + 'Timber::get_attachment_by()', + 'Passing "url" as the first arg requires passing a URL as the second arg.', + '2.0.0' + ); + + return false; + } + $id = attachment_url_to_postid($ident); return $id ? (new PostFactory())->from($id) : false; } if ($field_or_ident === 'path') { + if (empty($ident)) { + Helper::doing_it_wrong( + 'Timber::get_attachment_by()', + 'Passing "path" as the first arg requires passing an absolute path as the second arg.', + '2.0.0' + ); + + return false; + } + return self::get_attachment_by('url', URLHelper::file_system_to_url($ident)); } diff --git a/tests/test-timber-attachment.php b/tests/test-timber-attachment.php index e7e960ebc..9e172008b 100644 --- a/tests/test-timber-attachment.php +++ b/tests/test-timber-attachment.php @@ -71,6 +71,20 @@ function testGetAttachmentByUrlNonsense() { $this->assertFalse(Timber::get_attachment_by('you two, dig up, dig up dinosaurs')); } + /** + * @expectedIncorrectUsage Timber::get_attachment_by() + */ + function testGetAttachmentByUrlDoingItWrong() { + $this->assertFalse(Timber::get_attachment_by('url')); + } + + /** + * @expectedIncorrectUsage Timber::get_attachment_by() + */ + function testGetAttachmentByPathDoingItWrong() { + $this->assertFalse(Timber::get_attachment_by('path')); + } + function testAttachmentByExtension() { // Add support for "uploading" WEBP images. $this->add_filter_temporarily('upload_mimes', function($types) { From 00336f6bee90f10e8f917982ec7f51847661f29a Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Thu, 3 Sep 2020 10:58:08 -0700 Subject: [PATCH 51/87] #2093 update tests & comments for accuracy, clarity --- lib/PostQuery.php | 29 +++++++---------------------- lib/Timber.php | 15 ++++++++------- tests/test-timber-attachment.php | 10 +++++----- tests/test-timber-pagination.php | 26 +++++++++++++++----------- 4 files changed, 35 insertions(+), 45 deletions(-) diff --git a/lib/PostQuery.php b/lib/PostQuery.php index c649b410b..a87f52e6c 100644 --- a/lib/PostQuery.php +++ b/lib/PostQuery.php @@ -69,29 +69,14 @@ class PostQuery extends ArrayObject implements PostCollectionInterface, JsonSeri * // Get posts from default query * $posts = new Timber\PostQuery(); * - * // Get custom posts collection with a query string - * $posts = new Timber\PostQuery( array( - * 'query' => 'post_type=article', - * ) ); - * * // Using the WP_Query argument format - * $posts = new Timber\PostQuery( array( - * 'query' => array( - * 'post_type' => 'article', - * 'category_name' => 'sports', - * ), - * ) ); - * - * // Using a class map for $post_class - * $posts = new Timber\PostQuery( array( - * 'query' => array( - * 'post_type' => 'any', - * ), - * 'post_class' => array( - * 'portfolio' => 'MyPortfolioClass', - * 'alert' => 'MyAlertClass', - * ), - * ) ); + * $posts = new Timber\PostQuery( [ + * 'post_type' => 'article', + * 'category_name' => 'sports', + * ] ); + * + * // Passing a WP_Query instance + * $posts = new Timber\PostQuery( new WP_Query( 'post_type=any' ) ); * ``` * * @param array $args { diff --git a/lib/Timber.php b/lib/Timber.php index e982358fd..87699c240 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -22,13 +22,14 @@ * @api * @example * ```php - * $posts = new Timber\PostQuery(); - * $posts = new Timber\PostQuery( 'post_type = article' ); - * $posts = new Timber\PostQuery( array( + * // Get default posts on an archive page + * $posts = Timber::get_posts(); + * + * // Query for some posts + * $posts = Timber::get_posts( [ * 'post_type' => 'article', * 'category_name' => 'sports', - * ) ); - * $posts = new Timber\PostQuery( array( 23, 24, 35, 67 ), 'InkwellArticle' ); + * ] ); * * $context = Timber::context(); * $context['posts'] = $posts; @@ -437,10 +438,10 @@ public static function query_posts( $query = false, array $options = [] ) { * ```php * // By URL * $attachment = Timber::get_attachment_by( 'url', 'https://example.com/uploads/2020/09/cat.gif' ); - * + * * // By filepath * $attachment = Timber::get_attachment_by( 'path', '/path/to/wp-content/uploads/2020/09/cat.gif' ); - * + * * // Try to handle either case * $mystery_string = some_function(); * $attachment = Timber::get_attachment_by( $mystery_string ); diff --git a/tests/test-timber-attachment.php b/tests/test-timber-attachment.php index 9e172008b..3dcfe32a0 100644 --- a/tests/test-timber-attachment.php +++ b/tests/test-timber-attachment.php @@ -11,15 +11,12 @@ */ class TestTimberAttachment extends TimberAttachment_UnitTestCase { - /** - * - */ function testGetAttachment() { $this->markTestSkipped(); $pid = $this->factory->post->create(); $iid = self::get_attachment( $pid, 'dummy-pdf.pdf' ); $file = URLHelper::file_system_to_url(Timber::get_post($iid)->file_loc); - echo ABSPATH; + $attachment = Timber::get_attachment($file); $this->assertEquals('dummy-pdf.pdf', basename($attachment->src())); @@ -66,8 +63,11 @@ function testGetImageByUrl() { } function testGetAttachmentByUrlNonsense() { - $this->assertFalse(Timber::get_attachment_by('url', 'life finds a way')); + // Nonsense URL + $this->assertFalse(Timber::get_attachment_by('url', 'life, uh, finds a way')); + // Nonsense Path $this->assertFalse(Timber::get_attachment_by('path', 'must go faster')); + // Nonsense single arg $this->assertFalse(Timber::get_attachment_by('you two, dig up, dig up dinosaurs')); } diff --git a/tests/test-timber-pagination.php b/tests/test-timber-pagination.php index febcebb5f..480bf160c 100644 --- a/tests/test-timber-pagination.php +++ b/tests/test-timber-pagination.php @@ -56,10 +56,9 @@ function testPaginationWithPostQuery() { $pids = $this->factory->post->create_many( 55, array( 'post_type' => 'portfolio' ) ); $this->go_to( home_url( '/' ) ); - // @todo once the Posts API uses Factories, simplify this to Timber::get_posts([...]) - $query = new PostQuery(new WP_Query([ + $query = Timber::get_posts([ 'post_type' => 'portfolio', - ])); + ]); $this->assertCount(6, $query->pagination()->pages); } @@ -223,19 +222,24 @@ function testPaginationHomePrettyNonTrailingSlash() { } function testPaginationInCategory() { - $no_posts = $this->factory->post->create_many( 73 ); + $this->factory->post->create_many( 73 ); + + $news_id = $this->factory->term->create( [ + 'name' => 'News', + 'taxonomy' => 'category', + ] ); $posts = $this->factory->post->create_many( 31 ); - $news_id = wp_insert_term( 'News', 'category' ); foreach ( $posts as $post ) { wp_set_object_terms( $post, $news_id, 'category' ); } - $this->go_to( home_url( '/category/news' ) ); + + // Overwrite the main query. query_posts('category_name=news'); - $post_objects = new PostQuery( array( - 'query' => false, - ) ); - $pagination = $post_objects->pagination(); - $this->assertEquals(4, count($pagination->pages)); + + // Let Timber fall back on the main query. + $pagination = Timber::get_posts()->pagination(); + + $this->assertCount(4, $pagination->pages); } /** From 353296d30731b51c3cd71d75a5e69978a8d650e8 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Thu, 3 Sep 2020 11:07:48 -0700 Subject: [PATCH 52/87] #2093 mark failing @expectedIncorrectUsage tests incomplete --- tests/test-timber-attachment.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test-timber-attachment.php b/tests/test-timber-attachment.php index 3dcfe32a0..4d2c5074a 100644 --- a/tests/test-timber-attachment.php +++ b/tests/test-timber-attachment.php @@ -75,6 +75,7 @@ function testGetAttachmentByUrlNonsense() { * @expectedIncorrectUsage Timber::get_attachment_by() */ function testGetAttachmentByUrlDoingItWrong() { + $this->markTestIncomplete('@todo why does the @expectedIncorrectUsage tag not work?'); $this->assertFalse(Timber::get_attachment_by('url')); } @@ -82,6 +83,7 @@ function testGetAttachmentByUrlDoingItWrong() { * @expectedIncorrectUsage Timber::get_attachment_by() */ function testGetAttachmentByPathDoingItWrong() { + $this->markTestIncomplete('@todo why does the @expectedIncorrectUsage tag not work?'); $this->assertFalse(Timber::get_attachment_by('path')); } From 18b5c721ec7cfcdcf17577d2b717d7412abc9419 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Thu, 3 Sep 2020 11:08:35 -0700 Subject: [PATCH 53/87] #2093 simplify Pagination test using new ::get_posts() --- tests/test-timber-pagination.php | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/test-timber-pagination.php b/tests/test-timber-pagination.php index 480bf160c..b6a3c3d77 100644 --- a/tests/test-timber-pagination.php +++ b/tests/test-timber-pagination.php @@ -278,14 +278,9 @@ function testPaginationWithMoreThan10Pages() { // tests for pagination object set on PostCollection function testPostsCollectionPagination() { - $pids = $this->factory->post->create_many( 13 ); - $posts = new PostQuery( array( - 'query' => array( - 'post_type' => 'post' - ) - ) ); - $pagination = $posts->pagination(); - $this->assertEquals( 2, count( $pagination->pages ) ); + $this->factory->post->create_many( 13 ); + $pagination = Timber::get_posts(['post_type' => 'post'])->pagination(); + $this->assertCount( 2, $pagination->pages ); } function testCollectionPaginationSearch() { From 7aa8bf5518e7c0a89e4c273a6c384269d88bcc93 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Thu, 3 Sep 2020 11:33:29 -0700 Subject: [PATCH 54/87] #2093 only accept a WP_Query in PostQuery::__construct() --- lib/Factory/PostFactory.php | 4 +- lib/PostQuery.php | 74 +++------------------------ lib/Twig.php | 5 +- tests/test-timber-post-collection.php | 6 +-- tests/test-timber-twig-objects.php | 11 +--- 5 files changed, 13 insertions(+), 87 deletions(-) diff --git a/lib/Factory/PostFactory.php b/lib/Factory/PostFactory.php index cfdc3f568..68b82fd01 100644 --- a/lib/Factory/PostFactory.php +++ b/lib/Factory/PostFactory.php @@ -67,9 +67,7 @@ protected function from_post_object(object $obj) : CoreInterface { } protected function from_wp_query(WP_Query $query) : Iterable { - return new PostQuery([ - 'query' => $query, - ]); + return new PostQuery($query); } protected function get_post_class(WP_Post $post) : string { diff --git a/lib/PostQuery.php b/lib/PostQuery.php index a87f52e6c..652c2317a 100644 --- a/lib/PostQuery.php +++ b/lib/PostQuery.php @@ -67,7 +67,8 @@ class PostQuery extends ArrayObject implements PostCollectionInterface, JsonSeri * @example * ```php * // Get posts from default query - * $posts = new Timber\PostQuery(); + * global $wp_query; + * $posts = new Timber\PostQuery( $wp_query ); * * // Using the WP_Query argument format * $posts = new Timber\PostQuery( [ @@ -79,74 +80,13 @@ class PostQuery extends ArrayObject implements PostCollectionInterface, JsonSeri * $posts = new Timber\PostQuery( new WP_Query( 'post_type=any' ) ); * ``` * - * @param array $args { - * Optional. An array of arguments. - * - * @type mixed $query Optional. A query string or an array of arguments for - * `WP_Query`. Default `false`, which means that the - * default WordPress query is used. - * @type string|array $post_class Optional. Class string or class map to wrap the post - * objects in the collection. Default `Timber\Post`. - * @type bool $merge_default Optional. Whether to merge the arguments passed in - * `query` with the default arguments that WordPress uses - * for the current template. Default `false`. - * } + * @param WP_Query $query The WP_Query object to wrap. */ - public function __construct( $args = null ) { - // @todo remove these if/else clauses completely and deal directly w/ WP_Query - if (is_array($args)) { - // Backwards compatibility. - if ( ! empty( $args ) && ! isset( $args['query'] ) ) { - $args = array( - 'query' => $args, - ); - - Helper::deprecated( - 'Passing query arguments directly to PostQuery', - 'Put your query in an array with a "query" key', - '2.0.0' - ); - } - - $args = wp_parse_args( $args, array( - 'query' => false, - 'merge_default' => false, - 'post_class' => '\Timber\Post', - ) ); - } else { - $args = ['query' => $args]; - } - - if ($args['query'] instanceof WP_Query) { - // @todo this is the new happy path - $this->wp_query = $args['query']; - $this->found_posts = $this->wp_query->found_posts; - - $posts = $this->wp_query->posts ?: []; - - } else { - - // @todo we can eventually (mostly) remove this path - if ( $args['merge_default'] ) { - global $wp_query; + public function __construct( WP_Query $query ) { + $this->wp_query = $query; + $this->found_posts = $this->wp_query->found_posts; - // Merge query arguments with default query. - $args['query'] = wp_parse_args( $args['query'], $wp_query->query_vars ); - } - - // NOTE: instead of doing this here, PostFactory should know whether to instantiate a PostQuery or not. - // So if we're at this point we already know we want a QueryIterator! - // @todo pass a WP_Query instance directly (we should get one from PostFactory) - $this->userQuery = $args['query']; - $this->queryIterator = PostGetter::query_posts( $args['query'], $args['post_class'] ); - - if ( $this->queryIterator instanceof QueryIterator ) { - $this->found_posts = $this->queryIterator->found_posts(); - } - - // @todo if we already have a WP_Query instance, we can just get its posts directly. - $posts = $this->queryIterator->get_posts(); - } + $posts = $this->wp_query->posts ?: []; parent::__construct( $posts, 0, PostsIterator::class ); } diff --git a/lib/Twig.php b/lib/Twig.php index c4aca52af..0c47f67a0 100644 --- a/lib/Twig.php +++ b/lib/Twig.php @@ -52,9 +52,8 @@ public function add_timber_functions( $twig ) { return self::maybe_convert_array( $post_id, $PostClass ); } ) ); - $twig->addFunction( new TwigFunction( 'PostQuery', function( $args ) { - return new PostQuery( $args ); - } ) ); + // @todo fixing this here for peace of mind, but it will cause a merge conflict. The change in #2178 is the one you want. + $twig->addFunction( new TwigFunction( 'PostQuery', [Timber::class, 'get_posts'] ) ); $twig->addFunction(new TwigFunction('Image', function( $post_id, $ImageClass = 'Timber\Image' ) { return self::maybe_convert_array( $post_id, $ImageClass ); diff --git a/tests/test-timber-post-collection.php b/tests/test-timber-post-collection.php index 2780b3ffc..3a5de2996 100644 --- a/tests/test-timber-post-collection.php +++ b/tests/test-timber-post-collection.php @@ -68,11 +68,7 @@ function testBasicCollectionWithPagination() { function testGetPostsDeprecated() { $this->factory->post->create_many( 3 ); - $query = new Timber\PostQuery( [ - 'query' => new WP_Query('post_type=post') - ] ); - - $this->assertCount( 3, $query->get_posts() ); + $this->assertCount( 3, Timber::get_posts(['post_type' => 'post'])->get_posts() ); } function testFoundPosts() { diff --git a/tests/test-timber-twig-objects.php b/tests/test-timber-twig-objects.php index 21433b7de..c22abdbf0 100644 --- a/tests/test-timber-twig-objects.php +++ b/tests/test-timber-twig-objects.php @@ -88,18 +88,11 @@ function testPostsInTwig(){ $this->assertEquals('FooBar', Timber::compile_string($str, array('pids' => $pids))); } - function testPostQueryWithStringInTwig(){ - $pids[] = $this->factory->post->create( array( 'post_title' => 'Foo' ) ); - $pids[] = $this->factory->post->create( array( 'post_title' => 'Bar' ) ); - $str = "{% for post in PostQuery({ query: 'post_type=post&posts_per_page=-1&order=ASC'}) %}{{ post.title }}{% endfor %}"; - - $this->assertEquals( 'FooBar', Timber::compile_string( $str, array( 'pids' => $pids ) ) ); - } - function testPostQueryWithArgsInTwig(){ + // @todo use change from #2178 to resolve merge conflict $pids[] = $this->factory->post->create( array( 'post_title' => 'Foo' ) ); $pids[] = $this->factory->post->create( array( 'post_title' => 'Bar' ) ); - $str = "{% for post in PostQuery({ query: { post_type: 'post', posts_per_page: -1, order: 'ASC'} }) %}{{ post.title }}{% endfor %}"; + $str = "{% for post in PostQuery({ post_type: 'post', posts_per_page: -1, order: 'ASC' }) %}{{ post.title }}{% endfor %}"; $this->assertEquals( 'FooBar', Timber::compile_string( $str, array( 'pids' => $pids ) ) ); } From 9cbbd0eebe7f8120985eb80b30bbd6d8c4e33c9b Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Fri, 4 Sep 2020 10:00:35 -0700 Subject: [PATCH 55/87] #2093 bugfixes && relative path fix --- lib/Attachment.php | 2 +- lib/Integrations/CoAuthorsPlusUser.php | 4 +++- lib/Site.php | 4 ++-- lib/Timber.php | 5 +++++ lib/User.php | 2 +- tests/test-timber-attachment.php | 21 ++++++++++---------- tests/test-timber-integrations-coauthors.php | 1 + 7 files changed, 24 insertions(+), 15 deletions(-) diff --git a/lib/Attachment.php b/lib/Attachment.php index 7d64c9ea0..ba47d2b43 100644 --- a/lib/Attachment.php +++ b/lib/Attachment.php @@ -138,7 +138,7 @@ public function __toString() { * @param int|mixed $iid An attachment identifier. */ public function init( $iid = null ) { - // @todo extract important logic out into ::from_url(), ::from_file() + // @todo simplify this whole init process $iid = $this->determine_id( $iid ); /** diff --git a/lib/Integrations/CoAuthorsPlusUser.php b/lib/Integrations/CoAuthorsPlusUser.php index a361d1b61..844aaf272 100644 --- a/lib/Integrations/CoAuthorsPlusUser.php +++ b/lib/Integrations/CoAuthorsPlusUser.php @@ -2,6 +2,8 @@ namespace Timber\Integrations; +use Timber\Timber; + class CoAuthorsPlusUser extends \Timber\User { /** @@ -44,7 +46,7 @@ protected function init( $coauthor = false ) { /** * @property string url to use for avatar image */ - $this->avatar = new \Timber\Image($avatar_url); + $this->avatar = Timber::get_attachment_by('url', $avatar_url); } } diff --git a/lib/Site.php b/lib/Site.php index e1be4b667..b49d3861b 100644 --- a/lib/Site.php +++ b/lib/Site.php @@ -291,7 +291,7 @@ public function icon() { } $iid = get_option('site_icon'); if ( $iid ) { - return new Image($iid); + return Timber::get_post($iid); } } @@ -300,7 +300,7 @@ protected function icon_multisite( $site_id ) { $blog_id = self::switch_to_blog($site_id); $iid = get_blog_option($blog_id, 'site_icon'); if ( $iid ) { - $image = new Image($iid); + $image = Timber::get_post($iid); } restore_current_blog(); return $image; diff --git a/lib/Timber.php b/lib/Timber.php index 87699c240..d588ff600 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -478,6 +478,11 @@ public static function get_attachment_by( string $field_or_ident, string $ident return false; } + + if (!file_exists($ident)) { + // Deal with a relative path. + $ident = URLHelper::get_full_path($ident); + } return self::get_attachment_by('url', URLHelper::file_system_to_url($ident)); } diff --git a/lib/User.php b/lib/User.php index bed7fe5a1..8f7dfa522 100644 --- a/lib/User.php +++ b/lib/User.php @@ -546,6 +546,6 @@ public function avatar( $args = null ) { return $this->avatar_override; } - return new Image( get_avatar_url( $this->id, $args ) ); + return Timber::get_attachment_by( 'url', get_avatar_url( $this->id, $args ) ); } } diff --git a/tests/test-timber-attachment.php b/tests/test-timber-attachment.php index 4d2c5074a..fb02848c1 100644 --- a/tests/test-timber-attachment.php +++ b/tests/test-timber-attachment.php @@ -44,6 +44,17 @@ function testGetAttachmentByPath() { $this->assertEquals('dummy-pdf.pdf', basename($attachment->src())); } + function testGetAttachmentByPathRelative() { + $pid = $this->factory->post->create(); + $iid = self::get_attachment( $pid, 'dummy-pdf.pdf' ); + $path = URLHelper::url_to_file_system( Timber::get_post($iid)->src() ); + + $attachment = Timber::get_attachment_by('path', str_replace(ABSPATH, '/', $path)); + + $this->assertInstanceOf(Attachment::class, $attachment); + $this->assertEquals('dummy-pdf.pdf', basename($attachment->src())); + } + function testGetAttachmentBy() { $pid = $this->factory->post->create(); $iid = self::get_attachment( $pid, 'dummy-pdf.pdf' ); @@ -240,16 +251,6 @@ function testInitFromRelativePath() { $this->assertEquals( 154752, $size ); } - function testInitFromURL() { - $this->markTestSkipped('@todo Image::from_url'); - $destination_path = self::copyTestAttachment(); - $destination_path = Timber\URLHelper::get_rel_path( $destination_path ); - $destination_url = 'http://'.$_SERVER['HTTP_HOST'].$destination_path; - $image = Attachment::from_url( $destination_url ); - $this->assertEquals( $destination_url, $image->src() ); - $this->assertEquals( $destination_url, (string)$image ); - } - function testPathInfo() { $this->markTestSkipped('@todo Image::from_file'); $filename = self::copyTestAttachment( 'arch.jpg' ); diff --git a/tests/test-timber-integrations-coauthors.php b/tests/test-timber-integrations-coauthors.php index d13d14359..58bfe452f 100644 --- a/tests/test-timber-integrations-coauthors.php +++ b/tests/test-timber-integrations-coauthors.php @@ -187,6 +187,7 @@ function testLinkedGuestAuthor(){ * @group attachments */ function testGuestAuthorAvatar(){ + $this->markTestIncomplete('@todo we might need something like ExternalImage for this after all...'); $pid = $this->factory->post->create(); $post = Timber::get_post($pid); $user_login = 'withfeaturedimage'; From 009d2baba184d419cea1a244550287b2cb8c9a74 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Fri, 4 Sep 2020 10:29:09 -0700 Subject: [PATCH 56/87] #2093 remove redundant (skipped) tests --- tests/test-timber-attachment.php | 44 -------------------------------- 1 file changed, 44 deletions(-) diff --git a/tests/test-timber-attachment.php b/tests/test-timber-attachment.php index fb02848c1..1c11645d6 100644 --- a/tests/test-timber-attachment.php +++ b/tests/test-timber-attachment.php @@ -11,17 +11,6 @@ */ class TestTimberAttachment extends TimberAttachment_UnitTestCase { - function testGetAttachment() { - $this->markTestSkipped(); - $pid = $this->factory->post->create(); - $iid = self::get_attachment( $pid, 'dummy-pdf.pdf' ); - $file = URLHelper::file_system_to_url(Timber::get_post($iid)->file_loc); - - $attachment = Timber::get_attachment($file); - - $this->assertEquals('dummy-pdf.pdf', basename($attachment->src())); - } - function testGetAttachmentByUrl() { $pid = $this->factory->post->create(); $iid = self::get_attachment( $pid, 'dummy-pdf.pdf' ); @@ -209,22 +198,6 @@ function testAttachmentArray() { $this->assertEquals('arch.jpg', $filename); } - function testAttachmentPath() { - $this->markTestSkipped('@todo ::from_file'); - $filename = self::copyTestAttachment( 'arch.jpg' ); - $image = Attachment::from_file( $filename ); - $this->assertStringStartsWith('/wp-content', $image->path()); - $this->assertStringEndsWith('.jpg', $image->path()); - } - - function testAttachmentFromUrl() { - $this->markTestSkipped('@todo ::from_url'); - $filename = self::copyTestAttachment( 'arch.jpg' ); - $image = Attachment::from_url( $filename ); - $this->assertStringStartsWith('/wp-content', $image->path()); - $this->assertStringEndsWith('.jpg', $image->path()); - } - function testInitFromID() { $pid = $this->factory->post->create(); $filename = self::copyTestAttachment( 'arch.jpg' ); @@ -234,23 +207,6 @@ function testInitFromID() { $this->assertEquals( 'The Arch', $attachment->title() ); } - function testInitFromFilePath() { - $this->markTestSkipped('@todo Image::from_file'); - $attachment_file = self::copyTestAttachment(); - $attachment = Attachment::from_file( $attachment_file ); - $size = $attachment->size_raw(); - $this->assertEquals( 154752, $size ); - } - - function testInitFromRelativePath() { - $this->markTestSkipped('@todo Image::from_file'); - $filename = self::copyTestAttachment( 'arch.jpg' ); - $path = str_replace(ABSPATH, '/', $filename); - $attachment = Attachment::from_file( $path ); - $size = $attachment->size_raw(); - $this->assertEquals( 154752, $size ); - } - function testPathInfo() { $this->markTestSkipped('@todo Image::from_file'); $filename = self::copyTestAttachment( 'arch.jpg' ); From ccb9947b8023702e285e1131c45981ff8eec4b59 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Fri, 4 Sep 2020 18:16:45 -0700 Subject: [PATCH 57/87] #2093 just return a string from User::avatar() --- lib/Integrations/CoAuthorsPlusUser.php | 32 +++++++++++--------- lib/User.php | 4 +-- tests/test-timber-integrations-coauthors.php | 4 +-- tests/test-timber-user.php | 1 + 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/lib/Integrations/CoAuthorsPlusUser.php b/lib/Integrations/CoAuthorsPlusUser.php index 844aaf272..f699927bc 100644 --- a/lib/Integrations/CoAuthorsPlusUser.php +++ b/lib/Integrations/CoAuthorsPlusUser.php @@ -5,12 +5,12 @@ use Timber\Timber; class CoAuthorsPlusUser extends \Timber\User { - /** - * @api - * @var \Timber\Image of a user's avatar image. + * This user's avatar thumbnail + * + * @var string */ - public $avatar; + protected $thumbnail; public static function from_guest_author( \stdclass $coauthor ) { $user = new static(); @@ -36,18 +36,20 @@ protected function init( $coauthor = false ) { */ $this->display_name = $coauthor->display_name; $this->_link = get_author_posts_url(null, $coauthor->user_nicename ); + } - // 96 is the default wordpress avatar size - $avatar_url = get_the_post_thumbnail_url($this->id, 96); - if ( CoAuthorsPlus::$prefer_gravatar || !$avatar_url ) { - $avatar_url = get_avatar_url($coauthor->user_email); - } - if ( $avatar_url ) { - /** - * @property string url to use for avatar image - */ - $this->avatar = Timber::get_attachment_by('url', $avatar_url); + /** + * Get the user's avatar or Gravatar URL. + * + * @param array $args optional array arg to `get_avatar_url()` + * @return string + */ + public function avatar( $args = null ) { + if ( CoAuthorsPlus::$prefer_gravatar ) { + return get_avatar_url( $this->user_email, $args ); + } else { + // 96 is the default wordpress avatar size + return get_the_post_thumbnail_url( $this->id, 96 ); } - } } diff --git a/lib/User.php b/lib/User.php index 8f7dfa522..066d0f420 100644 --- a/lib/User.php +++ b/lib/User.php @@ -539,13 +539,13 @@ public function can( $capability ) { * * @param null|array $args Parameters for * [`get_avatar_url()`](https://developer.wordpress.org/reference/functions/get_avatar_url/). - * @return string|\Timber\Image The avatar URL. + * @return string The avatar URL. */ public function avatar( $args = null ) { if ( $this->avatar_override ) { return $this->avatar_override; } - return Timber::get_attachment_by( 'url', get_avatar_url( $this->id, $args ) ); + return get_avatar_url( $this->id, $args ); } } diff --git a/tests/test-timber-integrations-coauthors.php b/tests/test-timber-integrations-coauthors.php index 58bfe452f..a18355873 100644 --- a/tests/test-timber-integrations-coauthors.php +++ b/tests/test-timber-integrations-coauthors.php @@ -187,7 +187,6 @@ function testLinkedGuestAuthor(){ * @group attachments */ function testGuestAuthorAvatar(){ - $this->markTestIncomplete('@todo we might need something like ExternalImage for this after all...'); $pid = $this->factory->post->create(); $post = Timber::get_post($pid); $user_login = 'withfeaturedimage'; @@ -206,7 +205,8 @@ function testGuestAuthorAvatar(){ global $coauthors_plus; $coauthors_plus->add_coauthors($pid, array($user_login)); - $template_string = '{% for author in post.authors %}{{author.avatar.src}}{% endfor %}'; + // NOTE: this used to be `{{author.avatar.src}}` but now avatar() just returns a string + $template_string = '{% for author in post.authors %}{{author.avatar}}{% endfor %}'; Timber\Integrations\CoAuthorsPlus::$prefer_gravatar = false; $str1 = Timber::compile_string($template_string, array('post' => $post)); $this->assertEquals($image->src(), $str1); diff --git a/tests/test-timber-user.php b/tests/test-timber-user.php index d84b1758f..7a58a9f94 100644 --- a/tests/test-timber-user.php +++ b/tests/test-timber-user.php @@ -91,5 +91,6 @@ function testAvatar() { $uid = $this->factory->user->create(array('display_name' => 'Maciej Palmowski', 'user_login' => 'palmiak', 'user_email' => 'm.palmowski@spiders.agency')); $user = Timber::get_user($uid); $this->assertEquals('http://2.gravatar.com/avatar/b2965625410b81a2b25ef02b54493ce0?s=96&d=mm&r=g', $user->avatar()); + $this->assertEquals('http://2.gravatar.com/avatar/b2965625410b81a2b25ef02b54493ce0?s=120&d=mm&r=g', $user->avatar(['size' => 120])); } } From f7be7684accf0b6ced56ee59e153ec2126fba12f Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Fri, 4 Sep 2020 18:27:10 -0700 Subject: [PATCH 58/87] #2093 consolidate Attachment::get_pathinfo() deprecation notice --- lib/Attachment.php | 15 +++++++++------ lib/Image.php | 14 -------------- tests/test-timber-attachment.php | 7 +++++-- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/lib/Attachment.php b/lib/Attachment.php index ba47d2b43..1652fbe8b 100644 --- a/lib/Attachment.php +++ b/lib/Attachment.php @@ -523,13 +523,16 @@ public function parent() { } /** - * Gets a PHP array with pathinfo() info from the file. - * - * @api - * - * @return array Path info from the file. + * Get a PHP array with pathinfo() info from the file + * @deprecated 2.0.0, functionality will no longer be supported in future releases. + * @return array */ public function get_pathinfo() { - return pathinfo( $this->file ); + Helper::deprecated( + "{{ image.get_pathinfo }}", + "{{ function('pathinfo', image.file) }}", + '2.0.0' + ); + return PathHelper::pathinfo($this->file); } } diff --git a/lib/Image.php b/lib/Image.php index 3fa35182f..43906104b 100644 --- a/lib/Image.php +++ b/lib/Image.php @@ -90,20 +90,6 @@ public function __toString() { return ''; } - /** - * Get a PHP array with pathinfo() info from the file - * @deprecated 2.0.0, functionality will no longer be supported in future releases. - * @return array - */ - public function get_pathinfo() { - Helper::deprecated( - "{{ image.get_pathinfo }}", - "{{ function('pathinfo', image.file) }}", - '2.0.0' - ); - return PathHelper::pathinfo($this->file); - } - /** * Processes an image's dimensions. * @deprecated 2.0.0, use `{{ image.width }}` or `{{ image.height }}` in Twig diff --git a/tests/test-timber-attachment.php b/tests/test-timber-attachment.php index 1c11645d6..debd51c8c 100644 --- a/tests/test-timber-attachment.php +++ b/tests/test-timber-attachment.php @@ -207,10 +207,13 @@ function testInitFromID() { $this->assertEquals( 'The Arch', $attachment->title() ); } + /** + * @expectedDeprecated {{ image.get_pathinfo }} + */ function testPathInfo() { - $this->markTestSkipped('@todo Image::from_file'); + $this->markTestSkipped('@todo this one is also erroring despite the @expectedDeprecated tag...'); $filename = self::copyTestAttachment( 'arch.jpg' ); - $image = Attachment::from_file( $filename ); + $image = Timber::get_attachment_by( 'path', $filename ); $path_parts = $image->get_pathinfo(); $this->assertEquals('jpg', $path_parts['extension']); } From 18e23394fae097a485f23e6c5a3a37ddab813a9f Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Wed, 9 Sep 2020 10:43:08 -0700 Subject: [PATCH 59/87] #2093 deprecate Attachment::get_pathinfo() in favor of ::pathinfo() For consistency with other method names. Special support for filenames w/ special chars added in #2072. --- lib/Attachment.php | 14 ++++++++++++-- tests/test-timber-attachment.php | 6 +----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/Attachment.php b/lib/Attachment.php index 1652fbe8b..d06d073e6 100644 --- a/lib/Attachment.php +++ b/lib/Attachment.php @@ -524,15 +524,25 @@ public function parent() { /** * Get a PHP array with pathinfo() info from the file - * @deprecated 2.0.0, functionality will no longer be supported in future releases. + * + * @deprecated 2.0.0, use Attachment::pathinfo() instead * @return array */ public function get_pathinfo() { Helper::deprecated( "{{ image.get_pathinfo }}", - "{{ function('pathinfo', image.file) }}", + "{{ image.pathinfo }}", '2.0.0' ); return PathHelper::pathinfo($this->file); } + + /** + * Get a PHP array with pathinfo() info from the file + * + * @return array + */ + public function pathinfo() { + return PathHelper::pathinfo($this->file); + } } diff --git a/tests/test-timber-attachment.php b/tests/test-timber-attachment.php index debd51c8c..c112c1777 100644 --- a/tests/test-timber-attachment.php +++ b/tests/test-timber-attachment.php @@ -207,14 +207,10 @@ function testInitFromID() { $this->assertEquals( 'The Arch', $attachment->title() ); } - /** - * @expectedDeprecated {{ image.get_pathinfo }} - */ function testPathInfo() { - $this->markTestSkipped('@todo this one is also erroring despite the @expectedDeprecated tag...'); $filename = self::copyTestAttachment( 'arch.jpg' ); $image = Timber::get_attachment_by( 'path', $filename ); - $path_parts = $image->get_pathinfo(); + $path_parts = $image->pathinfo(); $this->assertEquals('jpg', $path_parts['extension']); } From 9a841de6d33cc54df09d2f5a98c1ac532126adc0 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Wed, 9 Sep 2020 13:27:06 -0700 Subject: [PATCH 60/87] #2093 grudgingly support ACF-style post array ;-) --- lib/Factory/PostFactory.php | 4 ++++ lib/Timber.php | 6 ++++++ tests/test-post-factory.php | 9 +++++++++ 3 files changed, 19 insertions(+) diff --git a/lib/Factory/PostFactory.php b/lib/Factory/PostFactory.php index 68b82fd01..442283088 100644 --- a/lib/Factory/PostFactory.php +++ b/lib/Factory/PostFactory.php @@ -34,6 +34,10 @@ public function from($params) { return new PostArrayObject(array_map([$this, 'from'], $params)); } + if (is_array($params) && !empty($params['ID'])) { + return $this->from_id($params['ID']); + } + if (is_array($params)) { return $this->from_wp_query(new WP_Query($params)); } diff --git a/lib/Timber.php b/lib/Timber.php index d588ff600..2b831c6d6 100644 --- a/lib/Timber.php +++ b/lib/Timber.php @@ -199,6 +199,12 @@ class_alias( 'Timber\Timber', 'Timber' ); * * // Use currently queried post. Same as using get_the_ID() as a parameter. * $post = Timber::get_post(); + * + * // From an associative array with an `ID` key. For ACF compatibility. Using this + * // approach directly is not recommended. If you can, configure the return type of your + * // ACF field to just the ID. + * $post = Timber::get_post( get_field('associated_post_array') ); // Just OK. + * $post = Timber::get_post( get_field('associated_post_id') ); // Better! * ``` * @see https://developer.wordpress.org/reference/classes/wp_query/__construct/ * diff --git a/tests/test-post-factory.php b/tests/test-post-factory.php index 1f4c0853e..015efc117 100644 --- a/tests/test-post-factory.php +++ b/tests/test-post-factory.php @@ -137,6 +137,15 @@ public function testFromWpQuery() { $this->assertInstanceOf(MyCustom::class, $posts[2]); } + public function testFromAcfArray() { + $id = $this->factory->post->create(['post_type' => 'page', 'post_title' => 'Title One']); + + $postFactory = new PostFactory(); + $post = $postFactory->from(['ID' => $id]); + + $this->assertEquals($id, $post->id); + } + public function testFromArray() { $this->factory->post->create(['post_type' => 'page', 'post_title' => 'Title One']); $this->factory->post->create(['post_type' => 'page', 'post_title' => 'Title Two']); From 55044cc353e4c9d4485df27f8e42ef069fc3480f Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Wed, 9 Sep 2020 13:32:48 -0700 Subject: [PATCH 61/87] #2093 restore attachment test for passing ACF array --- tests/test-timber-attachment.php | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tests/test-timber-attachment.php b/tests/test-timber-attachment.php index c112c1777..0702ffd3d 100644 --- a/tests/test-timber-attachment.php +++ b/tests/test-timber-attachment.php @@ -179,23 +179,22 @@ function testAttachmentInitWithWP_Post() { $this->assertEquals($wp_post->ID, $attach->id); } - function testAttachmentArray() { - $this->markTestSkipped('@todo drop support for this?'); - $post_id = $this->factory->post->create(); + function testAttachmentAcfArray() { + $post_id = $this->factory->post->create(); $filename = self::copyTestAttachment('arch.jpg'); - $wp_filetype = wp_check_filetype( basename( $filename ), null ); + $attachment = array( - 'post_mime_type' => $wp_filetype['type'], + 'post_mime_type' => 'image/jpeg', 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ), 'post_content' => '', 'post_status' => 'inherit' ); + $attach_id = wp_insert_attachment( $attachment, $filename, $post_id ); - $data = array('ID' => $attach_id); - $image = new Timber\Image($data); - $filename = explode('/', $image->file); - $filename = array_pop($filename); - $this->assertEquals('arch.jpg', $filename); + $image = Timber::get_post(['ID' => $attach_id]); + $path = explode('/', $image->file); + + $this->assertEquals('arch.jpg', $path[2]); } function testInitFromID() { From 9a6d74b94f448a6ee77c23680540666ea71f1b60 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Wed, 9 Sep 2020 14:44:15 -0700 Subject: [PATCH 62/87] #2093 restore more skipped tests; refactor some for clarity --- tests/test-timber-helper.php | 1 - tests/test-timber-image-retina.php | 1 - tests/test-timber-image.php | 17 ----------------- tests/test-timber-post.php | 23 +++++++++-------------- 4 files changed, 9 insertions(+), 33 deletions(-) diff --git a/tests/test-timber-helper.php b/tests/test-timber-helper.php index c032a65f9..36b6992e1 100644 --- a/tests/test-timber-helper.php +++ b/tests/test-timber-helper.php @@ -222,7 +222,6 @@ function testOSort() { * @ticket #2124 */ function testNewArrayFilter() { - $this->markTestSkipped(); $posts = []; $posts[] = $this->factory->post->create(array('post_title' => 'Stringer Bell', 'post_content' => 'Idris Elba')); $posts[] = $this->factory->post->create(array('post_title' => 'Snoop', 'post_content' => 'Felicia Pearson')); diff --git a/tests/test-timber-image-retina.php b/tests/test-timber-image-retina.php index 45240ac4b..f58f032fe 100644 --- a/tests/test-timber-image-retina.php +++ b/tests/test-timber-image-retina.php @@ -3,7 +3,6 @@ /** * @group posts-api * @group attachments - * @todo figure out how to distinguish Image instances in Class Maps */ class TestTimberImageRetina extends Timber_UnitTestCase { diff --git a/tests/test-timber-image.php b/tests/test-timber-image.php index 97b1da4eb..3e5a35edb 100644 --- a/tests/test-timber-image.php +++ b/tests/test-timber-image.php @@ -21,23 +21,6 @@ public function get_post_with_image() { return $post; } - function testInitFromFilePath() { - $this->markTestSkipped('@todo ::from_file'); - $attachment_file = self::copyTestAttachment(); - $image = Attachment::from_file( $attachment_file ); - $size = $image->width(); - $this->assertEquals( 1500, $size ); - } - - function testInitFromRelativePath() { - $this->markTestSkipped('@todo ::from_file'); - $filename = self::copyTestAttachment( 'arch.jpg' ); - $path = str_replace(ABSPATH, '/', $filename); - $image = Attachment::from_file( $path ); - $width = $image->width(); - $this->assertEquals( 1500, $width ); - } - function testTimberImageSrc() { $iid = self::get_attachment(); $image = Timber::get_post($iid); diff --git a/tests/test-timber-post.php b/tests/test-timber-post.php index 7f8345348..8ba9cfcd4 100644 --- a/tests/test-timber-post.php +++ b/tests/test-timber-post.php @@ -44,16 +44,15 @@ function testNameMethod() { $this->assertEquals('Battlestar Galactica', $post->name()); } - function testGetImage() { - $this->markTestSkipped('@todo how to handle Image instances in Class Map?'); + function testGetImageViaPostMeta() { $post_id = $this->factory->post->create(array('post_title' => 'St. Louis History')); $filename = TestTimberImage::copyTestAttachment( 'arch.jpg' ); $attachment = array( 'post_title' => 'The Arch', 'post_content' => '' ); $iid = wp_insert_attachment( $attachment, $filename, $post_id ); update_post_meta($post_id, 'landmark', $iid); $post = Timber::get_post($post_id); - $image = $post->meta('landmark'); - $image = Timber::get_post($image); + + $image = Timber::get_post($post->meta('landmark')); $this->assertEquals('The Arch', $image->title()); } @@ -239,15 +238,13 @@ function testPostInitObject(){ $this->assertEquals($post->ID, $post_id); } - /** - * @deprecated since 2.0 - */ - function testPostByName(){ - $this->markTestSkipped(); + function testPostBySlug(){ $post_id = $this->factory->post->create(); - $post = Timber::get_post($post_id); - $post2 = Timber::get_post($post->post_name); - $this->assertEquals($post2->id, $post_id); + $slug = Timber::get_post($post_id)->post_name; + + $postFromSlug = Timber::get_post_by('slug', $slug); + + $this->assertEquals($postFromSlug->id, $post_id); } function testCanEdit(){ @@ -364,7 +361,6 @@ function testContentPaged(){ } function testPagedContent(){ - $this->markTestSkipped(); $quote = $page1 = 'Named must your fear be before banish it you can.'; $quote .= ''; $quote .= $page2 = "No, try not. Do or do not. There is no try."; @@ -373,7 +369,6 @@ function testPagedContent(){ $this->go_to( get_permalink( $post_id ) ); - // @todo The below should work magically when the iterators are merged setup_postdata( get_post( $post_id ) ); $post = Timber::get_post(); From 0ac358dbcbfc5e11b8a68ef9cacfa297c09091b2 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Wed, 9 Sep 2020 14:50:16 -0700 Subject: [PATCH 63/87] whitespace --- tests/test-timber-post.php | 1748 ++++++++++++++++++------------------ 1 file changed, 874 insertions(+), 874 deletions(-) diff --git a/tests/test-timber-post.php b/tests/test-timber-post.php index 8ba9cfcd4..6de340540 100644 --- a/tests/test-timber-post.php +++ b/tests/test-timber-post.php @@ -1,1017 +1,1017 @@ assertFalse(Timber::get_post()); + } - /** - * @group posts-api - * @group users-api - * @group terms-api - * @group post-terms - */ - class TestTimberPost extends Timber_UnitTestCase { + function testPostObject(){ + $post_id = $this->factory->post->create(); + $post = Timber::get_post($post_id); + $this->assertEquals('Timber\Post', get_class($post)); + $this->assertEquals($post_id, $post->ID); + } - function testGetPostWithNoPosts() { - $this->assertFalse(Timber::get_post()); - } + function testIDDataType() { + $uid = $this->factory->post->create(array('title' => 'Air Force Once')); + $post = Timber::get_post($uid); + $this->assertEquals('integer', gettype($post->id)); + $this->assertEquals('integer', gettype($post->ID)); + } - function testPostObject(){ - $post_id = $this->factory->post->create(); - $post = Timber::get_post($post_id); - $this->assertEquals('Timber\Post', get_class($post)); - $this->assertEquals($post_id, $post->ID); - } + function testPostPasswordReqd(){ + $post_id = $this->factory->post->create(); + $post = Timber::get_post($post_id); + $this->assertFalse($post->password_required()); - function testIDDataType() { - $uid = $this->factory->post->create(array('title' => 'Air Force Once')); - $post = Timber::get_post($uid); - $this->assertEquals('integer', gettype($post->id)); - $this->assertEquals('integer', gettype($post->ID)); - } + $post_id = $this->factory->post->create(array('post_password' => 'jiggypoof')); + $post = Timber::get_post($post_id); + $this->assertTrue($post->password_required()); + } - function testPostPasswordReqd(){ - $post_id = $this->factory->post->create(); - $post = Timber::get_post($post_id); - $this->assertFalse($post->password_required()); + function testNameMethod() { + $post_id = $this->factory->post->create(array('post_title' => 'Battlestar Galactica')); + $post = Timber::get_post($post_id); + $this->assertEquals('Battlestar Galactica', $post->name()); + } - $post_id = $this->factory->post->create(array('post_password' => 'jiggypoof')); - $post = Timber::get_post($post_id); - $this->assertTrue($post->password_required()); - } + function testGetImageViaPostMeta() { + $post_id = $this->factory->post->create(array('post_title' => 'St. Louis History')); + $filename = TestTimberImage::copyTestAttachment( 'arch.jpg' ); + $attachment = array( 'post_title' => 'The Arch', 'post_content' => '' ); + $iid = wp_insert_attachment( $attachment, $filename, $post_id ); + update_post_meta($post_id, 'landmark', $iid); + $post = Timber::get_post($post_id); - function testNameMethod() { - $post_id = $this->factory->post->create(array('post_title' => 'Battlestar Galactica')); - $post = Timber::get_post($post_id); - $this->assertEquals('Battlestar Galactica', $post->name()); - } - - function testGetImageViaPostMeta() { - $post_id = $this->factory->post->create(array('post_title' => 'St. Louis History')); - $filename = TestTimberImage::copyTestAttachment( 'arch.jpg' ); - $attachment = array( 'post_title' => 'The Arch', 'post_content' => '' ); - $iid = wp_insert_attachment( $attachment, $filename, $post_id ); - update_post_meta($post_id, 'landmark', $iid); - $post = Timber::get_post($post_id); + $image = Timber::get_post($post->meta('landmark')); + $this->assertEquals('The Arch', $image->title()); + } - $image = Timber::get_post($post->meta('landmark')); - $this->assertEquals('The Arch', $image->title()); - } + function testPostString() { + $post_id = $this->factory->post->create(array('post_title' => 'Gobbles')); + $post = Timber::get_post($post_id); + $str = Timber::compile_string('

    {{post}}

    ', array('post' => $post)); + $this->assertEquals('

    Gobbles

    ', $str); + } - function testPostString() { - $post_id = $this->factory->post->create(array('post_title' => 'Gobbles')); - $post = Timber::get_post($post_id); - $str = Timber::compile_string('

    {{post}}

    ', array('post' => $post)); - $this->assertEquals('

    Gobbles

    ', $str); - } + function testFalseParent() { + $pid = $this->factory->post->create(); + $filename = TestTimberImage::copyTestAttachment( 'arch.jpg' ); + $attachment = array( 'post_title' => 'The Arch', 'post_content' => '' ); + $iid = wp_insert_attachment( $attachment, $filename, $pid ); + update_post_meta( $iid, 'architect', 'Eero Saarinen' ); + $image = Timber::get_post( $iid ); + $parent = $image->parent(); + $this->assertEquals($pid, $parent->ID); + $this->assertFalse($parent->parent()); + } - function testFalseParent() { - $pid = $this->factory->post->create(); - $filename = TestTimberImage::copyTestAttachment( 'arch.jpg' ); - $attachment = array( 'post_title' => 'The Arch', 'post_content' => '' ); - $iid = wp_insert_attachment( $attachment, $filename, $pid ); - update_post_meta( $iid, 'architect', 'Eero Saarinen' ); - $image = Timber::get_post( $iid ); - $parent = $image->parent(); - $this->assertEquals($pid, $parent->ID); - $this->assertFalse($parent->parent()); - } + function testPostOnSingle(){ + $post_id = $this->factory->post->create(); + $this->go_to(home_url('/?p='.$post_id)); + $post = Timber::get_post(); + $this->assertEquals($post_id, $post->ID); + } - function testPostOnSingle(){ - $post_id = $this->factory->post->create(); - $this->go_to(home_url('/?p='.$post_id)); - $post = Timber::get_post(); - $this->assertEquals($post_id, $post->ID); - } + function testPostOnSingleQuery(){ + $this->factory->post->create(); + $post_id = $this->factory->post->create(); + $this->go_to(home_url('/?p='.$post_id)); - function testPostOnSingleQuery(){ - $this->factory->post->create(); - $post_id = $this->factory->post->create(); - $this->go_to(home_url('/?p='.$post_id)); + $post = Timber::get_post($post_id); + $this->assertEquals($post_id, $post->ID); + } - $post = Timber::get_post($post_id); - $this->assertEquals($post_id, $post->ID); - } + function testPostOnSingleQueryNoParams(){ + $post_id = $this->factory->post->create(); + $this->go_to(home_url('/?p='.$post_id)); + $post = Timber::get_post(); + $this->assertEquals($post_id, $post->ID); + $this->assertEquals($post_id, get_the_ID()); + } - function testPostOnSingleQueryNoParams(){ - $post_id = $this->factory->post->create(); - $this->go_to(home_url('/?p='.$post_id)); - $post = Timber::get_post(); - $this->assertEquals($post_id, $post->ID); - $this->assertEquals($post_id, get_the_ID()); - } + function testNonexistentProperty(){ + $post_id = $this->factory->post->create(); + $post = Timber::get_post( $post_id ); + $this->assertFalse( $post->zebra ); + } - function testNonexistentProperty(){ - $post_id = $this->factory->post->create(); - $post = Timber::get_post( $post_id ); - $this->assertFalse( $post->zebra ); - } + function testNonexistentMethod(){ + $post_id = $this->factory->post->create(); + $post = Timber::get_post( $post_id ); + $template = '{{post.donkey}}'; + $str = Timber::compile_string($template, array('post' => $post)); + $this->assertEquals('', $str); + //$this->assertFalse( $post->donkey() ); + } - function testNonexistentMethod(){ - $post_id = $this->factory->post->create(); - $post = Timber::get_post( $post_id ); - $template = '{{post.donkey}}'; - $str = Timber::compile_string($template, array('post' => $post)); - $this->assertEquals('', $str); - //$this->assertFalse( $post->donkey() ); + function testNext(){ + $posts = array(); + for($i = 0; $i<2; $i++){ + $j = $i + 1; + $posts[] = $this->factory->post->create(array('post_date' => '2014-02-0'.$j.' 12:00:00')); } + $firstPost = Timber::get_post($posts[0]); + $nextPost = Timber::get_post($posts[1]); + $this->assertEquals($firstPost->next()->ID, $nextPost->ID); + } - function testNext(){ - $posts = array(); - for($i = 0; $i<2; $i++){ - $j = $i + 1; - $posts[] = $this->factory->post->create(array('post_date' => '2014-02-0'.$j.' 12:00:00')); - } - $firstPost = Timber::get_post($posts[0]); - $nextPost = Timber::get_post($posts[1]); - $this->assertEquals($firstPost->next()->ID, $nextPost->ID); - } + function testNextCategory(){ + $posts = array(); + for($i = 0; $i<4; $i++){ + $j = $i + 1; + $posts[] = $this->factory->post->create(array('post_date' => '2014-02-0'.$j.' 12:00:00')); + } + wp_set_object_terms($posts[0], 'TestMe', 'category', false); + wp_set_object_terms($posts[2], 'TestMe', 'category', false); + $firstPost = Timber::get_post($posts[0]); + $nextPost = Timber::get_post($posts[2]); + $this->assertEquals($firstPost->next('category')->ID, $nextPost->ID); + } - function testNextCategory(){ + function testNextCustomTax(){ + $v = get_bloginfo('version'); + if (version_compare($v, '3.8', '<')) { + $this->markTestSkipped('Custom taxonomy prev/next not supported until 3.8'); + } else { + register_taxonomy('pizza', 'post'); $posts = array(); for($i = 0; $i<4; $i++){ $j = $i + 1; $posts[] = $this->factory->post->create(array('post_date' => '2014-02-0'.$j.' 12:00:00')); } - wp_set_object_terms($posts[0], 'TestMe', 'category', false); - wp_set_object_terms($posts[2], 'TestMe', 'category', false); + wp_set_object_terms($posts[0], 'Cheese', 'pizza', false); + wp_set_object_terms($posts[2], 'Cheese', 'pizza', false); + wp_set_object_terms($posts[3], 'Mushroom', 'pizza', false); $firstPost = Timber::get_post($posts[0]); $nextPost = Timber::get_post($posts[2]); - $this->assertEquals($firstPost->next('category')->ID, $nextPost->ID); + $this->assertEquals($firstPost->next('pizza')->ID, $nextPost->ID); } + } - function testNextCustomTax(){ - $v = get_bloginfo('version'); - if (version_compare($v, '3.8', '<')) { - $this->markTestSkipped('Custom taxonomy prev/next not supported until 3.8'); - } else { - register_taxonomy('pizza', 'post'); - $posts = array(); - for($i = 0; $i<4; $i++){ - $j = $i + 1; - $posts[] = $this->factory->post->create(array('post_date' => '2014-02-0'.$j.' 12:00:00')); - } - wp_set_object_terms($posts[0], 'Cheese', 'pizza', false); - wp_set_object_terms($posts[2], 'Cheese', 'pizza', false); - wp_set_object_terms($posts[3], 'Mushroom', 'pizza', false); - $firstPost = Timber::get_post($posts[0]); - $nextPost = Timber::get_post($posts[2]); - $this->assertEquals($firstPost->next('pizza')->ID, $nextPost->ID); - } + function testPrev(){ + $posts = array(); + for($i = 0; $i<2; $i++){ + $j = $i + 1; + $posts[] = $this->factory->post->create(array('post_date' => '2014-02-0'.$j.' 12:00:00')); } + $lastPost = Timber::get_post($posts[1]); + $prevPost = Timber::get_post($posts[0]); + $this->assertEquals($lastPost->prev()->ID, $prevPost->ID); + } - function testPrev(){ + function testPrevCustomTax(){ + $v = get_bloginfo('version'); + if (version_compare($v, '3.8', '<')) { + $this->markTestSkipped('Custom taxonomy prev/next not supported until 3.8'); + } else { + register_taxonomy('pizza', 'post'); $posts = array(); - for($i = 0; $i<2; $i++){ + for( $i = 0; $i < 3; $i++ ){ $j = $i + 1; - $posts[] = $this->factory->post->create(array('post_date' => '2014-02-0'.$j.' 12:00:00')); + $posts[] = $this->factory->post->create(array('post_date' => '2014-02-0'.$j.' 12:00:00', 'post_title' => "Pizza $j is so good!")); } - $lastPost = Timber::get_post($posts[1]); - $prevPost = Timber::get_post($posts[0]); - $this->assertEquals($lastPost->prev()->ID, $prevPost->ID); + $cat = wp_insert_term('Cheese', 'pizza'); + self::set_object_terms($posts[0], $cat, 'pizza', false); + self::set_object_terms($posts[2], $cat, 'pizza', false); + $lastPost = Timber::get_post($posts[2]); + $this->assertEquals($posts[0], $lastPost->prev('pizza')->ID); } + } - function testPrevCustomTax(){ - $v = get_bloginfo('version'); - if (version_compare($v, '3.8', '<')) { - $this->markTestSkipped('Custom taxonomy prev/next not supported until 3.8'); - } else { - register_taxonomy('pizza', 'post'); - $posts = array(); - for( $i = 0; $i < 3; $i++ ){ - $j = $i + 1; - $posts[] = $this->factory->post->create(array('post_date' => '2014-02-0'.$j.' 12:00:00', 'post_title' => "Pizza $j is so good!")); - } - $cat = wp_insert_term('Cheese', 'pizza'); - self::set_object_terms($posts[0], $cat, 'pizza', false); - self::set_object_terms($posts[2], $cat, 'pizza', false); - $lastPost = Timber::get_post($posts[2]); - $this->assertEquals($posts[0], $lastPost->prev('pizza')->ID); - } - } + function testPrevCategory(){ + $posts = array(); + for($i = 0; $i<3; $i++){ + $j = $i + 1; + $posts[] = $this->factory->post->create(array('post_date' => '2014-02-0'.$j.' 12:00:00')); + } + $cat = wp_insert_term('TestMe', 'category'); + self::set_object_terms($posts[0], $cat, 'category', false); + self::set_object_terms($posts[2], $cat, 'category', false); + $lastPost = Timber::get_post($posts[2]); + $prevPost = Timber::get_post($posts[0]); + $this->assertEquals($lastPost->prev('category')->ID, $prevPost->ID); + } - function testPrevCategory(){ - $posts = array(); - for($i = 0; $i<3; $i++){ - $j = $i + 1; - $posts[] = $this->factory->post->create(array('post_date' => '2014-02-0'.$j.' 12:00:00')); - } - $cat = wp_insert_term('TestMe', 'category'); - self::set_object_terms($posts[0], $cat, 'category', false); - self::set_object_terms($posts[2], $cat, 'category', false); - $lastPost = Timber::get_post($posts[2]); - $prevPost = Timber::get_post($posts[0]); - $this->assertEquals($lastPost->prev('category')->ID, $prevPost->ID); - } + function testNextWithDraftAndFallover(){ + $posts = array(); + for($i = 0; $i<3; $i++){ + $j = $i + 1; + $posts[] = $this->factory->post->create(array('post_date' => '2014-02-0'.$j.' 12:00:00')); + } + $firstPost = Timber::get_post($posts[0]); + $nextPost = Timber::get_post($posts[1]); + $nextPostAfter = Timber::get_post($posts[2]); + wp_update_post( array('ID' =>$nextPost->ID, 'post_status' => 'draft') ); + $this->assertEquals($nextPostAfter->ID, $firstPost->next()->ID); + } - function testNextWithDraftAndFallover(){ - $posts = array(); - for($i = 0; $i<3; $i++){ - $j = $i + 1; - $posts[] = $this->factory->post->create(array('post_date' => '2014-02-0'.$j.' 12:00:00')); - } - $firstPost = Timber::get_post($posts[0]); - $nextPost = Timber::get_post($posts[1]); - $nextPostAfter = Timber::get_post($posts[2]); - wp_update_post( array('ID' =>$nextPost->ID, 'post_status' => 'draft') ); - $this->assertEquals($nextPostAfter->ID, $firstPost->next()->ID); - } + function testNextWithDraft(){ + $posts = array(); + for($i = 0; $i<2; $i++){ + $j = $i + 1; + $posts[] = $this->factory->post->create(array('post_date' => '2014-02-0'.$j.' 12:00:00')); + } + $firstPost = Timber::get_post($posts[0]); + $nextPost = Timber::get_post($posts[1]); + $nextPost->post_status = 'draft'; + wp_update_post($nextPost); + $nextPostTest = $firstPost->next(); + // because $nextPost has a status of "draft" now (and thus isn't public) + // it should not be retured when we call $firstPost->next(); + $this->assertFalse($nextPostTest); + } - function testNextWithDraft(){ - $posts = array(); - for($i = 0; $i<2; $i++){ - $j = $i + 1; - $posts[] = $this->factory->post->create(array('post_date' => '2014-02-0'.$j.' 12:00:00')); - } - $firstPost = Timber::get_post($posts[0]); - $nextPost = Timber::get_post($posts[1]); - $nextPost->post_status = 'draft'; - wp_update_post($nextPost); - $nextPostTest = $firstPost->next(); - // because $nextPost has a status of "draft" now (and thus isn't public) - // it should not be retured when we call $firstPost->next(); - $this->assertFalse($nextPostTest); - } + function testPostInitObject(){ + $post_id = $this->factory->post->create(); + $post = get_post($post_id); + $post = Timber::get_post($post); + $this->assertEquals($post->ID, $post_id); + } - function testPostInitObject(){ - $post_id = $this->factory->post->create(); - $post = get_post($post_id); - $post = Timber::get_post($post); - $this->assertEquals($post->ID, $post_id); - } + function testPostBySlug(){ + $post_id = $this->factory->post->create(); + $slug = Timber::get_post($post_id)->post_name; - function testPostBySlug(){ - $post_id = $this->factory->post->create(); - $slug = Timber::get_post($post_id)->post_name; + $postFromSlug = Timber::get_post_by('slug', $slug); - $postFromSlug = Timber::get_post_by('slug', $slug); + $this->assertEquals($postFromSlug->id, $post_id); + } - $this->assertEquals($postFromSlug->id, $post_id); - } + function testCanEdit(){ + wp_set_current_user(1); + $post_id = $this->factory->post->create(array('post_author' => 1)); + $post = Timber::get_post($post_id); + $this->assertTrue($post->can_edit()); + wp_set_current_user(0); + } - function testCanEdit(){ - wp_set_current_user(1); - $post_id = $this->factory->post->create(array('post_author' => 1)); - $post = Timber::get_post($post_id); - $this->assertTrue($post->can_edit()); - wp_set_current_user(0); - } + function testTitle(){ + $title = 'Fifteen Million Merits'; + $post_id = $this->factory->post->create(); + $post = Timber::get_post($post_id); + $post->post_title = $title; + wp_update_post($post); + $this->assertEquals($title, trim(strip_tags($post->title()))); + } - function testTitle(){ - $title = 'Fifteen Million Merits'; - $post_id = $this->factory->post->create(); - $post = Timber::get_post($post_id); - $post->post_title = $title; - wp_update_post($post); - $this->assertEquals($title, trim(strip_tags($post->title()))); - } + function testCustomFieldPreviewRevision(){ + global $current_user; + global $wp_query; + + $post_id = $this->factory->post->create(array( + 'post_author' => 5, + )); + update_field('test_field', 'The custom field content', $post_id); + + $assertCustomFieldVal = 'This has been revised'; + $revision_id = $this->factory->post->create(array( + 'post_type' => 'revision', + 'post_status' => 'inherit', + 'post_parent' => $post_id, + )); + update_field('test_field', $assertCustomFieldVal, $revision_id); + + $uid = $this->factory->user->create(array( + 'user_login' => 'timber', + 'user_pass' => 'timber', + )); + $user = wp_set_current_user($uid); + $user->add_role('administrator'); + + $wp_query->queried_object_id = $post_id; + $wp_query->queried_object = get_post($post_id); + $_GET['preview'] = true; + $_GET['preview_nonce'] = wp_create_nonce('post_preview_' . $post_id); + $post = new \Timber\Post($post_id); + $str_direct = Timber::compile_string('{{post.test_field}}', array('post' => $post)); + $str_getfield = Timber::compile_string('{{post.meta(\'test_field\')}}', array('post' => $post)); + + $this->assertEquals( $assertCustomFieldVal, $str_direct ); + $this->assertEquals( $assertCustomFieldVal, $str_getfield ); + } - function testCustomFieldPreviewRevision(){ - global $current_user; - global $wp_query; - - $post_id = $this->factory->post->create(array( - 'post_author' => 5, - )); - update_field('test_field', 'The custom field content', $post_id); - - $assertCustomFieldVal = 'This has been revised'; - $revision_id = $this->factory->post->create(array( - 'post_type' => 'revision', - 'post_status' => 'inherit', - 'post_parent' => $post_id, - )); - update_field('test_field', $assertCustomFieldVal, $revision_id); - - $uid = $this->factory->user->create(array( - 'user_login' => 'timber', - 'user_pass' => 'timber', - )); - $user = wp_set_current_user($uid); - $user->add_role('administrator'); - - $wp_query->queried_object_id = $post_id; - $wp_query->queried_object = get_post($post_id); - $_GET['preview'] = true; - $_GET['preview_nonce'] = wp_create_nonce('post_preview_' . $post_id); - $post = new \Timber\Post($post_id); - $str_direct = Timber::compile_string('{{post.test_field}}', array('post' => $post)); - $str_getfield = Timber::compile_string('{{post.meta(\'test_field\')}}', array('post' => $post)); - - $this->assertEquals( $assertCustomFieldVal, $str_direct ); - $this->assertEquals( $assertCustomFieldVal, $str_getfield ); - } + function testCustomFieldPreviewNotRevision() { + global $current_user; + global $wp_query; + $original_content = 'The custom field content'; + + $post_id = $this->factory->post->create(array( + 'post_author' => 5, + )); + update_field('test_field', $original_content, $post_id); + + $assertCustomFieldVal = 'This has been revised'; + $revision_id = $this->factory->post->create(array( + 'post_type' => 'revision', + 'post_status' => 'inherit', + 'post_parent' => $post_id, + )); + update_field('test_field', $assertCustomFieldVal, $revision_id); + + $uid = $this->factory->user->create(array( + 'user_login' => 'timber', + 'user_pass' => 'timber', + )); + $user = wp_set_current_user($uid); + $user->add_role('administrator'); + + $wp_query->queried_object_id = $post_id; + $wp_query->queried_object = get_post($post_id); + + $post = new \Timber\Post($post_id); + + $str_direct = Timber::compile_string('{{post.test_field}}', array('post' => $post)); + $str_getfield = Timber::compile_string('{{post.meta(\'test_field\')}}', array('post' => $post)); + + $this->assertEquals( $original_content, $str_direct ); + $this->assertEquals( $original_content, $str_getfield ); + } - function testCustomFieldPreviewNotRevision() { - global $current_user; - global $wp_query; - $original_content = 'The custom field content'; - - $post_id = $this->factory->post->create(array( - 'post_author' => 5, - )); - update_field('test_field', $original_content, $post_id); - - $assertCustomFieldVal = 'This has been revised'; - $revision_id = $this->factory->post->create(array( - 'post_type' => 'revision', - 'post_status' => 'inherit', - 'post_parent' => $post_id, - )); - update_field('test_field', $assertCustomFieldVal, $revision_id); - - $uid = $this->factory->user->create(array( - 'user_login' => 'timber', - 'user_pass' => 'timber', - )); - $user = wp_set_current_user($uid); - $user->add_role('administrator'); - - $wp_query->queried_object_id = $post_id; - $wp_query->queried_object = get_post($post_id); - - $post = new \Timber\Post($post_id); - - $str_direct = Timber::compile_string('{{post.test_field}}', array('post' => $post)); - $str_getfield = Timber::compile_string('{{post.meta(\'test_field\')}}', array('post' => $post)); - - $this->assertEquals( $original_content, $str_direct ); - $this->assertEquals( $original_content, $str_getfield ); - } + function testContent(){ + $quote = 'The way to do well is to do well.'; + $post_id = $this->factory->post->create(); + $post = Timber::get_post($post_id); + $post->post_content = $quote; + wp_update_post($post); + $this->assertEquals($quote, trim(strip_tags($post->content()))); + } - function testContent(){ - $quote = 'The way to do well is to do well.'; - $post_id = $this->factory->post->create(); - $post = Timber::get_post($post_id); - $post->post_content = $quote; - wp_update_post($post); - $this->assertEquals($quote, trim(strip_tags($post->content()))); - } + function testContentPaged(){ + $quote = $page1 = 'The way to do well is to do well.'; + $quote .= ''; + $quote .= $page2 = "And do not let your tongue get ahead of your mind."; - function testContentPaged(){ - $quote = $page1 = 'The way to do well is to do well.'; - $quote .= ''; - $quote .= $page2 = "And do not let your tongue get ahead of your mind."; + $post_id = $this->factory->post->create(); + $post = Timber::get_post($post_id); + $post->post_content = $quote; + wp_update_post($post); - $post_id = $this->factory->post->create(); - $post = Timber::get_post($post_id); - $post->post_content = $quote; - wp_update_post($post); + $this->assertEquals($page1, trim(strip_tags($post->content(1)))); + $this->assertEquals($page2, trim(strip_tags($post->content(2)))); + } - $this->assertEquals($page1, trim(strip_tags($post->content(1)))); - $this->assertEquals($page2, trim(strip_tags($post->content(2)))); - } + function testPagedContent(){ + $quote = $page1 = 'Named must your fear be before banish it you can.'; + $quote .= ''; + $quote .= $page2 = "No, try not. Do or do not. There is no try."; - function testPagedContent(){ - $quote = $page1 = 'Named must your fear be before banish it you can.'; - $quote .= ''; - $quote .= $page2 = "No, try not. Do or do not. There is no try."; + $post_id = $this->factory->post->create(array('post_content' => $quote)); - $post_id = $this->factory->post->create(array('post_content' => $quote)); + $this->go_to( get_permalink( $post_id ) ); - $this->go_to( get_permalink( $post_id ) ); + setup_postdata( get_post( $post_id ) ); - setup_postdata( get_post( $post_id ) ); + $post = Timber::get_post(); + $this->assertEquals($page1, trim(strip_tags( $post->paged_content() ))); - $post = Timber::get_post(); - $this->assertEquals($page1, trim(strip_tags( $post->paged_content() ))); + $pagination = $post->pagination(); + $this->go_to( $pagination['pages'][1]['link'] ); - $pagination = $post->pagination(); - $this->go_to( $pagination['pages'][1]['link'] ); + setup_postdata( get_post( $post_id ) ); + $post = Timber::get_post(); - setup_postdata( get_post( $post_id ) ); - $post = Timber::get_post(); + $this->assertEquals($page2, trim(strip_tags( $post->paged_content() ))); + } - $this->assertEquals($page2, trim(strip_tags( $post->paged_content() ))); - } + function testPostParent(){ + $parent_id = $this->factory->post->create(); + $child_id = $this->factory->post->create(array('post_parent' => $parent_id)); + $child_post = Timber::get_post($child_id); + $this->assertEquals($parent_id, $child_post->parent()->ID); + } - function testPostParent(){ - $parent_id = $this->factory->post->create(); - $child_id = $this->factory->post->create(array('post_parent' => $parent_id)); - $child_post = Timber::get_post($child_id); - $this->assertEquals($parent_id, $child_post->parent()->ID); - } + function testPostSlug(){ + $pid = $this->factory->post->create(array('post_name' => 'the-adventures-of-tom-sawyer')); + $post = Timber::get_post($pid); + $this->assertEquals('the-adventures-of-tom-sawyer', $post->slug); + } - function testPostSlug(){ - $pid = $this->factory->post->create(array('post_name' => 'the-adventures-of-tom-sawyer')); - $post = Timber::get_post($pid); - $this->assertEquals('the-adventures-of-tom-sawyer', $post->slug); - } + function testPostAuthor(){ + $author_id = $this->factory->user->create(array('display_name' => 'Jared Novack', 'user_login' => 'jared-novack')); + $pid = $this->factory->post->create(array('post_author' => $author_id)); + $post = Timber::get_post($pid); + $this->assertEquals('jared-novack', $post->author()->slug()); + $this->assertEquals('Jared Novack', $post->author()->name()); + $template = 'By {{post.author}}'; + $authorCompile = Timber::compile_string($template, array('post' => $post)); + $template = 'By {{post.author.name}}'; + $authorNameCompile = Timber::compile_string($template, array('post' => $post)); + $this->assertEquals($authorCompile, $authorNameCompile); + $this->assertEquals('By Jared Novack', $authorCompile); + } - function testPostAuthor(){ - $author_id = $this->factory->user->create(array('display_name' => 'Jared Novack', 'user_login' => 'jared-novack')); - $pid = $this->factory->post->create(array('post_author' => $author_id)); - $post = Timber::get_post($pid); - $this->assertEquals('jared-novack', $post->author()->slug()); - $this->assertEquals('Jared Novack', $post->author()->name()); - $template = 'By {{post.author}}'; - $authorCompile = Timber::compile_string($template, array('post' => $post)); - $template = 'By {{post.author.name}}'; - $authorNameCompile = Timber::compile_string($template, array('post' => $post)); - $this->assertEquals($authorCompile, $authorNameCompile); - $this->assertEquals('By Jared Novack', $authorCompile); - } + function testPostAuthorInTwig(){ + $author_id = $this->factory->user->create(array('display_name' => 'Jon Stewart', 'user_login' => 'jon-stewart')); + $pid = $this->factory->post->create(array('post_author' => $author_id)); + $post = Timber::get_post($pid); + $this->assertEquals('jon-stewart', $post->author()->slug()); + $this->assertEquals('Jon Stewart', $post->author()->name()); + $template = 'By {{post.author}}'; + $authorCompile = Timber::compile_string($template, array('post' => $post)); + $template = 'By {{post.author.name}}'; + $authorNameCompile = Timber::compile_string($template, array('post' => $post)); + $this->assertEquals($authorCompile, $authorNameCompile); + $this->assertEquals('By Jon Stewart', $authorCompile); + } - function testPostAuthorInTwig(){ - $author_id = $this->factory->user->create(array('display_name' => 'Jon Stewart', 'user_login' => 'jon-stewart')); - $pid = $this->factory->post->create(array('post_author' => $author_id)); - $post = Timber::get_post($pid); - $this->assertEquals('jon-stewart', $post->author()->slug()); - $this->assertEquals('Jon Stewart', $post->author()->name()); - $template = 'By {{post.author}}'; - $authorCompile = Timber::compile_string($template, array('post' => $post)); - $template = 'By {{post.author.name}}'; - $authorNameCompile = Timber::compile_string($template, array('post' => $post)); - $this->assertEquals($authorCompile, $authorNameCompile); - $this->assertEquals('By Jon Stewart', $authorCompile); - } + function testPostModifiedAuthor() { + $author_id = $this->factory->user->create(array('display_name' => 'Woodward', 'user_login' => 'bob-woodward')); + $mod_author_id = $this->factory->user->create(array('display_name' => 'Bernstein', 'user_login' => 'carl-bernstein')); + $pid = $this->factory->post->create(array('post_author' => $author_id)); + $post = Timber::get_post($pid); + $this->assertEquals('bob-woodward', $post->author()->slug()); + $this->assertEquals('bob-woodward', $post->modified_author()->slug()); + $this->assertEquals('Woodward', $post->author()->name()); + $this->assertEquals('Woodward', $post->modified_author()->name()); + update_post_meta($pid, '_edit_last', $mod_author_id); + $this->assertEquals('bob-woodward', $post->author()->slug()); + $this->assertEquals('carl-bernstein', $post->modified_author()->slug()); + $this->assertEquals('Woodward', $post->author()->name()); + $this->assertEquals('Bernstein', $post->modified_author()->name()); + } - function testPostModifiedAuthor() { - $author_id = $this->factory->user->create(array('display_name' => 'Woodward', 'user_login' => 'bob-woodward')); - $mod_author_id = $this->factory->user->create(array('display_name' => 'Bernstein', 'user_login' => 'carl-bernstein')); - $pid = $this->factory->post->create(array('post_author' => $author_id)); - $post = Timber::get_post($pid); - $this->assertEquals('bob-woodward', $post->author()->slug()); - $this->assertEquals('bob-woodward', $post->modified_author()->slug()); - $this->assertEquals('Woodward', $post->author()->name()); - $this->assertEquals('Woodward', $post->modified_author()->name()); - update_post_meta($pid, '_edit_last', $mod_author_id); - $this->assertEquals('bob-woodward', $post->author()->slug()); - $this->assertEquals('carl-bernstein', $post->modified_author()->slug()); - $this->assertEquals('Woodward', $post->author()->name()); - $this->assertEquals('Bernstein', $post->modified_author()->name()); - } + function tearDown() { + global $wpdb; + $query = "DELETE from $wpdb->users WHERE ID > 1"; + $wpdb->query($query); + $query = "truncate $wpdb->term_relationships"; + $wpdb->query($query); + $query = "truncate $wpdb->term_taxonomy"; + $wpdb->query($query); + $query = "truncate $wpdb->terms"; + $wpdb->query($query); + $query = "truncate $wpdb->termmeta"; + $wpdb->query($query); + $query = "truncate $wpdb->posts"; + $wpdb->query($query); + } - function tearDown() { - global $wpdb; - $query = "DELETE from $wpdb->users WHERE ID > 1"; - $wpdb->query($query); - $query = "truncate $wpdb->term_relationships"; - $wpdb->query($query); - $query = "truncate $wpdb->term_taxonomy"; - $wpdb->query($query); - $query = "truncate $wpdb->terms"; - $wpdb->query($query); - $query = "truncate $wpdb->termmeta"; - $wpdb->query($query); - $query = "truncate $wpdb->posts"; - $wpdb->query($query); - } + function testPostFormat() { + add_theme_support( 'post-formats', array( 'aside', 'gallery' ) ); + $pid = $this->factory->post->create(); + set_post_format($pid, 'aside'); + $post = Timber::get_post($pid); + $this->assertEquals('aside', $post->format()); + } - function testPostFormat() { - add_theme_support( 'post-formats', array( 'aside', 'gallery' ) ); - $pid = $this->factory->post->create(); - set_post_format($pid, 'aside'); - $post = Timber::get_post($pid); - $this->assertEquals('aside', $post->format()); - } + function testPostClassInTwig(){ + $pid = $this->factory->post->create(); + $category = wp_insert_term('Uncategorized', 'category'); + self::set_object_terms($pid, $category, 'category', true); + $post = Timber::get_post($pid); + $str = Timber::compile_string("{{ post.class }}", array('post' => $post)); + $this->assertEquals('post-'.$pid.' post type-post status-publish format-standard hentry category-uncategorized', $str); + } - function testPostClassInTwig(){ - $pid = $this->factory->post->create(); - $category = wp_insert_term('Uncategorized', 'category'); - self::set_object_terms($pid, $category, 'category', true); - $post = Timber::get_post($pid); - $str = Timber::compile_string("{{ post.class }}", array('post' => $post)); - $this->assertEquals('post-'.$pid.' post type-post status-publish format-standard hentry category-uncategorized', $str); - } + function testPostClass(){ + $pid = $this->factory->post->create(); + $category = wp_insert_term('Uncategorized', 'category'); + self::set_object_terms($pid, $category, 'category', true); + $post = Timber::get_post($pid); + $this->assertEquals('post-'.$pid.' post type-post status-publish format-standard hentry category-uncategorized', $post->post_class()); + } - function testPostClass(){ - $pid = $this->factory->post->create(); - $category = wp_insert_term('Uncategorized', 'category'); - self::set_object_terms($pid, $category, 'category', true); - $post = Timber::get_post($pid); - $this->assertEquals('post-'.$pid.' post type-post status-publish format-standard hentry category-uncategorized', $post->post_class()); - } + function testCssClass(){ + $pid = $this->factory->post->create(); + $category = wp_insert_term('Uncategorized', 'category'); + self::set_object_terms($pid, $category, 'category', true); + $post = Timber::get_post($pid); + $this->assertEquals('post-'.$pid.' post type-post status-publish format-standard hentry category-uncategorized', $post->css_class()); + $this->assertEquals('post-'.$pid.' post type-post status-publish format-standard hentry category-uncategorized additional-css-class', $post->css_class('additional-css-class')); + } - function testCssClass(){ - $pid = $this->factory->post->create(); - $category = wp_insert_term('Uncategorized', 'category'); - self::set_object_terms($pid, $category, 'category', true); - $post = Timber::get_post($pid); - $this->assertEquals('post-'.$pid.' post type-post status-publish format-standard hentry category-uncategorized', $post->css_class()); - $this->assertEquals('post-'.$pid.' post type-post status-publish format-standard hentry category-uncategorized additional-css-class', $post->css_class('additional-css-class')); - } + function testCssClassMagicCall(){ + $pid = $this->factory->post->create(); + $category = wp_insert_term('Uncategorized', 'category'); + self::set_object_terms($pid, $category, 'category', true); + $post = Timber::get_post($pid); + $this->assertEquals('post-'.$pid.' post type-post status-publish format-standard hentry category-uncategorized', $post->class()); + $this->assertEquals('post-'.$pid.' post type-post status-publish format-standard hentry category-uncategorized additional-css-class', $post->class('additional-css-class')); + } - function testCssClassMagicCall(){ - $pid = $this->factory->post->create(); - $category = wp_insert_term('Uncategorized', 'category'); - self::set_object_terms($pid, $category, 'category', true); - $post = Timber::get_post($pid); - $this->assertEquals('post-'.$pid.' post type-post status-publish format-standard hentry category-uncategorized', $post->class()); - $this->assertEquals('post-'.$pid.' post type-post status-publish format-standard hentry category-uncategorized additional-css-class', $post->class('additional-css-class')); - } + function testCssClassMagicGet(){ + $pid = $this->factory->post->create(); + $category = wp_insert_term('Uncategorized', 'category'); + self::set_object_terms($pid, $category, 'category', true); + $post = Timber::get_post($pid); + $this->assertEquals('post-'.$pid.' post type-post status-publish format-standard hentry category-uncategorized', $post->class); + } - function testCssClassMagicGet(){ - $pid = $this->factory->post->create(); - $category = wp_insert_term('Uncategorized', 'category'); - self::set_object_terms($pid, $category, 'category', true); - $post = Timber::get_post($pid); - $this->assertEquals('post-'.$pid.' post type-post status-publish format-standard hentry category-uncategorized', $post->class); - } + function testPostChildren(){ + $parent_id = $this->factory->post->create(); + $children = $this->factory->post->create_many(8, array('post_parent' => $parent_id)); + $parent = Timber::get_post($parent_id); + $this->assertEquals(8, count($parent->children())); + } - function testPostChildren(){ - $parent_id = $this->factory->post->create(); - $children = $this->factory->post->create_many(8, array('post_parent' => $parent_id)); - $parent = Timber::get_post($parent_id); - $this->assertEquals(8, count($parent->children())); - } + function testPostChildrenOfInheritStatus(){ + $parent_id = $this->factory->post->create(); + $children = $this->factory->post->create_many(4, array('post_parent' => $parent_id)); + $children = $this->factory->post->create_many(4, array('post_parent' => $parent_id, + 'post_status' => 'inherit')); + $parent = Timber::get_post($parent_id); + $this->assertEquals(8, count($parent->children())); + } - function testPostChildrenOfInheritStatus(){ - $parent_id = $this->factory->post->create(); - $children = $this->factory->post->create_many(4, array('post_parent' => $parent_id)); - $children = $this->factory->post->create_many(4, array('post_parent' => $parent_id, - 'post_status' => 'inherit')); - $parent = Timber::get_post($parent_id); - $this->assertEquals(8, count($parent->children())); - } + function testPostChildrenOfParentType(){ + $parent_id = $this->factory->post->create(array('post_type' => 'foo')); + $children = $this->factory->post->create_many(8, array('post_parent' => $parent_id)); + $children = $this->factory->post->create_many(4, array('post_parent' => $parent_id, 'post_type' => 'foo')); + $parent = Timber::get_post($parent_id); + $this->assertEquals(4, count($parent->children('parent'))); + } - function testPostChildrenOfParentType(){ - $parent_id = $this->factory->post->create(array('post_type' => 'foo')); - $children = $this->factory->post->create_many(8, array('post_parent' => $parent_id)); - $children = $this->factory->post->create_many(4, array('post_parent' => $parent_id, 'post_type' => 'foo')); - $parent = Timber::get_post($parent_id); - $this->assertEquals(4, count($parent->children('parent'))); - } + function testPostChildrenWithArray(){ + $parent_id = $this->factory->post->create(array('post_type' => 'foo')); + $children = $this->factory->post->create_many(8, array('post_parent' => $parent_id, 'post_type' => 'bar')); + $children = $this->factory->post->create_many(4, array('post_parent' => $parent_id, 'post_type' => 'foo')); + $parent = Timber::get_post($parent_id); + $this->assertEquals(12, count($parent->children(array('foo', 'bar')))); + } - function testPostChildrenWithArray(){ - $parent_id = $this->factory->post->create(array('post_type' => 'foo')); - $children = $this->factory->post->create_many(8, array('post_parent' => $parent_id, 'post_type' => 'bar')); - $children = $this->factory->post->create_many(4, array('post_parent' => $parent_id, 'post_type' => 'foo')); - $parent = Timber::get_post($parent_id); - $this->assertEquals(12, count($parent->children(array('foo', 'bar')))); - } + function testPostNoConstructorArgument(){ + $pid = $this->factory->post->create(); + $this->go_to('?p='.$pid); + $post = Timber::get_post(); + $this->assertEquals($pid, $post->ID); + } - function testPostNoConstructorArgument(){ - $pid = $this->factory->post->create(); - $this->go_to('?p='.$pid); - $post = Timber::get_post(); - $this->assertEquals($pid, $post->ID); - } + function testPostPathUglyPermalinks(){ + update_option('permalink_structure', ''); + $pid = $this->factory->post->create(); + $post = Timber::get_post($pid); + $this->assertEquals('http://example.org/?p='.$pid, $post->link()); + $this->assertEquals('/?p='.$pid, $post->path()); + } - function testPostPathUglyPermalinks(){ - update_option('permalink_structure', ''); - $pid = $this->factory->post->create(); - $post = Timber::get_post($pid); - $this->assertEquals('http://example.org/?p='.$pid, $post->link()); - $this->assertEquals('/?p='.$pid, $post->path()); - } + function testPostPathPrettyPermalinks(){ + $struc = '/blog/%year%/%monthnum%/%postname%/'; + update_option('permalink_structure', $struc); + $pid = $this->factory->post->create(array('post_date' => '2014-05-28')); + $post = Timber::get_post($pid); + $this->assertStringStartsWith('http://example.org/blog/2014/05/post-title', $post->link()); + $this->assertStringStartsWith('/blog/2014/05/post-title', $post->path()); + } - function testPostPathPrettyPermalinks(){ - $struc = '/blog/%year%/%monthnum%/%postname%/'; - update_option('permalink_structure', $struc); - $pid = $this->factory->post->create(array('post_date' => '2014-05-28')); - $post = Timber::get_post($pid); - $this->assertStringStartsWith('http://example.org/blog/2014/05/post-title', $post->link()); - $this->assertStringStartsWith('/blog/2014/05/post-title', $post->path()); - } + function testPostCategory(){ + $cat = wp_insert_term('News', 'category'); + $pid = $this->factory->post->create(); + self::set_object_terms($pid, $cat, 'category'); + $post = Timber::get_post($pid); + $this->assertEquals('News', $post->category()->name); + } + + function testPostCategories() { + $pid = $this->factory->post->create(); + $cat = wp_insert_term('Uncategorized', 'category'); + self::set_object_terms($pid, $cat, 'category'); + $post = Timber::get_post($pid); + $category_names = array('News', 'Sports', 'Obits'); - function testPostCategory(){ - $cat = wp_insert_term('News', 'category'); - $pid = $this->factory->post->create(); - self::set_object_terms($pid, $cat, 'category'); - $post = Timber::get_post($pid); - $this->assertEquals('News', $post->category()->name); + // Uncategorized is applied by default + $default_categories = $post->categories(); + $this->assertEquals('uncategorized', $default_categories[0]->slug); + foreach ( $category_names as $category_name ) { + $category_name = wp_insert_term($category_name, 'category'); + self::set_object_terms($pid, $category_name, 'category'); } - function testPostCategories() { - $pid = $this->factory->post->create(); - $cat = wp_insert_term('Uncategorized', 'category'); - self::set_object_terms($pid, $cat, 'category'); - $post = Timber::get_post($pid); - $category_names = array('News', 'Sports', 'Obits'); - - // Uncategorized is applied by default - $default_categories = $post->categories(); - $this->assertEquals('uncategorized', $default_categories[0]->slug); - foreach ( $category_names as $category_name ) { - $category_name = wp_insert_term($category_name, 'category'); - self::set_object_terms($pid, $category_name, 'category'); - } + $this->assertEquals(count($default_categories) + count($category_names), count($post->categories())); + } + + function testPostTags() { + $pid = $this->factory->post->create(); + $post = Timber::get_post($pid); + $tag_names = array('News', 'Sports', 'Obits'); - $this->assertEquals(count($default_categories) + count($category_names), count($post->categories())); + foreach ( $tag_names as $tag_name ) { + $tag = wp_insert_term($tag_name, 'post_tag'); + wp_set_object_terms($pid, $tag['term_id'], 'post_tag', true); } - function testPostTags() { - $pid = $this->factory->post->create(); - $post = Timber::get_post($pid); - $tag_names = array('News', 'Sports', 'Obits'); + $this->assertEquals(count($tag_names), count($post->tags())); + } - foreach ( $tag_names as $tag_name ) { - $tag = wp_insert_term($tag_name, 'post_tag'); - wp_set_object_terms($pid, $tag['term_id'], 'post_tag', true); - } + function testPostTerms() { + $pid = $this->factory->post->create(); + $post = Timber::get_post($pid); + $category = wp_insert_term('Uncategorized', 'category'); + self::set_object_terms($pid, $category, 'category'); + + // create a new tag and associate it with the post + $dummy_tag = wp_insert_term('whatever', 'post_tag'); + self::set_object_terms($pid, $dummy_tag, 'post_tag'); + + // test expected tags + $timber_tags = $post->terms('post_tag'); + $dummy_timber_tag = Timber::get_term($dummy_tag['term_id'], 'post_tag'); + $this->assertEquals('whatever', $timber_tags[0]->slug); + $this->assertEquals($dummy_timber_tag, $timber_tags[0]); - $this->assertEquals(count($tag_names), count($post->tags())); + // register a custom taxonomy, create some terms in it and associate to post + register_taxonomy('team', 'post'); + $team_names = array('Patriots', 'Bills', 'Dolphins', 'Jets'); + + foreach ( $team_names as $team_name ) { + $team_term = wp_insert_term($team_name, 'team'); + self::set_object_terms($pid, $team_term, 'team'); } - function testPostTerms() { - $pid = $this->factory->post->create(); - $post = Timber::get_post($pid); - $category = wp_insert_term('Uncategorized', 'category'); - self::set_object_terms($pid, $category, 'category'); - - // create a new tag and associate it with the post - $dummy_tag = wp_insert_term('whatever', 'post_tag'); - self::set_object_terms($pid, $dummy_tag, 'post_tag'); - - // test expected tags - $timber_tags = $post->terms('post_tag'); - $dummy_timber_tag = Timber::get_term($dummy_tag['term_id'], 'post_tag'); - $this->assertEquals('whatever', $timber_tags[0]->slug); - $this->assertEquals($dummy_timber_tag, $timber_tags[0]); - - // register a custom taxonomy, create some terms in it and associate to post - register_taxonomy('team', 'post'); - $team_names = array('Patriots', 'Bills', 'Dolphins', 'Jets'); - - foreach ( $team_names as $team_name ) { - $team_term = wp_insert_term($team_name, 'team'); - self::set_object_terms($pid, $team_term, 'team'); - } + $this->assertEquals(count($team_names), count($post->terms('team'))); - $this->assertEquals(count($team_names), count($post->terms('team'))); + // check presence of specific terms + $this->assertTrue($post->has_term('Uncategorized')); + $this->assertTrue($post->has_term('whatever')); + $this->assertTrue($post->has_term('Dolphins')); + $this->assertTrue($post->has_term('Patriots', 'team')); - // check presence of specific terms - $this->assertTrue($post->has_term('Uncategorized')); - $this->assertTrue($post->has_term('whatever')); - $this->assertTrue($post->has_term('Dolphins')); - $this->assertTrue($post->has_term('Patriots', 'team')); + // 4 teams + 1 tag + default category (Uncategorized) + $this->assertEquals(6, count($post->terms())); - // 4 teams + 1 tag + default category (Uncategorized) - $this->assertEquals(6, count($post->terms())); + // test tags method - wrapper for $this->get_terms('tags') + $this->assertEquals($post->tags(), $post->terms('post_tag')); - // test tags method - wrapper for $this->get_terms('tags') - $this->assertEquals($post->tags(), $post->terms('post_tag')); + // test categories method - wrapper for $this->get_terms('category') + $this->assertEquals($post->categories(), $post->terms('category')); - // test categories method - wrapper for $this->get_terms('category') - $this->assertEquals($post->categories(), $post->terms('category')); + // test using an array of taxonomies + $post_tag_terms = $post->terms(array('post_tag')); + $this->assertEquals(1, count($post_tag_terms)); + $post_team_terms = $post->terms(array('team')); + $this->assertEquals(count($team_names), count($post_team_terms)); - // test using an array of taxonomies - $post_tag_terms = $post->terms(array('post_tag')); - $this->assertEquals(1, count($post_tag_terms)); - $post_team_terms = $post->terms(array('team')); - $this->assertEquals(count($team_names), count($post_team_terms)); + // test multiple taxonomies + $post_tag_and_team_terms = $post->terms(array('post_tag','team')); + $this->assertEquals(count($post_tag_terms) + count($post_team_terms), count($post_tag_and_team_terms)); + } - // test multiple taxonomies - $post_tag_and_team_terms = $post->terms(array('post_tag','team')); - $this->assertEquals(count($post_tag_terms) + count($post_team_terms), count($post_tag_and_team_terms)); + function testPostTermsArgumentStyle() { + $pid = $this->factory->post->create(); + $post = Timber::get_post( $pid ); + $category = wp_insert_term( 'Uncategorized', 'category' ); + self::set_object_terms( $pid, $category, 'category' ); + + // create a new tag and associate it with the post + $dummy_tag = wp_insert_term( 'whatever', 'post_tag' ); + self::set_object_terms( $pid, $dummy_tag, 'post_tag' ); + + // test expected tags + $timber_tags = $post->terms( array( + 'query' => array( + 'taxonomy' => 'post_tag', + ), + ) ); + $dummy_timber_tag = Timber::get_term( $dummy_tag['term_id'], 'post_tag' ); + $this->assertEquals( 'whatever', $timber_tags[0]->slug ); + $this->assertEquals( $dummy_timber_tag, $timber_tags[0] ); + + // register a custom taxonomy, create some terms in it and associate to post + register_taxonomy( 'team', 'post' ); + $team_names = array( 'Patriots', 'Bills', 'Dolphins', 'Jets' ); + + foreach ( $team_names as $team_name ) { + $team_term = wp_insert_term( $team_name, 'team' ); + self::set_object_terms( $pid, $team_term, 'team' ); + } + + $this->assertEquals( count( $team_names ), count( $post->terms( array( + 'query' => array( + 'taxonomy' => 'team', + ), + ) ) ) ); + + // test tags method - wrapper for $this->get_terms('tags') + $this->assertEquals($post->tags(), $post->terms( array( + 'query' => array( + 'taxonomy' => 'post_tag', + ), + ) ) ); + + // test categories method - wrapper for $this->get_terms('category') + $this->assertEquals($post->categories(), $post->terms( array( + 'query' => array( + 'taxonomy' => 'category', + ), + ) ) ); + + // test using an array of taxonomies + $post_tag_terms = $post->terms( array( + 'query' => array( + 'taxonomy' => array( 'post_tag' ), + ), + ) ); + $this->assertEquals(1, count($post_tag_terms)); + $post_team_terms = $post->terms( array( + 'query' => array( + 'taxonomy' => array( 'team' ), + ), + ) ); + $this->assertEquals(count($team_names), count($post_team_terms)); + + // test multiple taxonomies + $post_tag_and_team_terms = $post->terms( array( + 'query' => array( + 'taxonomy' => array( 'post_tag', 'team' ), + ), + ) ); + $this->assertEquals(count($post_tag_terms) + count($post_team_terms), count($post_tag_and_team_terms)); + } + + function testPostTermsMerge() { + $pid = $this->factory->post->create(); + $post = Timber::get_post( $pid ); + + // register a custom taxonomy, create some terms in it and associate to post + register_taxonomy( 'team', 'post' ); + $team_names = array( 'Patriots', 'Bills', 'Dolphins', 'Jets' ); + + foreach ( $team_names as $team_name ) { + $team_term = wp_insert_term( $team_name, 'team' ); + self::set_object_terms( $pid, $team_term, 'team' ); } - function testPostTermsArgumentStyle() { - $pid = $this->factory->post->create(); - $post = Timber::get_post( $pid ); - $category = wp_insert_term( 'Uncategorized', 'category' ); - self::set_object_terms( $pid, $category, 'category' ); - - // create a new tag and associate it with the post - $dummy_tag = wp_insert_term( 'whatever', 'post_tag' ); - self::set_object_terms( $pid, $dummy_tag, 'post_tag' ); - - // test expected tags - $timber_tags = $post->terms( array( - 'query' => array( - 'taxonomy' => 'post_tag', - ), - ) ); - $dummy_timber_tag = Timber::get_term( $dummy_tag['term_id'], 'post_tag' ); - $this->assertEquals( 'whatever', $timber_tags[0]->slug ); - $this->assertEquals( $dummy_timber_tag, $timber_tags[0] ); - - // register a custom taxonomy, create some terms in it and associate to post - register_taxonomy( 'team', 'post' ); - $team_names = array( 'Patriots', 'Bills', 'Dolphins', 'Jets' ); - - foreach ( $team_names as $team_name ) { - $team_term = wp_insert_term( $team_name, 'team' ); - self::set_object_terms( $pid, $team_term, 'team' ); - } + register_taxonomy( 'book', 'post' ); + $book_names = array( 'Fall of Giants', 'Winter of the World', 'Edge of Eternity' ); - $this->assertEquals( count( $team_names ), count( $post->terms( array( - 'query' => array( - 'taxonomy' => 'team', - ), - ) ) ) ); - - // test tags method - wrapper for $this->get_terms('tags') - $this->assertEquals($post->tags(), $post->terms( array( - 'query' => array( - 'taxonomy' => 'post_tag', - ), - ) ) ); - - // test categories method - wrapper for $this->get_terms('category') - $this->assertEquals($post->categories(), $post->terms( array( - 'query' => array( - 'taxonomy' => 'category', - ), - ) ) ); - - // test using an array of taxonomies - $post_tag_terms = $post->terms( array( - 'query' => array( - 'taxonomy' => array( 'post_tag' ), - ), - ) ); - $this->assertEquals(1, count($post_tag_terms)); - $post_team_terms = $post->terms( array( - 'query' => array( - 'taxonomy' => array( 'team' ), - ), - ) ); - $this->assertEquals(count($team_names), count($post_team_terms)); - - // test multiple taxonomies - $post_tag_and_team_terms = $post->terms( array( - 'query' => array( - 'taxonomy' => array( 'post_tag', 'team' ), - ), - ) ); - $this->assertEquals(count($post_tag_terms) + count($post_team_terms), count($post_tag_and_team_terms)); + foreach ( $book_names as $book_name ) { + $book_term = wp_insert_term( $book_name, 'book' ); + self::set_object_terms( $pid, $book_term, 'book' ); } - function testPostTermsMerge() { - $pid = $this->factory->post->create(); - $post = Timber::get_post( $pid ); + $team_and_book_terms = $post->terms( array( + 'query' => array( + 'taxonomy' => array( 'team', 'book' ), + ), + 'merge' => false, + ) ); + $this->assertEquals(4, count($team_and_book_terms['team'])); + $this->assertEquals(3, count($team_and_book_terms['book'])); + } - // register a custom taxonomy, create some terms in it and associate to post - register_taxonomy( 'team', 'post' ); - $team_names = array( 'Patriots', 'Bills', 'Dolphins', 'Jets' ); + function testPostTermQueryArgs() { + $pid = $this->factory->post->create(); + $post = Timber::get_post( $pid ); - foreach ( $team_names as $team_name ) { - $team_term = wp_insert_term( $team_name, 'team' ); - self::set_object_terms( $pid, $team_term, 'team' ); - } + // register a custom taxonomy, create some terms in it and associate to post + register_taxonomy( 'team', 'post' ); + $team_names = array( 'Patriots', 'Bills', 'Dolphins', 'Jets' ); - register_taxonomy( 'book', 'post' ); - $book_names = array( 'Fall of Giants', 'Winter of the World', 'Edge of Eternity' ); + foreach ( $team_names as $team_name ) { + $team_term = wp_insert_term( $team_name, 'team' ); + self::set_object_terms( $pid, $team_term, 'team' ); + } - foreach ( $book_names as $book_name ) { - $book_term = wp_insert_term( $book_name, 'book' ); - self::set_object_terms( $pid, $book_term, 'book' ); - } + register_taxonomy( 'book', 'post' ); + $book_names = array( 'Fall of Giants', 'Winter of the World', 'Edge of Eternity' ); - $team_and_book_terms = $post->terms( array( - 'query' => array( - 'taxonomy' => array( 'team', 'book' ), - ), - 'merge' => false, - ) ); - $this->assertEquals(4, count($team_and_book_terms['team'])); - $this->assertEquals(3, count($team_and_book_terms['book'])); + foreach ( $book_names as $book_name ) { + $book_term = wp_insert_term( $book_name, 'book' ); + self::set_object_terms( $pid, $book_term, 'book' ); } - function testPostTermQueryArgs() { - $pid = $this->factory->post->create(); - $post = Timber::get_post( $pid ); + // Test order. + $team_and_book_terms = $post->terms( array( + 'query' => array( + 'taxonomy' => array( 'team', 'book' ), + 'orderby' => 'name', + ), + ) ); - // register a custom taxonomy, create some terms in it and associate to post - register_taxonomy( 'team', 'post' ); - $team_names = array( 'Patriots', 'Bills', 'Dolphins', 'Jets' ); + $this->assertEquals( 'Bills', $team_and_book_terms[0]->title ); + $this->assertEquals( 'Edge of Eternity', $team_and_book_terms[2]->title ); - foreach ( $team_names as $team_name ) { - $team_term = wp_insert_term( $team_name, 'team' ); - self::set_object_terms( $pid, $team_term, 'team' ); - } + // Test number of terms + $team_and_book_terms = $post->terms( array( + 'query' => array( + 'taxonomy' => array( 'team', 'book' ), + 'number' => 3, + ), + ) ); - register_taxonomy( 'book', 'post' ); - $book_names = array( 'Fall of Giants', 'Winter of the World', 'Edge of Eternity' ); + $this->assertCount( 3, $team_and_book_terms ); - foreach ( $book_names as $book_name ) { - $book_term = wp_insert_term( $book_name, 'book' ); - self::set_object_terms( $pid, $book_term, 'book' ); - } + // Test query in Twig + $string = Timber::compile_string( "{{ + post.terms({ + query: { + taxonomy: ['team', 'book'], + number: 3, + orderby: 'name' + } + })|join(', ') }}", array( 'post' => $post ) ); - // Test order. - $team_and_book_terms = $post->terms( array( - 'query' => array( - 'taxonomy' => array( 'team', 'book' ), - 'orderby' => 'name', - ), - ) ); - - $this->assertEquals( 'Bills', $team_and_book_terms[0]->title ); - $this->assertEquals( 'Edge of Eternity', $team_and_book_terms[2]->title ); - - // Test number of terms - $team_and_book_terms = $post->terms( array( - 'query' => array( - 'taxonomy' => array( 'team', 'book' ), - 'number' => 3, - ), - ) ); - - $this->assertCount( 3, $team_and_book_terms ); - - // Test query in Twig - $string = Timber::compile_string( "{{ - post.terms({ - query: { - taxonomy: ['team', 'book'], - number: 3, - orderby: 'name' - } - })|join(', ') }}", array( 'post' => $post ) ); - - $this->assertEquals( 'Bills, Dolphins, Edge of Eternity', $string ); - } + $this->assertEquals( 'Bills, Dolphins, Edge of Eternity', $string ); + } - function set_object_terms( $pid, $term_info, $taxonomy = 'post_tag' , $append = true ) { - $term_id = 0; - if ( is_array($term_info) ) { - $term_id = $term_info['term_id']; - } else if ( is_object($term_info) && get_class($term_info) == 'WP_Error' ) { - $term_id = $term_info->error_data['term_exists']; - } - if ( $term_id ) { - wp_set_object_terms($pid, $term_id, $taxonomy, $append); - } + function set_object_terms( $pid, $term_info, $taxonomy = 'post_tag' , $append = true ) { + $term_id = 0; + if ( is_array($term_info) ) { + $term_id = $term_info['term_id']; + } else if ( is_object($term_info) && get_class($term_info) == 'WP_Error' ) { + $term_id = $term_info->error_data['term_exists']; } - - function testPostTermClass() { - // create new post - $pid = $this->factory->post->create(); - $post = Timber::get_post($pid); - - // create a new tag, associate with post - $dummy_tag = wp_insert_term('whatever', 'post_tag'); - self::set_object_terms($pid, $dummy_tag, 'post_tag'); - - $this->add_filter_temporarily('timber/term/classmap', function() { - return [ - 'post_tag' => TimberTermSubclass::class - ]; - }); - - // Test argument style. - $terms = $post->terms([ - 'query' => [ - 'taxonomy' => 'post_tag', - ], - ]); - - $this->assertInstanceOf(TimberTermSubclass::class, $terms[0]); + if ( $term_id ) { + wp_set_object_terms($pid, $term_id, $taxonomy, $append); } + } - function testPostContentLength() { - $crawl = "The evil leaders of Planet Spaceball having foolishly spuandered their precious atmosphere, have devised a secret plan to take every breath of air away from their peace-loving neighbor, Planet Druidia. Today is Princess Vespa's wedding day. Unbeknownest to the princess, but knowest to us, danger lurks in the stars above..."; - $pid = $this->factory->post->create(array('post_content' => $crawl)); - $post = Timber::get_post($pid); - $content = trim(strip_tags($post->content(0, 6))); - $this->assertEquals("The evil leaders of Planet Spaceball…", $content); - } + function testPostTermClass() { + // create new post + $pid = $this->factory->post->create(); + $post = Timber::get_post($pid); + + // create a new tag, associate with post + $dummy_tag = wp_insert_term('whatever', 'post_tag'); + self::set_object_terms($pid, $dummy_tag, 'post_tag'); + + $this->add_filter_temporarily('timber/term/classmap', function() { + return [ + 'post_tag' => TimberTermSubclass::class + ]; + }); + + // Test argument style. + $terms = $post->terms([ + 'query' => [ + 'taxonomy' => 'post_tag', + ], + ]); + + $this->assertInstanceOf(TimberTermSubclass::class, $terms[0]); + } - function testPostTypeObject() { - $pid = $this->factory->post->create(); - $post = Timber::get_post($pid); - $pto = $post->type(); - $this->assertEquals('Posts', $pto->label); - } + function testPostContentLength() { + $crawl = "The evil leaders of Planet Spaceball having foolishly spuandered their precious atmosphere, have devised a secret plan to take every breath of air away from their peace-loving neighbor, Planet Druidia. Today is Princess Vespa's wedding day. Unbeknownest to the princess, but knowest to us, danger lurks in the stars above..."; + $pid = $this->factory->post->create(array('post_content' => $crawl)); + $post = Timber::get_post($pid); + $content = trim(strip_tags($post->content(0, 6))); + $this->assertEquals("The evil leaders of Planet Spaceball…", $content); + } - function testPage() { - $pid = $this->factory->post->create(array('post_type' => 'page', 'post_title' => 'My Page')); - $post = Timber::get_post($pid); - $this->assertEquals($pid, $post->ID); - $this->assertEquals('My Page', $post->title()); - } + function testPostTypeObject() { + $pid = $this->factory->post->create(); + $post = Timber::get_post($pid); + $pto = $post->type(); + $this->assertEquals('Posts', $pto->label); + } - function testCommentFormOnPost() { - $post_id = $this->factory->post->create(); - $post = Timber::get_post($post_id); - $form = $post->comment_form(); - $this->assertStringStartsWith('
    factory->post->create(array('post_type' => 'page', 'post_title' => 'My Page')); + $post = Timber::get_post($pid); + $this->assertEquals($pid, $post->ID); + $this->assertEquals('My Page', $post->title()); + } - function testPostWithoutGallery() { - $pid = $this->factory->post->create(); - $post = Timber::get_post($pid); + function testCommentFormOnPost() { + $post_id = $this->factory->post->create(); + $post = Timber::get_post($post_id); + $form = $post->comment_form(); + $this->assertStringStartsWith('
    assertEquals(null, $post->gallery()); - } + function testPostWithoutGallery() { + $pid = $this->factory->post->create(); + $post = Timber::get_post($pid); - function testPostWithoutAudio() { - $pid = $this->factory->post->create(); - $post = Timber::get_post($pid); + $this->assertEquals(null, $post->gallery()); + } - $this->assertEquals(array(), $post->audio()); - } + function testPostWithoutAudio() { + $pid = $this->factory->post->create(); + $post = Timber::get_post($pid); - function testPostWithAudio() { - $quote = 'Named must your fear be before banish it you can.'; - $quote .= '[embed]http://www.noiseaddicts.com/samples_1w72b820/280.mp3[/embed]'; - $quote .= "No, try not. Do or do not. There is no try."; + $this->assertEquals(array(), $post->audio()); + } - $pid = $this->factory->post->create(array('post_content' => $quote)); - $post = Timber::get_post($pid); - $expected = array( - '', - ); + function testPostWithAudio() { + $quote = 'Named must your fear be before banish it you can.'; + $quote .= '[embed]http://www.noiseaddicts.com/samples_1w72b820/280.mp3[/embed]'; + $quote .= "No, try not. Do or do not. There is no try."; - $this->assertEquals($expected, $post->audio()); - } + $pid = $this->factory->post->create(array('post_content' => $quote)); + $post = Timber::get_post($pid); + $expected = array( + '', + ); - function testPostWithAudioCustomField() { - $quote = 'Named must your fear be before banish it you can.'; - $quote .= '[embed]http://www.noiseaddicts.com/samples_1w72b820/280.mp3[/embed]'; - $quote .= "No, try not. Do or do not. There is no try."; - - $pid = $this->factory->post->create(array('post_content' => $quote)); - update_post_meta($pid, 'audio', 'foo'); - $expected = array( - '', - ); - $post = Timber::get_post($pid); - $this->assertEquals($expected, $post->audio()); - } + $this->assertEquals($expected, $post->audio()); + } - function testPostWithoutVideo() { - $pid = $this->factory->post->create(); - $post = Timber::get_post($pid); + function testPostWithAudioCustomField() { + $quote = 'Named must your fear be before banish it you can.'; + $quote .= '[embed]http://www.noiseaddicts.com/samples_1w72b820/280.mp3[/embed]'; + $quote .= "No, try not. Do or do not. There is no try."; + + $pid = $this->factory->post->create(array('post_content' => $quote)); + update_post_meta($pid, 'audio', 'foo'); + $expected = array( + '', + ); + $post = Timber::get_post($pid); + $this->assertEquals($expected, $post->audio()); + } - $this->assertEquals(array(), $post->video()); - } + function testPostWithoutVideo() { + $pid = $this->factory->post->create(); + $post = Timber::get_post($pid); - function testPostWithVideo() { - $quote = 'Named must your fear be before banish it you can.'; - $quote .= '[embed]https://www.youtube.com/watch?v=Jf37RalsnEs[/embed]'; - $quote .= "No, try not. Do or do not. There is no try."; + $this->assertEquals(array(), $post->video()); + } - $pid = $this->factory->post->create(array('post_content' => $quote)); - $post = Timber::get_post($pid); + function testPostWithVideo() { + $quote = 'Named must your fear be before banish it you can.'; + $quote .= '[embed]https://www.youtube.com/watch?v=Jf37RalsnEs[/embed]'; + $quote .= "No, try not. Do or do not. There is no try."; - $video = $post->video(); - if ( is_array($video) ) { - $video = array_shift( $video ); - } - $expected = '/