diff --git a/CHANGELOG.md b/CHANGELOG.md index d1ce21a..0ffa9cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ All notable changes to Procore Connect are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.5] — 2026-08-08 + +### Fixed + +- **`[procore_team]` rendered an empty Email column.** Email suppression is on by + default, so the Email header appeared above a blank cell for every team member — + visible dead weight on the most commonly used shortcode, on every default install. + Columns that render nothing for any row are now dropped. This also covers a column + no record happens to populate, and a table is never reduced to no columns at all. + + Found by standing up a real WordPress site, serving it over HTTP and reading what a + visitor actually gets, rather than by asserting on strings. + ## [2.0.4] — 2026-08-08 ### Security @@ -231,6 +244,7 @@ every install was non-functional regardless of configuration. - Initial release. +[2.0.5]: https://github.com/ibuilder/ProcoreWP/releases/tag/v2.0.5 [2.0.4]: https://github.com/ibuilder/ProcoreWP/releases/tag/v2.0.4 [2.0.3]: https://github.com/ibuilder/ProcoreWP/releases/tag/v2.0.3 [2.0.2]: https://github.com/ibuilder/ProcoreWP/releases/tag/v2.0.2 diff --git a/procore-connect.php b/procore-connect.php index db5b2ed..8b8f6cd 100644 --- a/procore-connect.php +++ b/procore-connect.php @@ -3,7 +3,7 @@ * Plugin Name: Procore Connect * Plugin URI: https://github.com/ibuilder/ProcoreWP * Description: Connect WordPress to the Procore construction management platform. Display projects, teams, drawings, RFIs and more with shortcodes, blocks and a cached REST proxy. - * Version: 2.0.4 + * Version: 2.0.5 * Requires at least: 6.5 * Requires PHP: 7.4 * Author: ibuilder @@ -22,7 +22,7 @@ defined( 'ABSPATH' ) || exit; -const VERSION = '2.0.4'; +const VERSION = '2.0.5'; define( 'PROCORE_CONNECT_VERSION', VERSION ); define( 'PROCORE_CONNECT_FILE', __FILE__ ); diff --git a/readme.txt b/readme.txt index 22e633a..6268a23 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: procore, construction, project management, shortcode, api Requires at least: 6.5 Tested up to: 7.0 Requires PHP: 7.4 -Stable tag: 2.0.4 +Stable tag: 2.0.5 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html @@ -127,6 +127,10 @@ Yes. Caching goes through the transient API, so a persistent object cache such a == Changelog == += 2.0.5 = + +* Fixed: `[procore_team]` showed an empty Email column. Email output is suppressed by default, so the column appeared with a header and blank cells on every default install. Columns with no value in any row are now hidden. + = 2.0.4 = * Security documentation no longer recommends 2.0.0 or 2.0.1, the versions that damage the stored Client Secret. Both are now marked unsupported with the remedy stated plainly. @@ -183,6 +187,9 @@ A complete rewrite. See the upgrade notice below before updating. == Upgrade Notice == += 2.0.5 = +Cosmetic fix: the team table no longer shows an empty Email column when email output is suppressed, which is the default. + = 2.0.4 = Documentation and test coverage only. No functional change from 2.0.3. diff --git a/src/Frontend/Shortcodes/CollectionShortcode.php b/src/Frontend/Shortcodes/CollectionShortcode.php index ed8f936..c2b8135 100644 --- a/src/Frontend/Shortcodes/CollectionShortcode.php +++ b/src/Frontend/Shortcodes/CollectionShortcode.php @@ -54,7 +54,7 @@ protected function output( $data, array $atts ): string { $this->template( $atts ), array( 'rows' => $rows, - 'columns' => $this->resolve_columns( $atts ), + 'columns' => $this->drop_empty_columns( $this->resolve_columns( $atts ), $rows, ! empty( $atts['show_email'] ) ), 'title' => $this->title( $atts ), 'class' => Format::classes( 'procore-connect procore-connect-collection procore-connect-' . str_replace( '_', '-', $this->endpoint ), (string) $atts['class'] ), 'show_email' => ! empty( $atts['show_email'] ), @@ -64,6 +64,44 @@ protected function output( $data, array $atts ): string { ); } + /** + * Remove columns that render nothing for every row. + * + * The visible case is `[procore_team]`: email suppression is on by default, + * so the Email column produced a header and a blank cell for every member — + * dead weight on the most commonly used shortcode. This also covers a + * column no record happens to populate. + * + * A column an author asked for explicitly is always kept, so `columns=""` + * still means what it says. + * + * @param array> $columns Column definitions. + * @param array $rows Records being rendered. + * @param bool $show_email Whether the shortcode opted in to email output. + * @return array> Columns that carry at least one value. + */ + protected function drop_empty_columns( array $columns, array $rows, bool $show_email ): array { + $kept = array(); + + foreach ( $columns as $column ) { + $has_value = false; + + foreach ( $rows as $row ) { + if ( '' !== trim( Format::cell( $row, $column, $show_email ) ) ) { + $has_value = true; + break; + } + } + + if ( $has_value ) { + $kept[] = $column; + } + } + + // Never render a table with no columns at all. + return empty( $kept ) ? $columns : $kept; + } + /** * The field to sort on, honouring the ProcoreWP 1.x `sort_by` alias. * diff --git a/tests/unit/ShortcodeTest.php b/tests/unit/ShortcodeTest.php index eba1fc4..72b0d73 100644 --- a/tests/unit/ShortcodeTest.php +++ b/tests/unit/ShortcodeTest.php @@ -293,6 +293,76 @@ public function test_team_hides_emails_by_default(): void { $this->assertStringNotContainsString( 'dana@example.com', $html ); } + /** + * A column that renders nothing for every row must not be shown. + * + * Email suppression is on by default, so `[procore_team]` used to emit an + * Email header and a blank cell for every member. + * + * @return void + */ + public function test_drops_a_column_that_is_empty_for_every_row(): void { + $this->client_returning( + array( + $this->response( + array( + array( + 'id' => 3, + 'name' => 'Dana Reed', + 'job_title' => 'PM', + 'email_address' => 'dana@example.com', + ), + ) + ), + ) + ); + + $html = $this->shortcode( 'procore_team' )->render( + array( + 'project_id' => '5', + 'company_id' => '9', + ) + ); + + $this->assertStringContainsString( 'Dana Reed', $html ); + $this->assertStringNotContainsString( '>Email<', $html ); + } + + /** + * A column with data must survive the empty-column filter. + * + * @return void + */ + public function test_keeps_columns_that_carry_a_value(): void { + Settings::set( 'suppress_emails', false ); + + $this->client_returning( + array( + $this->response( + array( + array( + 'id' => 3, + 'name' => 'Dana Reed', + 'job_title' => 'PM', + 'email_address' => 'dana@example.com', + ), + ) + ), + ) + ); + + $html = $this->shortcode( 'procore_team' )->render( + array( + 'project_id' => '5', + 'company_id' => '9', + 'show_email' => 'true', + ) + ); + + $this->assertStringContainsString( '>Email<', $html ); + $this->assertStringContainsString( 'dana@example.com', $html ); + } + /** * A field outside the allow-list must be refused. *