diff --git a/liveblog.php b/liveblog.php index e58d512c..da2fd598 100644 --- a/liveblog.php +++ b/liveblog.php @@ -2304,20 +2304,29 @@ public static function get_liveblog_metadata( $metadata, $post ) { $blog_updates[] = json_decode( wp_json_encode( $blog_item ) ); } - $metadata['@context'] = 'https://schema.org'; - $metadata['@type'] = 'LiveBlogPosting'; - $metadata['headline'] = get_the_title( $post ); - $metadata['url'] = get_permalink( $post ); - $metadata['datePublished'] = get_post_datetime( $post, 'date', 'gmt' )->format( 'c' ); - $metadata['dateModified'] = get_post_datetime( $post, 'modified', 'gmt' )->format( 'c' ); - - // Add coverage times for LiveBlogPosting (helps with Google's "LIVE" badge). - $metadata['coverageStartTime'] = $metadata['datePublished']; - - // Add coverageEndTime only if the liveblog is archived. - $liveblog_state = self::get_liveblog_state( $post->ID ); - if ( 'archive' === $liveblog_state ) { - $metadata['coverageEndTime'] = $metadata['dateModified']; + $metadata['@context'] = 'https://schema.org'; + $metadata['@type'] = 'LiveBlogPosting'; + $metadata['headline'] = get_the_title( $post ); + $metadata['url'] = get_permalink( $post ); + // Unpublished posts (drafts, pending, auto-drafts) store a `0000-00-00 00:00:00` + // GMT date, for which get_post_datetime() returns false. Guard against calling + // format() on false to avoid a fatal when such a post is previewed. + $published_datetime = get_post_datetime( $post, 'date', 'gmt' ); + if ( false !== $published_datetime ) { + $metadata['datePublished'] = $published_datetime->format( 'c' ); + + // Add coverage times for LiveBlogPosting (helps with Google's "LIVE" badge). + $metadata['coverageStartTime'] = $metadata['datePublished']; + } + + $modified_datetime = get_post_datetime( $post, 'modified', 'gmt' ); + if ( false !== $modified_datetime ) { + $metadata['dateModified'] = $modified_datetime->format( 'c' ); + + // Add coverageEndTime only if the liveblog is archived. + if ( 'archive' === self::get_liveblog_state( $post->ID ) ) { + $metadata['coverageEndTime'] = $metadata['dateModified']; + } } $metadata['liveBlogUpdate'] = $blog_updates; diff --git a/tests/Integration/SchemaMetadataTest.php b/tests/Integration/SchemaMetadataTest.php index 8639a21a..e2821847 100644 --- a/tests/Integration/SchemaMetadataTest.php +++ b/tests/Integration/SchemaMetadataTest.php @@ -358,6 +358,51 @@ public function test_entries_present_for_password_protected_post_with_password() $this->assertNotEmpty( $metadata['liveBlogUpdate'] ); } + /** + * Test that metadata generation does not fatal for an unpublished post. + * + * Drafts (and pending/auto-draft posts) store a `0000-00-00 00:00:00` GMT + * date, for which get_post_datetime() returns false. Previously this caused + * a fatal `Call to a member function format() on false` when such a post was + * previewed. See https://github.com/Automattic/liveblog/issues/919. + */ + public function test_metadata_omits_dates_for_unpublished_post(): void { + $draft_id = self::factory()->post->create( + array( + 'post_title' => 'Draft Liveblog', + 'post_status' => 'draft', + ) + ); + update_post_meta( $draft_id, WPCOM_Liveblog::KEY, 'enable' ); + + // Confirm the fixture reproduces the original conditions: the GMT date is + // unavailable, so get_post_datetime() returns false. + $this->assertFalse( get_post_datetime( $draft_id, 'date', 'gmt' ) ); + + $metadata = WPCOM_Liveblog::get_liveblog_metadata( array(), get_post( $draft_id ) ); + + // The metadata is still generated (proving the date code did not fatal)... + $this->assertEquals( 'LiveBlogPosting', $metadata['@type'] ); + + // ...but the date-derived properties are omitted rather than fatalling. + $this->assertArrayNotHasKey( 'datePublished', $metadata ); + $this->assertArrayNotHasKey( 'dateModified', $metadata ); + $this->assertArrayNotHasKey( 'coverageStartTime', $metadata ); + } + + /** + * Test that a published post still includes the date-derived properties. + */ + public function test_metadata_includes_dates_for_published_post(): void { + $this->insert_entry( array( 'content' => '

Test entry

' ) ); + + $metadata = WPCOM_Liveblog::get_liveblog_metadata( array(), get_post( $this->post_id ) ); + + $this->assertArrayHasKey( 'datePublished', $metadata ); + $this->assertArrayHasKey( 'dateModified', $metadata ); + $this->assertArrayHasKey( 'coverageStartTime', $metadata ); + } + /** * Insert a liveblog entry. *