Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions src/DataObject/Storage/CustomPostTypeStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ public function insert( array $data ): int {
$post_id = wp_insert_post( [
'post_type' => $this->slug,
'post_status' => 'publish',
'post_title' => $data['title'] ?? '',
'post_title' => $this->prepare_data( $data['title'] ?? '' ),
], true );

if ( is_wp_error( $post_id ) ) {
return 0;
}

update_post_meta( $post_id, self::META_KEY, wp_json_encode( $data ) );
update_post_meta( $post_id, self::META_KEY, $this->prepare_data( $data ) );

return $post_id;
}
Expand All @@ -42,11 +42,11 @@ public function update( int $id, array $data ): void {
if ( isset( $data['title'] ) ) {
wp_update_post( [
'ID' => $id,
'post_title' => $data['title'],
'post_title' => $this->prepare_data( $data['title'] ),
] );
}

update_post_meta( $id, self::META_KEY, wp_json_encode( $data ) );
update_post_meta( $id, self::META_KEY, $this->prepare_data( $data ) );
}

public function delete( int $id ): void {
Expand Down Expand Up @@ -89,4 +89,19 @@ public function all(): array {

return $results;
}

/**
* We expect $value to be unslashed, as it will either come
* from Request::get_body_params() or be manually set
*
* Post and meta functions both expect slashed data:
* @see https://developer.wordpress.org/reference/hooks/wp_insert_post_data/
* @see https://developer.wordpress.org/reference/functions/update_post_meta/
*/
protected function prepare_data( string|array $value ): string {
if ( is_array( $value ) ) {
$value = wp_json_encode( $value );
}
return wp_slash( $value );
}
}
2 changes: 1 addition & 1 deletion src/DataView/FieldTypeRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ public function sanitize_boolean( mixed $value ): bool {
public function sanitize_repeater( mixed $value ): string {
// Handle JSON string input (from Tangible Fields hidden input).
if ( is_string( $value ) ) {
$decoded = json_decode( stripslashes( $value ), true );
$decoded = json_decode( $value, true );
if ( json_last_error() === JSON_ERROR_NONE && is_array( $decoded ) ) {
return wp_json_encode( $this->sanitize_repeater_rows( $decoded ) );
}
Expand Down
7 changes: 7 additions & 0 deletions src/DataView/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,11 @@ public function get_nonce( ?string $name = '_wpnonce' ): string {
public function is_post(): bool {
return $this->rest_request->is_method( 'POST' );
}

/**
* Get the POST body parameters (unslashed)
*/
public function get_body_params(): array {
return $this->rest_request->get_body_params();
}
}
11 changes: 4 additions & 7 deletions src/DataView/RequestRouter.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use Tangible\Renderer\HtmlRenderer;
use Tangible\RequestHandler\PluralHandler;
use Tangible\RequestHandler\SingularHandler;
use Tangible\RequestHandler\Result;

/**
* Handles request routing and rendering for DataView admin pages.
Expand Down Expand Up @@ -441,15 +440,14 @@ protected function handle_settings_submit(): void {
protected function extract_post_data(): array {
$data = [];

// phpcs:ignore WordPress.Security.NonceVerification.Missing
$nested = $_POST[ $this->config->slug ] ?? [];
$params = $this->request->get_body_params();
$nested = $params[ $this->config->slug ] ?? [];

foreach ( $this->config->field_configs as $name => $config ) {
$type = $config['type'];

// Check nested array first (singular/settings mode), then flat POST
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$has_value = isset( $nested[ $name ] ) || isset( $_POST[ $name ] );
$has_value = isset( $nested[ $name ] ) || isset( $params[ $name ] );

if ( ! $has_value ) {
// Handle missing boolean fields (unchecked checkboxes).
Expand All @@ -464,8 +462,7 @@ protected function extract_post_data(): array {
}

$sanitizer = $this->registry->get_sanitizer( $type );
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$raw_value = $nested[ $name ] ?? $_POST[ $name ];
$raw_value = $nested[ $name ] ?? $params[ $name ];
$data[ $name ] = $sanitizer( $raw_value );
}

Expand Down
14 changes: 0 additions & 14 deletions tests/phpunit/data-view.php
Original file line number Diff line number Diff line change
Expand Up @@ -487,20 +487,6 @@ public function test_repeater_sanitizer_handles_json_string(): void {
$this->assertEquals( 5, $decoded[0]['count'] );
}

public function test_repeater_sanitizer_handles_escaped_json(): void {
$registry = new FieldTypeRegistry();
$sanitizer = $registry->get_sanitizer( 'repeater' );

// Simulates WordPress POST data with escaped quotes.
$input = addslashes( '[{"key":"abc","name":"Test"}]' );
$result = $sanitizer( $input );
$decoded = json_decode( $result, true );

$this->assertIsArray( $decoded );
$this->assertCount( 1, $decoded );
$this->assertEquals( 'Test', $decoded[0]['name'] );
}

public function test_repeater_sanitizer_handles_array_input(): void {
$registry = new FieldTypeRegistry();
$sanitizer = $registry->get_sanitizer( 'repeater' );
Expand Down
Loading