import { connection } from "./database"; const server = Bun.serve({ port: 3490, routes: { "/api/post-grids/:id": async req => { const gridId = Number(req.params.id); if (!gridId) { return Response.json({ error: "Invalid grid id" }, { status: 400 }); } // pagination params const url = new URL(req.url); const page = Math.max(1, Number(url.searchParams.get("page") ?? 1)); // 1. Load grid config post const gridPost = await connection.run(` SELECT ID, post_title FROM wp_posts WHERE ID = $id LIMIT 1; `, { id: gridId }); const [grid] = await gridPost.getRowObjectsJson(); if (!grid) { return Response.json(null, { status: 404 }); } // 2. Load grid meta const metaRes = await connection.run(` SELECT meta_key, meta_value FROM wp_postmeta WHERE post_id = $id; `, { id: gridId }); const meta = Object.fromEntries( (await metaRes.getRowObjectsJson()) .map(m => [m.meta_key, m.meta_value]) ); const postType = meta._rt_tp_post_type ?? "post"; const perPage = Math.max(1, Number(meta._rt_tp_posts_per_page ?? 6)); const orderBy = meta._rt_tp_orderby ?? "post_date"; const order = meta._rt_tp_order === "ASC" ? "ASC" : "DESC"; const offset = (page - 1) * perPage; // 3. Total count (for pagination) const totalRes = await connection.run(` SELECT COUNT(*)::int AS total FROM wp_posts WHERE post_status = 'publish' AND post_type = $postType; `, { postType }); const [{ total }] = await totalRes.getRowObjectsJson(); const totalPages = Math.max(1, Math.ceil(total / perPage)); // clamp page if out of range const safePage = Math.min(page, totalPages); const safeOffset = (safePage - 1) * perPage; // 4. Fetch paginated posts const postsRes = await connection.run(` SELECT ID, post_title, post_name, post_excerpt, post_date FROM wp_posts WHERE post_status = 'publish' AND post_type = $postType ORDER BY ${orderBy} ${order} LIMIT $perPage OFFSET $offset; `, { postType, perPage, offset: safeOffset }); const posts = await postsRes.getRowObjectsJson(); return Response.json({ id: grid.ID, title: grid.post_title, page: safePage, perPage, total, totalPages, posts }); }, "/api/posts/slugs": async req => { const res = await connection.run(` SELECT post_name, post_type FROM wp_posts WHERE post_status = 'publish' AND post_type IN ('post', 'page') ORDER BY post_date DESC; `); const data = await res.getRowObjectsJson() if (data.length === 0) { return Response.json(null, { status: 404 }); } return Response.json(data[0]); }, "/api/posts/id/:id": async req => { const res = await connection.run(` SELECT p.* FROM wp_posts p WHERE p.ID = $id LIMIT 1; `, { slug: Number(req.params.id) }); const data = await res.getRowObjectsJson() if (data.length === 0) { return Response.json(null, { status: 404 }); } return Response.json(data[0]); }, "/api/posts/:slug": async req => { const res = await connection.run(` SELECT * FROM wp_posts WHERE post_name = $slug AND post_status = 'publish' AND post_type IN ('post', 'page') LIMIT 1; `, { slug: req.params.slug.toString() }); const data = await res.getRowObjectsJson() if (data.length === 0) { return Response.json(null, { status: 404 }); } return Response.json(data[0], { status: 200 }); }, "/api/pages/:slug": async req => { const res = await connection.run(` SELECT * FROM wp_posts WHERE post_name = $slug AND post_status = 'publish' AND post_type IN ('post', 'page') LIMIT 1; `, { slug: req.params.slug.toString() }); const data = await res.getRowObjectsJson() if (data.length === 0) { return Response.json(null, { status: 404 }); } return Response.json(data[0]); }, "/api/pages/id/:id": async req => { const res = await connection.run(` SELECT p.* FROM wp_posts p WHERE p.ID = $id LIMIT 1;`, { id: Number(req.params.id) }); const data = await res.getRowObjectsJson() if (data.length === 0) { return Response.json(null, { status: 404 }); } return Response.json(data[0]); }, "/api/home": async req => { const res = await connection.run(` SELECT p.* FROM wp_posts p WHERE p.ID = ( SELECT option_value FROM wp_options WHERE option_name = 'page_on_front' LIMIT 1 ) LIMIT 1;`); const data = await res.getRowObjectsJson() if (data.length === 0) { return Response.json(null, { status: 404 }); } return Response.json(data); }, "/api/menu/footer": async req => { const res = await connection.run(` SELECT menu_item.ID AS menu_item_id, menu_item.post_title AS menu_title, menu_item.menu_order, menu_item.post_parent, -- Get the actual page/post content actual_post.ID AS actual_post_id, actual_post.post_title AS actual_post_title, actual_post.post_type, actual_post.post_status, actual_post.post_name AS slug, -- Get the URL (for custom links) url_meta.meta_value AS custom_url, -- Get the object type (post, page, category, custom, etc.) object_type_meta.meta_value AS object_type, -- Get parent menu item info menu_parent_meta.meta_value AS parent_menu_item_id, FROM wp_posts AS menu_item INNER JOIN wp_term_relationships r ON menu_item.ID = r.object_id -- Join to get the actual post ID INNER JOIN wp_postmeta AS object_id_meta ON menu_item.ID = object_id_meta.post_id AND object_id_meta.meta_key = '_menu_item_object_id' -- Join to get the actual post content INNER JOIN wp_posts AS actual_post ON object_id_meta.meta_value = actual_post.ID -- Left joins for additional info LEFT JOIN wp_postmeta AS url_meta ON menu_item.ID = url_meta.post_id AND url_meta.meta_key = '_menu_item_url' LEFT JOIN wp_postmeta AS object_type_meta ON menu_item.ID = object_type_meta.post_id AND object_type_meta.meta_key = '_menu_item_object' LEFT JOIN wp_postmeta AS menu_parent_meta ON menu_item.ID = menu_parent_meta.post_id AND menu_parent_meta.meta_key = '_menu_item_menu_item_parent' WHERE r.term_taxonomy_id = 10 AND menu_item.post_type = 'nav_menu_item' AND menu_item.post_status = 'publish' ORDER BY menu_item.menu_order; `); const data = await res.getRowObjectsJson() if (data.length === 0) { return Response.json(null, { status: 404 }); } return Response.json(data); }, "/api/menu/navbar": async req => { const res = await connection.run(` SELECT menu_item.ID AS menu_item_id, menu_item.post_title AS menu_title, menu_item.menu_order, menu_item.post_parent, -- Get the actual page/post content actual_post.ID AS actual_post_id, actual_post.post_title AS actual_post_title, actual_post.post_type, actual_post.post_status, actual_post.post_name AS slug, -- Get the URL (for custom links) url_meta.meta_value AS custom_url, -- Get the object type (post, page, category, custom, etc.) object_type_meta.meta_value AS object_type, -- Get parent menu item info menu_parent_meta.meta_value AS parent_menu_item_id, FROM wp_posts AS menu_item INNER JOIN wp_term_relationships r ON menu_item.ID = r.object_id -- Join to get the actual post ID INNER JOIN wp_postmeta AS object_id_meta ON menu_item.ID = object_id_meta.post_id AND object_id_meta.meta_key = '_menu_item_object_id' -- Join to get the actual post content INNER JOIN wp_posts AS actual_post ON object_id_meta.meta_value = actual_post.ID -- Left joins for additional info LEFT JOIN wp_postmeta AS url_meta ON menu_item.ID = url_meta.post_id AND url_meta.meta_key = '_menu_item_url' LEFT JOIN wp_postmeta AS object_type_meta ON menu_item.ID = object_type_meta.post_id AND object_type_meta.meta_key = '_menu_item_object' LEFT JOIN wp_postmeta AS menu_parent_meta ON menu_item.ID = menu_parent_meta.post_id AND menu_parent_meta.meta_key = '_menu_item_menu_item_parent' WHERE r.term_taxonomy_id = 24 AND menu_item.post_type = 'nav_menu_item' AND menu_item.post_status = 'publish' ORDER BY menu_item.menu_order; `); const data = await res.getRowObjectsJson() if (data.length === 0) { return Response.json(null, { status: 404 }); } return Response.json(data); }, } }) console.log(`Server running at ${server.url}`);