Skip to content

Commit c346cf3

Browse files
GaryJonesclaude
andcommitted
fix: prevent type errors in Syndication_Logger when no logs exist
When the Syndication_Logger attempts to retrieve logs from post meta or options that don't yet exist, WordPress returns an empty string rather than an empty array. This caused "Array to string conversion" warnings when the code attempted array operations (count, array_slice, array index) on the returned value. The fix adds defensive type checking after both get_post_meta() and get_option() calls to ensure the log variable is always an array before performing array operations. The get_option() call also now correctly specifies an empty array as its default value instead of boolean true. Integration tests verify that logging works correctly for posts with no existing logs, posts with existing logs, and that error counts are tracked properly. Fixes #152 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 25858b0 commit c346cf3

File tree

2 files changed

+131
-3
lines changed

2 files changed

+131
-3
lines changed

includes/class-syndication-logger.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,13 @@ private function log( $storage_type, $msg_type, $object_type, $object_id, $statu
305305
return new WP_Error( 'logger_no_post', __( 'The post_id provided does not exist.', 'push-syndication' ) );
306306
}
307307

308-
$log = get_post_meta( $post->ID, 'syn_log', true);
308+
$log = get_post_meta( $post->ID, 'syn_log', true );
309+
310+
// When no meta exists, get_post_meta() with $single=true returns ''.
311+
// Initialize as empty array for first log entry.
312+
if ( '' === $log ) {
313+
$log = array();
314+
}
309315

310316
if ( empty( $log ) ) {
311317
$log[0] = $log_entry;
@@ -339,9 +345,10 @@ private function log( $storage_type, $msg_type, $object_type, $object_id, $statu
339345
}
340346

341347
} else if ( 'option' == $storage_type ) {
342-
// Storing the log in an option value
348+
// Storing the log in an option value.
349+
// Default to empty array when option doesn't exist.
350+
$log = get_option( 'syn_log', array() );
343351

344-
$log = get_option( 'syn_log', true );
345352
if ( empty( $log ) ) {
346353
$log[0] = $log_entry;
347354
} else {

tests/Integration/LoggerTest.php

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<?php
2+
/**
3+
* Tests for the Syndication_Logger class.
4+
*
5+
* @package Automattic\Syndication\Tests
6+
*/
7+
8+
namespace Syndication\Tests;
9+
10+
use Yoast\WPTestUtils\WPIntegration\TestCase as WPIntegrationTestCase;
11+
use Syndication_Logger;
12+
13+
/**
14+
* Class LoggerTest
15+
*
16+
* @covers Syndication_Logger
17+
*/
18+
class LoggerTest extends WPIntegrationTestCase {
19+
20+
/**
21+
* Test that logging to a post without existing logs works correctly.
22+
*
23+
* This tests the fix for the "Array to string conversion" error that occurred
24+
* when get_post_meta was called with the third parameter as true, returning
25+
* an empty string instead of an empty array when no meta existed.
26+
*
27+
* Uses log_post_error because log_post_info requires debug_level='info'.
28+
*
29+
* @covers Syndication_Logger::log_post_error
30+
*/
31+
public function test_log_to_post_without_existing_logs(): void {
32+
// Create a site post.
33+
$site_id = $this->factory()->post->create(
34+
array(
35+
'post_type' => 'syn_site',
36+
'post_status' => 'publish',
37+
)
38+
);
39+
40+
// Log should work without throwing an error.
41+
Syndication_Logger::log_post_error(
42+
$site_id,
43+
'test_status',
44+
'Test message',
45+
null,
46+
array()
47+
);
48+
49+
// Verify the log was stored.
50+
$log = get_post_meta( $site_id, 'syn_log', true );
51+
$this->assertIsArray( $log );
52+
$this->assertNotEmpty( $log );
53+
}
54+
55+
/**
56+
* Test that logging to a post with existing logs appends correctly.
57+
*
58+
* @covers Syndication_Logger::log_post_error
59+
*/
60+
public function test_log_to_post_with_existing_logs(): void {
61+
$site_id = $this->factory()->post->create(
62+
array(
63+
'post_type' => 'syn_site',
64+
'post_status' => 'publish',
65+
)
66+
);
67+
68+
// Create initial log entry.
69+
Syndication_Logger::log_post_error(
70+
$site_id,
71+
'first_status',
72+
'First message',
73+
null,
74+
array()
75+
);
76+
77+
// Add second log entry.
78+
Syndication_Logger::log_post_error(
79+
$site_id,
80+
'second_status',
81+
'Second message',
82+
null,
83+
array()
84+
);
85+
86+
// Verify both logs exist.
87+
$log = get_post_meta( $site_id, 'syn_log', true );
88+
$this->assertIsArray( $log );
89+
$this->assertCount( 2, $log );
90+
}
91+
92+
/**
93+
* Test that error logging works correctly.
94+
*
95+
* @covers Syndication_Logger::log_post_error
96+
*/
97+
public function test_log_post_error(): void {
98+
$site_id = $this->factory()->post->create(
99+
array(
100+
'post_type' => 'syn_site',
101+
'post_status' => 'publish',
102+
)
103+
);
104+
105+
Syndication_Logger::log_post_error(
106+
$site_id,
107+
'error_status',
108+
'Error message',
109+
null,
110+
array()
111+
);
112+
113+
$log = get_post_meta( $site_id, 'syn_log', true );
114+
$this->assertIsArray( $log );
115+
$this->assertNotEmpty( $log );
116+
117+
// Error count should be tracked.
118+
$errors = get_post_meta( $site_id, 'syn_log_errors', true );
119+
$this->assertEquals( 1, (int) $errors );
120+
}
121+
}

0 commit comments

Comments
 (0)