} } $settings['visibility'] = $visibility; return $settings; } /** * Add item to visibility group (excluded or specific) * * @since 2.5.0 * @param int|array $item Item ID or {id, type} object * @param array &$group Reference to visibility group (excluded or specific) */ private static function add_item_to_visibility_group($item, array &$group): void { // Handle legacy format: just an integer ID (assume it's a page) if (is_numeric($item)) { $id = absint($item); if ($id > 0 && !in_array($id, $group['pages'], true)) { $group['pages'][] = $id; } return; } // Handle new format: {id, type} object if (!is_array($item) || !isset($item['id'])) { return; } $type = $item['type'] ?? 'page'; // Normalize 'post' to 'page' (WordPress posts are treated as pages in visibility) if ($type === 'post') { $type = 'page'; } switch ($type) { case 'page': $id = absint($item['id']); if ($id > 0 && !in_array($id, $group['pages'], true)) { $group['pages'][] = $id; } break; case 'category': $id = absint($item['id']); if ($id > 0 && !in_array($id, $group['categories'], true)) { $group['categories'][] = $id; } break; case 'post_type': // For post types, the ID is actually the slug $slug = is_numeric($item['id']) ? '' : sanitize_key($item['id']); if (!empty($slug) && !in_array($slug, $group['custom_post_types'], true)) { $group['custom_post_types'][] = $slug; } break; } } /** * Convert timestamp to relative date string * * @since 2.5.0 * @param int $timestamp Unix timestamp * @return string Relative date (e.g., "3d ago", "1w ago") */ private static function get_relative_date(int $timestamp): string { if ($timestamp <= 0) { return ''; } $diff = time() - $timestamp; if ($diff < 60) { return __('just now', 'reviews-feed'); } elseif ($diff < 3600) { $mins = (int) floor($diff / 60); return sprintf(_n('%dm ago', '%dm ago', $mins, 'reviews-feed'), $mins); } elseif ($diff < 86400) { $hours = (int) floor($diff / 3600); return sprintf(_n('%dh ago', '%dh ago', $hours, 'reviews-feed'), $hours); } elseif ($diff < 604800) { $days = (int) floor($diff / 86400); return sprintf(_n('%dd ago', '%dd ago', $days, 'reviews-feed'), $days); } elseif ($diff < 2592000) { $weeks = (int) floor($diff / 604800); return sprintf(_n('%dw ago', '%dw ago', $weeks, 'reviews-feed'), $weeks); } elseif ($diff < 31536000) { $months = (int) floor($diff / 2592000); return sprintf(_n('%dmo ago', '%dmo ago', $months, 'reviews-feed'), $months); } else { $years = (int) floor($diff / 31536000); return sprintf(_n('%dy ago', '%dy ago', $years, 'reviews-feed'), $years); } } /** * Sanitize visibility pages array * Handles both old format (ID-only) and new format (objects with metadata) * * @since 2.5.0 * @param array $pages Array of pages (IDs or objects) * @return array Sanitized pages array */ private static function sanitize_visibility_pages(array $pages): array { $sanitized = []; foreach ($pages as $page) { if (is_array($page)) { // New format: {id, title, url} $item = [ 'id' => isset($page['id']) ? absint($page['id']) : 0, ]; if (isset($page['title'])) { $item['title'] = sanitize_text_field($page['title']); } if (isset($page['url'])) { $item['url'] = esc_url_raw($page['url']); } // ID 0 is valid (homepage) if ($item['id'] >= 0) { $sanitized[] = $item; } } else { // Old format: just ID $id = absint($page); if ($id >= 0) { $sanitized[] = $id; } } } return array_values($sanitized); } /** * Sanitize visibility categories array * Handles both old format (ID-only) and new format (objects with metadata) * * @since 2.5.0 * @param array $categories Array of categories (IDs or objects) * @return array Sanitized categories array */ private static function sanitize_visibility_categories(array $categories): array { $sanitized = []; foreach ($categories as $category) { if (is_array($category)) { // New format: {id, name, url} $id = isset($category['id']) ? absint($category['id']) : 0; if ($id > 0) { $item = ['id' => $id]; if (isset($category['name'])) { $item['name'] = sanitize_text_field($category['name']); } if (isset($category['url'])) { $item['url'] = esc_url_raw($category['url']); } $sanitized[] = $item; } } else { // Old format: just ID $id = absint($category); if ($id > 0) { $sanitized[] = $id; } } } return array_values($sanitized); } /** * Sanitize visibility custom post types array * Handles both old format (slug-only) and new format (objects with metadata) * * @since 2.5.0 * @param array $post_types Array of post types (slugs or objects) * @return array Sanitized post types array */ private static function sanitize_visibility_post_types(array $post_types): array { $sanitized = []; foreach ($post_types as $post_type) { if (is_array($post_type)) { // New format: {name (slug), label} $slug = isset($post_type['name']) ? sanitize_key($post_type['name']) : ''; if (!empty($slug)) { $item = ['name' => $slug]; if (isset($post_type['label'])) { $item['label'] = sanitize_text_field($post_type['label']); } $sanitized[] = $item; } } else { // Old format: just slug $slug = sanitize_key($post_type); if (!empty($slug)) { $sanitized[] = $slug; } } } return array_values($sanitized); } } } } $settings['visibility'] = $visibility; return $settings; } /** * Add item to visibility group (excluded or specific) * * @since 2.5.0 * @param int|array $item Item ID or {id, type} object * @param array &$group Reference to visibility group (excluded or specific) */ private static function add_item_to_visibility_group($item, array &$group): void { // Handle legacy format: just an integer ID (assume it's a page) if (is_numeric($item)) { $id = absint($item); if ($id > 0 && !in_array($id, $group['pages'], true)) { $group['pages'][] = $id; } return; } // Handle new format: {id, type} object if (!is_array($item) || !isset($item['id'])) { return; } $type = $item['type'] ?? 'page'; // Normalize 'post' to 'page' (WordPress posts are treated as pages in visibility) if ($type === 'post') { $type = 'page'; } switch ($type) { case 'page': $id = absint($item['id']); if ($id > 0 && !in_array($id, $group['pages'], true)) { $group['pages'][] = $id; } break; case 'category': $id = absint($item['id']); if ($id > 0 && !in_array($id, $group['categories'], true)) { $group['categories'][] = $id; } break; case 'post_type': // For post types, the ID is actually the slug $slug = is_numeric($item['id']) ? '' : sanitize_key($item['id']); if (!empty($slug) && !in_array($slug, $group['custom_post_types'], true)) { $group['custom_post_types'][] = $slug; } break; } } /** * Convert timestamp to relative date string * * @since 2.5.0 * @param int $timestamp Unix timestamp * @return string Relative date (e.g., "3d ago", "1w ago") */ private static function get_relative_date(int $timestamp): string { if ($timestamp <= 0) { return ''; } $diff = time() - $timestamp; if ($diff < 60) { return __('just now', 'reviews-feed'); } elseif ($diff < 3600) { $mins = (int) floor($diff / 60); return sprintf(_n('%dm ago', '%dm ago', $mins, 'reviews-feed'), $mins); } elseif ($diff < 86400) { $hours = (int) floor($diff / 3600); return sprintf(_n('%dh ago', '%dh ago', $hours, 'reviews-feed'), $hours); } elseif ($diff < 604800) { $days = (int) floor($diff / 86400); return sprintf(_n('%dd ago', '%dd ago', $days, 'reviews-feed'), $days); } elseif ($diff < 2592000) { $weeks = (int) floor($diff / 604800); return sprintf(_n('%dw ago', '%dw ago', $weeks, 'reviews-feed'), $weeks); } elseif ($diff < 31536000) { $months = (int) floor($diff / 2592000); return sprintf(_n('%dmo ago', '%dmo ago', $months, 'reviews-feed'), $months); } else { $years = (int) floor($diff / 31536000); return sprintf(_n('%dy ago', '%dy ago', $years, 'reviews-feed'), $years); } } /** * Sanitize visibility pages array * Handles both old format (ID-only) and new format (objects with metadata) * * @since 2.5.0 * @param array $pages Array of pages (IDs or objects) * @return array Sanitized pages array */ private static function sanitize_visibility_pages(array $pages): array { $sanitized = []; foreach ($pages as $page) { if (is_array($page)) { // New format: {id, title, url} $item = [ 'id' => isset($page['id']) ? absint($page['id']) : 0, ]; if (isset($page['title'])) { $item['title'] = sanitize_text_field($page['title']); } if (isset($page['url'])) { $item['url'] = esc_url_raw($page['url']); } // ID 0 is valid (homepage) if ($item['id'] >= 0) { $sanitized[] = $item; } } else { // Old format: just ID $id = absint($page); if ($id >= 0) { $sanitized[] = $id; } } } return array_values($sanitized); } /** * Sanitize visibility categories array * Handles both old format (ID-only) and new format (objects with metadata) * * @since 2.5.0 * @param array $categories Array of categories (IDs or objects) * @return array Sanitized categories array */ private static function sanitize_visibility_categories(array $categories): array { $sanitized = []; foreach ($categories as $category) { if (is_array($category)) { // New format: {id, name, url} $id = isset($category['id']) ? absint($category['id']) : 0; if ($id > 0) { $item = ['id' => $id]; if (isset($category['name'])) { $item['name'] = sanitize_text_field($category['name']); } if (isset($category['url'])) { $item['url'] = esc_url_raw($category['url']); } $sanitized[] = $item; } } else { // Old format: just ID $id = absint($category); if ($id > 0) { $sanitized[] = $id; } } } return array_values($sanitized); } /** * Sanitize visibility custom post types array * Handles both old format (slug-only) and new format (objects with metadata) * * @since 2.5.0 * @param array $post_types Array of post types (slugs or objects) * @return array Sanitized post types array */ private static function sanitize_visibility_post_types(array $post_types): array { $sanitized = []; foreach ($post_types as $post_type) { if (is_array($post_type)) { // New format: {name (slug), label} $slug = isset($post_type['name']) ? sanitize_key($post_type['name']) : ''; if (!empty($slug)) { $item = ['name' => $slug]; if (isset($post_type['label'])) { $item['label'] = sanitize_text_field($post_type['label']); } $sanitized[] = $item; } } else { // Old format: just slug $slug = sanitize_key($post_type); if (!empty($slug)) { $sanitized[] = $slug; } } } return array_values($sanitized); } }