Hollis Creek Family Dental · Repair report

Exhibit B-2 Evidence: commit d27aeda

Committed · d27aeda313b059d4476a8770a93235f8fe39f339

The team page raised a PHP warning per person

The repository itself is private; this page carries the commit as it is recorded there.

Commit message

Fix B-2: PHP 8 warnings when the team option or the next slot is missing

Root cause: the team loop read get_option( 'hctd_display' ) as an array,
but the option was deleted years ago, so PHP 8 raised "Trying to access
array offset on false" once per team member on every team page (PHP 7
was silent). The home page read the next booking slot the same way and
would warn the day no slot is open.

Fix: treat the missing option as empty settings, and only print the
"Next open appointment" line when there is a slot.

Proof: tests/phpunit/repair/Php8WarningsTest.php.

Exhibit: B-2

The change

Text files only, as recorded in git. Lines starting with + were added, lines with − removed.

Files changed

---
 site/wp-content/plugins/hc-team-directory/hc-team-directory.php |  4 ++--
 site/wp-content/themes/hollis-child/front-page.php              |  4 ++--
 tests/phpunit/repair/Php8WarningsTest.php                       | 36 +++++++++++++++++++++++++++++
 3 files changed, 40 insertions(+), 4 deletions(-)
diff --git a/site/wp-content/plugins/hc-team-directory/hc-team-directory.php b/site/wp-content/plugins/hc-team-directory/hc-team-directory.php
index 9ddb84f..ac37a2c 100644
--- a/site/wp-content/plugins/hc-team-directory/hc-team-directory.php
+++ b/site/wp-content/plugins/hc-team-directory/hc-team-directory.php
@@ -94,7 +94,7 @@ function hc_team_directory_language_name( $term ) {
  */
 function hc_team_directory_render( $limit = -1, $full = true ) {
 	global $wpdb;
-	$opts = get_option( 'hctd_display' );
+	$opts = (array) get_option( 'hctd_display', array() );
 	$sql  = "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'hc_team' AND post_status = 'publish' ORDER BY menu_order ASC, post_title ASC";
 	if ( $limit > 0 ) {
 		$sql .= ' LIMIT ' . intval( $limit );
@@ -138,7 +138,7 @@ function hc_team_directory_render( $limit = -1, $full = true ) {
 		if ( $full ) {
 			$bio   = $ko && $bio_ko ? $bio_ko : $member->post_content;
 			$html .= '<p class="team-bio">' . esc_html( wp_strip_all_tags( $bio ) ) . '</p>';
-			if ( $opts['show_languages'] || $names ) {
+			if ( ! empty( $opts['show_languages'] ) || $names ) {
 				/* translators: %s: comma-separated languages. */
 				$html .= '<p class="team-langs">' . esc_html( sprintf( __( 'Speaks: %s', 'hc-team-directory' ), implode( ', ', $names ) ) ) . '</p>';
 			}
diff --git a/site/wp-content/themes/hollis-child/front-page.php b/site/wp-content/themes/hollis-child/front-page.php
index 79997a4..174a1cf 100644
--- a/site/wp-content/themes/hollis-child/front-page.php
+++ b/site/wp-content/themes/hollis-child/front-page.php
@@ -27,8 +27,8 @@ $hollis_office = (int) get_theme_mod( 'hollis_office_image' );
 				</a>
 			</p>
 			<?php
-			if ( function_exists( 'hc_booking_next_open' ) ) {
-				$hollis_slot = hc_booking_next_open();
+			$hollis_slot = function_exists( 'hc_booking_next_open' ) ? hc_booking_next_open() : null;
+			if ( $hollis_slot ) {
 				echo '<p class="next-slot">' . esc_html__( 'Next open appointment:', 'hollis-child' ) . ' <strong>' . esc_html( $hollis_slot['label'] ) . '</strong> ' . esc_html( $hollis_slot['time'] ) . '</p>';
 			}
 			?>
diff --git a/tests/phpunit/repair/Php8WarningsTest.php b/tests/phpunit/repair/Php8WarningsTest.php
new file mode 100644
index 0000000..ffae7a5
--- /dev/null
+++ b/tests/phpunit/repair/Php8WarningsTest.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Exhibit B-2: the team list and the home page render without PHP 8 warnings when optional data is missing.
+ *
+ * @package Hollis\Tests
+ */
+
+/**
+ * PHP 8 warnings.
+ */
+class Php8WarningsTest extends WP_UnitTestCase {
+
+	public function test_team_list_renders_without_the_display_option() {
+		delete_option( 'hctd_display' );
+		self::factory()->post->create(
+			array(
+				'post_type'    => 'hc_team',
+				'post_title'   => 'Avery Lindqvist',
+				'post_content' => 'Front desk.',
+			)
+		);
+		// A warning here would be an exception (convertWarningsToExceptions).
+		$html = do_shortcode( '[hc_team]' );
+		$this->assertStringContainsString( 'Avery Lindqvist', $html );
+		$this->assertStringContainsString( 'Front desk.', $html );
+	}
+
+	public function test_home_page_renders_when_no_slot_is_open() {
+		$this->go_to( home_url( '/' ) );
+		ob_start();
+		include get_stylesheet_directory() . '/front-page.php';
+		$html = ob_get_clean();
+		$this->assertStringContainsString( 'Gentle dental care', $html );
+		$this->assertStringNotContainsString( 'Next open appointment', $html );
+	}
+}

The proving test

tests/phpunit/repair/Php8WarningsTest.php

tests/phpunit/repair/Php8WarningsTest.php, as committed.

<?php
/**
 * Exhibit B-2: the team list and the home page render without PHP 8 warnings when optional data is missing.
 *
 * @package Hollis\Tests
 */

/**
 * PHP 8 warnings.
 */
class Php8WarningsTest extends WP_UnitTestCase {

	public function test_team_list_renders_without_the_display_option() {
		delete_option( 'hctd_display' );
		self::factory()->post->create(
			array(
				'post_type'    => 'hc_team',
				'post_title'   => 'Avery Lindqvist',
				'post_content' => 'Front desk.',
			)
		);
		// A warning here would be an exception (convertWarningsToExceptions).
		$html = do_shortcode( '[hc_team]' );
		$this->assertStringContainsString( 'Avery Lindqvist', $html );
		$this->assertStringContainsString( 'Front desk.', $html );
	}

	public function test_home_page_renders_when_no_slot_is_open() {
		hc_booking_install_table();
		$this->go_to( home_url( '/' ) );
		ob_start();
		include get_stylesheet_directory() . '/front-page.php';
		$html = ob_get_clean();
		$this->assertStringContainsString( 'Gentle dental care', $html );
		$this->assertStringNotContainsString( 'Next open appointment', $html );
	}
}

Back to Exhibit B-2