| @@ -143,8 +143,12 @@ | ||
| 143 | 143 | * |
| 144 | 144 | * @return void |
| 145 | 145 | */ |
| 146 | 146 | public static function maybe_unlock_post() { |
| 147 | + if ( ! is_singular() ) { | |
| 148 | + return; | |
| 149 | + } | |
| 150 | + | |
| 147 | 151 | $post_id = get_queried_object_id(); |
| 148 | 152 | |
| 149 | 153 | if ( ! $post_id ) { |
| 150 | 154 | return; |
| @@ -155,10 +159,25 @@ | ||
| 155 | 159 | if ( ! $post ) { |
| 156 | 160 | return; |
| 157 | 161 | } |
| 158 | 162 | |
| 163 | + $post_item = FrmGatedItem::make( | |
| 164 | + array( | |
| 165 | + 'type' => $post->post_type, | |
| 166 | + 'id' => $post_id, | |
| 167 | + ) | |
| 168 | + ); | |
| 169 | + | |
| 170 | + // Only act on posts that are registered in an active gated content action. | |
| 171 | + // Posts unrelated to gated content must not have their access interfered with. | |
| 172 | + if ( ! self::has_gated_action_for_item( $post_item ) ) { | |
| 173 | + return; | |
| 174 | + } | |
| 175 | + | |
| 159 | 176 | $is_password_protected = '' !== $post->post_password; |
| 160 | - $is_restricted_private = 'private' === $post->post_status && ! current_user_can( 'read_private_posts', $post_id ); | |
| 177 | + $post_type_obj = get_post_type_object( $post->post_type ); | |
| 178 | + $read_private_cap = $post_type_obj ? $post_type_obj->cap->read_private_posts : 'read_private_posts'; | |
| 179 | + $is_restricted_private = 'private' === $post->post_status && ! current_user_can( $read_private_cap, $post_id ); | |
| 161 | 180 | $access_code_from_url = FrmAppHelper::simple_get( 'access_code' ); |
| 162 | 181 | |
| 163 | 182 | // Nothing to unlock — post is publicly accessible. |
| 164 | 183 | if ( ! $is_password_protected && ! $is_restricted_private ) { |
| @@ -168,14 +187,8 @@ | ||
| 168 | 187 | |
| 169 | 188 | return; |
| 170 | 189 | } |
| 171 | 190 | |
| 172 | - $post_item = FrmGatedItem::make( | |
| 173 | - array( | |
| 174 | - 'type' => $post->post_type, | |
| 175 | - 'id' => $post_id, | |
| 176 | - ) | |
| 177 | - ); | |
| 178 | 191 | $valid_token = FrmGatedTokenHelper::get_valid_token( $post_item ); |
| 179 | 192 | |
| 180 | 193 | if ( $valid_token ) { |
| 181 | 194 | // Password-protected posts need an explicit filter; private posts are |
| @@ -198,8 +211,44 @@ | ||
| 198 | 211 | // No valid token — force a 404 to prevent private posts from being exposed. |
| 199 | 212 | if ( $is_restricted_private ) { |
| 200 | 213 | self::force_404(); |
| 201 | 214 | } |
| 215 | + } | |
| 216 | + | |
| 217 | + /** | |
| 218 | + * Check whether a content item is registered in at least one active gated content action. | |
| 219 | + * | |
| 220 | + * Used by maybe_unlock_post() to avoid interfering with private posts that are unrelated | |
| 221 | + * to gated content — only items explicitly listed in a published gated content action | |
| 222 | + * should have their access controlled by this plugin. | |
| 223 | + * | |
| 224 | + * @param FrmGatedItem $item Content item to look up. | |
| 225 | + * | |
| 226 | + * @return bool True if any published gated content action lists this item. | |
| 227 | + */ | |
| 228 | + private static function has_gated_action_for_item( FrmGatedItem $item ): bool { | |
| 229 | + global $wpdb; | |
| 230 | + | |
| 231 | + // Direct query — FrmDb caches results per-request which would hide newly | |
| 232 | + // created actions until the cache expires. action_contains_item() already | |
| 233 | + // handles per-action caching via transients. | |
| 234 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 235 | + $action_ids = $wpdb->get_col( | |
| 236 | + $wpdb->prepare( | |
| 237 | + "SELECT ID FROM %i WHERE post_type = %s AND post_excerpt = %s AND post_status = 'publish'", | |
| 238 | + $wpdb->posts, | |
| 239 | + FrmFormActionsController::$action_post_type, | |
| 240 | + FrmGatedContentAction::$slug | |
| 241 | + ) | |
| 242 | + ); | |
| 243 | + | |
| 244 | + foreach ( $action_ids as $action_id ) { | |
| 245 | + if ( FrmGatedTokenHelper::action_contains_item( (int) $action_id, $item ) ) { | |
| 246 | + return true; | |
| 247 | + } | |
| 248 | + } | |
| 249 | + | |
| 250 | + return false; | |
| 202 | 251 | } |
| 203 | 252 | |
| 204 | 253 | /** |
| 205 | 254 | * Force the current request to a 404 response. |