| @@ -1395,5 +1395,42 @@ | ||
| 1395 | 1395 | return $countries; |
| 1396 | 1396 | } |
| 1397 | 1397 | |
| 1398 | 1398 | |
| 1399 | + /** | |
| 1400 | + * Delete a design document that NotificationX itself owns. | |
| 1401 | + * | |
| 1402 | + * The ID reaching the callers of this method arrives in a REST payload, so | |
| 1403 | + * it is attacker-controlled. Without a post-type check, any user holding | |
| 1404 | + * `edit_notificationx` could pass an arbitrary ID and force-delete any post | |
| 1405 | + * on the site -- pages, products, orders -- with no trash to recover from. | |
| 1406 | + * Only documents of a post type NotificationX creates may be removed here. | |
| 1407 | + * | |
| 1408 | + * A `current_user_can( 'delete_post' )` check is deliberately NOT applied. | |
| 1409 | + * These post types register with `capability_type => 'post'`, so that meta | |
| 1410 | + * cap resolves to the primitive `delete_posts`. A custom role delegated only | |
| 1411 | + * "Who Can Create Notification?" does not hold `delete_posts`, and gating on | |
| 1412 | + * it would stop that role from removing its own designs -- breaking exactly | |
| 1413 | + * the delegated workflow this boundary exists to support. Actor authority is | |
| 1414 | + * already established by the route's `edit_notificationx` permission | |
| 1415 | + * callback; what was missing, and what this restores, is object authority. | |
| 1416 | + * | |
| 1417 | + * @param int|string $post_id Candidate post ID, untrusted. | |
| 1418 | + * @param string $expected_type Post type NotificationX owns. | |
| 1419 | + * @return bool True when a post was deleted. | |
| 1420 | + */ | |
| 1421 | + public static function delete_owned_post( $post_id, $expected_type ) { | |
| 1422 | + $post_id = absint( $post_id ); | |
| 1423 | + if ( ! $post_id ) { | |
| 1424 | + return false; | |
| 1425 | + } | |
| 1426 | + | |
| 1427 | + $post = get_post( $post_id ); | |
| 1428 | + if ( ! $post || $expected_type !== $post->post_type ) { | |
| 1429 | + return false; | |
| 1430 | + } | |
| 1431 | + | |
| 1432 | + return (bool) wp_delete_post( $post_id, true ); | |
| 1433 | + } | |
| 1434 | + | |
| 1435 | + | |
| 1399 | 1436 | } |