query(" SELECT s.id, s.name, s.occasion, s.mystery_set, s.subject_name, s.photo_path, s.slug, s.is_pinned, s.created_at, u.username, u.display_name FROM sessions s JOIN users u ON u.id = s.user_id WHERE s.is_public = 1 AND s.occasion NOT IN ('novena_deceased', 'divine_mercy_novena') AND s.is_pinned = 1 ORDER BY s.created_at DESC LIMIT 20 ")->fetchAll(); // Pinned novena groups $pinned_novenas = $pdo->query(" SELECT ng.id, ng.name, ng.mystery_set, ng.subject_name, ng.photo_path, ng.slug, ng.is_pinned, ng.created_at, u.username, u.display_name, COUNT(s.id) AS day_count FROM novena_groups ng JOIN users u ON u.id = ng.user_id LEFT JOIN sessions s ON s.novena_group_id = ng.id WHERE ng.is_public = 1 AND ng.is_pinned = 1 GROUP BY ng.id ORDER BY ng.created_at DESC LIMIT 20 ")->fetchAll(); // Regular (unpinned) sessions $sessions = $pdo->query(" SELECT s.id, s.name, s.occasion, s.mystery_set, s.subject_name, s.photo_path, s.slug, s.is_pinned, s.created_at, u.username, u.display_name FROM sessions s JOIN users u ON u.id = s.user_id WHERE s.is_public = 1 AND s.occasion NOT IN ('novena_deceased', 'divine_mercy_novena') AND s.is_pinned = 0 ORDER BY s.created_at DESC LIMIT 60 ")->fetchAll(); // Regular (unpinned) novena groups $novenas = $pdo->query(" SELECT ng.id, ng.name, ng.mystery_set, ng.subject_name, ng.photo_path, ng.slug, ng.is_pinned, ng.created_at, u.username, u.display_name, COUNT(s.id) AS day_count FROM novena_groups ng JOIN users u ON u.id = ng.user_id LEFT JOIN sessions s ON s.novena_group_id = ng.id WHERE ng.is_public = 1 AND ng.is_pinned = 0 GROUP BY ng.id ORDER BY ng.created_at DESC LIMIT 30 ")->fetchAll(); // Public users list (for search user-pill links) $public_users_rows = $pdo->query(" SELECT DISTINCT u.username, COALESCE(NULLIF(u.display_name,''), u.username) AS display_name FROM users u WHERE u.id IN ( SELECT user_id FROM sessions WHERE is_public = 1 UNION SELECT user_id FROM novena_groups WHERE is_public = 1 ) ORDER BY u.username LIMIT 300 ")->fetchAll(PDO::FETCH_ASSOC); // Merge and sort each group newest-first function merge_and_sort(array $sessions, array $novenas): array { $all = []; foreach ($sessions as $r) { $r['_type'] = 'session'; $all[] = $r; } foreach ($novenas as $r) { $r['_type'] = 'novena'; $all[] = $r; } usort($all, fn($a, $b) => strcmp($b['created_at'], $a['created_at'])); return $all; } $pinned = merge_and_sort($pinned_sessions, $pinned_novenas); $regular = merge_and_sort($sessions, $novenas); // --------------------------------------------------------------------------- // Label maps // --------------------------------------------------------------------------- $mystery_labels = [ 'sorrowful' => 'Sorrowful Mysteries', 'joyful' => 'Joyful Mysteries', 'glorious' => 'Glorious Mysteries', 'luminous' => 'Luminous Mysteries', 'by_day_of_week' => 'By Day of Week', 'chaplet' => 'Chaplet of Divine Mercy', ]; $occasion_labels = [ 'general_rosary' => 'General Rosary', 'memorial' => 'Memorial', 'novena_deceased' => 'Novena for Deceased', 'divine_mercy_novena'=> 'Divine Mercy Novena', ]; // --------------------------------------------------------------------------- // Card renderer (shared by pinned + regular sections) // --------------------------------------------------------------------------- function render_card(array $row, bool $is_admin, array $mystery_labels, array $occasion_labels): void { $disp_name = $row['display_name'] ?: $row['username']; $slug = $row['slug'] ?? ''; $is_novena = ($row['_type'] === 'novena'); $is_pinned = !empty($row['is_pinned']); $url = $slug ? (BASE_URL . '/' . rawurlencode($row['username']) . '/' . rawurlencode($slug)) : '#'; $link_text = $is_novena ? 'Select a Day →' : 'Pray →'; // For the Divine Mercy Novena badge (mystery_set = 'chaplet') $is_dm = ($is_novena && ($row['mystery_set'] ?? '') === 'chaplet'); $card_class = 'rosary-card' . ($is_pinned ? ' is-pinned' : ''); // Data attributes for client-side search $d_name = htmlspecialchars($row['name'], ENT_QUOTES); $d_subject = htmlspecialchars($row['subject_name'] ?? '', ENT_QUOTES); $d_uname = htmlspecialchars($row['username'], ENT_QUOTES); $d_display = htmlspecialchars($disp_name, ENT_QUOTES); $type_str = $is_novena ? 'novena' : 'session'; $row_id = (int)$row['id']; ?>
A shared presentation for families and communities praying the Holy Rosary.
No featured rosaries match your search.
No public rosary sessions yet. Create an account to get started.
All rosaries are currently featured above.
No rosaries match your search.