File "useCreateSite.js"
Full Path: /home/shadsolw/public_html/wp-content/plugins/extendify/src/AutoLaunch/hooks/useCreateSite.js
File size: 13.78 KB
MIME-type: text/x-java
Charset: utf-8
import { handleHome } from '@auto-launch/fetchers/get-home';
import { handleSiteImages } from '@auto-launch/fetchers/get-images';
import { handleSiteLogo } from '@auto-launch/fetchers/get-logo';
import { handlePages } from '@auto-launch/fetchers/get-pages';
import { handleSitePlugins } from '@auto-launch/fetchers/get-plugins';
import { handleSiteProfile } from '@auto-launch/fetchers/get-profile';
import { handleSiteStrings } from '@auto-launch/fetchers/get-strings';
import { handleSiteStyle } from '@auto-launch/fetchers/get-style';
import {
installFontFamilies,
mergeFontsIntoVariation,
} from '@auto-launch/functions/fonts';
import { apiFetchWithTimeout } from '@auto-launch/functions/helpers';
import { checkIn } from '@auto-launch/functions/insights';
import {
updateButtonLinks,
updateSinglePageLinksToSections,
} from '@auto-launch/functions/links';
import {
addPageLinksToNav,
addSectionLinksToNav,
createNavigation,
updateNavAttributes,
} from '@auto-launch/functions/nav';
import {
addImprintPage,
createWpPages,
getPagesToCreate,
setHelloWorldFeaturedImage,
updatePageTitlePattern,
} from '@auto-launch/functions/pages';
import { generatePageContent } from '@auto-launch/functions/patterns';
import {
alreadyActive,
getActivePlugins,
replacePlaceholderPatterns,
} from '@auto-launch/functions/plugins';
import {
postLaunchFunctions,
prefetchAssistData,
} from '@auto-launch/functions/setup';
import {
setThemeRenderingMode,
updateTemplatePart,
updateVariation,
} from '@auto-launch/functions/theme';
import { updateNaturalVibeStyles } from '@auto-launch/functions/vibes';
import {
createBlogSampleData,
getOption,
getPageById,
updateOption,
} from '@auto-launch/functions/wp';
import { useWarnOnLeave } from '@auto-launch/hooks/useWarnOnLeave';
import { useLaunchDataStore } from '@auto-launch/state/launch-data';
import { useAIConsentStore } from '@shared/state/ai-consent';
import { useEffect, useRef, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import useSWRImmutable from 'swr/immutable';
const { homeUrl, showImprint, wpLanguage } = window.extSharedData;
// TODO: I think a good strategy is "if something fails, try to refetch some state"
export const useCreateSite = () => {
// All the data we need to finish
const { setErrorMessage, addStatusMessage, needToStall, ...data } =
useLaunchDataStore();
const { setUserGaveConsent } = useAIConsentStore();
const homeStretch = useRef(false);
const [warnOnReload, setWarnOnReload] = useState(!needToStall());
const [done, setDone] = useState(false);
// We keep the data on reload but show this to prevent movement
useWarnOnLeave(warnOnReload, () => {
// TODO: do we want to reset state here?
});
// needs: title, description
// provides: siteProfile: { type, category, description, title, keywords, logoObjectName }
useRunStep(
'siteProfile',
() => {
if (!data.description && !data.title) return null;
return data;
},
handleSiteProfile,
);
// needs: siteProfile
// provides: logoUrl
useRunStep(
'siteLogo',
() => {
if (!data.siteProfile?.title) return null;
return data;
},
handleSiteLogo,
);
// needs: siteProfile
// provides:sitePlugins: [{name, wordpressSlug}]
useRunStep(
'sitePlugins',
() => {
// We just need the site profile, which has this
if (!data.siteProfile?.title) return null;
return data;
},
handleSitePlugins,
);
// needs: siteProfile
// provides: style: {}
useRunStep(
'siteStyle',
() => {
// We just need the site profile, which has this
if (!data.siteProfile?.title) return null;
return data;
},
handleSiteStyle,
);
// needs: siteProfile
// provides: aiHeaders: [], aiBlogTitles: []
useRunStep(
'siteStrings',
() => {
// We just need the site profile, which has this
if (!data.siteProfile?.title) return null;
return data;
},
handleSiteStrings,
);
// needs: siteProfile
// provides: siteImages: []
useRunStep(
'siteImages',
() => {
// We just need the site profile, which has this
if (!data.siteProfile?.title) return null;
return data;
},
handleSiteImages,
);
// needs: siteProfile, sitePlugins, siteStyle, siteImages
// provides: home: { id, slug, patterns, siteStyle }
useRunStep(
'home',
() => {
// Checking various data from calls above
const ok = [
data.siteProfile,
data.siteStyle,
data.siteImages,
data.sitePlugins,
].every((v) => v !== undefined);
return ok ? data : null;
},
handleHome,
);
// siteProfile, sitePlugins, siteStyle, siteImages
// provides: pages: [{ id, slug, name, patterns, siteStyle }]
useRunStep(
'pages',
() => {
// Checking various data from calls above
const ok = [
data.siteProfile,
data.siteStyle,
data.siteImages,
data.sitePlugins,
].every((v) => v !== undefined);
return ok ? data : null;
},
handlePages,
);
// basic defaults
useRunStep(
'basicUpdates',
() => {
const ok = [data.siteProfile, data.home, data.pages].every(
(v) => v !== undefined,
);
return ok ? data : null;
},
async ({ siteProfile, sitePlugins, siteStyle }) => {
const { title } = siteProfile;
// translators: this is for a action log UI. Keep it short
addStatusMessage(__('Adding admin configurations', 'extendify-local'));
// update permalinks
await updateOption('permalink_structure', '/%postname%/');
// make sure consent is set
setUserGaveConsent(true);
// Update title
if (title) await updateOption('blogname', title);
checkIn({ stage: 'basic_updates', siteProfile, sitePlugins, siteStyle });
},
);
// basic defaults
useRunStep(
'pluginConfigurations',
() => {
if (!data.sitePlugins) return null;
return data;
},
async () => {
const activePlugins = await getActivePlugins();
if (alreadyActive(activePlugins, 'wpforms-lite')) {
await updateOption('wpforms_activation_redirect', 'skip');
}
if (alreadyActive(activePlugins, 'all-in-one-seo-pack')) {
await updateOption('aioseo_activation_redirect', 'skip');
}
if (alreadyActive(activePlugins, 'google-analytics-for-wordpress')) {
const param = '_transient__monsterinsights_activation_redirect';
await updateOption(param, null);
}
},
);
// If we have home and (maybe) pages then we're ready
useEffect(() => {
if (needToStall()) return;
const {
home,
pages,
siteProfile,
sitePlugins,
siteStyle,
addSiteStrings,
siteImages,
} = data;
// pages could be [] and pass here, that's ok
if (!home || !pages) return;
if (homeStretch.current) return;
homeStretch.current = true;
(async () => {
const { objective, structure, category } = siteProfile;
// Do they need an imprint page?
const needsImprint = Array.isArray(showImprint)
? showImprint.includes(wpLanguage ?? '') && category === 'Business'
: false;
// install fonts and updateVariation
const customFonts =
siteStyle?.variation?.settings?.typography?.fontFamilies?.custom;
let variation = siteStyle?.variation;
if (customFonts?.length) {
// translators: this is for a action log UI. Keep it short
addStatusMessage(__('Installing fonts locally', 'extendify-local'));
const installed = await installFontFamilies(customFonts).catch(
() => [],
);
variation = mergeFontsIntoVariation(siteStyle.variation, installed);
}
await updateVariation(variation);
// natural-1 is the default vibe
if (siteStyle?.vibe !== 'natural-1') {
// translators: vibe in this context is a noun - the feeling of their site design.
addStatusMessage(__('Setting the website style', 'extendify-local'));
await updateNaturalVibeStyles(siteStyle?.vibe);
}
// navigation menu
addStatusMessage(__('Working on the navigation', 'extendify-local'));
const { id: headerNavId } = await createNavigation({
title: __('Header Navigation', 'extendify-local'),
slug: 'site-navigation',
});
let headerCode = updateNavAttributes(home.headerCode || '', {
ref: headerNavId,
});
// remove the header navigation from the landing page
if (objective === 'landing-page') {
// translators: this is for a action log UI. Keep it short
addStatusMessage(__('Perfecting a landing page', 'extendify-local'));
const social =
/<!--\s*wp:social-links\b[^>]*>.*?<!--\s*\/wp:social-links\s*-->/gis;
headerCode = headerCode
.replace(/<!--\s*wp:navigation\b[^>]*.*\/-->/gis, '')
.replace(social, '');
}
await updateTemplatePart('extendable/header', headerCode);
// footer
let footerNavId = null;
let footerCode = home.footerCode || '';
if (needsImprint) {
const nav = await createNavigation({
title: __('Footer Navigation', 'extendify-local'),
slug: 'footer-navigation',
});
footerNavId = nav.id;
footerCode = updateNavAttributes(footerCode, { ref: footerNavId });
}
await updateTemplatePart('extendable/footer', footerCode);
// pages
// translators: this is for a action log UI. Keep it short
addStatusMessage(__('Creating pages', 'extendify-local'));
const pagesToCreate = getPagesToCreate(data);
const titlePattern = pages?.[0]?.patterns?.find((p) =>
p.patternTypes?.includes('page-title'),
);
if (titlePattern) await updatePageTitlePattern(titlePattern.code);
// Some patterns have preview html, we can replace those
// which may install some plugins too.
const pagesReplaced = [];
// Run these one page at a time so we don't end up
// with duplicate dependency issues
for (const page of pagesToCreate) {
const patterns = await replacePlaceholderPatterns(page.patterns);
const updatedPage = { ...page, patterns };
pagesReplaced.push(updatedPage);
}
const customPages = await generatePageContent(pagesReplaced, data);
const stickyNav =
structure === 'single-page' && objective !== 'landing-page';
const createdPagesWP = await createWpPages(customPages, { stickyNav });
// Aux pages
const hasBlogPattern = home?.patterns?.some((pattern) =>
pattern.patternTypes.includes('blog-section'),
);
if (objective === 'blog' || hasBlogPattern) {
// translators: this is for a action log UI. Keep it short
addStatusMessage(__('Creating blog sample data', 'extendify-local'));
await createBlogSampleData(addSiteStrings, siteImages);
}
// If we have site images then set up the hello world image
if (siteImages?.length) await setHelloWorldFeaturedImage(siteImages);
// Do we need an imprint page?
const imprint = await addImprintPage({ siteStyle }).catch(() => null);
// install partner plugins
const activePlugins = await getActivePlugins();
// Collect pages we need to add to the nav
const pluginPages = [];
if (alreadyActive(activePlugins, 'woocommerce')) {
addStatusMessage(
// translators: this is for a action log UI. Keep it short
__('Setting up your online store', 'extendify-local'),
);
await apiFetchWithTimeout({
path: '/extendify/v1/auto-launch/import-woocommerce',
}).catch(() => null);
const id = await getOption('woocommerce_shop_page_id');
const shopPage = id ? await getPageById(id) : null;
if (shopPage) pluginPages.push(shopPage);
}
if (alreadyActive(activePlugins, 'the-events-calendar')) {
pluginPages.push({
title: { rendered: __('Events', 'extendify-local') },
slug: 'events',
link: `${homeUrl}/events`,
});
}
// Adding pages to the nav
const pagesWithLinksUpdated =
structure === 'single-page'
? await updateSinglePageLinksToSections(createdPagesWP, customPages, {
objective,
activePlugins,
})
: await updateButtonLinks(createdPagesWP, pluginPages);
const footerNavPages = [];
if (footerNavId && imprint?.title) {
const { originalSlug, title } = imprint;
footerNavPages.push({
id: originalSlug,
name: title.rendered,
slug: originalSlug,
patterns: [],
});
}
if (objective !== 'landing-page') {
if (structure === 'single-page') {
addSectionLinksToNav;
await addSectionLinksToNav(
headerNavId,
home?.patterns,
pluginPages,
createdPagesWP,
);
} else {
await addPageLinksToNav(
headerNavId,
pagesToCreate,
pagesWithLinksUpdated,
pluginPages,
);
}
if (footerNavId) {
await addPageLinksToNav(
footerNavId,
footerNavPages,
pagesWithLinksUpdated,
[],
);
}
}
await prefetchAssistData();
await postLaunchFunctions();
await setThemeRenderingMode('template-locked');
await updateOption(
'extendify_onboarding_completed',
new Date().toISOString(),
);
// translators: this is for a action log UI. Keep it short
addStatusMessage(__('All done!', 'extendify-local'));
await checkIn({ stage: 'finished', siteProfile, sitePlugins, siteStyle });
setWarnOnReload(false);
setDone(true);
})().catch((error) => {
console.error(error);
// if we error here we can try again by resetting the home stretch and stalling again to refetch data
homeStretch.current = false;
needToStall(true);
setErrorMessage(
__(
'Something went wrong during the final steps. We will try again but you may need to refresh the page.',
'extendify-local',
),
);
});
}, [data, needToStall, setUserGaveConsent]);
return { done };
};
const useRunStep = (stepKey, getParams, fetcher) => {
const { setData, setErrorMessage, needToStall } = useLaunchDataStore();
const p = getParams?.() ?? null;
const { data, error } = useSWRImmutable(
p && !needToStall() ? stepKey : null,
() => fetcher(getParams()),
);
useEffect(() => {
if (!data) return;
Object.entries(data).forEach(([k, v]) => {
setData(k, v);
});
}, [data, setData]);
useEffect(() => {
if (!error || needToStall()) return;
console.error(error);
setErrorMessage(
__(
'Having some trouble with this step. Trying again...',
'extendify-local',
),
);
}, [error, setErrorMessage, needToStall]);
};