diff --git a/src/routes/sitemap.xml/+server.ts b/src/routes/sitemap.xml/+server.ts
index 328ebd18..7481a275 100644
--- a/src/routes/sitemap.xml/+server.ts
+++ b/src/routes/sitemap.xml/+server.ts
@@ -1,120 +1,41 @@
-import { convertToSlug } from "$lib/utils";
const pages = [
- { title: "/" },
- { title: "/reddit-tracker" },
- { title: "/list/most-shorted-stocks" },
- { title: "/stocks" },
- { title: "/etf" },
- { title: "/etf/etf-providers" },
- { title: "/etf/new-launches" },
- { title: "/price-alert" },
- { title: "/donation" },
- { title: "/insider-tracker" },
- { title: "/industry" },
- { title: "/industry/sectors" },
- { title: "/industry/all" },
- { title: "/newsletter" },
- { title: "/options-flow" },
- { title: "/ipos" },
- { title: "/ipos/news" },
- { title: "/list" },
- { title: "/list/dividend/dividend-kings" },
- { title: "/list/dividend/dividend-aristocrats" },
- { title: "/list/magnificent-seven" },
- { title: "/list/most-buybacks" },
- { title: "/list/market-cap/mega-cap-stocks" },
- { title: "/list/market-cap/large-cap-stocks" },
- { title: "/list/market-cap/mid-cap-stocks" },
- { title: "/list/market-cap/small-cap-stocks" },
- { title: "/list/market-cap/micro-cap-stocks" },
- { title: "/list/market-cap/nano-cap-stocks" },
- { title: "/list/highest-open-interest" },
- { title: "/list/highest-open-interest-change" },
- { title: "/list/highest-option-iv-rank" },
- { title: "/list/highest-option-premium" },
- { title: "/list/bitcoin-etfs" },
- { title: "/stock-screener" },
- { title: "/market-news" },
- { title: "/advertise" },
- { title: "/data-disclaimer" },
- { title: "/market-news/general" },
- { title: "/earnings-calendar" },
- { title: "/economic-calendar" },
- { title: "/dividends-calendar" },
- { title: "/market-mover/gainers" },
- { title: "/market-mover/losers" },
- { title: "/market-mover/active" },
- { title: "/market-mover/premarket/gainers" },
- { title: "/market-mover/premarket/losers" },
- { title: "/market-mover/afterhours/gainers" },
- { title: "/market-mover/afterhours/losers" },
- { title: "/hedge-funds" },
- { title: "/login" },
- { title: "/register" },
- { title: "/watchlist/stocks" },
- { title: "/watchlist/options" },
- { title: "/pricing" },
- { title: "/terms-of-use" },
- { title: "/privacy-policy" },
- { title: "/imprint" },
- { title: "/about" },
- { title: "/contact" },
- { title: "/blog" },
- { title: "/politicians" },
- { title: "/politicians/flow-data" },
- { title: "/analysts" },
- { title: "/analysts/top-stocks" },
- { title: "/heatmap" },
- { title: "/market-flow" },
- { title: "/market-flow/sector-flow" },
- { title: "/affiliate-program" },
- { title: "/dark-pool-flow" },
+ { title: "/sitemaps/sitemap1.xml" },
+ { title: "/sitemaps/sitemap2.xml" }
];
const website = "https://stocknear.com";
+// Helper function to create an XML URL element with optional SEO tags.
+const createUrlElement = (loc, { lastmod, changefreq, priority } = {}) => {
+ return `
+
+ ${loc}
+ ${lastmod ? `${lastmod}` : ""}
+ ${changefreq ? `${changefreq}` : ""}
+ ${priority ? `${priority}` : ""}
+
+ `;
+};
+
/** @type {import('./$types').RequestHandler} */
export async function GET({ locals }) {
- //get all posts;
- const { apiKey, apiURL, pb } = locals;
- const rawData = await fetch(apiURL + "/full-searchbar", {
- method: "GET",
- headers: {
- "Content-Type": "application/json",
- "X-API-KEY": apiKey,
- },
- });
- const outputStocks = await rawData.json();
- const stocks = outputStocks?.map((item) => ({
- id: item?.symbol,
- type: item?.type,
- }));
+
- const articles = await pb.collection("articles").getFullList({
- sort: "-created",
- });
-
- const tutorials = await pb.collection("tutorials").getFullList({
- sort: "-created",
- });
-
- const body = sitemap(stocks, articles, pages, tutorials);
+ const body = sitemap(pages);
const response = new Response(body);
- response.headers.set("Cache-Control", "max-age=0, s-maxage=3600");
response.headers.set("Content-Type", "application/xml");
return response;
}
-// Modified sitemap function
-const sitemap = (
- stocks,
- articles,
- pages,
- tutorials,
-) => `
+// Default settings for different content types.
+const defaultStaticPageSettings = { changefreq: "daily", priority: "1.0" };
+
+
+
+const sitemap = (pages) => `
${pages
- .map(
- (page) => `
-
- ${website}${page.title}
-
- `,
- )
- .join("")}
- ${articles
- .map(
- (item) => `
-
- ${website}/blog/article/${convertToSlug(item?.title)}
-
- `,
- )
- .join("")}
- ${tutorials
- .map(
- (item) => `
-
- ${website}/learning-center/article/${convertToSlug(item?.title)}
-
- `,
- )
- .join("")}
- ${stocks
- .map((ticker) => {
- // Determine the path based on the type of the ticker
- const path =
- ticker.type === "Stock"
- ? "/stocks/"
- : ticker.type === "ETF"
- ? "/etf/"
- : "/crypto/";
- return `
-
- ${website}${path}${ticker.id}
-
- `;
+ ?.map((page) => {
+ const loc = `${website}${page.title}`;
+ const settings = defaultStaticPageSettings;
+ return createUrlElement(loc, settings);
})
- .join("")}
-`;
+ ?.join("")}
+
+`;
+
diff --git a/src/routes/sitemaps/+page.server.ts b/src/routes/sitemaps/+page.server.ts
new file mode 100644
index 00000000..65004874
--- /dev/null
+++ b/src/routes/sitemaps/+page.server.ts
@@ -0,0 +1,8 @@
+import { redirect } from "@sveltejs/kit";
+
+export const load = async ({ locals }) => {
+ const { pb, user } = locals;
+ if (!pb.authStore.isValid) {
+ redirect(303, "/sitemap");
+ }
+}
\ No newline at end of file
diff --git a/src/routes/sitemaps/[slug]/+server.ts b/src/routes/sitemaps/[slug]/+server.ts
new file mode 100644
index 00000000..52ace5fb
--- /dev/null
+++ b/src/routes/sitemaps/[slug]/+server.ts
@@ -0,0 +1,209 @@
+import { convertToSlug } from "$lib/utils";
+
+const pages = [
+ { title: "/" },
+ { title: "/reddit-tracker" },
+ { title: "/list/most-shorted-stocks" },
+ { title: "/stocks" },
+ { title: "/etf" },
+ { title: "/etf/etf-providers" },
+ { title: "/etf/new-launches" },
+ { title: "/price-alert" },
+ { title: "/donation" },
+ { title: "/insider-tracker" },
+ { title: "/industry" },
+ { title: "/industry/sectors" },
+ { title: "/industry/all" },
+ { title: "/newsletter" },
+ { title: "/options-flow" },
+ { title: "/ipos" },
+ { title: "/ipos/news" },
+ { title: "/list" },
+ { title: "/list/dividend/dividend-kings" },
+ { title: "/list/dividend/dividend-aristocrats" },
+ { title: "/list/magnificent-seven" },
+ { title: "/list/most-buybacks" },
+ { title: "/list/market-cap/mega-cap-stocks" },
+ { title: "/list/market-cap/large-cap-stocks" },
+ { title: "/list/market-cap/mid-cap-stocks" },
+ { title: "/list/market-cap/small-cap-stocks" },
+ { title: "/list/market-cap/micro-cap-stocks" },
+ { title: "/list/market-cap/nano-cap-stocks" },
+ { title: "/list/highest-open-interest" },
+ { title: "/list/highest-open-interest-change" },
+ { title: "/list/highest-option-iv-rank" },
+ { title: "/list/highest-option-premium" },
+ { title: "/list/bitcoin-etfs" },
+ { title: "/stock-screener" },
+ { title: "/market-news" },
+ { title: "/advertise" },
+ { title: "/data-disclaimer" },
+ { title: "/market-news/general" },
+ { title: "/earnings-calendar" },
+ { title: "/economic-calendar" },
+ { title: "/dividends-calendar" },
+ { title: "/market-mover/gainers" },
+ { title: "/market-mover/losers" },
+ { title: "/market-mover/active" },
+ { title: "/market-mover/premarket/gainers" },
+ { title: "/market-mover/premarket/losers" },
+ { title: "/market-mover/afterhours/gainers" },
+ { title: "/market-mover/afterhours/losers" },
+ { title: "/hedge-funds" },
+ { title: "/login" },
+ { title: "/register" },
+ { title: "/watchlist/stocks" },
+ { title: "/watchlist/options" },
+ { title: "/pricing" },
+ { title: "/terms-of-use" },
+ { title: "/privacy-policy" },
+ { title: "/imprint" },
+ { title: "/about" },
+ { title: "/contact" },
+ { title: "/blog" },
+ { title: "/politicians" },
+ { title: "/politicians/flow-data" },
+ { title: "/analysts" },
+ { title: "/analysts/top-stocks" },
+ { title: "/heatmap" },
+ { title: "/market-flow" },
+ { title: "/market-flow/sector-flow" },
+ { title: "/affiliate-program" },
+ { title: "/dark-pool-flow" },
+];
+
+const website = "https://stocknear.com";
+
+// Helper function to create an XML URL element with optional SEO tags.
+const createUrlElement = (loc, { lastmod, changefreq, priority } = {}) => {
+ return `
+
+ ${loc}
+ ${lastmod ? `${lastmod}` : ""}
+ ${changefreq ? `${changefreq}` : ""}
+ ${priority ? `${priority}` : ""}
+
+ `;
+};
+
+/** @type {import('./$types').RequestHandler} */
+export async function GET({ params, locals }) {
+ const { apiKey, apiURL, pb } = locals;
+
+ const rawData = await fetch(apiURL + "/full-searchbar", {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ "X-API-KEY": apiKey,
+ },
+ });
+
+ const outputStocks = await rawData.json();
+ const stocks = outputStocks?.map((item) => ({
+ id: item?.symbol,
+ type: item?.type,
+ }));
+
+ const articles = await pb.collection("articles").getFullList({
+ sort: "-created",
+ });
+
+ const tutorials = await pb.collection("tutorials").getFullList({
+ sort: "-created",
+ });
+
+ // Split stocks into two halves.
+ const half = Math.ceil(stocks.length / 2);
+ let chosenStocks, chosenArticles, chosenPages, chosenTutorials;
+
+ if (params.slug === 'sitemap1.xml') {
+ // Sitemap1 shows pages, articles, tutorials, and the first half of stocks.
+ chosenPages = pages;
+ chosenArticles = articles;
+ chosenTutorials = tutorials;
+ chosenStocks = stocks.slice(0, half);
+ } else if (params.slug === 'sitemap2.xml') {
+ // Sitemap2 shows only the second half of stocks.
+ chosenPages = [];
+ chosenArticles = [];
+ chosenTutorials = [];
+ chosenStocks = stocks.slice(half);
+ } else {
+ return new Response("Not Found", { status: 404 });
+ }
+
+ const body = sitemap(chosenStocks, chosenArticles, chosenPages, chosenTutorials);
+ const response = new Response(body);
+ response.headers.set("Content-Type", "application/xml");
+ return response;
+}
+
+// Default settings for different content types.
+const defaultStaticPageSettings = { changefreq: "weekly", priority: "0.8" };
+const homePageSettings = { changefreq: "daily", priority: "1.0" };
+const articleSettings = { changefreq: "daily", priority: "0.7" };
+const tutorialSettings = { changefreq: "daily", priority: "0.7" };
+const stockSettings = { changefreq: "daily", priority: "0.6" };
+
+// Define extra subdirectories for stocks.
+const stockExtraSubPaths = ["/financials", "/financials/balance-sheet","/financials/cash-flow","/financials/ratios","/statistics","/statistics/market-cap","/statistics/revenue","/statistics/price-reaction","/statistics/fail-to-deliver","/metrics","/forecast","/forecast/analyst","/forecast/ai","/dark-pool","/options","/options/unusual-activity","/options/hottest-contracts","/options/volatility","/options/oi","/insider","/dividends","/history","/profile","/profile/employees"];
+const etfExtraSubPaths = ["/holdings","/dark-pool","/options","/options/unusual-activity","/options/hottest-contracts","/options/volatility","/options/oi","/insider","/dividends","/history"];
+
+
+const sitemap = (stocks, articles, pages, tutorials) => `
+
+ ${pages
+ ?.map((page) => {
+ const loc = `${website}${page.title}`;
+ const settings = page.title === "/" ? homePageSettings : defaultStaticPageSettings;
+ return createUrlElement(loc, settings);
+ })
+ ?.join("")}
+ ${articles
+ ?.map((item) => {
+ const loc = `${website}/blog/article/${convertToSlug(item?.title)}`;
+ return createUrlElement(loc, { ...articleSettings, lastmod: item.created });
+ })
+ ?.join("")}
+ ${tutorials
+ ?.map((item) => {
+ const loc = `${website}/learning-center/article/${convertToSlug(item?.title)}`;
+ return createUrlElement(loc, { ...tutorialSettings, lastmod: item.created });
+ })
+ ?.join("")}
+ ${stocks
+ ?.map((ticker) => {
+ // Determine the base path.
+ const basePath =
+ ticker.type === "Stock"
+ ? "/stocks/"
+ : ticker.type === "ETF"
+ ? "/etf/"
+ : "/index/";
+ // Main URL element for the ticker.
+ let urlElements = createUrlElement(`${website}${basePath}${ticker.id}`, stockSettings);
+
+ // For stocks only, add extra subdirectory URLs.
+ if (ticker.type === "Stock") {
+ stockExtraSubPaths?.forEach((subPath) => {
+ urlElements += createUrlElement(`${website}${basePath}${ticker.id}${subPath}`, stockSettings);
+ });
+ }
+ else if (ticker.type === "ETF") {
+ etfExtraSubPaths?.forEach((subPath) => {
+ urlElements += createUrlElement(`${website}${basePath}${ticker.id}${subPath}`, stockSettings);
+ });
+ }
+
+ return urlElements;
+ })
+ ?.join("")}
+
+`;