setIsHovered( true ) }
+ onMouseLeave={ () => setIsHovered( false ) }
+ />
+
+ );
+}
+
+/**
+ * HoverLink component with hover color transition.
+ *
+ * @param {Object} props - Component props.
+ * @param {string} props.link - Link URL.
+ * @param {string} props.color - Default color.
+ * @param {string} props.hoverColor - Color on hover.
+ * @param {string} props.textDecoration - Default text-decoration.
+ * @param {string} props.hoverTextDecoration - Text-decoration on hover.
+ * @param {string} props.children - Link text.
+ * @return {JSX.Element} The link element.
+ */
+function HoverLink( {
+ link,
+ color,
+ hoverColor,
+ textDecoration = 'none',
+ hoverTextDecoration = 'underline',
+ children,
+} ) {
+ const [ isHovered, setIsHovered ] = useState( false );
+
+ const style = {
+ color: isHovered ? hoverColor : color,
+ textDecoration: isHovered ? hoverTextDecoration : textDecoration,
+ };
+
+ return (
+
setIsHovered( true ) }
+ onMouseLeave={ () => setIsHovered( false ) }
+ >
+ { children }
+
+ );
+}
+
+/**
+ * What's New widget component.
+ *
+ * @param {Object} props - Component props.
+ * @param {Object} props.config - Widget configuration.
+ * @return {JSX.Element|null} The widget component or null if no posts.
+ */
+function WhatsNew( { config = {} } ) {
+ const { isLoading, data } = useApiData(
+ '/progress-planner/v1/widgets/whats-new'
+ );
+
+ // Get title - will come from widget registry metadata
+ const widgetTitle =
+ config?.title ||
+ __( "What's new on the Progress Planner blog", 'progress-planner' );
+
+ // Show loading state.
+ if ( isLoading ) {
+ return (
+
+
+
+
+
+ );
+ }
+
+ // Extract data
+ const posts = data?.posts || [];
+ const blogUrl = data?.blogUrl || '';
+
+ // Return null if no posts (widget should not render content).
+ if ( posts.length === 0 ) {
+ return null;
+ }
+
+ // Inline styles.
+ const listStyle = {
+ listStyle: 'none',
+ padding: 0,
+ margin: 0,
+ };
+
+ const titleStyle = {
+ marginTop: 0,
+ fontSize: 'var(--prpl-font-size-lg)',
+ lineHeight: 1.25,
+ fontWeight: 600,
+ marginBottom: '6px',
+ };
+
+ const excerptStyle = {
+ margin: 0,
+ };
+
+ const footerStyle = {
+ display: 'flex',
+ justifyContent: 'flex-end',
+ };
+
+ return (
+
+
+
+
+ { posts.map( ( post, index ) => (
+ -
+ { post.imageUrl && (
+
+ ) }
+
+
+ { post.title }
+
+
+ { post.excerpt }
+
+
+ ) ) }
+
+
+
+ { __( 'Read all posts', 'progress-planner' ) }
+
+
+
+ );
+}
+
+// Register widget
+registerWidget( {
+ id: 'whats-new',
+ component: WhatsNew,
+ priority: 10,
+ width: 1,
+ forceLastColumn: false,
+ title: __( "What's new on the Progress Planner blog", 'progress-planner' ),
+} );
+
+export default WhatsNew;
diff --git a/assets/src/widgets/shared/SimpleBadgeWidget.js b/assets/src/widgets/shared/SimpleBadgeWidget.js
new file mode 100644
index 0000000000..8ef5fbb00d
--- /dev/null
+++ b/assets/src/widgets/shared/SimpleBadgeWidget.js
@@ -0,0 +1,131 @@
+/**
+ * SimpleBadgeWidget Component
+ *
+ * Configurable badge widget used by ContentBadges and StreakBadges.
+ * Provides a consistent layout with gauge, progress info, and badge grid.
+ */
+
+import { __ } from '@wordpress/i18n';
+import { useMemo } from '@wordpress/element';
+import { useBadgeData } from '../../hooks/useBadgeData';
+import { useBadgeProgress } from '../../hooks/useBadgeProgress';
+import { useBadgeProgressSave } from '../../hooks/useBadgeProgressSave';
+import { CONTENT_BADGES, MAINTENANCE_BADGES } from '../../config/badges';
+import BadgeProgressInfo from '../../components/BadgeProgressInfo';
+import BadgeGrid from '../../components/BadgeGrid';
+import { ErrorState, EmptyState } from '../../components/WidgetStates';
+import SimpleBadgeWidgetSkeleton from './SimpleBadgeWidgetSkeleton';
+
+/**
+ * SimpleBadgeWidget component.
+ *
+ * @param {Object} props - Component props.
+ * @param {string} props.badgeType - Badge type: 'content' or 'maintenance'.
+ * @param {string} props.introText - Introduction/description text.
+ * @param {string} props.backgroundColor - Background color CSS variable.
+ * @param {string} props.badgeGroupClass - CSS class for badge group.
+ * @param {Function} props.getRemainingText - Function that returns remaining text for a given count.
+ * @return {JSX.Element} The SimpleBadgeWidget component.
+ */
+export default function SimpleBadgeWidget( {
+ badgeType,
+ introText,
+ backgroundColor,
+ badgeGroupClass = '',
+ getRemainingText,
+} ) {
+ const { isLoading, error, data } = useBadgeData();
+
+ // Calculate badge progress.
+ const badgeProgress = useBadgeProgress( {
+ activities: data?.activities || [],
+ savedStats: data?.savedStats || {},
+ totalPostsCount: data?.totalPostsCount || 0,
+ activationDate: data?.activationDate
+ ? new Date( data.activationDate )
+ : null,
+ } );
+
+ // Automatically save progress when it changes.
+ useBadgeProgressSave( badgeProgress, data?.savedStats || {} );
+
+ // Get badges for this type.
+ const badges = useMemo( () => {
+ return badgeType === 'content' ? CONTENT_BADGES : MAINTENANCE_BADGES;
+ }, [ badgeType ] );
+
+ // Get current badge (first incomplete).
+ const currentBadge = useMemo( () => {
+ for ( const badge of badges ) {
+ const progress = badgeProgress[ badge.id ];
+ if ( progress && progress.progress < 100 ) {
+ return {
+ id: badge.id,
+ name: badge.name,
+ background: badge.background,
+ progress: progress.progress,
+ remaining: progress.remaining,
+ };
+ }
+ }
+ return null;
+ }, [ badges, badgeProgress ] );
+
+ // Get all badges with progress.
+ const allBadges = useMemo( () => {
+ return badges.map( ( badge ) => {
+ const progress = badgeProgress[ badge.id ] || {
+ progress: 0,
+ remaining: 0,
+ };
+ return {
+ id: badge.id,
+ name: badge.name,
+ progress: progress.progress,
+ isComplete: progress.progress >= 100,
+ };
+ } );
+ }, [ badges, badgeProgress ] );
+
+ if ( isLoading ) {
+ return (
+
+ );
+ }
+
+ if ( error ) {
+ return
;
+ }
+
+ if ( ! currentBadge ) {
+ return (
+
+ );
+ }
+
+ return (
+ <>
+
{ introText }
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/assets/src/widgets/shared/SimpleBadgeWidgetSkeleton.js b/assets/src/widgets/shared/SimpleBadgeWidgetSkeleton.js
new file mode 100644
index 0000000000..ad65da0037
--- /dev/null
+++ b/assets/src/widgets/shared/SimpleBadgeWidgetSkeleton.js
@@ -0,0 +1,159 @@
+/**
+ * SimpleBadgeWidget Skeleton Component
+ *
+ * Skeleton loading state for the SimpleBadgeWidget component.
+ * Used by ContentBadges and StreakBadges widgets.
+ */
+
+import {
+ SkeletonRect,
+ SkeletonText,
+ SkeletonCircle,
+} from '../../components/Skeleton';
+import GaugeSkeleton from '../../components/Gauge/GaugeSkeleton';
+
+/**
+ * BadgeProgressInfoSkeleton component.
+ *
+ * Skeleton for the BadgeProgressInfo component (Gauge + progress text).
+ *
+ * @param {Object} props - Component props.
+ * @param {string} props.backgroundColor - Background color CSS variable.
+ * @return {JSX.Element} The BadgeProgressInfoSkeleton component.
+ */
+function BadgeProgressInfoSkeleton( {
+ backgroundColor = 'var(--prpl-background-content-badge)',
+} ) {
+ const wrapperStyle = {
+ display: 'flex',
+ flexDirection: 'row',
+ gap: '1rem',
+ };
+
+ const gaugeContainerStyle = {
+ flex: '0 0 auto',
+ width: '140px',
+ };
+
+ const contentStyle = {
+ flex: 1,
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ };
+
+ const progressLabelStyle = {
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ gap: '1rem',
+ marginBottom: '0.5rem',
+ };
+
+ return (
+
+ );
+}
+
+/**
+ * BadgeGridSkeleton component.
+ *
+ * Skeleton for the BadgeGrid component (3-column grid).
+ *
+ * @param {Object} props - Component props.
+ * @param {number} props.count - Number of badge placeholders.
+ * @param {string} props.backgroundColor - Background color CSS variable.
+ * @return {JSX.Element} The BadgeGridSkeleton component.
+ */
+function BadgeGridSkeleton( {
+ count = 6,
+ backgroundColor = 'var(--prpl-background-content-badge)',
+} ) {
+ const gridStyle = {
+ display: 'grid',
+ gridTemplateColumns: '1fr 1fr 1fr',
+ gap: 'calc(var(--prpl-gap) / 4)',
+ background: backgroundColor,
+ padding: 'calc(var(--prpl-padding) / 2)',
+ borderRadius: 'var(--prpl-border-radius-big)',
+ };
+
+ const badgeItemStyle = {
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ justifyContent: 'flex-start',
+ gap: '0.25rem',
+ minWidth: 0,
+ };
+
+ const labelStyle = {
+ fontSize: 'var(--prpl-font-size-small)',
+ textAlign: 'center',
+ };
+
+ return (
+
+ { Array.from( { length: count } ).map( ( _, index ) => (
+
+
+
+
+
+
+ ) ) }
+
+ );
+}
+
+/**
+ * SimpleBadgeWidgetSkeleton component.
+ *
+ * @param {Object} props - Component props.
+ * @param {string} props.backgroundColor - Background color CSS variable.
+ * @return {JSX.Element} The SimpleBadgeWidgetSkeleton component.
+ */
+export default function SimpleBadgeWidgetSkeleton( {
+ backgroundColor = 'var(--prpl-background-content-badge)',
+} ) {
+ return (
+ <>
+ { /* Intro text */ }
+
+
+
+
+ { /* BadgeProgressInfo skeleton */ }
+
+
+
+
+ { /* BadgeGrid skeleton */ }
+
+
+
+ >
+ );
+}
diff --git a/assets/src/widgets/shared/__tests__/SimpleBadgeWidget.test.js b/assets/src/widgets/shared/__tests__/SimpleBadgeWidget.test.js
new file mode 100644
index 0000000000..cfd9bc62a2
--- /dev/null
+++ b/assets/src/widgets/shared/__tests__/SimpleBadgeWidget.test.js
@@ -0,0 +1,421 @@
+/**
+ * Tests for SimpleBadgeWidget Component
+ */
+
+import { render, screen } from '@testing-library/react';
+import SimpleBadgeWidget from '../SimpleBadgeWidget';
+
+// Mock WordPress packages
+jest.mock( '@wordpress/i18n', () => ( {
+ __: ( str ) => str,
+} ) );
+
+// Mock hooks
+jest.mock( '../../../hooks/useBadgeData', () => ( {
+ useBadgeData: jest.fn(),
+} ) );
+
+jest.mock( '../../../hooks/useBadgeProgress', () => ( {
+ useBadgeProgress: jest.fn(),
+} ) );
+
+jest.mock( '../../../hooks/useBadgeProgressSave', () => ( {
+ useBadgeProgressSave: jest.fn(),
+} ) );
+
+// Mock badges config
+jest.mock( '../../../config/badges', () => ( {
+ CONTENT_BADGES: [
+ { id: 'content-1', name: 'Content Badge 1', background: '#fff' },
+ { id: 'content-2', name: 'Content Badge 2', background: '#fff' },
+ ],
+ MAINTENANCE_BADGES: [
+ {
+ id: 'maintenance-1',
+ name: 'Maintenance Badge 1',
+ background: '#fff',
+ },
+ {
+ id: 'maintenance-2',
+ name: 'Maintenance Badge 2',
+ background: '#fff',
+ },
+ ],
+} ) );
+
+// Mock child components
+jest.mock( '../../../components/BadgeProgressInfo', () => ( { badge } ) => (
+
{ badge.name }
+) );
+
+jest.mock( '../../../components/BadgeGrid', () => ( { badges, className } ) => (
+
+ { badges.map( ( b ) => (
+ { b.name }
+ ) ) }
+
+) );
+
+jest.mock( '../../../components/WidgetStates', () => ( {
+ LoadingState: () =>
Loading...
,
+ ErrorState: ( { message } ) => (
+
{ message }
+ ),
+ EmptyState: ( { message } ) => (
+
{ message }
+ ),
+} ) );
+
+describe( 'SimpleBadgeWidget', () => {
+ const { useBadgeData } = require( '../../../hooks/useBadgeData' );
+ const { useBadgeProgress } = require( '../../../hooks/useBadgeProgress' );
+
+ const mockGetRemainingText = ( count ) => `${ count } more needed`;
+
+ beforeEach( () => {
+ jest.clearAllMocks();
+
+ // Default mock setup
+ useBadgeData.mockReturnValue( {
+ isLoading: false,
+ error: null,
+ data: {
+ activities: [],
+ savedStats: {},
+ totalPostsCount: 10,
+ activationDate: '2024-01-01',
+ config: {},
+ },
+ } );
+
+ useBadgeProgress.mockReturnValue( {
+ 'content-1': { progress: 50, remaining: 5 },
+ 'content-2': { progress: 0, remaining: 10 },
+ 'maintenance-1': { progress: 75, remaining: 2 },
+ 'maintenance-2': { progress: 100, remaining: 0 },
+ } );
+ } );
+
+ describe( 'loading state', () => {
+ it( 'renders loading state when isLoading is true', () => {
+ useBadgeData.mockReturnValue( {
+ isLoading: true,
+ error: null,
+ data: null,
+ } );
+
+ const { container } = render(
+
+ );
+
+ // Skeleton should be rendered during loading
+ expect( container.firstChild ).not.toBeNull();
+ // Main content (intro text) should not be visible
+ expect(
+ screen.queryByText( 'Intro text' )
+ ).not.toBeInTheDocument();
+ } );
+ } );
+
+ describe( 'error state', () => {
+ it( 'renders error state when error exists', () => {
+ useBadgeData.mockReturnValue( {
+ isLoading: false,
+ error: 'Something went wrong',
+ data: null,
+ } );
+
+ render(
+
+ );
+
+ expect( screen.getByTestId( 'error-state' ) ).toBeInTheDocument();
+ expect(
+ screen.getByText( 'Something went wrong' )
+ ).toBeInTheDocument();
+ } );
+ } );
+
+ describe( 'empty state', () => {
+ it( 'renders empty state when no current badge', () => {
+ useBadgeProgress.mockReturnValue( {
+ 'content-1': { progress: 100, remaining: 0 },
+ 'content-2': { progress: 100, remaining: 0 },
+ } );
+
+ render(
+
+ );
+
+ expect( screen.getByTestId( 'empty-state' ) ).toBeInTheDocument();
+ } );
+ } );
+
+ describe( 'content rendering', () => {
+ it( 'renders intro text', () => {
+ render(
+
+ );
+
+ expect(
+ screen.getByText( 'This is the intro text' )
+ ).toBeInTheDocument();
+ } );
+
+ it( 'renders BadgeProgressInfo component', () => {
+ render(
+
+ );
+
+ expect(
+ screen.getByTestId( 'badge-progress-info' )
+ ).toBeInTheDocument();
+ } );
+
+ it( 'renders BadgeGrid component', () => {
+ render(
+
+ );
+
+ expect( screen.getByTestId( 'badge-grid' ) ).toBeInTheDocument();
+ } );
+
+ it( 'renders hr separator', () => {
+ const { container } = render(
+
+ );
+
+ expect( container.querySelector( 'hr' ) ).toBeInTheDocument();
+ } );
+ } );
+
+ describe( 'badge type selection', () => {
+ it( 'uses content badges when badgeType is content', () => {
+ render(
+
+ );
+
+ // Badge name appears in both BadgeProgressInfo and BadgeGrid
+ expect(
+ screen.getAllByText( 'Content Badge 1' ).length
+ ).toBeGreaterThan( 0 );
+ } );
+
+ it( 'uses maintenance badges when badgeType is maintenance', () => {
+ render(
+
+ );
+
+ // Badge name appears in both BadgeProgressInfo and BadgeGrid
+ expect(
+ screen.getAllByText( 'Maintenance Badge 1' ).length
+ ).toBeGreaterThan( 0 );
+ } );
+ } );
+
+ describe( 'current badge selection', () => {
+ it( 'selects first incomplete badge as current', () => {
+ useBadgeProgress.mockReturnValue( {
+ 'content-1': { progress: 100, remaining: 0 },
+ 'content-2': { progress: 50, remaining: 5 },
+ } );
+
+ render(
+
+ );
+
+ // BadgeProgressInfo should show the current badge
+ expect(
+ screen.getByTestId( 'badge-progress-info' )
+ ).toHaveTextContent( 'Content Badge 2' );
+ } );
+ } );
+
+ describe( 'badge group class', () => {
+ it( 'passes badgeGroupClass to BadgeGrid', () => {
+ render(
+
+ );
+
+ expect( screen.getByTestId( 'badge-grid' ) ).toHaveClass(
+ 'custom-class'
+ );
+ } );
+
+ it( 'defaults to empty badgeGroupClass', () => {
+ render(
+
+ );
+
+ expect( screen.getByTestId( 'badge-grid' ) ).not.toHaveClass(
+ 'custom-class'
+ );
+ } );
+ } );
+
+ describe( 'badges container', () => {
+ it( 'renders badges container', () => {
+ const { container } = render(
+
+ );
+
+ expect(
+ container.querySelector( '.prpl-badges-container-achievements' )
+ ).toBeInTheDocument();
+ } );
+ } );
+
+ describe( 'hook calls', () => {
+ it( 'calls useBadgeData hook', () => {
+ render(
+
+ );
+
+ expect( useBadgeData ).toHaveBeenCalled();
+ } );
+
+ it( 'calls useBadgeProgress with data from useBadgeData', () => {
+ render(
+
+ );
+
+ expect( useBadgeProgress ).toHaveBeenCalledWith(
+ expect.objectContaining( {
+ activities: [],
+ savedStats: {},
+ totalPostsCount: 10,
+ } )
+ );
+ } );
+ } );
+
+ describe( 'edge cases', () => {
+ it( 'handles missing config gracefully', () => {
+ useBadgeData.mockReturnValue( {
+ isLoading: false,
+ error: null,
+ data: {
+ activities: [],
+ savedStats: {},
+ totalPostsCount: 0,
+ activationDate: null,
+ },
+ } );
+
+ render(
+
+ );
+
+ // Should still render
+ expect( screen.getByText( 'Intro text' ) ).toBeInTheDocument();
+ } );
+
+ it( 'handles empty activities array', () => {
+ useBadgeData.mockReturnValue( {
+ isLoading: false,
+ error: null,
+ data: {
+ activities: [],
+ savedStats: {},
+ totalPostsCount: 0,
+ activationDate: '2024-01-01',
+ config: {},
+ },
+ } );
+
+ render(
+
+ );
+
+ expect( useBadgeProgress ).toHaveBeenCalledWith(
+ expect.objectContaining( { activities: [] } )
+ );
+ } );
+ } );
+} );
diff --git a/build/AIOSEOPopover.chunk.js b/build/AIOSEOPopover.chunk.js
new file mode 100644
index 0000000000..ef5e861563
--- /dev/null
+++ b/build/AIOSEOPopover.chunk.js
@@ -0,0 +1 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[426],{1110:(e,s,t)=>{t.d(s,{V:()=>r});var a=t(6087),n=t(7723);function r(e,s=[]){const[t,r]=(0,a.useState)(!1),[i,o]=(0,a.useState)(null);return{isLoading:t,error:i,handleSubmit:(0,a.useCallback)(async s=>{s.preventDefault(),r(!0),o(null);try{await e(s)}catch(e){o(e.message||(0,n.__)("Something went wrong. Please try again.","progress-planner"))}finally{r(!1)}},s)}}},2592:(e,s,t)=>{t.d(s,{A:()=>n});var a=t(790);function n({isLoading:e=!1,disabled:s=!1,label:t}){return(0,a.jsx)("button",{type:"submit",className:"prpl-button prpl-button-primary",disabled:e||s,children:e?(0,a.jsx)("span",{className:"spinner",style:{visibility:"visible"}}):t})}},3043:(e,s,t)=>{t.r(s),t.d(s,{default:()=>d});var a=t(7723),n=t(8537),r=t(5202),i=t(6979),o=t(2592),l=t(1110),p=t(4333),c=t(790);function d({task:e,onSubmit:s,onClose:t}){const{isLoading:d,error:u,handleSubmit:g}=(0,l.V)(async()=>{const t=`prpl-popover-${e.slug||e.id}`,a=e.slug||e.prpl_provider?.slug||e.id,n={"aioseo-author-archive":{setting:"aioseo_options",settingPath:JSON.stringify(["searchAppearance","archives","author","show"]),settingCallbackValue:()=>!1},"aioseo-date-archive":{setting:"aioseo_options",settingPath:JSON.stringify(["searchAppearance","archives","date","show"]),settingCallbackValue:()=>!1},"aioseo-media-pages":{setting:"aioseo_options_dynamic",settingPath:JSON.stringify(["searchAppearance","postTypes","attachment","redirectAttachmentUrls"]),settingCallbackValue:()=>"attachment"},"aioseo-crawl-settings-feed-authors":{setting:"aioseo_options",settingPath:JSON.stringify(["searchAppearance","advanced","crawlCleanup","feeds","authors"]),settingCallbackValue:()=>!1},"aioseo-crawl-settings-feed-comments":{multiUpdate:!0,updates:[{setting:"aioseo_options",settingPath:JSON.stringify(["searchAppearance","advanced","crawlCleanup","feeds","globalComments"]),value:!1},{setting:"aioseo_options",settingPath:JSON.stringify(["searchAppearance","advanced","crawlCleanup","feeds","postComments"]),value:!1}]}}[a];if(n)if(n.multiUpdate&&n.updates)for(const e of n.updates)await(0,p.nO)({setting:e.setting,settingPath:e.settingPath,popoverId:t,value:e.value});else await(0,p.nO)({setting:n.setting,settingPath:n.settingPath,popoverId:t,settingCallbackValue:n.settingCallbackValue,value:n.settingCallbackValue()});s&&await s(e.id,e)},[e,s]),h=(0,n.decodeEntities)(e.title?.rendered||e.title),v=e.description?.rendered||e.description||"";return(0,c.jsxs)(r.A,{isOpen:!0,taskId:e.slug||e.id,task:e,onClose:t,children:[(0,c.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,c.jsx)("h2",{className:"prpl-popover-title",children:h}),v&&(0,c.jsx)("p",{children:v})]}),(0,c.jsx)("div",{className:"prpl-column",children:(0,c.jsxs)("form",{onSubmit:g,children:[(0,c.jsx)(i.A,{error:u}),(0,c.jsx)("div",{className:"prpl-steps-nav-wrapper prpl-steps-nav-wrapper-align-left",children:(0,c.jsx)(o.A,{isLoading:d,label:(0,a.__)("Submit","progress-planner")})})]})})]})}},5202:(e,s,t)=>{t.d(s,{A:()=>o});var a=t(6087),n=t(7723),r=t(2619),i=t(790);function o({isOpen:e,taskId:s,onClose:t,children:o}){const l=(0,a.useRef)(null),p=`prpl-popover-${s}`;return(0,a.useEffect)(()=>{if(!l.current)return;const s=l.current;e?"function"==typeof s.showPopover&&s.showPopover():"function"==typeof s.hidePopover&&s.hidePopover()},[e]),e?(0,i.jsxs)("div",{id:p,ref:l,className:"prpl-popover prpl-popover-interactive",popover:"auto",onToggle:e=>{"closed"===e.newState&&((0,r.doAction)("prpl.popover.close",s),t&&t())},children:[(0,i.jsx)("div",{className:"prpl-columns-wrapper-flex",children:o}),(0,i.jsxs)("button",{className:"prpl-popover-close",type:"button",onClick:()=>{(0,r.doAction)("prpl.popover.close",s),t&&t()},"aria-label":(0,n.__)("Close","progress-planner"),children:[(0,i.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,i.jsx)("span",{className:"screen-reader-text",children:(0,n.__)("Close","progress-planner")})]})]}):null}},6979:(e,s,t)=>{t.d(s,{A:()=>n});var a=t(790);function n({error:e}){return e?(0,a.jsx)("p",{className:"prpl-note prpl-note-error prpl-interactive-task-error-message",children:e}):null}}}]);
\ No newline at end of file
diff --git a/build/BadgeStreakPopover.chunk.js b/build/BadgeStreakPopover.chunk.js
new file mode 100644
index 0000000000..007485e915
--- /dev/null
+++ b/build/BadgeStreakPopover.chunk.js
@@ -0,0 +1,5 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[937],{5202:(e,s,n)=>{n.d(s,{A:()=>l});var r=n(6087),a=n(7723),o=n(2619),t=n(790);function l({isOpen:e,taskId:s,onClose:n,children:l}){const i=(0,r.useRef)(null),p=`prpl-popover-${s}`;return(0,r.useEffect)(()=>{if(!i.current)return;const s=i.current;e?"function"==typeof s.showPopover&&s.showPopover():"function"==typeof s.hidePopover&&s.hidePopover()},[e]),e?(0,t.jsxs)("div",{id:p,ref:i,className:"prpl-popover prpl-popover-interactive",popover:"auto",onToggle:e=>{"closed"===e.newState&&((0,o.doAction)("prpl.popover.close",s),n&&n())},children:[(0,t.jsx)("div",{className:"prpl-columns-wrapper-flex",children:l}),(0,t.jsxs)("button",{className:"prpl-popover-close",type:"button",onClick:()=>{(0,o.doAction)("prpl.popover.close",s),n&&n()},"aria-label":(0,a.__)("Close","progress-planner"),children:[(0,t.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,t.jsx)("span",{className:"screen-reader-text",children:(0,a.__)("Close","progress-planner")})]})]}):null}},8691:(e,s,n)=>{n.d(s,{KS:()=>t});var r=n(6087),a=n(5337);const o=3e5;function t(e,s=[],n="Failed to load data",t={}){const{cache:l=!0,cacheTtl:i=o,skipCache:p=!1}=t,[c,d]=(0,r.useState)(!0),[h,u]=(0,r.useState)(null),[g,m]=(0,r.useState)(null),v=(0,r.useCallback)(async(s=!1)=>{if(e){d(!0),u(null);try{const n=await(0,a.BJ)({path:e},{skipCache:s||p||!l,ttl:i});m(n)}catch(e){const s=e.message||("string"==typeof n?n:n.message||"Failed to load data");u(s)}finally{d(!1)}}else d(!1)},[e,l,i,p,n]);return(0,r.useEffect)(()=>{v()},[e,...s]),{isLoading:c,error:h,data:g,refetch:(0,r.useCallback)((e=!0)=>{v(e)},[v])}}},9886:(e,s,n)=>{n.r(s),n.d(s,{default:()=>p});var r=n(7723),a=n(5202),o=n(6230),t=n(1971),l=n(8691),i=n(790);function p({task:e,onClose:s}){const{data:n,isLoading:p}=(0,l.KS)("/progress-planner/v1/badge-stats"),c=n?.badges||(n?{}:null),d=e=>{if(!c)return null;const s=Object.keys(c).filter(s=>s.startsWith(e+"-")).map(e=>({id:e,...c[e]})).sort((e,s)=>parseInt(e.id.match(/\d+/)?.[0]||"0")-parseInt(s.id.match(/\d+/)?.[0]||"0"));if(0===s.length)return null;const n=s[s.length-1];return{badges:s,progress:n.progress||0,remaining:n.remaining||0}},h=e=>{const s=d(e);if(!s)return null;const{progress:n,badges:a}=s;return(0,i.jsxs)("div",{className:"progress-badges",children:[(0,i.jsx)("span",{className:"badges-popover-progress-total",children:(0,i.jsx)("span",{style:{width:`${n}%`}})}),(0,i.jsx)("div",{className:"indicators",children:a.map(s=>((e,s)=>{const n=e.remaining||0;return(0,i.jsx)("div",{className:"indicator",children:(0,i.jsx)("span",{className:"indicator-label",children:0===n?"✔️":(0,i.jsx)("span",{dangerouslySetInnerHTML:{__html:(()=>{let e;return e="content"===s?1===n?/* translators: %s: number of posts remaining */
+"%s post to go":/* translators: %s: number of posts remaining */
+"%s posts to go":1===n?/* translators: %s: number of weeks remaining */
+"%s week to go":/* translators: %s: number of weeks remaining */
+"%s weeks to go",(0,r.sprintf)(e,(0,r.sprintf)('
%s',n))})()}})})},e.id)})(s,e))})]})},u=d("maintenance"),g=d("content"),m=(0,t.p)(e,"badge-streak");return(0,i.jsxs)(a.A,{isOpen:!0,taskId:m||"badge-streak",task:e,onClose:s,children:[(0,i.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,i.jsx)("h2",{className:"prpl-popover-title",children:(0,r.__)("You are on the right track!","progress-planner")}),(0,i.jsx)("p",{children:(0,r.__)("Find out which badges to unlock next and become a Progress Planner Professional!","progress-planner")})]}),(0,i.jsxs)("div",{className:"prpl-column",children:[(0,i.jsxs)("div",{className:"prpl-widgets-container in-popover",children:[(0,i.jsxs)("div",{className:"prpl-widget-wrapper in-popover",children:[(0,i.jsx)("h3",{children:(0,r.__)("Don't break your streak and stay active every week!","progress-planner")}),(0,i.jsx)("p",{children:(0,r.__)("Execute at least one website maintenance task every week. That could be publishing content, adding content, updating a post, or updating a plugin.","progress-planner")}),(0,i.jsx)("p",{children:(0,r.__)("Not able to work on your site for a week? Use your streak freeze!","progress-planner")}),p?(0,i.jsx)(o.A,{}):(0,i.jsx)("div",{id:"popover-badge-streak-content",children:u&&(0,i.jsx)("div",{className:"badge-display",children:h("maintenance")})})]}),(0,i.jsxs)("div",{className:"prpl-widget-wrapper in-popover",children:[(0,i.jsx)("h3",{children:(0,r.__)("Keep adding posts and pages","progress-planner")}),(0,i.jsx)("p",{children:(0,r.__)("The more you write, the sooner you unlock new badges. You can earn level 1 of this badge immediately after installing the plugin if you have written 20 or more blog posts.","progress-planner")}),p?(0,i.jsx)(o.A,{}):(0,i.jsx)("div",{id:"popover-badge-streak-maintenance",children:g&&(0,i.jsx)("div",{className:"badge-display",children:h("content")})})]})]}),(0,i.jsx)("div",{className:"footer",children:(0,i.jsxs)("div",{className:"string-freeze-explain",children:[(0,i.jsx)("h2",{children:(0,r.__)("Streak freeze","progress-planner")}),(0,i.jsx)("p",{children:(0,r.__)("Going on a holiday? Or don't have any time this week? You can skip your website maintenance for a maximum of one week. Your streak will continue afterward.","progress-planner")})]})})]})]})}}}]);
\ No newline at end of file
diff --git a/build/BlogDescriptionPopover.chunk.js b/build/BlogDescriptionPopover.chunk.js
new file mode 100644
index 0000000000..50980edfa4
--- /dev/null
+++ b/build/BlogDescriptionPopover.chunk.js
@@ -0,0 +1 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[510],{1110:(e,s,r)=>{r.d(s,{V:()=>a});var n=r(6087),t=r(7723);function a(e,s=[]){const[r,a]=(0,n.useState)(!1),[i,o]=(0,n.useState)(null);return{isLoading:r,error:i,handleSubmit:(0,n.useCallback)(async s=>{s.preventDefault(),a(!0),o(null);try{await e(s)}catch(e){o(e.message||(0,t.__)("Something went wrong. Please try again.","progress-planner"))}finally{a(!1)}},s)}}},2195:(e,s,r)=>{r.d(s,{e:()=>a});var n=r(6087),t=r(8691);function a(e=[]){const{data:s,isLoading:r,error:a}=(0,t.KS)("/wp/v2/settings");return{settings:(0,n.useMemo)(()=>{if(!s)return{};const r={};for(const t of e){var n;r[t]=null!==(n=s[t])&&void 0!==n?n:""}return r},[s,...e]),isLoading:r,error:a}}},2592:(e,s,r)=>{r.d(s,{A:()=>t});var n=r(790);function t({isLoading:e=!1,disabled:s=!1,label:r}){return(0,n.jsx)("button",{type:"submit",className:"prpl-button prpl-button-primary",disabled:e||s,children:e?(0,n.jsx)("span",{className:"spinner",style:{visibility:"visible"}}):r})}},5202:(e,s,r)=>{r.d(s,{A:()=>o});var n=r(6087),t=r(7723),a=r(2619),i=r(790);function o({isOpen:e,taskId:s,onClose:r,children:o}){const l=(0,n.useRef)(null),p=`prpl-popover-${s}`;return(0,n.useEffect)(()=>{if(!l.current)return;const s=l.current;e?"function"==typeof s.showPopover&&s.showPopover():"function"==typeof s.hidePopover&&s.hidePopover()},[e]),e?(0,i.jsxs)("div",{id:p,ref:l,className:"prpl-popover prpl-popover-interactive",popover:"auto",onToggle:e=>{"closed"===e.newState&&((0,a.doAction)("prpl.popover.close",s),r&&r())},children:[(0,i.jsx)("div",{className:"prpl-columns-wrapper-flex",children:o}),(0,i.jsxs)("button",{className:"prpl-popover-close",type:"button",onClick:()=>{(0,a.doAction)("prpl.popover.close",s),r&&r()},"aria-label":(0,t.__)("Close","progress-planner"),children:[(0,i.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,i.jsx)("span",{className:"screen-reader-text",children:(0,t.__)("Close","progress-planner")})]})]}):null}},6979:(e,s,r)=>{r.d(s,{A:()=>t});var n=r(790);function t({error:e}){return e?(0,n.jsx)("p",{className:"prpl-note prpl-note-error prpl-interactive-task-error-message",children:e}):null}},7815:(e,s,r)=>{r.r(s),r.d(s,{default:()=>h});var n=r(6087),t=r(7723),a=r(8537),i=r(5202),o=r(6979),l=r(2592),p=r(1110),c=r(2195),d=r(4333),u=r(790);function h({task:e,onSubmit:s,onClose:r}){const[h,g]=(0,n.useState)(""),{settings:m}=(0,c.e)(["description"]);(0,n.useEffect)(()=>{m.description&&g(m.description)},[m.description]);const{isLoading:v,error:b,handleSubmit:f}=(0,p.V)(async()=>{if(!h.trim())return;const r=`prpl-popover-${e.slug||e.id}`;await(0,d.nM)({settingAPIKey:"description",setting:"blogdescription",popoverId:r,settingCallbackValue:()=>h.trim(),value:h.trim()}),s&&await s(e.id,e)},[h,e,s]),x=(0,a.decodeEntities)(e.title?.rendered||e.title),y=e.description?.rendered||e.description||"";return(0,u.jsxs)(i.A,{isOpen:!0,taskId:e.slug||e.id,task:e,onClose:r,children:[(0,u.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,u.jsx)("h2",{className:"prpl-popover-title",children:x}),(0,u.jsx)("p",{children:(0,t.__)("In a few words, explain what this site is about. This information is used in your website's schema and RSS feeds, and can be displayed on your site. The tagline typically is your site's mission statement.","progress-planner")})]}),(0,u.jsx)("div",{className:"prpl-column",children:(0,u.jsxs)("form",{onSubmit:f,children:[y&&(0,u.jsx)("p",{children:y}),(0,u.jsxs)("label",{htmlFor:"blogdescription",children:[(0,u.jsx)("span",{className:"screen-reader-text",children:(0,t.__)("Blog Description","progress-planner")}),(0,u.jsx)("input",{name:"blogdescription",type:"text",id:"blogdescription",value:h,onChange:e=>g(e.target.value),placeholder:(0,t.__)("A catchy phrase to describe your website","progress-planner"),disabled:v})]}),(0,u.jsx)(o.A,{error:b}),(0,u.jsx)("div",{className:"prpl-steps-nav-wrapper",children:(0,u.jsx)(l.A,{isLoading:v,disabled:!h.trim(),label:(0,t.__)("Save","progress-planner")})})]})})]})}},8691:(e,s,r)=>{r.d(s,{KS:()=>i});var n=r(6087),t=r(5337);const a=3e5;function i(e,s=[],r="Failed to load data",i={}){const{cache:o=!0,cacheTtl:l=a,skipCache:p=!1}=i,[c,d]=(0,n.useState)(!0),[u,h]=(0,n.useState)(null),[g,m]=(0,n.useState)(null),v=(0,n.useCallback)(async(s=!1)=>{if(e){d(!0),h(null);try{const r=await(0,t.BJ)({path:e},{skipCache:s||p||!o,ttl:l});m(r)}catch(e){const s=e.message||("string"==typeof r?r:r.message||"Failed to load data");h(s)}finally{d(!1)}}else d(!1)},[e,o,l,p,r]);return(0,n.useEffect)(()=>{v()},[e,...s]),{isLoading:c,error:u,data:g,refetch:(0,n.useCallback)((e=!0)=>{v(e)},[v])}}}}]);
\ No newline at end of file
diff --git a/build/CustomPopover.chunk.js b/build/CustomPopover.chunk.js
new file mode 100644
index 0000000000..79a01d8e4e
--- /dev/null
+++ b/build/CustomPopover.chunk.js
@@ -0,0 +1 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[717],{2592:(e,r,t)=>{t.d(r,{A:()=>n});var a=t(790);function n({isLoading:e=!1,disabled:r=!1,label:t}){return(0,a.jsx)("button",{type:"submit",className:"prpl-button prpl-button-primary",disabled:e||r,children:e?(0,a.jsx)("span",{className:"spinner",style:{visibility:"visible"}}):t})}},5202:(e,r,t)=>{t.d(r,{A:()=>i});var a=t(6087),n=t(7723),s=t(2619),o=t(790);function i({isOpen:e,taskId:r,onClose:t,children:i}){const l=(0,a.useRef)(null),p=`prpl-popover-${r}`;return(0,a.useEffect)(()=>{if(!l.current)return;const r=l.current;e?"function"==typeof r.showPopover&&r.showPopover():"function"==typeof r.hidePopover&&r.hidePopover()},[e]),e?(0,o.jsxs)("div",{id:p,ref:l,className:"prpl-popover prpl-popover-interactive",popover:"auto",onToggle:e=>{"closed"===e.newState&&((0,s.doAction)("prpl.popover.close",r),t&&t())},children:[(0,o.jsx)("div",{className:"prpl-columns-wrapper-flex",children:i}),(0,o.jsxs)("button",{className:"prpl-popover-close",type:"button",onClick:()=>{(0,s.doAction)("prpl.popover.close",r),t&&t()},"aria-label":(0,n.__)("Close","progress-planner"),children:[(0,o.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,o.jsx)("span",{className:"screen-reader-text",children:(0,n.__)("Close","progress-planner")})]})]}):null}},5359:(e,r,t)=>{function a(e,r=""){var t,a,n;return null!==(t=null!==(a=null!==(n=window.prplDashboardConfig?.[e])&&void 0!==n?n:window.progressPlannerAdmin?.[e])&&void 0!==a?a:window.progressPlanner?.[e])&&void 0!==t?t:r}function n(){return a("brandingId",0)}function s(){return a("ajaxUrl","/wp-admin/admin-ajax.php")}function o(){return a("nonce","")}t.d(r,{m9:()=>o,nZ:()=>n,we:()=>s})},6979:(e,r,t)=>{t.d(r,{A:()=>n});var a=t(790);function n({error:e}){return e?(0,a.jsx)("p",{className:"prpl-note prpl-note-error prpl-interactive-task-error-message",children:e}):null}},8646:(e,r,t)=>{t.r(r),t.d(r,{default:()=>g});var a=t(6087),n=t(7723),s=t(8537),o=t(1455),i=t.n(o),l=t(5202),p=t(6979),c=t(2592),d=t(5359),u=t(790);function g({task:e,onSubmit:r,onClose:t,onCustomSubmit:o}){const g=e.slug||e.prpl_provider?.slug||e.id,[m,_]=(0,a.useState)(!1),[h,v]=(0,a.useState)(null),[x,f]=(0,a.useState)(""),[y,w]=(0,a.useState)(""),[b,j]=(0,a.useState)(""),[S,k]=(0,a.useState)(null),[C,z]=(0,a.useState)("");(0,a.useEffect)(()=>{if("update-term-description"===g){const r=e.target_term_id||e.prpl_task_data?.target_term_id,t=e.target_taxonomy||e.prpl_task_data?.target_taxonomy;if(r&&t){k(r),z(t);const e="category"===t?"categories":t;i()({path:`/wp/v2/${e}/${r}`}).then(e=>{j(e.description||"")}).catch(()=>{})}}else if("rename-uncategorized-category"===g){const r=e.prpl_task_data?.category_id||e.category_id;r&&i()({path:`/wp/v2/categories/${r}`}).then(e=>{f(e.name||""),w(e.slug||"")}).catch(()=>{f((0,n.__)("Uncategorized","progress-planner"))})}},[g,e]);const N=(0,a.useCallback)(async t=>{t.preventDefault(),_(!0),v(null);try{const t=`prpl-popover-${g}`;if("rename-uncategorized-category"===g){const e=(0,d.we)(),r=(0,d.m9)(),t=new URLSearchParams({action:"prpl_interactive_task_submit_rename-uncategorized-category",_ajax_nonce:r,uncategorized_category_name:x.trim(),uncategorized_category_slug:y.trim()}),a=await fetch(e,{method:"POST",body:t,credentials:"same-origin"}),s=await a.json();if(!s.success)throw new Error(s.data?.message||(0,n.__)("Failed to update category.","progress-planner"))}else if("update-term-description"===g){const e=(0,d.we)(),r=(0,d.m9)(),t=new URLSearchParams({action:"prpl_interactive_task_submit_update-term-description",_ajax_nonce:r,term_id:S,taxonomy:C,description:b}),a=await fetch(e,{method:"POST",body:t,credentials:"same-origin"}),s=await a.json();if(!s.success)throw new Error(s.data?.message||(0,n.__)("Failed to update term description.","progress-planner"))}else o&&await o(g,t);r&&await r(e.id,e)}catch(e){v(e.message||(0,n.__)("Something went wrong. Please try again.","progress-planner"))}finally{_(!1)}},[g,e,r,o,x,y,S,C,b]),P=(0,s.decodeEntities)(e.title?.rendered||e.title),A=e.description?.rendered||e.description||"";return(0,u.jsxs)(l.A,{isOpen:!0,taskId:g,task:e,onClose:t,children:[(0,u.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,u.jsx)("h2",{className:"prpl-popover-title",children:P}),A&&(0,u.jsx)("p",{children:A})]}),(0,u.jsx)("div",{className:"prpl-column",children:(0,u.jsxs)("form",{onSubmit:N,children:[(()=>{if("rename-uncategorized-category"===g)return(0,u.jsxs)(u.Fragment,{children:[(0,u.jsxs)("label",{htmlFor:"uncategorized_category_name",children:[(0,n.__)("Category Name","progress-planner"),(0,u.jsx)("input",{type:"text",id:"uncategorized_category_name",name:"uncategorized_category_name",value:x,onChange:e=>{f(e.target.value);const r=e.target.value.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"");w(r)},disabled:m,required:!0})]}),(0,u.jsxs)("label",{htmlFor:"uncategorized_category_slug",children:[(0,n.__)("Category Slug","progress-planner"),(0,u.jsx)("input",{type:"text",id:"uncategorized_category_slug",name:"uncategorized_category_slug",value:y,onChange:e=>w(e.target.value),disabled:m,required:!0})]})]});if("update-term-description"===g){const r=e.target_term_name||e.prpl_task_data?.target_term_name||"";return(0,u.jsxs)(u.Fragment,{children:[r&&(0,u.jsxs)("p",{children:[(0,n.__)("Term:","progress-planner")," ",(0,u.jsx)("strong",{children:r})]}),(0,u.jsxs)("label",{htmlFor:"term_description",children:[(0,n.__)("Description","progress-planner"),(0,u.jsx)("textarea",{id:"term_description",name:"description",value:b,onChange:e=>j(e.target.value),disabled:m,rows:5})]})]})}return null})(),(0,u.jsx)(p.A,{error:h}),(0,u.jsx)("div",{className:"prpl-steps-nav-wrapper prpl-steps-nav-wrapper-align-left",children:(0,u.jsx)(c.A,{isLoading:m,disabled:!("rename-uncategorized-category"!==g||x.trim()&&y.trim()),label:(0,n.__)("Submit","progress-planner")})})]})})]})}}}]);
\ No newline at end of file
diff --git a/build/DateFormatPopover.chunk.js b/build/DateFormatPopover.chunk.js
new file mode 100644
index 0000000000..c8661d5450
--- /dev/null
+++ b/build/DateFormatPopover.chunk.js
@@ -0,0 +1 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[941],{1110:(e,a,s)=>{s.d(a,{V:()=>n});var t=s(6087),r=s(7723);function n(e,a=[]){const[s,n]=(0,t.useState)(!1),[o,l]=(0,t.useState)(null);return{isLoading:s,error:o,handleSubmit:(0,t.useCallback)(async a=>{a.preventDefault(),n(!0),l(null);try{await e(a)}catch(e){l(e.message||(0,r.__)("Something went wrong. Please try again.","progress-planner"))}finally{n(!1)}},a)}}},2195:(e,a,s)=>{s.d(a,{e:()=>n});var t=s(6087),r=s(8691);function n(e=[]){const{data:a,isLoading:s,error:n}=(0,r.KS)("/wp/v2/settings");return{settings:(0,t.useMemo)(()=>{if(!a)return{};const s={};for(const r of e){var t;s[r]=null!==(t=a[r])&&void 0!==t?t:""}return s},[a,...e]),isLoading:s,error:n}}},2592:(e,a,s)=>{s.d(a,{A:()=>r});var t=s(790);function r({isLoading:e=!1,disabled:a=!1,label:s}){return(0,t.jsx)("button",{type:"submit",className:"prpl-button prpl-button-primary",disabled:e||a,children:e?(0,t.jsx)("span",{className:"spinner",style:{visibility:"visible"}}):s})}},5202:(e,a,s)=>{s.d(a,{A:()=>l});var t=s(6087),r=s(7723),n=s(2619),o=s(790);function l({isOpen:e,taskId:a,onClose:s,children:l}){const i=(0,t.useRef)(null),c=`prpl-popover-${a}`;return(0,t.useEffect)(()=>{if(!i.current)return;const a=i.current;e?"function"==typeof a.showPopover&&a.showPopover():"function"==typeof a.hidePopover&&a.hidePopover()},[e]),e?(0,o.jsxs)("div",{id:c,ref:i,className:"prpl-popover prpl-popover-interactive",popover:"auto",onToggle:e=>{"closed"===e.newState&&((0,n.doAction)("prpl.popover.close",a),s&&s())},children:[(0,o.jsx)("div",{className:"prpl-columns-wrapper-flex",children:l}),(0,o.jsxs)("button",{className:"prpl-popover-close",type:"button",onClick:()=>{(0,n.doAction)("prpl.popover.close",a),s&&s()},"aria-label":(0,r.__)("Close","progress-planner"),children:[(0,o.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,o.jsx)("span",{className:"screen-reader-text",children:(0,r.__)("Close","progress-planner")})]})]}):null}},5359:(e,a,s)=>{function t(e,a=""){var s,t,r;return null!==(s=null!==(t=null!==(r=window.prplDashboardConfig?.[e])&&void 0!==r?r:window.progressPlannerAdmin?.[e])&&void 0!==t?t:window.progressPlanner?.[e])&&void 0!==s?s:a}function r(){return t("brandingId",0)}function n(){return t("ajaxUrl","/wp-admin/admin-ajax.php")}function o(){return t("nonce","")}s.d(a,{m9:()=>o,nZ:()=>r,we:()=>n})},6979:(e,a,s)=>{s.d(a,{A:()=>r});var t=s(790);function r({error:e}){return e?(0,t.jsx)("p",{className:"prpl-note prpl-note-error prpl-interactive-task-error-message",children:e}):null}},7726:(e,a,s)=>{s.r(a),s.d(a,{default:()=>h});var t=s(6087),r=s(7723),n=s(8537),o=s(5202),l=s(6979),i=s(2592),c=s(1110),d=s(2195),p=s(5359),u=s(4333),m=s(790);function h({task:e,onSubmit:a,onClose:s}){const[h,f]=(0,t.useState)(""),[_,g]=(0,t.useState)(""),[x,v]=(0,t.useState)(""),[j,b]=(0,t.useState)([]),[w,y]=(0,t.useState)(!0),N=(0,t.useRef)(null),{settings:C}=(0,d.e)(["date_format"]);(0,t.useEffect)(()=>{if(C.date_format){const e=C.date_format;f(e),g(e),k(e)}},[C.date_format,k]),(0,t.useEffect)(()=>{const e=(0,p.we)(),a=(0,p.m9)();fetch(`${e}?action=prpl_get_date_formats&_ajax_nonce=${a}`,{credentials:"same-origin"}).then(e=>e.json()).then(e=>{e.success&&e.data?b(e.data):b(["F j, Y","Y-m-d","m/d/Y","d/m/Y","d.m.Y"])}).catch(()=>{b(["F j, Y","Y-m-d","m/d/Y","d/m/Y","d.m.Y"])}).finally(()=>{y(!1)})},[]);const k=(0,t.useCallback)(e=>{e&&(clearTimeout(N.current),N.current=setTimeout(async()=>{const a=(0,p.we)(),s=(0,p.m9)();try{const t=await fetch(`${a}?action=prpl_date_format_preview&format=${encodeURIComponent(e)}&_ajax_nonce=${s}`,{credentials:"same-origin"}),r=await t.json();r.success&&r.data&&v(r.data)}catch{}},300))},[]),S=(0,t.useCallback)(e=>{"custom"===e?f("custom"):(f(e),k(e))},[k]),A=(0,t.useCallback)(e=>{const a=e.target.value;g(a),"custom"===h&&k(a)},[h,k]),{isLoading:P,error:Y,handleSubmit:F}=(0,c.V)(async()=>{const s="custom"===h?_:h;if(!s)return;const t=`prpl-popover-${e.slug||e.id}`;await(0,u.nM)({settingAPIKey:"date_format",setting:"date_format",popoverId:t,settingCallbackValue:()=>s,value:s}),a&&await a(e.id,e)},[h,_,e,a]);(0,t.useEffect)(()=>()=>{N.current&&clearTimeout(N.current)},[]);const $=(0,n.decodeEntities)(e.title?.rendered||e.title);return(0,m.jsxs)(o.A,{isOpen:!0,taskId:e.slug||e.id,task:e,onClose:s,children:[(0,m.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,m.jsx)("h2",{className:"prpl-popover-title",children:$}),(0,m.jsx)("p",{children:(0,r.__)("Choosing the right date format helps your visitors instantly understand when something was published without confusion or guessing. It also makes your site feel more familiar and trustworthy, especially if your audience is local.","progress-planner")}),(0,m.jsx)("p",{children:(0,r.__)("By setting the correct format, you make sure dates show up clearly both in your dashboard and on your live site.","progress-planner")}),(0,m.jsx)("p",{children:(0,r.__)("Tip: Pick the format that matches what your audience expects.","progress-planner")})]}),(0,m.jsx)("div",{className:"prpl-column",children:(0,m.jsxs)("form",{onSubmit:F,children:[(0,m.jsx)("div",{className:"radios",children:(0,m.jsx)("fieldset",{children:w?(0,m.jsx)("p",{children:(0,r.__)("Loading formats…","progress-planner")}):(0,m.jsxs)(m.Fragment,{children:[j.map(e=>{const a=h===e;return(0,m.jsx)("div",{className:"prpl-radio-wrapper",children:(0,m.jsxs)("label",{className:"prpl-custom-radio",htmlFor:`date_format_${e}`,children:[(0,m.jsx)("input",{type:"radio",id:`date_format_${e}`,name:"date_format",value:e,checked:a,onChange:()=>S(e),disabled:P}),(0,m.jsx)("span",{className:"prpl-custom-control"}),(0,m.jsx)("span",{className:"date-time-text format-i18n",children:x||e}),(0,m.jsx)("code",{children:e})]})},e)}),(0,m.jsxs)("div",{className:"prpl-radio-wrapper",children:[(0,m.jsxs)("label",{className:"prpl-custom-radio",htmlFor:"date_format_custom_radio",children:[(0,m.jsx)("input",{type:"radio",name:"date_format",id:"date_format_custom_radio",value:"custom",checked:"custom"===h,onChange:()=>S("custom"),disabled:P}),(0,m.jsx)("span",{className:"prpl-custom-control"}),(0,m.jsxs)("span",{className:"date-time-text date-time-custom-text",children:[(0,r.__)("Custom:","progress-planner")," ",(0,m.jsx)("span",{className:"screen-reader-text",children:(0,r.__)("enter a custom date format in the following field","progress-planner")})]})]}),(0,m.jsx)("label",{htmlFor:"date_format_custom",className:"screen-reader-text",children:(0,r.__)("Custom date format:","progress-planner")}),(0,m.jsx)("input",{type:"text",name:"date_format_custom",id:"date_format_custom",value:_,onChange:A,className:"small-text",disabled:P||"custom"!==h})]}),(0,m.jsxs)("label",{htmlFor:"date_format_custom",children:[(0,m.jsx)("span",{className:"screen-reader-text",children:(0,r.__)("Custom date format:","progress-planner")}),(0,m.jsx)("input",{type:"text",id:"date_format_custom",name:"date_format_custom",value:_,onChange:A,className:"small-text",disabled:P||"custom"!==h})]}),(0,m.jsxs)("p",{children:[(0,m.jsx)("strong",{children:(0,r.__)("Preview:","progress-planner")})," ",(0,m.jsx)("span",{className:"example",children:x}),P&&(0,m.jsx)("span",{className:"spinner"})]})]})})}),(0,m.jsx)(l.A,{error:Y}),(0,m.jsx)("div",{className:"prpl-steps-nav-wrapper prpl-steps-nav-wrapper-align-left",children:(0,m.jsx)(i.A,{isLoading:P,disabled:!h,label:(0,r.__)("Set date format","progress-planner")})})]})})]})}},8691:(e,a,s)=>{s.d(a,{KS:()=>o});var t=s(6087),r=s(5337);const n=3e5;function o(e,a=[],s="Failed to load data",o={}){const{cache:l=!0,cacheTtl:i=n,skipCache:c=!1}=o,[d,p]=(0,t.useState)(!0),[u,m]=(0,t.useState)(null),[h,f]=(0,t.useState)(null),_=(0,t.useCallback)(async(a=!1)=>{if(e){p(!0),m(null);try{const s=await(0,r.BJ)({path:e},{skipCache:a||c||!l,ttl:i});f(s)}catch(e){const a=e.message||("string"==typeof s?s:s.message||"Failed to load data");m(a)}finally{p(!1)}}else p(!1)},[e,l,i,c,s]);return(0,t.useEffect)(()=>{_()},[e,...a]),{isLoading:d,error:u,data:h,refetch:(0,t.useCallback)((e=!0)=>{_(e)},[_])}}}}]);
\ No newline at end of file
diff --git a/build/DisableCommentsPopover.chunk.js b/build/DisableCommentsPopover.chunk.js
new file mode 100644
index 0000000000..340d2e6c15
--- /dev/null
+++ b/build/DisableCommentsPopover.chunk.js
@@ -0,0 +1 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[454],{1110:(e,s,n)=>{n.d(s,{V:()=>t});var r=n(6087),l=n(7723);function t(e,s=[]){const[n,t]=(0,r.useState)(!1),[a,o]=(0,r.useState)(null);return{isLoading:n,error:a,handleSubmit:(0,r.useCallback)(async s=>{s.preventDefault(),t(!0),o(null);try{await e(s)}catch(e){o(e.message||(0,l.__)("Something went wrong. Please try again.","progress-planner"))}finally{t(!1)}},s)}}},1599:(e,s,n)=>{n.r(s),n.d(s,{default:()=>d});var r=n(7723),l=n(8537),t=n(5202),a=n(6979),o=n(2592),p=n(1110),i=n(4333),c=n(790);function d({task:e,onSubmit:s,onClose:n}){const{isLoading:d,error:u,handleSubmit:m}=(0,p.V)(async()=>{const n=`prpl-popover-${e.slug||e.id}`,r=e.slug||e.prpl_provider?.slug||e.id;"disable-comments"===r?await(0,i.nM)({settingAPIKey:"default_comment_status",setting:"default_comment_status",popoverId:n,settingCallbackValue:()=>"closed",value:"closed"}):"disable-comment-pagination"===r?await(0,i.nM)({settingAPIKey:"page_comments",setting:"page_comments",popoverId:n,settingCallbackValue:()=>!1,value:!1}):"search-engine-visibility"===r&&await(0,i.nO)({setting:"blog_public",popoverId:n,settingCallbackValue:()=>"1",value:"1"}),s&&await s(e.id,e)},[e,s]),v=(0,l.decodeEntities)(e.title?.rendered||e.title),g=e.description?.rendered||e.description||"";return(0,c.jsxs)(t.A,{isOpen:!0,taskId:e.slug||e.id,task:e,onClose:n,children:[(0,c.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,c.jsx)("h2",{className:"prpl-popover-title",children:v}),g&&(0,c.jsx)("p",{children:g})]}),(0,c.jsx)("div",{className:"prpl-column",children:(0,c.jsxs)("form",{onSubmit:m,children:[(0,c.jsx)(a.A,{error:u}),(0,c.jsx)("div",{className:"prpl-steps-nav-wrapper prpl-steps-nav-wrapper-align-left",children:(0,c.jsx)(o.A,{isLoading:d,label:(0,r.__)("Submit","progress-planner")})})]})})]})}},2592:(e,s,n)=>{n.d(s,{A:()=>l});var r=n(790);function l({isLoading:e=!1,disabled:s=!1,label:n}){return(0,r.jsx)("button",{type:"submit",className:"prpl-button prpl-button-primary",disabled:e||s,children:e?(0,r.jsx)("span",{className:"spinner",style:{visibility:"visible"}}):n})}},5202:(e,s,n)=>{n.d(s,{A:()=>o});var r=n(6087),l=n(7723),t=n(2619),a=n(790);function o({isOpen:e,taskId:s,onClose:n,children:o}){const p=(0,r.useRef)(null),i=`prpl-popover-${s}`;return(0,r.useEffect)(()=>{if(!p.current)return;const s=p.current;e?"function"==typeof s.showPopover&&s.showPopover():"function"==typeof s.hidePopover&&s.hidePopover()},[e]),e?(0,a.jsxs)("div",{id:i,ref:p,className:"prpl-popover prpl-popover-interactive",popover:"auto",onToggle:e=>{"closed"===e.newState&&((0,t.doAction)("prpl.popover.close",s),n&&n())},children:[(0,a.jsx)("div",{className:"prpl-columns-wrapper-flex",children:o}),(0,a.jsxs)("button",{className:"prpl-popover-close",type:"button",onClick:()=>{(0,t.doAction)("prpl.popover.close",s),n&&n()},"aria-label":(0,l.__)("Close","progress-planner"),children:[(0,a.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,a.jsx)("span",{className:"screen-reader-text",children:(0,l.__)("Close","progress-planner")})]})]}):null}},6979:(e,s,n)=>{n.d(s,{A:()=>l});var r=n(790);function l({error:e}){return e?(0,r.jsx)("p",{className:"prpl-note prpl-note-error prpl-interactive-task-error-message",children:e}):null}}}]);
\ No newline at end of file
diff --git a/build/EmailSendingPopover.chunk.js b/build/EmailSendingPopover.chunk.js
new file mode 100644
index 0000000000..4058c4e05f
--- /dev/null
+++ b/build/EmailSendingPopover.chunk.js
@@ -0,0 +1,10 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[496],{4485:(e,s,r)=>{r.r(s),r.d(s,{default:()=>m});var n=r(6087),a=r(7723),l=r(1455),o=r.n(l),t=r(5202),p=r(790);const i="form",c="result",d="error",u="success",h="troubleshooting";function m({task:e,onSubmit:s,onClose:r}){const[l,m]=(0,n.useState)(i),[g,_]=(0,n.useState)(""),[x,j]=(0,n.useState)(!1),[b,v]=(0,n.useState)(null),[w,y]=(0,n.useState)(""),[f,N]=(0,n.useState)(""),[k,C]=(0,n.useState)(!1);(0,n.useEffect)(()=>{let e=!0;o()({path:"/progress-planner/v1/popover/email-sending-config"}).then(s=>{e&&(s.email_subject&&y(s.email_subject),s.troubleshooting_guide_url&&N(s.troubleshooting_guide_url),void 0!==s.has_email_override&&C(s.has_email_override),s.default_email&&_(e=>e||s.default_email))}).catch(()=>{e&&y((0,a.__)("Your Progress Planner test message!","progress-planner"))});const s=window.wp?.data?.select("core")?.getCurrentUser?.();return s?.email&&_(s.email),()=>{e=!1}},[]);const S=(0,n.useCallback)(async()=>{if(g){j(!0),v(null);try{const s=e.slug||e.id||"sending-email",r=await o()({path:"/progress-planner/v1/popover/test-email",method:"POST",data:{email_address:g,task_id:s}});r.success?m(c):(v(r.message||(0,a.__)("Unknown error","progress-planner")),m(d))}catch(e){const s=e?.message||e?.data?.message||(0,a.__)("Unknown error","progress-planner");v(s),m(d)}finally{j(!1)}}},[g,e]),T=(0,n.useCallback)(async e=>{e.preventDefault(),await S()},[S]),F=(0,n.useCallback)(e=>{const s=e.target.getAttribute("data-action");"showSuccess"===s?m(u):"showTroubleshooting"===s&&m(h)},[]),P=(0,n.useCallback)(async()=>{s&&await s(e.id,e)},[e,s]),W=(0,n.useCallback)(()=>{f&&window.open(f,"_blank"),r&&r()},[f,r]);return(0,p.jsx)(t.A,{isOpen:!0,taskId:e.slug||e.id,task:e,onClose:r,children:(()=>{switch(l){case i:return(0,p.jsxs)(p.Fragment,{children:[(0,p.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,p.jsx)("h2",{className:"prpl-popover-title",children:(0,a.__)("Test if your site can send emails","progress-planner")}),(0,p.jsx)("p",{children:(0,a.__)("Your WordPress site sometimes needs to send emails. For example, to reset a password, send a comment notification, or warn you when something breaks. Contact forms also use email.","progress-planner")}),(0,p.jsx)("p",{children:(0,a.__)("It is important to check if these emails are actually sent. Enter your email address on the right to get a test email.","progress-planner")})]}),(0,p.jsxs)("div",{className:"prpl-column",children:[(0,p.jsx)("p",{children:(0,a.__)("Where should we send the test email?","progress-planner")}),(0,p.jsxs)("div",{className:"prpl-note",children:[(0,p.jsx)("span",{className:"prpl-note-icon",children:(0,p.jsx)("span",{className:"dashicons dashicons-warning"})}),(0,p.jsx)("span",{className:"prpl-note-text",children:(0,a.__)("You should get the email in a few minutes. In rare cases, it might take a few hours.","progress-planner")})]}),(0,p.jsxs)("form",{onSubmit:T,children:[(0,p.jsxs)("label",{htmlFor:"prpl-sending-email-address",children:[(0,p.jsx)("span",{className:"screen-reader-text",children:(0,a.__)("Email address","progress-planner")}),(0,p.jsx)("input",{type:"email",id:"prpl-sending-email-address",placeholder:(0,a.__)("Enter your e-mail address","progress-planner"),value:g,onChange:e=>_(e.target.value),disabled:x,required:!0})]}),(0,p.jsx)("div",{className:"prpl-steps-nav-wrapper",children:(0,p.jsx)("button",{type:"submit",className:"prpl-button prpl-button-step",disabled:x||!g,children:x?(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)("span",{className:"spinner",style:{visibility:"visible"}}),(0,a.__)("Sending…","progress-planner")]}):(0,p.jsxs)(p.Fragment,{children:[(0,a.__)("Next step","progress-planner"),(0,p.jsx)("span",{className:"dashicons dashicons-arrow-right-alt2"})]})})})]})]})]});case d:return(0,p.jsxs)(p.Fragment,{children:[(0,p.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,p.jsx)("h2",{className:"prpl-popover-title",children:(0,a.__)("We tried to send a test email","progress-planner")}),(0,p.jsx)("p",{children:(0,a.sprintf)(
+// translators: %1$s is the email subject, %2$s is the email address.
+// translators: %1$s is the email subject, %2$s is the email address.
+(0,a.__)('We just tried to send the email "%1$s" to %2$s, but unfortunately it didn\'t work.',"progress-planner"),w,g)})]}),(0,p.jsxs)("div",{className:"prpl-column",children:[(0,p.jsxs)("div",{className:"prpl-note prpl-note-error",children:[(0,p.jsx)("span",{className:"prpl-note-icon",children:(0,p.jsx)("span",{className:"dashicons dashicons-warning"})}),(0,p.jsx)("span",{className:"prpl-note-text",children:(0,a.sprintf)(
+// translators: %s is the error message.
+// translators: %s is the error message.
+(0,a.__)("The test email did not work. The error message was: %s","progress-planner"),b||(0,a.__)("Unknown error","progress-planner"))})]}),f&&(0,p.jsxs)("p",{children:[(0,a.__)("There are a few common reasons why your email might not be sending. Check the","progress-planner")," ",(0,p.jsx)("a",{href:f,target:"_blank",rel:"noopener noreferrer",children:(0,a.__)("troubleshooting guide","progress-planner")})," ",(0,a.__)("to find out what is causing the issue and how to fix it.","progress-planner")]}),(0,p.jsxs)("div",{className:"prpl-steps-nav-wrapper",children:[(0,p.jsxs)("button",{type:"button",className:"prpl-button prpl-button-step",onClick:()=>m(i),children:[(0,p.jsx)("span",{className:"dashicons dashicons-arrow-left-alt2"}),(0,a.__)("Try again","progress-planner")]}),(0,p.jsx)("button",{type:"button",className:"prpl-button prpl-button-step",onClick:r,children:(0,a.__)("Retry later","progress-planner")})]})]})]});case c:return(0,p.jsxs)(p.Fragment,{children:[(0,p.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,p.jsx)("h2",{className:"prpl-popover-title",children:(0,a.__)("We sent a test email","progress-planner")}),(0,p.jsx)("p",{children:(0,a.sprintf)(
+// translators: %1$s is the email subject, %2$s is the email address.
+// translators: %1$s is the email subject, %2$s is the email address.
+(0,a.__)('We just sent the email "%1$s" to %2$s.',"progress-planner"),w,g)})]}),(0,p.jsxs)("div",{className:"prpl-column",children:[(0,p.jsx)("p",{children:(0,a.__)("Did you get the test email?","progress-planner")}),(0,p.jsxs)("div",{className:"prpl-note",children:[(0,p.jsx)("span",{className:"prpl-note-icon",children:(0,p.jsx)("span",{className:"dashicons dashicons-warning"})}),(0,p.jsx)("span",{className:"prpl-note-text",children:(0,a.__)("You should get the email in a few minutes. In rare cases, it might take a few hours.","progress-planner")})]}),(0,p.jsxs)("div",{className:"radios",children:[(0,p.jsx)("div",{className:"prpl-radio-wrapper",children:(0,p.jsxs)("label",{htmlFor:"prpl-sending-email-result-yes",className:"prpl-custom-radio",children:[(0,p.jsx)("input",{type:"radio",id:"prpl-sending-email-result-yes",name:"prpl-sending-email-result","data-action":"showSuccess",onChange:F}),(0,p.jsx)("span",{className:"prpl-custom-control"}),(0,a.__)("Yes","progress-planner")]})}),(0,p.jsx)("div",{className:"prpl-radio-wrapper",children:(0,p.jsxs)("label",{htmlFor:"prpl-sending-email-result-no",className:"prpl-custom-radio",children:[(0,p.jsx)("input",{type:"radio",id:"prpl-sending-email-result-no",name:"prpl-sending-email-result","data-action":"showTroubleshooting",onChange:F}),(0,p.jsx)("span",{className:"prpl-custom-control"}),(0,a.__)("No","progress-planner")]})})]})]})]});case u:return(0,p.jsxs)(p.Fragment,{children:[(0,p.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,p.jsx)("h2",{className:"prpl-popover-title",children:(0,a.__)("Your email is set up properly!","progress-planner")}),(0,p.jsx)("p",{children:(0,a.__)("Great, you received the test email! This indicates email is set up properly on your website.","progress-planner")})]}),(0,p.jsxs)("div",{className:"prpl-column",children:[(0,p.jsx)("p",{children:(0,a.__)("Celebrate this achievement!","progress-planner")}),(0,p.jsx)("div",{className:"prpl-steps-nav-wrapper",children:(0,p.jsx)("button",{type:"button",className:"prpl-button prpl-button-step",onClick:P,children:(0,a.__)("Collect your point!","progress-planner")})})]})]});case h:return(0,p.jsxs)(p.Fragment,{children:[(0,p.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,p.jsx)("h2",{className:"prpl-popover-title",children:(0,a.__)("Your email might not be working well","progress-planner")}),(0,p.jsx)("p",{children:(0,a.__)("We're sorry to hear you did not receive our confirmation email yet. On some websites, it make take up to a few hours to send email. That's why we strongly advise you to check back in a few hours from now.","progress-planner")}),(0,p.jsx)("p",{children:(0,a.__)("If you already waited a couple of hours and you still didn't get our email, your email might not be working well.","progress-planner")})]}),(0,p.jsxs)("div",{className:"prpl-column",children:[k?(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)("p",{children:(0,a.__)("What can you do next? Well, it looks like you are already running an SMTP plugin on your website, but it might not be configured correctly.","progress-planner")}),(0,p.jsx)("p",{children:(0,a.__)("You can find more information about running an SMTP plugin in our troubleshooting guide.","progress-planner")})]}):(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)("p",{children:(0,a.__)("What can you do next? If you haven't already, you may need to install a plugin to handle email for you (an SMTP plugin).","progress-planner")}),(0,p.jsx)("p",{children:(0,a.__)("You can find more information about installing an SMTP plugin in our troubleshooting guide.","progress-planner")})]}),(0,p.jsx)("div",{className:"prpl-steps-nav-wrapper",children:(0,p.jsx)("button",{type:"button",className:"prpl-button prpl-button-step",onClick:W,children:(0,a.__)("Take me to your troubleshooting guide","progress-planner")})})]})]});default:return null}})()})}},5202:(e,s,r)=>{r.d(s,{A:()=>t});var n=r(6087),a=r(7723),l=r(2619),o=r(790);function t({isOpen:e,taskId:s,onClose:r,children:t}){const p=(0,n.useRef)(null),i=`prpl-popover-${s}`;return(0,n.useEffect)(()=>{if(!p.current)return;const s=p.current;e?"function"==typeof s.showPopover&&s.showPopover():"function"==typeof s.hidePopover&&s.hidePopover()},[e]),e?(0,o.jsxs)("div",{id:i,ref:p,className:"prpl-popover prpl-popover-interactive",popover:"auto",onToggle:e=>{"closed"===e.newState&&((0,l.doAction)("prpl.popover.close",s),r&&r())},children:[(0,o.jsx)("div",{className:"prpl-columns-wrapper-flex",children:t}),(0,o.jsxs)("button",{className:"prpl-popover-close",type:"button",onClick:()=>{(0,l.doAction)("prpl.popover.close",s),r&&r()},"aria-label":(0,a.__)("Close","progress-planner"),children:[(0,o.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,o.jsx)("span",{className:"screen-reader-text",children:(0,a.__)("Close","progress-planner")})]})]}):null}}}]);
\ No newline at end of file
diff --git a/build/ImprovePdfHandlingPopover-rtl.css b/build/ImprovePdfHandlingPopover-rtl.css
new file mode 100644
index 0000000000..a1cd4a9e2b
--- /dev/null
+++ b/build/ImprovePdfHandlingPopover-rtl.css
@@ -0,0 +1 @@
+.prpl-button-link{align-items:center;background:none;border:none;color:var(--prpl-color-link);cursor:pointer;display:flex!important;font-size:inherit;font-weight:inherit;gap:.5rem;justify-content:center;line-height:inherit;margin:0;padding:0;text-align:inherit;text-decoration:underline}.prpl-install-button-loader{animation:install-button-rotation 1s linear infinite;border:3px solid var(--prpl-color-link);border-bottom:3px solid transparent;border-radius:50%;box-sizing:border-box;display:none;height:1rem;width:1rem}button:disabled .prpl-install-button-loader{display:block}@keyframes install-button-rotation{0%{transform:rotate(0deg)}to{transform:rotate(-1turn)}}
diff --git a/build/ImprovePdfHandlingPopover.chunk.js b/build/ImprovePdfHandlingPopover.chunk.js
new file mode 100644
index 0000000000..70fd906d0d
--- /dev/null
+++ b/build/ImprovePdfHandlingPopover.chunk.js
@@ -0,0 +1,7 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[869],{3831:(e,s,r)=>{r.r(s),r.d(s,{default:()=>h});var n=r(6087),t=r(7723),a=r(5202),l=r(1455),p=r.n(l),o=r(790);function i({pluginSlug:e,pluginName:s,action:r="install",completeTask:a=!0,providerId:l,className:i="prpl-button-link"}){const[c,d]=(0,n.useState)(r),[u,h]=(0,n.useState)(!1),[g,m]=(0,n.useState)("idle"),v=(0,n.useCallback)(async()=>{h(!0),m("installing");try{await p()({path:"/progress-planner/v1/plugins/install",method:"POST",data:{plugin_slug:e}}),await _()}catch(e){console.error("Error installing plugin:",e),m("idle"),h(!1)}},[e,_]),_=(0,n.useCallback)(async()=>{m("activating");try{if(await p()({path:"/progress-planner/v1/plugins/activate",method:"POST",data:{plugin_slug:e}}),m("activated"),d("activated"),a&&l&&window.prplSuggestedTask?.maybeComplete){const e=document.querySelector(`#prpl-suggested-tasks-list .prpl-suggested-task[data-task-id="${l}"]`);if(e){const s=parseInt(e.dataset.postId);s&&window.prplSuggestedTask.maybeComplete(s)}}}catch(e){console.error("Error activating plugin:",e),m("idle")}finally{h(!1)}},[e,a,l]),b=(0,n.useCallback)(()=>{"install"===c?v():"activate"===c&&_()},[c,v,_]);return(0,o.jsxs)("button",{type:"button",className:i,onClick:b,disabled:u||"activated"===g,children:[("installing"===g||"activating"===g)&&(0,o.jsx)("span",{className:"prpl-install-button-loader",children:(0,o.jsx)("span",{className:"spinner",style:{visibility:"visible"}})}),"activated"===g?(0,t.__)("Activated","progress-planner"):"activating"===g?(0,t.__)("Activating…","progress-planner"):"installing"===g?(0,t.__)("Installing…","progress-planner"):"install"===c?(0,t.sprintf)(
+// translators: %s is the plugin name.
+// translators: %s is the plugin name.
+(0,t.__)("Install %s","progress-planner"),s):(0,t.sprintf)(
+// translators: %s is the plugin name.
+// translators: %s is the plugin name.
+(0,t.__)("Activate %s","progress-planner"),s)]})}const c="first",d="pdf-xml-sitemap",u="success";function h({task:e,onSubmit:s,onClose:r}){const[l,p]=(0,n.useState)(c),[h,g]=(0,n.useState)(!1),[m,v]=(0,n.useState)(!1);(0,n.useEffect)(()=>{(async()=>{try{const s=window.prplDashboardConfig?.isMultisite||!1,r=!1!==window.prplDashboardConfig?.canInstallPlugins;if(s||!r)return void g(!1);const n=window.prplDashboardConfig?.plugins?.yoast||e.prpl_task_data?.plugins?.yoast||!1,t=window.prplDashboardConfig?.plugins?.pdfLibrary||e.prpl_task_data?.plugins?.pdfLibrary||!1;g(n&&!t);const a=window.prplDashboardConfig?.plugins?.pdfSitemap||e.prpl_task_data?.plugins?.pdfSitemap||!1;v(a)}catch(e){g(!1)}})()},[e]);const _=(0,n.useCallback)(async()=>{s&&await s(e.id,e)},[e,s]);return(0,o.jsx)(a.A,{isOpen:!0,taskId:e.slug||e.id,task:e,onClose:r,children:(()=>{switch(l){case c:return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,o.jsx)("h2",{className:"prpl-popover-title",children:(0,t.__)("Improve your site's PDF handling","progress-planner")}),(0,o.jsx)("p",{children:(0,t.__)("We have detected that your site has quite a few PDF files.","progress-planner")}),(0,o.jsx)("p",{children:(0,t.__)("It would be great if you could improve the way your site handles them.","progress-planner")})]}),(0,o.jsxs)("div",{className:"prpl-column",children:[(0,o.jsx)("p",{children:(0,t.__)("Do you need to show a folder structure with the files to make them more discoverable?","progress-planner")}),(0,o.jsx)("p",{children:(0,t.__)("If so, you can improve the way your site handles them by adding a folder structure.","progress-planner")}),(0,o.jsx)("p",{children:(0,o.jsx)("a",{href:"https://barn2.com/blog/wordpress-pdf-library-plugin/",target:"_blank",rel:"noopener noreferrer",children:(0,t.__)("Learn more about the PDF Library plugin","progress-planner")})}),(0,o.jsx)("div",{className:"prpl-steps-nav-wrapper",children:h?(0,o.jsxs)("button",{type:"button",className:"prpl-button prpl-button-step",onClick:()=>p(d),children:[(0,t.__)("Next step","progress-planner"),(0,o.jsx)("span",{className:"dashicons dashicons-arrow-right-alt2"})]}):(0,o.jsx)("button",{type:"button",className:"prpl-button prpl-button-step",onClick:_,children:(0,t.__)("Collect your point!","progress-planner")})})]})]});case d:return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,o.jsx)("h2",{className:"prpl-popover-title",children:(0,t.__)("Do you want these PDFs to be found in search engines better?","progress-planner")}),(0,o.jsx)("p",{children:(0,t.__)("Adding an XML sitemap for your PDF files helps search engines discover and index them more effectively. This can improve visibility in search results and drive more organic traffic to your valuable PDF content.","progress-planner")})]}),(0,o.jsxs)("div",{className:"prpl-column",children:[(0,o.jsx)("p",{children:(0,t.__)("XML Sitemap for PDFs for Yoast SEO","progress-planner")}),(0,o.jsx)("p",{children:(0,t.__)("This plugin adds an XML sitemap for PDFs. It adds this XML sitemap to the sitemap_index.xml that Yoast SEO generates.","progress-planner")}),(0,o.jsx)("div",{children:(0,o.jsx)(i,{pluginSlug:"pdf-sitemap",pluginName:"XML Sitemap for PDFs for Yoast SEO",action:m?"activate":"install",completeTask:!1,providerId:e.prpl_provider?.slug||e.slug||e.id})}),(0,o.jsx)("div",{className:"prpl-steps-nav-wrapper",children:(0,o.jsxs)("button",{type:"button",className:"prpl-button prpl-button-step",onClick:()=>p(u),children:[(0,t.__)("Next step","progress-planner"),(0,o.jsx)("span",{className:"dashicons dashicons-arrow-right-alt2"})]})})]})]});case u:return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,o.jsx)("h2",{className:"prpl-popover-title",children:(0,t.__)("Your PDF handling is improved!","progress-planner")}),(0,o.jsx)("p",{children:(0,t.__)("Great, you improved the way your site handles PDFs! This indicates PDF handling is set up properly on your website.","progress-planner")})]}),(0,o.jsxs)("div",{className:"prpl-column",children:[(0,o.jsx)("p",{children:(0,t.__)("Celebrate this achievement!","progress-planner")}),(0,o.jsx)("div",{className:"prpl-steps-nav-wrapper",children:(0,o.jsx)("button",{type:"button",className:"prpl-button prpl-button-step",onClick:_,children:(0,t.__)("Collect your point!","progress-planner")})})]})]});default:return null}})()})}},5202:(e,s,r)=>{r.d(s,{A:()=>p});var n=r(6087),t=r(7723),a=r(2619),l=r(790);function p({isOpen:e,taskId:s,onClose:r,children:p}){const o=(0,n.useRef)(null),i=`prpl-popover-${s}`;return(0,n.useEffect)(()=>{if(!o.current)return;const s=o.current;e?"function"==typeof s.showPopover&&s.showPopover():"function"==typeof s.hidePopover&&s.hidePopover()},[e]),e?(0,l.jsxs)("div",{id:i,ref:o,className:"prpl-popover prpl-popover-interactive",popover:"auto",onToggle:e=>{"closed"===e.newState&&((0,a.doAction)("prpl.popover.close",s),r&&r())},children:[(0,l.jsx)("div",{className:"prpl-columns-wrapper-flex",children:p}),(0,l.jsxs)("button",{className:"prpl-popover-close",type:"button",onClick:()=>{(0,a.doAction)("prpl.popover.close",s),r&&r()},"aria-label":(0,t.__)("Close","progress-planner"),children:[(0,l.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,l.jsx)("span",{className:"screen-reader-text",children:(0,t.__)("Close","progress-planner")})]})]}):null}}}]);
\ No newline at end of file
diff --git a/build/ImprovePdfHandlingPopover.css b/build/ImprovePdfHandlingPopover.css
new file mode 100644
index 0000000000..7ef0f248a6
--- /dev/null
+++ b/build/ImprovePdfHandlingPopover.css
@@ -0,0 +1 @@
+.prpl-button-link{align-items:center;background:none;border:none;color:var(--prpl-color-link);cursor:pointer;display:flex!important;font-size:inherit;font-weight:inherit;gap:.5rem;justify-content:center;line-height:inherit;margin:0;padding:0;text-align:inherit;text-decoration:underline}.prpl-install-button-loader{animation:install-button-rotation 1s linear infinite;border:3px solid var(--prpl-color-link);border-bottom:3px solid transparent;border-radius:50%;box-sizing:border-box;display:none;height:1rem;width:1rem}button:disabled .prpl-install-button-loader{display:block}@keyframes install-button-rotation{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}
diff --git a/build/LocalePopover.chunk.js b/build/LocalePopover.chunk.js
new file mode 100644
index 0000000000..cd4c151b5b
--- /dev/null
+++ b/build/LocalePopover.chunk.js
@@ -0,0 +1 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[152],{869:(e,n,r)=>{r.r(n),r.d(n,{default:()=>h});var s=r(6087),a=r(7723),t=r(8537),l=r(5202),o=r(6979),i=r(2592),c=r(1110),p=r(2195),u=r(5359),d=r(4333),g=r(790);function h({task:e,onSubmit:n,onClose:r}){const[h,v]=(0,s.useState)(""),f=(0,s.useRef)(null),[m,b]=(0,s.useState)(!0),{settings:x}=(0,p.e)(["WPLANG"]);(0,s.useEffect)(()=>{void 0!==x.WPLANG&&v(x.WPLANG)},[x.WPLANG]),(0,s.useEffect)(()=>{const e=(0,u.we)(),n=(0,u.m9)();fetch(`${e}?action=prpl_get_locale_options&_ajax_nonce=${n}`,{credentials:"same-origin"}).then(e=>e.json()).then(e=>{e.success&&e.data&&f.current&&(f.current.innerHTML=e.data,h&&(f.current.value=h))}).catch(()=>{f.current&&(f.current.innerHTML='
")}).finally(()=>{b(!1)})},[h]);const{isLoading:j,error:w,handleSubmit:y}=(0,c.V)(async()=>{if(!h)return;const r=`prpl-popover-${e.slug||e.id}`;await(0,d.nM)({settingAPIKey:"WPLANG",setting:"WPLANG",popoverId:r,settingCallbackValue:()=>h,value:h}),n&&await n(e.id,e)},[h,e,n]),_=(0,t.decodeEntities)(e.title?.rendered||e.title);return(0,g.jsxs)(l.A,{isOpen:!0,taskId:e.slug||e.id,task:e,onClose:r,children:[(0,g.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,g.jsx)("h2",{className:"prpl-popover-title",children:_}),(0,g.jsx)("p",{children:(0,a.__)("Select your site locale to ensure your site is displayed correctly in the correct language","progress-planner")})]}),(0,g.jsx)("div",{className:"prpl-column",children:(0,g.jsxs)("form",{onSubmit:y,children:[(0,g.jsx)("label",{htmlFor:"language",children:(0,g.jsx)("select",{id:"language",name:"language",ref:f,value:h,onChange:e=>v(e.target.value),disabled:j||m,children:m&&(0,g.jsx)("option",{value:"",children:(0,a.__)("Loading…","progress-planner")})})}),(0,g.jsx)(o.A,{error:w}),(0,g.jsx)("div",{className:"prpl-steps-nav-wrapper prpl-steps-nav-wrapper-align-left",children:(0,g.jsx)(i.A,{isLoading:j,disabled:!h||m,label:(0,a.__)("Select locale","progress-planner")})})]})})]})}},1110:(e,n,r)=>{r.d(n,{V:()=>t});var s=r(6087),a=r(7723);function t(e,n=[]){const[r,t]=(0,s.useState)(!1),[l,o]=(0,s.useState)(null);return{isLoading:r,error:l,handleSubmit:(0,s.useCallback)(async n=>{n.preventDefault(),t(!0),o(null);try{await e(n)}catch(e){o(e.message||(0,a.__)("Something went wrong. Please try again.","progress-planner"))}finally{t(!1)}},n)}}},2195:(e,n,r)=>{r.d(n,{e:()=>t});var s=r(6087),a=r(8691);function t(e=[]){const{data:n,isLoading:r,error:t}=(0,a.KS)("/wp/v2/settings");return{settings:(0,s.useMemo)(()=>{if(!n)return{};const r={};for(const a of e){var s;r[a]=null!==(s=n[a])&&void 0!==s?s:""}return r},[n,...e]),isLoading:r,error:t}}},2592:(e,n,r)=>{r.d(n,{A:()=>a});var s=r(790);function a({isLoading:e=!1,disabled:n=!1,label:r}){return(0,s.jsx)("button",{type:"submit",className:"prpl-button prpl-button-primary",disabled:e||n,children:e?(0,s.jsx)("span",{className:"spinner",style:{visibility:"visible"}}):r})}},5202:(e,n,r)=>{r.d(n,{A:()=>o});var s=r(6087),a=r(7723),t=r(2619),l=r(790);function o({isOpen:e,taskId:n,onClose:r,children:o}){const i=(0,s.useRef)(null),c=`prpl-popover-${n}`;return(0,s.useEffect)(()=>{if(!i.current)return;const n=i.current;e?"function"==typeof n.showPopover&&n.showPopover():"function"==typeof n.hidePopover&&n.hidePopover()},[e]),e?(0,l.jsxs)("div",{id:c,ref:i,className:"prpl-popover prpl-popover-interactive",popover:"auto",onToggle:e=>{"closed"===e.newState&&((0,t.doAction)("prpl.popover.close",n),r&&r())},children:[(0,l.jsx)("div",{className:"prpl-columns-wrapper-flex",children:o}),(0,l.jsxs)("button",{className:"prpl-popover-close",type:"button",onClick:()=>{(0,t.doAction)("prpl.popover.close",n),r&&r()},"aria-label":(0,a.__)("Close","progress-planner"),children:[(0,l.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,l.jsx)("span",{className:"screen-reader-text",children:(0,a.__)("Close","progress-planner")})]})]}):null}},5359:(e,n,r)=>{function s(e,n=""){var r,s,a;return null!==(r=null!==(s=null!==(a=window.prplDashboardConfig?.[e])&&void 0!==a?a:window.progressPlannerAdmin?.[e])&&void 0!==s?s:window.progressPlanner?.[e])&&void 0!==r?r:n}function a(){return s("brandingId",0)}function t(){return s("ajaxUrl","/wp-admin/admin-ajax.php")}function l(){return s("nonce","")}r.d(n,{m9:()=>l,nZ:()=>a,we:()=>t})},6979:(e,n,r)=>{r.d(n,{A:()=>a});var s=r(790);function a({error:e}){return e?(0,s.jsx)("p",{className:"prpl-note prpl-note-error prpl-interactive-task-error-message",children:e}):null}},8691:(e,n,r)=>{r.d(n,{KS:()=>l});var s=r(6087),a=r(5337);const t=3e5;function l(e,n=[],r="Failed to load data",l={}){const{cache:o=!0,cacheTtl:i=t,skipCache:c=!1}=l,[p,u]=(0,s.useState)(!0),[d,g]=(0,s.useState)(null),[h,v]=(0,s.useState)(null),f=(0,s.useCallback)(async(n=!1)=>{if(e){u(!0),g(null);try{const r=await(0,a.BJ)({path:e},{skipCache:n||c||!o,ttl:i});v(r)}catch(e){const n=e.message||("string"==typeof r?r:r.message||"Failed to load data");g(n)}finally{u(!1)}}else u(!1)},[e,o,i,c,r]);return(0,s.useEffect)(()=>{f()},[e,...n]),{isLoading:p,error:d,data:h,refetch:(0,s.useCallback)((e=!0)=>{f(e)},[f])}}}}]);
\ No newline at end of file
diff --git a/build/MonthlyBadgesPopover.chunk.js b/build/MonthlyBadgesPopover.chunk.js
new file mode 100644
index 0000000000..0432b1caed
--- /dev/null
+++ b/build/MonthlyBadgesPopover.chunk.js
@@ -0,0 +1 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[393],{645:(e,r,n)=>{n.d(r,{Ge:()=>p,HY:()=>s,TV:()=>t,Tn:()=>a,cs:()=>o,et:()=>i});const s=[{id:"content-curator",name:"Content Curator",description:"20 existing posts/pages, or 10 new posts/pages",type:"content",background:"var(--prpl-background-content-badge)",thresholds:{existingPosts:20,newPosts:10}},{id:"revision-ranger",name:"Revision Ranger",description:"Write 30 new posts or pages",type:"content",background:"var(--prpl-background-content-badge)",thresholds:{newPosts:30}},{id:"purposeful-publisher",name:"Purposeful Publisher",description:"Write 50 new posts or pages",type:"content",background:"var(--prpl-background-content-badge)",thresholds:{newPosts:50}}],a=[{id:"progress-padawan",name:"Progress Padawan",description:"6 weeks streak",type:"maintenance",background:"var(--prpl-background-streak)",thresholds:{weeks:6}},{id:"maintenance-maniac",name:"Maintenance Maniac",description:"26 weeks streak",type:"maintenance",background:"var(--prpl-background-streak)",thresholds:{weeks:26}},{id:"super-site-specialist",name:"Super Site Specialist",description:"52 weeks streak",type:"maintenance",background:"var(--prpl-background-streak)",thresholds:{weeks:52}}],t={targetPoints:10,months:{m1:"Jack January",m2:"Felix February",m3:"Mary March",m4:"Avery April",m5:"Matteo May",m6:"Jasmine June",m7:"Joey July",m8:"Abed August",m9:"Sam September",m10:"Oksana October",m11:"Noah November",m12:"Daisy December"}};function o(e){return`monthly-${e.getFullYear()}-m${e.getMonth()+1}`}function p(e){const r=`m${e.getMonth()+1}`;return t.months[r]||""}function i(e){const r=s.find(r=>r.id===e);if(r)return r;const n=a.find(r=>r.id===e);if(n)return n;if(e.startsWith("monthly-")){const r=e.split("-");if(3===r.length){const n=parseInt(r[1],10),s=r[2].replace("m",""),a=parseInt(s,10);if(n&&a>=1&&a<=12){const r=new Date(n,a-1,1);return{id:e,name:p(r),description:"",type:"monthly",background:"var(--prpl-background-content-badge)",thresholds:{points:t.targetPoints}}}}}return null}},3971:(e,r,n)=>{n.d(r,{A:()=>a});var s=n(790);function a({badgeId:e,badgeName:r,brandingId:n=0,isComplete:a=!0}){const t=window.progressPlannerBadge||{};let o=t.remoteServerRootUrl||"https://progressplanner.com";const p=t.placeholderImageUrl||"";(o.includes("localhost")||o.includes("127.0.0.1"))&&(o="https://progressplanner.com");let i=`${o}/wp-json/progress-planner-saas/v1/badge-svg/?badge_id=${e}`;n&&(i+=`&branding_id=${n}`);const l=r&&"null"!==r?r:"Badge",c={maxWidth:"100%",height:"auto",verticalAlign:"bottom",transition:"opacity 0.3s ease-in-out, filter 0.3s ease-in-out",...!a&&{opacity:.25,filter:"grayscale(1)"}};return(0,s.jsx)("img",{src:i,alt:l,onError:e=>{p&&e.target.src!==p&&(e.target.onerror=null,e.target.src=p)},style:c})}},5202:(e,r,n)=>{n.d(r,{A:()=>p});var s=n(6087),a=n(7723),t=n(2619),o=n(790);function p({isOpen:e,taskId:r,onClose:n,children:p}){const i=(0,s.useRef)(null),l=`prpl-popover-${r}`;return(0,s.useEffect)(()=>{if(!i.current)return;const r=i.current;e?"function"==typeof r.showPopover&&r.showPopover():"function"==typeof r.hidePopover&&r.hidePopover()},[e]),e?(0,o.jsxs)("div",{id:l,ref:i,className:"prpl-popover prpl-popover-interactive",popover:"auto",onToggle:e=>{"closed"===e.newState&&((0,t.doAction)("prpl.popover.close",r),n&&n())},children:[(0,o.jsx)("div",{className:"prpl-columns-wrapper-flex",children:p}),(0,o.jsxs)("button",{className:"prpl-popover-close",type:"button",onClick:()=>{(0,t.doAction)("prpl.popover.close",r),n&&n()},"aria-label":(0,a.__)("Close","progress-planner"),children:[(0,o.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,o.jsx)("span",{className:"screen-reader-text",children:(0,a.__)("Close","progress-planner")})]})]}):null}},5359:(e,r,n)=>{function s(e,r=""){var n,s,a;return null!==(n=null!==(s=null!==(a=window.prplDashboardConfig?.[e])&&void 0!==a?a:window.progressPlannerAdmin?.[e])&&void 0!==s?s:window.progressPlanner?.[e])&&void 0!==n?n:r}function a(){return s("brandingId",0)}function t(){return s("ajaxUrl","/wp-admin/admin-ajax.php")}function o(){return s("nonce","")}n.d(r,{m9:()=>o,nZ:()=>a,we:()=>t})},8670:(e,r,n)=>{n.r(r),n.d(r,{default:()=>u});var s=n(6087),a=n(7723),t=n(5202),o=n(6230),p=n(3971),i=n(1971),l=n(645),c=n(8691),d=n(5359),g=n(790);function u({task:e,onClose:r}){const{data:n,isLoading:u}=(0,c.KS)("/progress-planner/v1/badge-stats"),m=(0,s.useMemo)(()=>n?.badges||(n?{}:null),[n]),h=(0,d.nZ)(),b=(0,s.useMemo)(()=>{if(!m)return{};const e={},r=(new Date).getFullYear();Object.keys(m).filter(e=>e.startsWith("monthly-")).forEach(r=>{const n=r.split("-");if(3===n.length){const s=n[1];e[s]||(e[s]=[]),e[s].push({id:r,...m[r]})}}),e[r]||(e[r]=[]);const n=(0,l.cs)(new Date);e[r].find(e=>e.id===n)||e[r].push({id:n,progress:m[n]?.progress||0,remaining:m[n]?.remaining||0});const s={};return Object.keys(e).sort((e,r)=>parseInt(r)-parseInt(e)).forEach(r=>{s[r]=e[r].sort((e,r)=>parseInt(e.id.split("-")[2].replace("m",""))-parseInt(r.id.split("-")[2].replace("m","")))}),s},[m]),v=(0,s.useCallback)(e=>m?e.map(e=>({id:e.id,name:e.name,progress:m[e.id]?.progress||0,remaining:m[e.id]?.remaining||0})):[],[m]),w=(0,s.useMemo)(()=>v(l.HY),[v]),k=(0,s.useMemo)(()=>v(l.Tn),[v]),f=e=>{const r=e.progress>=100;return(0,g.jsxs)("span",{className:"prpl-badge","data-value":e.progress,children:[(0,g.jsx)(p.A,{badgeId:e.id,badgeName:e.name||e.id,isComplete:r,brandingId:h}),e.name&&(0,g.jsx)("p",{children:e.name})]},e.id)},y=(0,i.p)(e,"monthly-badges");return(0,g.jsxs)(t.A,{isOpen:!0,taskId:y||"monthly-badges",task:e,onClose:r,children:[(0,g.jsx)("div",{className:"prpl-column prpl-column-content",children:(0,g.jsx)("h2",{className:"prpl-popover-title",children:(0,a.__)("Your badges","progress-planner")})}),(0,g.jsx)("div",{className:"prpl-column",children:(0,g.jsx)("div",{className:"prpl-widgets-container in-popover",children:u?(0,g.jsx)(o.A,{}):(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)("div",{className:"prpl-popover-column",children:Object.keys(b).map(e=>(0,g.jsxs)("div",{className:"prpl-monthly-badges-year",children:[(0,g.jsx)("h3",{children:e}),(0,g.jsx)("div",{className:"progress-wrapper badge-group-monthly",children:b[e].map(e=>f(e))})]},e))}),(0,g.jsxs)("div",{className:"prpl-popover-column",children:[(0,g.jsxs)("div",{className:"prpl-widget-wrapper prpl-widget-wrapper-content in-popover prpl-badge-streak",children:[(0,g.jsx)("h3",{className:"prpl-widget-title",children:(0,a.__)("Content badges","progress-planner")}),(0,g.jsx)("div",{className:"prpl-badges-container-achievements",children:(0,g.jsx)("div",{className:"progress-wrapper badge-group-content",children:w.map(e=>f(e))})})]}),(0,g.jsxs)("div",{className:"prpl-widget-wrapper prpl-widget-wrapper-maintenance in-popover prpl-badge-streak",children:[(0,g.jsx)("h3",{className:"prpl-widget-title",children:(0,a.__)("Streak badges","progress-planner")}),(0,g.jsx)("div",{className:"prpl-badges-container-achievements",children:(0,g.jsx)("div",{className:"progress-wrapper badge-group-maintenance",children:k.map(e=>f(e))})})]})]})]})})})]})}},8691:(e,r,n)=>{n.d(r,{KS:()=>o});var s=n(6087),a=n(5337);const t=3e5;function o(e,r=[],n="Failed to load data",o={}){const{cache:p=!0,cacheTtl:i=t,skipCache:l=!1}=o,[c,d]=(0,s.useState)(!0),[g,u]=(0,s.useState)(null),[m,h]=(0,s.useState)(null),b=(0,s.useCallback)(async(r=!1)=>{if(e){d(!0),u(null);try{const n=await(0,a.BJ)({path:e},{skipCache:r||l||!p,ttl:i});h(n)}catch(e){const r=e.message||("string"==typeof n?n:n.message||"Failed to load data");u(r)}finally{d(!1)}}else d(!1)},[e,p,i,l,n]);return(0,s.useEffect)(()=>{b()},[e,...r]),{isLoading:c,error:g,data:m,refetch:(0,s.useCallback)((e=!0)=>{b(e)},[b])}}}}]);
\ No newline at end of file
diff --git a/build/PermalinkStructurePopover.chunk.js b/build/PermalinkStructurePopover.chunk.js
new file mode 100644
index 0000000000..942a03e358
--- /dev/null
+++ b/build/PermalinkStructurePopover.chunk.js
@@ -0,0 +1 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[624],{1110:(e,r,s)=>{s.d(r,{V:()=>l});var n=s(6087),a=s(7723);function l(e,r=[]){const[s,l]=(0,n.useState)(!1),[t,i]=(0,n.useState)(null);return{isLoading:s,error:t,handleSubmit:(0,n.useCallback)(async r=>{r.preventDefault(),l(!0),i(null);try{await e(r)}catch(e){i(e.message||(0,a.__)("Something went wrong. Please try again.","progress-planner"))}finally{l(!1)}},r)}}},2195:(e,r,s)=>{s.d(r,{e:()=>l});var n=s(6087),a=s(8691);function l(e=[]){const{data:r,isLoading:s,error:l}=(0,a.KS)("/wp/v2/settings");return{settings:(0,n.useMemo)(()=>{if(!r)return{};const s={};for(const a of e){var n;s[a]=null!==(n=r[a])&&void 0!==n?n:""}return s},[r,...e]),isLoading:s,error:l}}},2592:(e,r,s)=>{s.d(r,{A:()=>a});var n=s(790);function a({isLoading:e=!1,disabled:r=!1,label:s}){return(0,n.jsx)("button",{type:"submit",className:"prpl-button prpl-button-primary",disabled:e||r,children:e?(0,n.jsx)("span",{className:"spinner",style:{visibility:"visible"}}):s})}},5202:(e,r,s)=>{s.d(r,{A:()=>i});var n=s(6087),a=s(7723),l=s(2619),t=s(790);function i({isOpen:e,taskId:r,onClose:s,children:i}){const o=(0,n.useRef)(null),p=`prpl-popover-${r}`;return(0,n.useEffect)(()=>{if(!o.current)return;const r=o.current;e?"function"==typeof r.showPopover&&r.showPopover():"function"==typeof r.hidePopover&&r.hidePopover()},[e]),e?(0,t.jsxs)("div",{id:p,ref:o,className:"prpl-popover prpl-popover-interactive",popover:"auto",onToggle:e=>{"closed"===e.newState&&((0,l.doAction)("prpl.popover.close",r),s&&s())},children:[(0,t.jsx)("div",{className:"prpl-columns-wrapper-flex",children:i}),(0,t.jsxs)("button",{className:"prpl-popover-close",type:"button",onClick:()=>{(0,l.doAction)("prpl.popover.close",r),s&&s()},"aria-label":(0,a.__)("Close","progress-planner"),children:[(0,t.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,t.jsx)("span",{className:"screen-reader-text",children:(0,a.__)("Close","progress-planner")})]})]}):null}},5359:(e,r,s)=>{function n(e,r=""){var s,n,a;return null!==(s=null!==(n=null!==(a=window.prplDashboardConfig?.[e])&&void 0!==a?a:window.progressPlannerAdmin?.[e])&&void 0!==n?n:window.progressPlanner?.[e])&&void 0!==s?s:r}function a(){return n("brandingId",0)}function l(){return n("ajaxUrl","/wp-admin/admin-ajax.php")}function t(){return n("nonce","")}s.d(r,{m9:()=>t,nZ:()=>a,we:()=>l})},6979:(e,r,s)=>{s.d(r,{A:()=>a});var n=s(790);function a({error:e}){return e?(0,n.jsx)("p",{className:"prpl-note prpl-note-error prpl-interactive-task-error-message",children:e}):null}},7249:(e,r,s)=>{s.r(r),s.d(r,{default:()=>h});var n=s(6087),a=s(7723),l=s(8537),t=s(5202),i=s(6979),o=s(2592),p=s(1110),c=s(2195),u=s(5359),d=s(4333),m=s(790);function h({task:e,onSubmit:r,onClose:s}){const[h,g]=(0,n.useState)(""),[_,v]=(0,n.useState)(""),[x,f]=(0,n.useState)([]),[b,j]=(0,n.useState)(!0),{settings:k}=(0,c.e)(["permalink_structure"]);(0,n.useEffect)(()=>{k.permalink_structure&&(g(k.permalink_structure),v(k.permalink_structure))},[k.permalink_structure]),(0,n.useEffect)(()=>{const e=(0,u.we)(),r=(0,u.m9)();fetch(`${e}?action=prpl_get_permalink_structures&_ajax_nonce=${r}`,{credentials:"same-origin"}).then(e=>e.json()).then(e=>{e.success&&e.data&&f(e.data)}).catch(()=>{f([])}).finally(()=>{j(!1)})},[]);const y=(0,n.useCallback)(e=>{g("custom"===e?"custom":e)},[]),{isLoading:w,error:N,handleSubmit:C}=(0,p.V)(async()=>{const s="custom"===h?_:h;if(!s)return;const n=`prpl-popover-${e.slug||e.id}`;await(0,d.nM)({settingAPIKey:"permalink_structure",setting:"permalink_structure",popoverId:n,settingCallbackValue:()=>s,value:s}),r&&await r(e.id,e)},[h,_,e,r]),S=(0,l.decodeEntities)(e.title?.rendered||e.title),A=x.length>0?x:[{id:"day-name",value:"/%year%/%monthnum%/%day%/%postname%/",label:(0,a.__)("Day and name","progress-planner")},{id:"month-name",value:"/%year%/%monthnum%/%postname%/",label:(0,a.__)("Month and name","progress-planner")},{id:"numeric",value:"/archives/%post_id%",label:(0,a.__)("Numeric","progress-planner")},{id:"post-name",value:"/%postname%/",label:(0,a.__)("Post name","progress-planner")}];return(0,m.jsxs)(t.A,{isOpen:!0,taskId:e.slug||e.id,task:e,onClose:s,children:[(0,m.jsx)("div",{className:"prpl-column prpl-column-content",children:(0,m.jsx)("h2",{className:"prpl-popover-title",children:S})}),(0,m.jsx)("div",{className:"prpl-column",children:(0,m.jsxs)("form",{onSubmit:C,children:[(0,m.jsx)("div",{className:"radios",children:(0,m.jsx)("fieldset",{className:"prpl-structure-selection",children:b?(0,m.jsx)("p",{children:(0,a.__)("Loading structures…","progress-planner")}):(0,m.jsxs)(m.Fragment,{children:[A.map(e=>{const r=h===e.value;return(0,m.jsx)("div",{className:"prpl-radio-wrapper",children:(0,m.jsxs)("label",{className:"prpl-custom-radio",htmlFor:`prpl-permalink-input-${e.id}`,"aria-label":e.label,children:[(0,m.jsx)("input",{id:`prpl-permalink-input-${e.id}`,name:"prpl_permalink_structure",type:"radio",value:e.value,checked:r,onChange:()=>y(e.value),disabled:w}),(0,m.jsx)("span",{className:"prpl-custom-control"}),(0,m.jsxs)("div",{children:[(0,m.jsx)("span",{children:e.label}),(0,m.jsx)("code",{style:{display:"block"},children:e.value})]})]})},e.id)}),(0,m.jsx)("div",{className:"prpl-radio-wrapper",children:(0,m.jsxs)("label",{className:"prpl-custom-radio",htmlFor:"prpl_permalink_structure_custom_radio",children:[(0,m.jsx)("input",{id:"prpl_permalink_structure_custom_radio",name:"prpl_permalink_structure",type:"radio",value:"custom",checked:"custom"===h,onChange:()=>y("custom"),disabled:w}),(0,m.jsx)("span",{className:"prpl-custom-control"}),(0,m.jsxs)("span",{children:[(0,a.__)("Custom:","progress-planner")," ",(0,m.jsx)("span",{className:"screen-reader-text",children:(0,a.__)("enter a custom permalink structure in the following field","progress-planner")})]})]})}),(0,m.jsxs)("label",{htmlFor:"prpl_custom_permalink_structure",children:[(0,m.jsx)("span",{className:"screen-reader-text",children:(0,a.__)("Custom permalink structure:","progress-planner")}),(0,m.jsxs)("div",{style:{display:"flex",gap:"0.5rem",alignItems:"center"},children:[(0,m.jsx)("code",{style:{display:"flex",alignItems:"center",height:"1.25rem"},children:window.location.origin}),(0,m.jsx)("input",{type:"text",name:"prpl_custom_permalink_structure",id:"prpl_custom_permalink_structure",value:_,onChange:e=>v(e.target.value),className:"small-text",disabled:w||"custom"!==h})]})]})]})})}),(0,m.jsx)(i.A,{error:N}),(0,m.jsx)("div",{className:"prpl-steps-nav-wrapper prpl-steps-nav-wrapper-align-left",children:(0,m.jsx)(o.A,{isLoading:w,disabled:!h,label:(0,a.__)("Set permalink structure","progress-planner")})})]})})]})}},8691:(e,r,s)=>{s.d(r,{KS:()=>t});var n=s(6087),a=s(5337);const l=3e5;function t(e,r=[],s="Failed to load data",t={}){const{cache:i=!0,cacheTtl:o=l,skipCache:p=!1}=t,[c,u]=(0,n.useState)(!0),[d,m]=(0,n.useState)(null),[h,g]=(0,n.useState)(null),_=(0,n.useCallback)(async(r=!1)=>{if(e){u(!0),m(null);try{const s=await(0,a.BJ)({path:e},{skipCache:r||p||!i,ttl:o});g(s)}catch(e){const r=e.message||("string"==typeof s?s:s.message||"Failed to load data");m(r)}finally{u(!1)}}else u(!1)},[e,i,o,p,s]);return(0,n.useEffect)(()=>{_()},[e,...r]),{isLoading:c,error:d,data:h,refetch:(0,n.useCallback)((e=!0)=>{_(e)},[_])}}}}]);
\ No newline at end of file
diff --git a/build/SiteIconPopover.chunk.js b/build/SiteIconPopover.chunk.js
new file mode 100644
index 0000000000..bd12f57063
--- /dev/null
+++ b/build/SiteIconPopover.chunk.js
@@ -0,0 +1 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[4],{1110:(e,s,n)=>{n.d(s,{V:()=>l});var r=n(6087),t=n(7723);function l(e,s=[]){const[n,l]=(0,r.useState)(!1),[o,a]=(0,r.useState)(null);return{isLoading:n,error:o,handleSubmit:(0,r.useCallback)(async s=>{s.preventDefault(),l(!0),a(null);try{await e(s)}catch(e){a(e.message||(0,t.__)("Something went wrong. Please try again.","progress-planner"))}finally{l(!1)}},s)}}},2592:(e,s,n)=>{n.d(s,{A:()=>t});var r=n(790);function t({isLoading:e=!1,disabled:s=!1,label:n}){return(0,r.jsx)("button",{type:"submit",className:"prpl-button prpl-button-primary",disabled:e||s,children:e?(0,r.jsx)("span",{className:"spinner",style:{visibility:"visible"}}):n})}},5202:(e,s,n)=>{n.d(s,{A:()=>a});var r=n(6087),t=n(7723),l=n(2619),o=n(790);function a({isOpen:e,taskId:s,onClose:n,children:a}){const i=(0,r.useRef)(null),p=`prpl-popover-${s}`;return(0,r.useEffect)(()=>{if(!i.current)return;const s=i.current;e?"function"==typeof s.showPopover&&s.showPopover():"function"==typeof s.hidePopover&&s.hidePopover()},[e]),e?(0,o.jsxs)("div",{id:p,ref:i,className:"prpl-popover prpl-popover-interactive",popover:"auto",onToggle:e=>{"closed"===e.newState&&((0,l.doAction)("prpl.popover.close",s),n&&n())},children:[(0,o.jsx)("div",{className:"prpl-columns-wrapper-flex",children:a}),(0,o.jsxs)("button",{className:"prpl-popover-close",type:"button",onClick:()=>{(0,l.doAction)("prpl.popover.close",s),n&&n()},"aria-label":(0,t.__)("Close","progress-planner"),children:[(0,o.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,o.jsx)("span",{className:"screen-reader-text",children:(0,t.__)("Close","progress-planner")})]})]}):null}},6979:(e,s,n)=>{n.d(s,{A:()=>t});var r=n(790);function t({error:e}){return e?(0,r.jsx)("p",{className:"prpl-note prpl-note-error prpl-interactive-task-error-message",children:e}):null}},8217:(e,s,n)=>{n.r(s),n.d(s,{default:()=>m});var r=n(6087),t=n(7723),l=n(8537),o=n(1455),a=n.n(o),i=n(5202),p=n(6979),c=n(2592),d=n(1110),u=n(790);function m({task:e,onSubmit:s,onClose:n}){const[o,m]=(0,r.useState)(null),[h,v]=(0,r.useState)(""),b=(0,r.useCallback)(()=>{if(!window.wp?.media)return;const e=window.wp.media({title:(0,t.__)("Select Site Icon","progress-planner"),button:{text:(0,t.__)("Use as site icon","progress-planner")},multiple:!1,library:{type:"image"}});e.on("select",()=>{const s=e.state().get("selection").first().toJSON();m(s.id),v(s.url)}),e.open()},[]),{isLoading:g,error:x,handleSubmit:f}=(0,d.V)(async()=>{o&&(await a()({path:"/wp/v2/settings",method:"POST",data:{site_icon:parseInt(o)}}),s&&await s(e.id,e))},[o,e,s]),w=(0,l.decodeEntities)(e.title?.rendered||e.title);return(0,u.jsxs)(i.A,{isOpen:!0,taskId:e.slug||e.id,task:e,onClose:n,children:[(0,u.jsx)("div",{className:"prpl-column prpl-column-content",children:(0,u.jsx)("h2",{className:"prpl-popover-title",children:w})}),(0,u.jsx)("div",{className:"prpl-column",children:(0,u.jsxs)("form",{onSubmit:f,children:[h&&(0,u.jsx)("div",{className:"prpl-site-icon-preview",children:(0,u.jsx)("img",{src:h,alt:(0,t.__)("Site icon preview","progress-planner")})}),(0,u.jsx)("button",{type:"button",className:"prpl-upload-site-icon prpl-button",onClick:b,disabled:g,children:(0,t.__)("Select Site Icon","progress-planner")}),(0,u.jsx)("input",{type:"hidden",name:"site_icon",value:o||""}),(0,u.jsx)(p.A,{error:x}),(0,u.jsx)("div",{className:"prpl-steps-nav-wrapper",children:(0,u.jsx)(c.A,{isLoading:g,disabled:!o,label:(0,t.__)("Save","progress-planner")})})]})})]})}}}]);
\ No newline at end of file
diff --git a/build/SubscribeFormPopover.chunk.js b/build/SubscribeFormPopover.chunk.js
new file mode 100644
index 0000000000..a43ec749f3
--- /dev/null
+++ b/build/SubscribeFormPopover.chunk.js
@@ -0,0 +1,2 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[770],{2592:(e,s,r)=>{r.d(s,{A:()=>l});var n=r(790);function l({isLoading:e=!1,disabled:s=!1,label:r}){return(0,n.jsx)("button",{type:"submit",className:"prpl-button prpl-button-primary",disabled:e||s,children:e?(0,n.jsx)("span",{className:"spinner",style:{visibility:"visible"}}):r})}},2903:(e,s,r)=>{r.r(s),r.d(s,{default:()=>b});var n=r(6087),l=r(7723),a=r(8537),o=r(1455),t=r.n(o),i=r(5202),p=r(6979),c=r(2592),d=r(1971),u=r(5359),m=r(790);function b({task:e,onClose:s}){const[r,o]=(0,n.useState)(""),[b,h]=(0,n.useState)(""),[f,g]=(0,n.useState)(!1),[v,w]=(0,n.useState)(null),[_,x]=(0,n.useState)(!1);(0,n.useEffect)(()=>{const e=window.wp?.data?.select("core")?.getCurrentUser?.();e&&(e.first_name&&o(e.first_name),e.email&&h(e.email))},[]);const y=(0,n.useCallback)(async e=>{if(e.preventDefault(),r.trim()&&b.trim()){g(!0),w(null);try{const e=window.location.origin,s=(new Date).getTimezoneOffset()/-60,n=await t()({path:"/progress-planner/v1/popover/subscribe",method:"POST",data:{name:r.trim(),email:b.trim(),site:e,timezone_offset:s,with_email:"yes"}});if(!n.success)throw new Error(n.message||(0,l.__)("Failed to submit subscription.","progress-planner"));if(x(!0),n.license_key){const e=(0,u.we)(),s=(0,u.m9)();if(e&&s){const r=new FormData;r.append("action","progress_planner_save_onboard_data"),r.append("_ajax_nonce",s),r.append("key",n.license_key),await fetch(e,{method:"POST",body:r})}window.location.reload()}}catch(e){w(e.message||(0,l.__)("Something went wrong. Please try again.","progress-planner"))}finally{g(!1)}}else w((0,l.__)("Please fill in all fields.","progress-planner"))},[r,b]),j=(0,a.decodeEntities)(e.title?.rendered||e.title||(0,l.__)("Subscribe to weekly emails","progress-planner")),k=(0,d.p)(e,"subscribe-form");return(0,m.jsxs)(i.A,{isOpen:!0,taskId:k||"subscribe-form",task:e,onClose:s,children:[(0,m.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,m.jsx)("h2",{className:"prpl-popover-title",children:j}),(0,m.jsx)("p",{dangerouslySetInnerHTML:{__html:(0,l.sprintf)(/* translators: %s: progressplanner.com link */ /* translators: %s: progressplanner.com link */
+(0,l.__)("We can send you weekly emails with your own to-dos, your activity stats and nudges to keep you working on your site. To do this, we'll create an account for you on %s.","progress-planner"),'
progressplanner.com')}})]}),(0,m.jsx)("div",{className:"prpl-column",children:_?(0,m.jsx)("div",{className:"prpl-note prpl-note-success",children:(0,m.jsx)("p",{children:(0,l.__)("Subscription successful! You will receive weekly emails.","progress-planner")})}):(0,m.jsxs)("form",{id:"prpl-settings-license-form",onSubmit:y,children:[(0,m.jsxs)("div",{className:"prpl-form-fields",children:[(0,m.jsxs)("label",{htmlFor:"prpl-subscribe-name",children:[(0,m.jsx)("span",{className:"prpl-label-content",children:(0,l.__)("First name","progress-planner")}),(0,m.jsx)("input",{id:"prpl-subscribe-name",type:"text",name:"name",className:"prpl-input",value:r,onChange:e=>o(e.target.value),disabled:f,required:!0})]}),(0,m.jsxs)("label",{htmlFor:"prpl-subscribe-email",children:[(0,m.jsx)("span",{className:"prpl-label-content",children:(0,l.__)("Email","progress-planner")}),(0,m.jsx)("input",{id:"prpl-subscribe-email",type:"email",name:"email",className:"prpl-input",value:b,onChange:e=>h(e.target.value),disabled:f,required:!0})]})]}),(0,m.jsx)(p.A,{error:v}),(0,m.jsx)(c.A,{isLoading:f,disabled:!r.trim()||!b.trim(),label:(0,l.__)("Subscribe","progress-planner")})]})})]})}},5202:(e,s,r)=>{r.d(s,{A:()=>t});var n=r(6087),l=r(7723),a=r(2619),o=r(790);function t({isOpen:e,taskId:s,onClose:r,children:t}){const i=(0,n.useRef)(null),p=`prpl-popover-${s}`;return(0,n.useEffect)(()=>{if(!i.current)return;const s=i.current;e?"function"==typeof s.showPopover&&s.showPopover():"function"==typeof s.hidePopover&&s.hidePopover()},[e]),e?(0,o.jsxs)("div",{id:p,ref:i,className:"prpl-popover prpl-popover-interactive",popover:"auto",onToggle:e=>{"closed"===e.newState&&((0,a.doAction)("prpl.popover.close",s),r&&r())},children:[(0,o.jsx)("div",{className:"prpl-columns-wrapper-flex",children:t}),(0,o.jsxs)("button",{className:"prpl-popover-close",type:"button",onClick:()=>{(0,a.doAction)("prpl.popover.close",s),r&&r()},"aria-label":(0,l.__)("Close","progress-planner"),children:[(0,o.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,o.jsx)("span",{className:"screen-reader-text",children:(0,l.__)("Close","progress-planner")})]})]}):null}},5359:(e,s,r)=>{function n(e,s=""){var r,n,l;return null!==(r=null!==(n=null!==(l=window.prplDashboardConfig?.[e])&&void 0!==l?l:window.progressPlannerAdmin?.[e])&&void 0!==n?n:window.progressPlanner?.[e])&&void 0!==r?r:s}function l(){return n("brandingId",0)}function a(){return n("ajaxUrl","/wp-admin/admin-ajax.php")}function o(){return n("nonce","")}r.d(s,{m9:()=>o,nZ:()=>l,we:()=>a})},6979:(e,s,r)=>{r.d(s,{A:()=>l});var n=r(790);function l({error:e}){return e?(0,n.jsx)("p",{className:"prpl-note prpl-note-error prpl-interactive-task-error-message",children:e}):null}}}]);
\ No newline at end of file
diff --git a/build/TimezonePopover.chunk.js b/build/TimezonePopover.chunk.js
new file mode 100644
index 0000000000..84f3ebf336
--- /dev/null
+++ b/build/TimezonePopover.chunk.js
@@ -0,0 +1 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[529],{1110:(e,n,s)=>{s.d(n,{V:()=>a});var t=s(6087),r=s(7723);function a(e,n=[]){const[s,a]=(0,t.useState)(!1),[o,l]=(0,t.useState)(null);return{isLoading:s,error:o,handleSubmit:(0,t.useCallback)(async n=>{n.preventDefault(),a(!0),l(null);try{await e(n)}catch(e){l(e.message||(0,r.__)("Something went wrong. Please try again.","progress-planner"))}finally{a(!1)}},n)}}},2195:(e,n,s)=>{s.d(n,{e:()=>a});var t=s(6087),r=s(8691);function a(e=[]){const{data:n,isLoading:s,error:a}=(0,r.KS)("/wp/v2/settings");return{settings:(0,t.useMemo)(()=>{if(!n)return{};const s={};for(const r of e){var t;s[r]=null!==(t=n[r])&&void 0!==t?t:""}return s},[n,...e]),isLoading:s,error:a}}},2592:(e,n,s)=>{s.d(n,{A:()=>r});var t=s(790);function r({isLoading:e=!1,disabled:n=!1,label:s}){return(0,t.jsx)("button",{type:"submit",className:"prpl-button prpl-button-primary",disabled:e||n,children:e?(0,t.jsx)("span",{className:"spinner",style:{visibility:"visible"}}):s})}},4506:(e,n,s)=>{s.r(n),s.d(n,{default:()=>g});var t=s(6087),r=s(7723),a=s(8537),o=s(5202),l=s(6979),i=s(2592),p=s(1110),c=s(2195),d=s(8691),u=s(4333),h=s(790);function g({task:e,onSubmit:n,onClose:s}){const[g,m]=(0,t.useState)(""),{settings:v}=(0,c.e)(["timezone_string"]),{data:f,isLoading:b}=(0,d.KS)("/progress-planner/v1/timezone-options");(0,t.useEffect)(()=>{v.timezone_string&&m(v.timezone_string)},[v.timezone_string]);const{isLoading:y,error:x,handleSubmit:j}=(0,p.V)(async()=>{if(!g)return;const s=`prpl-popover-${e.slug||e.id}`;await(0,u.nM)({settingAPIKey:"timezone_string",setting:"timezone_string",popoverId:s,settingCallbackValue:()=>g,value:g}),n&&await n(e.id,e)},[g,e,n]),_=(0,a.decodeEntities)(e.title?.rendered||e.title);return(0,h.jsxs)(o.A,{isOpen:!0,taskId:e.slug||e.id,task:e,onClose:s,children:[(0,h.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,h.jsx)("h2",{className:"prpl-popover-title",children:_}),(0,h.jsx)("p",{children:(0,r.__)("Setting the time zone correctly on your site is valuable. By setting the correct time zone, you ensure scheduled tasks happen exactly when you want them to happen. To correctly account for daylight savings', we recommend you use the city-based time zone instead of the UTC offset (e.g. Amsterdam or London).","progress-planner")})]}),(0,h.jsx)("div",{className:"prpl-column",children:(0,h.jsxs)("form",{onSubmit:j,children:[(0,h.jsx)("label",{htmlFor:"timezone",children:(0,h.jsx)("select",{id:"timezone",name:"timezone",value:g,onChange:e=>m(e.target.value),disabled:y||b,children:b?(0,h.jsx)("option",{value:"",children:(0,r.__)("Loading…","progress-planner")}):(Array.isArray(f)?f:[]).map(e=>(0,h.jsx)("option",{value:e.value,children:e.label},e.value))})}),(0,h.jsx)(l.A,{error:x}),(0,h.jsx)("div",{className:"prpl-steps-nav-wrapper prpl-steps-nav-wrapper-align-left",children:(0,h.jsx)(i.A,{isLoading:y,disabled:!g||b,label:(0,r.__)("Set site timezone","progress-planner")})})]})})]})}},5202:(e,n,s)=>{s.d(n,{A:()=>l});var t=s(6087),r=s(7723),a=s(2619),o=s(790);function l({isOpen:e,taskId:n,onClose:s,children:l}){const i=(0,t.useRef)(null),p=`prpl-popover-${n}`;return(0,t.useEffect)(()=>{if(!i.current)return;const n=i.current;e?"function"==typeof n.showPopover&&n.showPopover():"function"==typeof n.hidePopover&&n.hidePopover()},[e]),e?(0,o.jsxs)("div",{id:p,ref:i,className:"prpl-popover prpl-popover-interactive",popover:"auto",onToggle:e=>{"closed"===e.newState&&((0,a.doAction)("prpl.popover.close",n),s&&s())},children:[(0,o.jsx)("div",{className:"prpl-columns-wrapper-flex",children:l}),(0,o.jsxs)("button",{className:"prpl-popover-close",type:"button",onClick:()=>{(0,a.doAction)("prpl.popover.close",n),s&&s()},"aria-label":(0,r.__)("Close","progress-planner"),children:[(0,o.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,o.jsx)("span",{className:"screen-reader-text",children:(0,r.__)("Close","progress-planner")})]})]}):null}},6979:(e,n,s)=>{s.d(n,{A:()=>r});var t=s(790);function r({error:e}){return e?(0,t.jsx)("p",{className:"prpl-note prpl-note-error prpl-interactive-task-error-message",children:e}):null}},8691:(e,n,s)=>{s.d(n,{KS:()=>o});var t=s(6087),r=s(5337);const a=3e5;function o(e,n=[],s="Failed to load data",o={}){const{cache:l=!0,cacheTtl:i=a,skipCache:p=!1}=o,[c,d]=(0,t.useState)(!0),[u,h]=(0,t.useState)(null),[g,m]=(0,t.useState)(null),v=(0,t.useCallback)(async(n=!1)=>{if(e){d(!0),h(null);try{const s=await(0,r.BJ)({path:e},{skipCache:n||p||!l,ttl:i});m(s)}catch(e){const n=e.message||("string"==typeof s?s:s.message||"Failed to load data");h(n)}finally{d(!1)}}else d(!1)},[e,l,i,p,s]);return(0,t.useEffect)(()=>{v()},[e,...n]),{isLoading:c,error:u,data:g,refetch:(0,t.useCallback)((e=!0)=>{v(e)},[v])}}}}]);
\ No newline at end of file
diff --git a/build/UpgradeTasksPopover.chunk.js b/build/UpgradeTasksPopover.chunk.js
new file mode 100644
index 0000000000..ff2266c832
--- /dev/null
+++ b/build/UpgradeTasksPopover.chunk.js
@@ -0,0 +1 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[880],{841:(e,s,r)=>{r.r(s),r.d(s,{default:()=>i});var n=r(6087),o=r(7723),a=r(1455),l=r.n(a),p=r(5202),t=r(1971),d=r(790);function i({task:e,onClose:s}){const[r,a]=(0,n.useState)([]),[i,c]=(0,n.useState)(!0),[g,h]=(0,n.useState)(0),[u,b]=(0,n.useState)({brandingId:0,remoteServerUrl:"https://progressplanner.com",placeholderSvg:"",badgeId:""});(0,n.useEffect)(()=>{let e=!0;return l()({path:"/progress-planner/v1/popover/upgrade-tasks-config"}).then(s=>{if(!e)return;const r=s.taskProviders||[];a(r);const n=r.reduce((e,s)=>e+(s.points||0),0);h(n),b({brandingId:s.brandingId||0,remoteServerUrl:s.remoteServerUrl||"https://progressplanner.com",placeholderSvg:s.placeholderSvg||"",badgeId:s.badgeId||""})}).catch(()=>{e&&a([])}).finally(()=>{e&&c(!1)}),()=>{e=!1}},[]);const m=(0,n.useCallback)(()=>{s&&s()},[s]),v=`${u.remoteServerUrl}/wp-json/progress-planner-saas/v1/badge-svg/?badge_id=${u.badgeId}&branding_id=${u.brandingId}`,k=(0,o.__)("We've added new recommendations to the Progress Planner plugin","progress-planner"),x=(0,o.__)("Let's check if you've already done those tasks, this will take only a minute…","progress-planner"),j=(0,t.p)(e,"upgrade-tasks");return(0,d.jsxs)(p.A,{isOpen:!0,taskId:j||"upgrade-tasks",task:e,onClose:m,children:[(0,d.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,d.jsx)("h2",{className:"prpl-popover-title",children:k}),x&&(0,d.jsx)("p",{children:x})]}),(0,d.jsxs)("div",{className:"prpl-column",children:[i&&(0,d.jsx)("p",{children:(0,o.__)("Loading…","progress-planner")}),!i&&0===r.length&&(0,d.jsx)("p",{children:(0,o.__)("No new tasks available.","progress-planner")}),!i&&r.length>0&&(0,d.jsxs)("div",{id:"prpl-onboarding-tasks",children:[(0,d.jsx)("strong",{className:"prpl-onboarding-tasks-title",children:k}),x&&(0,d.jsx)("span",{className:"prpl-onboarding-tasks-description",children:x}),(0,d.jsx)("ul",{className:"prpl-onboarding-tasks-list",children:r.map(e=>{const s=e.completed||!1;return(0,d.jsxs)("li",{className:"prpl-onboarding-task","data-prpl-task-completed":s?"true":"false",children:[(0,d.jsx)("h3",{children:e.title||e.task_id}),(0,d.jsxs)("span",{className:"prpl-onboarding-task-status",children:[(0,d.jsxs)("span",{className:"prpl-suggested-task-points",children:["+",e.points||0]}),(0,d.jsx)("span",{className:"prpl-suggested-task-loader"}),s&&(0,d.jsx)("span",{className:"icon icon-check-circle",children:"✓"})]})]},e.task_id)})}),u.badgeId&&(0,d.jsxs)("div",{className:"prpl-onboarding-tasks-footer",children:[(0,d.jsxs)("span",{className:"prpl-onboarding-tasks-montly-badge",children:[(0,d.jsx)("span",{className:"prpl-onboarding-tasks-montly-badge-image",children:(0,d.jsx)("img",{src:v,alt:(0,o.__)("Badge","progress-planner"),onError:e=>{e.target.onerror=null,e.target.src=u.placeholderSvg||""}})}),(0,o.__)("These tasks contribute to your monthly badge. Every check completed brings you closer!","progress-planner")]}),(0,d.jsxs)("span",{className:"prpl-onboarding-tasks-total-points",children:[g,"pt"]})]}),(0,d.jsx)("button",{id:"prpl-onboarding-continue-button",className:"prpl-button-primary prpl-disabled",onClick:()=>{s&&s(),window.prplOnboardRedirect?window.prplOnboardRedirect():window.location.href=window.location.href.split("#")[0]},children:(0,o.__)("Continue","progress-planner")})]})]})]})}"undefined"!=typeof window&&(window.prplOnboardRedirect=()=>{const e=window.location.href.replace("&show-tour=true","");window.location.href=e})},5202:(e,s,r)=>{r.d(s,{A:()=>p});var n=r(6087),o=r(7723),a=r(2619),l=r(790);function p({isOpen:e,taskId:s,onClose:r,children:p}){const t=(0,n.useRef)(null),d=`prpl-popover-${s}`;return(0,n.useEffect)(()=>{if(!t.current)return;const s=t.current;e?"function"==typeof s.showPopover&&s.showPopover():"function"==typeof s.hidePopover&&s.hidePopover()},[e]),e?(0,l.jsxs)("div",{id:d,ref:t,className:"prpl-popover prpl-popover-interactive",popover:"auto",onToggle:e=>{"closed"===e.newState&&((0,a.doAction)("prpl.popover.close",s),r&&r())},children:[(0,l.jsx)("div",{className:"prpl-columns-wrapper-flex",children:p}),(0,l.jsxs)("button",{className:"prpl-popover-close",type:"button",onClick:()=>{(0,a.doAction)("prpl.popover.close",s),r&&r()},"aria-label":(0,o.__)("Close","progress-planner"),children:[(0,l.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,l.jsx)("span",{className:"screen-reader-text",children:(0,o.__)("Close","progress-planner")})]})]}):null}}}]);
\ No newline at end of file
diff --git a/build/YoastPopover.chunk.js b/build/YoastPopover.chunk.js
new file mode 100644
index 0000000000..8c0259e04b
--- /dev/null
+++ b/build/YoastPopover.chunk.js
@@ -0,0 +1 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[648],{1110:(e,t,s)=>{s.d(t,{V:()=>r});var a=s(6087),n=s(7723);function r(e,t=[]){const[s,r]=(0,a.useState)(!1),[l,i]=(0,a.useState)(null);return{isLoading:s,error:l,handleSubmit:(0,a.useCallback)(async t=>{t.preventDefault(),r(!0),i(null);try{await e(t)}catch(e){i(e.message||(0,n.__)("Something went wrong. Please try again.","progress-planner"))}finally{r(!1)}},t)}}},2592:(e,t,s)=>{s.d(t,{A:()=>n});var a=s(790);function n({isLoading:e=!1,disabled:t=!1,label:s}){return(0,a.jsx)("button",{type:"submit",className:"prpl-button prpl-button-primary",disabled:e||t,children:e?(0,a.jsx)("span",{className:"spinner",style:{visibility:"visible"}}):s})}},3369:(e,t,s)=>{s.r(t),s.d(t,{default:()=>d});var a=s(7723),n=s(8537),r=s(5202),l=s(6979),i=s(2592),o=s(1110),p=s(4333),c=s(790);function d({task:e,onSubmit:t,onClose:s}){const{isLoading:d,error:u,handleSubmit:g}=(0,o.V)(async()=>{const s=`prpl-popover-${e.slug||e.id}`,a=e.slug||e.prpl_provider?.slug||e.id,n={"yoast-author-archive":{setting:"wpseo_titles",settingPath:JSON.stringify(["disable-author"]),settingCallbackValue:()=>!0},"yoast-date-archive":{setting:"wpseo_titles",settingPath:JSON.stringify(["disable-date"]),settingCallbackValue:()=>!0},"yoast-format-archive":{setting:"wpseo_titles",settingPath:JSON.stringify(["disable-post_format"]),settingCallbackValue:()=>!0},"yoast-media-pages":{setting:"wpseo_titles",settingPath:JSON.stringify(["disable-attachment"]),settingCallbackValue:()=>!0},"yoast-crawl-settings-emoji-scripts":{setting:"wpseo",settingPath:JSON.stringify(["remove_emoji_scripts"]),settingCallbackValue:()=>!0},"yoast-crawl-settings-feed-authors":{setting:"wpseo",settingPath:JSON.stringify(["remove_feed_authors"]),settingCallbackValue:()=>!0},"yoast-crawl-settings-feed-global-comments":{setting:"wpseo",settingPath:JSON.stringify(["remove_feed_global_comments"]),settingCallbackValue:()=>!0}}[a];n&&await(0,p.nO)({setting:n.setting,settingPath:n.settingPath,popoverId:s,settingCallbackValue:n.settingCallbackValue,value:n.settingCallbackValue()}),t&&await t(e.id,e)},[e,t]),h=(0,n.decodeEntities)(e.title?.rendered||e.title),m=e.description?.rendered||e.description||"";return(0,c.jsxs)(r.A,{isOpen:!0,taskId:e.slug||e.id,task:e,onClose:s,children:[(0,c.jsxs)("div",{className:"prpl-column prpl-column-content",children:[(0,c.jsx)("h2",{className:"prpl-popover-title",children:h}),m&&(0,c.jsx)("p",{children:m})]}),(0,c.jsx)("div",{className:"prpl-column",children:(0,c.jsxs)("form",{onSubmit:g,children:[(0,c.jsx)(l.A,{error:u}),(0,c.jsx)("div",{className:"prpl-steps-nav-wrapper prpl-steps-nav-wrapper-align-left",children:(0,c.jsx)(i.A,{isLoading:d,label:(0,a.__)("Submit","progress-planner")})})]})})]})}},5202:(e,t,s)=>{s.d(t,{A:()=>i});var a=s(6087),n=s(7723),r=s(2619),l=s(790);function i({isOpen:e,taskId:t,onClose:s,children:i}){const o=(0,a.useRef)(null),p=`prpl-popover-${t}`;return(0,a.useEffect)(()=>{if(!o.current)return;const t=o.current;e?"function"==typeof t.showPopover&&t.showPopover():"function"==typeof t.hidePopover&&t.hidePopover()},[e]),e?(0,l.jsxs)("div",{id:p,ref:o,className:"prpl-popover prpl-popover-interactive",popover:"auto",onToggle:e=>{"closed"===e.newState&&((0,r.doAction)("prpl.popover.close",t),s&&s())},children:[(0,l.jsx)("div",{className:"prpl-columns-wrapper-flex",children:i}),(0,l.jsxs)("button",{className:"prpl-popover-close",type:"button",onClick:()=>{(0,r.doAction)("prpl.popover.close",t),s&&s()},"aria-label":(0,n.__)("Close","progress-planner"),children:[(0,l.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,l.jsx)("span",{className:"screen-reader-text",children:(0,n.__)("Close","progress-planner")})]})]}):null}},6979:(e,t,s)=>{s.d(t,{A:()=>n});var a=s(790);function n({error:e}){return e?(0,a.jsx)("p",{className:"prpl-note prpl-note-error prpl-interactive-task-error-message",children:e}):null}}}]);
\ No newline at end of file
diff --git a/build/dashboard-rtl.css b/build/dashboard-rtl.css
new file mode 100644
index 0000000000..be28e99dab
--- /dev/null
+++ b/build/dashboard-rtl.css
@@ -0,0 +1 @@
+.prpl-custom-checkbox input[type=checkbox],.prpl-custom-radio input[type=radio]{height:0;opacity:0;position:absolute;width:0}.prpl-custom-control{box-sizing:border-box;display:inline-block;flex-shrink:0;height:20px;margin-left:12px;position:relative;transition:border-color .2s,background .2s;vertical-align:middle;width:20px}.prpl-custom-checkbox,.prpl-custom-radio{align-items:center;cursor:pointer;display:flex;margin-bottom:.5rem;-webkit-user-select:none;-moz-user-select:none;user-select:none}.prpl-custom-checkbox .prpl-custom-control{background-color:var(--prpl-onboarding-popover-background,#fff);border:1px solid var(--prpl-color-selection-controls-inactive,#9ca3af)}.prpl-custom-checkbox input[type=checkbox]:checked+.prpl-custom-control{background:var(--prpl-color-selection-controls,#534786);border-color:var(--prpl-color-selection-controls,#534786)}.prpl-custom-checkbox .prpl-custom-control:after{border-width:medium;border-bottom:2px solid var(--prpl-onboarding-popover-background,#fff);border-right:0 solid var(--prpl-onboarding-popover-background,#fff);border-left:2px solid var(--prpl-onboarding-popover-background,#fff);border-top:0 solid var(--prpl-onboarding-popover-background,#fff);content:"";height:9px;right:6px;opacity:0;position:absolute;top:2px;transform:scale(.8) rotate(-45deg);transition:opacity .2s,transform .2s;width:4px}.prpl-custom-checkbox input[type=checkbox]:checked+.prpl-custom-control:after{opacity:1;transform:scale(1) rotate(-45deg)}.prpl-custom-radio .prpl-custom-control{background-color:var(--prpl-onboarding-popover-background,#fff);border:1px solid var(--prpl-color-selection-controls-inactive,#9ca3af);border-radius:50%}.prpl-custom-radio input[type=radio]:checked+.prpl-custom-control{background:var(--prpl-color-selection-controls,#534786);border-color:var(--prpl-color-selection-controls,#534786)}.prpl-custom-radio .prpl-custom-control:after{background-color:var(--prpl-onboarding-popover-background,#fff);border-radius:50%;content:"";height:8px;right:5px;opacity:0;position:absolute;top:5px;transition:opacity .2s;width:8px}.prpl-custom-radio input[type=radio]:checked+.prpl-custom-control:after{opacity:1}.prpl-post-type-toggle-label,.prpl-post-type-toggle-wrapper{align-items:center;display:flex}.prpl-post-type-toggle-label{cursor:pointer;gap:.75rem;position:relative}.prpl-post-type-toggle-input{height:0;margin:0;opacity:0;padding:0;position:absolute;width:0}.prpl-post-type-toggle-switch{align-items:center;background-color:var(--prpl-color-selection-controls-inactive,#9ca3af);border-radius:12px;display:flex;flex-shrink:0;height:24px;justify-content:center;position:relative;transition:background-color .2s;width:44px}.prpl-post-type-toggle-switch:after{background-color:var(--prpl-onboarding-popover-background,#fff);border-radius:50%;content:"";height:20px;right:2px;position:absolute;top:2px;transition:transform .2s;width:20px;z-index:1}.prpl-post-type-toggle-switch svg{color:var(--prpl-color-ui-icon,#6b7280);height:12px;right:6px;position:absolute;top:50%;transform:translateY(-50%);transition:opacity .2s,right .2s,color .2s;width:12px;z-index:2}.prpl-post-type-toggle-switch .prpl-toggle-icon-check{display:none}.prpl-post-type-toggle-switch .prpl-toggle-icon-x{display:block}.prpl-post-type-toggle-label:hover .prpl-post-type-toggle-switch svg{opacity:.6}.prpl-post-type-toggle-input:checked~.prpl-post-type-toggle-switch{background-color:var(--prpl-background-step-active,#534786)}.prpl-post-type-toggle-input:checked~.prpl-post-type-toggle-switch:after{transform:translateX(-20px)}.prpl-post-type-toggle-input:checked~.prpl-post-type-toggle-switch svg{color:var(--prpl-background-step-active,#534786);right:26px;transform:translateY(-50%)}.prpl-post-type-toggle-input:checked~.prpl-post-type-toggle-switch .prpl-toggle-icon-check{display:block}.prpl-post-type-toggle-input:checked~.prpl-post-type-toggle-switch .prpl-toggle-icon-x{display:none}.prpl-post-type-toggle-text{font-size:16px;line-height:1.5;transition:opacity .2s}
diff --git a/build/dashboard.asset.php b/build/dashboard.asset.php
new file mode 100644
index 0000000000..cb1fdab525
--- /dev/null
+++ b/build/dashboard.asset.php
@@ -0,0 +1 @@
+ array('react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '97370c6ebc9c6c9f0305', 'handle' => 'undefined-dashboard');
diff --git a/build/dashboard.css b/build/dashboard.css
new file mode 100644
index 0000000000..58372bd0e0
--- /dev/null
+++ b/build/dashboard.css
@@ -0,0 +1 @@
+.prpl-custom-checkbox input[type=checkbox],.prpl-custom-radio input[type=radio]{height:0;opacity:0;position:absolute;width:0}.prpl-custom-control{box-sizing:border-box;display:inline-block;flex-shrink:0;height:20px;margin-right:12px;position:relative;transition:border-color .2s,background .2s;vertical-align:middle;width:20px}.prpl-custom-checkbox,.prpl-custom-radio{align-items:center;cursor:pointer;display:flex;margin-bottom:.5rem;-webkit-user-select:none;-moz-user-select:none;user-select:none}.prpl-custom-checkbox .prpl-custom-control{background-color:var(--prpl-onboarding-popover-background,#fff);border:1px solid var(--prpl-color-selection-controls-inactive,#9ca3af)}.prpl-custom-checkbox input[type=checkbox]:checked+.prpl-custom-control{background:var(--prpl-color-selection-controls,#534786);border-color:var(--prpl-color-selection-controls,#534786)}.prpl-custom-checkbox .prpl-custom-control:after{border-width:medium;border-bottom:2px solid var(--prpl-onboarding-popover-background,#fff);border-left:0 solid var(--prpl-onboarding-popover-background,#fff);border-right:2px solid var(--prpl-onboarding-popover-background,#fff);border-top:0 solid var(--prpl-onboarding-popover-background,#fff);content:"";height:9px;left:6px;opacity:0;position:absolute;top:2px;transform:scale(.8) rotate(45deg);transition:opacity .2s,transform .2s;width:4px}.prpl-custom-checkbox input[type=checkbox]:checked+.prpl-custom-control:after{opacity:1;transform:scale(1) rotate(45deg)}.prpl-custom-radio .prpl-custom-control{background-color:var(--prpl-onboarding-popover-background,#fff);border:1px solid var(--prpl-color-selection-controls-inactive,#9ca3af);border-radius:50%}.prpl-custom-radio input[type=radio]:checked+.prpl-custom-control{background:var(--prpl-color-selection-controls,#534786);border-color:var(--prpl-color-selection-controls,#534786)}.prpl-custom-radio .prpl-custom-control:after{background-color:var(--prpl-onboarding-popover-background,#fff);border-radius:50%;content:"";height:8px;left:5px;opacity:0;position:absolute;top:5px;transition:opacity .2s;width:8px}.prpl-custom-radio input[type=radio]:checked+.prpl-custom-control:after{opacity:1}.prpl-post-type-toggle-label,.prpl-post-type-toggle-wrapper{align-items:center;display:flex}.prpl-post-type-toggle-label{cursor:pointer;gap:.75rem;position:relative}.prpl-post-type-toggle-input{height:0;margin:0;opacity:0;padding:0;position:absolute;width:0}.prpl-post-type-toggle-switch{align-items:center;background-color:var(--prpl-color-selection-controls-inactive,#9ca3af);border-radius:12px;display:flex;flex-shrink:0;height:24px;justify-content:center;position:relative;transition:background-color .2s;width:44px}.prpl-post-type-toggle-switch:after{background-color:var(--prpl-onboarding-popover-background,#fff);border-radius:50%;content:"";height:20px;left:2px;position:absolute;top:2px;transition:transform .2s;width:20px;z-index:1}.prpl-post-type-toggle-switch svg{color:var(--prpl-color-ui-icon,#6b7280);height:12px;left:6px;position:absolute;top:50%;transform:translateY(-50%);transition:opacity .2s,left .2s,color .2s;width:12px;z-index:2}.prpl-post-type-toggle-switch .prpl-toggle-icon-check{display:none}.prpl-post-type-toggle-switch .prpl-toggle-icon-x{display:block}.prpl-post-type-toggle-label:hover .prpl-post-type-toggle-switch svg{opacity:.6}.prpl-post-type-toggle-input:checked~.prpl-post-type-toggle-switch{background-color:var(--prpl-background-step-active,#534786)}.prpl-post-type-toggle-input:checked~.prpl-post-type-toggle-switch:after{transform:translateX(20px)}.prpl-post-type-toggle-input:checked~.prpl-post-type-toggle-switch svg{color:var(--prpl-background-step-active,#534786);left:26px;transform:translateY(-50%)}.prpl-post-type-toggle-input:checked~.prpl-post-type-toggle-switch .prpl-toggle-icon-check{display:block}.prpl-post-type-toggle-input:checked~.prpl-post-type-toggle-switch .prpl-toggle-icon-x{display:none}.prpl-post-type-toggle-text{font-size:16px;line-height:1.5;transition:opacity .2s}
diff --git a/build/dashboard.js b/build/dashboard.js
new file mode 100644
index 0000000000..bc98669638
--- /dev/null
+++ b/build/dashboard.js
@@ -0,0 +1,10 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[945],{475:(e,t,s)=>{s.d(t,{A:()=>i});var r=s(6087),a=s(790);function i({value:e=0,max:t=10,backgroundColor:s="var(--prpl-background-monthly)",color:i="var(--prpl-color-monthly)",color2:n="var(--prpl-color-monthly-2)",contentFontSize:o="var(--prpl-font-size-6xl)",children:l}){const p="180deg",c={padding:"var(--prpl-padding) var(--prpl-padding) calc(var(--prpl-padding) * 2) var(--prpl-padding)",background:s,borderRadius:"var(--prpl-border-radius-big)",aspectRatio:"2 / 1",overflow:"hidden",position:"relative",marginBottom:"var(--prpl-padding)"},d={width:"100%",aspectRatio:"1 / 1",borderRadius:"100%",position:"relative",background:`radial-gradient(${s} 0 57%, transparent 57% 100%), conic-gradient(from 270deg, ${(0,r.useMemo)(()=>{const s=t>0?e/t:0;let r;return s<=.5?r=`${i} calc(${p} * ${s})`:(r=`${i} calc(${p} * 0.5)`,r+=`, ${n} calc(${p} * ${s})`),r+=`, var(--prpl-color-gauge-remain) calc(${p} * ${s}) ${p}`,r},[e,t,i,n])}, transparent ${p})`,textAlign:"center"},u={fontSize:"var(--prpl-font-size-small)",position:"absolute",top:"50%",color:"var(--prpl-color-text)",width:"10%",textAlign:"center"},h={...u,left:0},g={...u,right:0},m={fontSize:o,bottom:"50%",display:"block",fontWeight:600,textAlign:"center",position:"absolute",color:"var(--prpl-color-text)",width:"100%",lineHeight:1.2};return(0,a.jsx)("div",{className:"prpl-gauge",style:c,children:(0,a.jsxs)("div",{className:"prpl-gauge__ring",style:d,children:[(0,a.jsx)("span",{className:"prpl-gauge__label prpl-gauge__label--min",style:h,children:"0"}),(0,a.jsx)("span",{className:"prpl-gauge__content",style:m,children:(0,a.jsx)("span",{className:"prpl-gauge__content-inner",style:{display:"inline-block",width:"50%"},children:l})}),(0,a.jsx)("span",{className:"prpl-gauge__label prpl-gauge__label--max",style:g,children:t})]})})}},714:(e,t,s)=>{var r=s(7723);class a{constructor(e={}){const t=this.constructor;let s=!0;void 0!==t.isSnoozable?s=t.isSnoozable:void 0!==e.isSnoozable&&(s=e.isSnoozable),this.config={providerId:t.providerId||e.providerId||"",capability:t.capability||e.capability||"manage_options",isOnboardingTask:void 0!==t.isOnboardingTask?t.isOnboardingTask:e.isOnboardingTask||!1,priority:void 0!==t.priority?t.priority:e.priority||50,points:void 0!==t.points?t.points:e.points||1,parent:void 0!==t.parent?t.parent:e.parent||0,isDismissable:void 0!==t.isDismissable?t.isDismissable:e.isDismissable||!1,isSnoozable:s,isRepetitive:void 0!==t.isRepetitive?t.isRepetitive:e.isRepetitive||!1,dependencies:t.dependencies||e.dependencies||[],externalLinkUrl:t.externalLinkUrl||e.externalLinkUrl||"",popoverId:t.popoverId||e.popoverId||"",isMultiTask:void 0!==t.isMultiTask?t.isMultiTask:e.isMultiTask||!1,...e}}static getStaticConfig(){return{providerId:this.providerId||"",capability:this.capability||"manage_options",isOnboardingTask:this.isOnboardingTask||!1,priority:void 0!==this.priority?this.priority:50,points:void 0!==this.points?this.points:1,parent:this.parent||0,isDismissable:this.isDismissable||!1,isSnoozable:void 0===this.isSnoozable||this.isSnoozable,isRepetitive:this.isRepetitive||!1,dependencies:this.dependencies||[],externalLinkUrl:this.externalLinkUrl||"",popoverId:this.popoverId||"",isMultiTask:this.isMultiTask||!1}}getProviderId(){return this.constructor.providerId||this.config.providerId||""}getPriority(){const e=this.constructor;return void 0!==e.priority?e.priority:this.config.priority||50}getPoints(){const e=this.constructor;return void 0!==e.points?e.points:this.config.points||1}buildAdminUrl(e="",t={}){const s=window.prplDashboardConfig?.adminUrl||"/wp-admin/",r=s.endsWith("/")?"":"/";let a=e?`${s}${r}${e}`:s;const i=Object.entries(t).filter(([,e])=>null!=e).map(([e,t])=>`${encodeURIComponent(e)}=${encodeURIComponent(t)}`).join("&");return i&&(a+=(a.includes("?")?"&":"?")+i),a}buildTaskDetails(e={},t={}){const s=this.constructor;return{task_id:this.getTaskId(e),provider_id:this.getProviderId(),post_title:"",description:"",priority:this.getPriority(),points:this.getPoints(),parent:s.parent||0,url:"",url_target:"_self",dismissable:void 0!==s.isDismissable?s.isDismissable:this.config.isDismissable,external_link_url:s.externalLinkUrl||this.config.externalLinkUrl,...t}}capabilityRequired(){return!0}async shouldAddTask(e={}){throw new Error("shouldAddTask() must be implemented by task provider")}async getTaskDetails(e={}){throw new Error("getTaskDetails() must be implemented by task provider")}getTaskId(e={}){const t=this.constructor,s=[t.providerId||this.config.providerId||""];if(e.targetPostId&&s.push(e.targetPostId),e.targetTermId&&s.push(e.targetTermId),e.targetTaxonomy&&s.push(e.targetTaxonomy),e.target_post_id&&s.push(e.target_post_id),e.target_term_id&&s.push(e.target_term_id),e.target_taxonomy&&s.push(e.target_taxonomy),void 0!==t.isRepetitive?t.isRepetitive:this.config.isRepetitive){const e=new Date,t=e.getFullYear(),r=this.getWeekNumber(e);s.push(`${t}${r.toString().padStart(2,"0")}`)}return s.join("-")}getWeekNumber(e){const t=new Date(Date.UTC(e.getFullYear(),e.getMonth(),e.getDate())),s=t.getUTCDay()||7;t.setUTCDate(t.getUTCDate()+4-s);const r=new Date(Date.UTC(t.getUTCFullYear(),0,1));return Math.ceil(((t-r)/864e5+1)/7)}async areDependenciesSatisfied(e){const t=this.constructor.dependencies||this.config.dependencies||[];if(!t||0===t.length)return!0;for(const s of t){const t="string"==typeof s?s:s.taskId,r="object"==typeof s?s.status:"completed";if(await e(t)!==r)return!1}return!0}getTaskActions(e={}){const t=[],s=this.constructor;e&&"object"==typeof e||(e={});const r=this.getProviderId(),a=e.slug||e.id||"",i=e.title?.rendered||e.title||e.post_title||"";this.capabilityRequired()&&this.config.isDismissable&&"user"!==r&&t.push({type:"complete",priority:20,taskId:a,taskTitle:i}),this.capabilityRequired()&&this.config.isSnoozable&&t.push({type:"snooze",priority:30,taskId:a,taskTitle:i});const n=!(!this.config.popoverId&&!s.popoverId);if(this.config.externalLinkUrl?t.push({type:"info",priority:40,externalUrl:this.config.externalLinkUrl}):!n&&e.content?.rendered&&""!==e.content.rendered&&t.push({type:"info",priority:40,taskId:a,taskTitle:i,content:e.content.rendered}),this.capabilityRequired()){const s=this.addTaskActions(e,t).map(e=>(e.priority||(e.priority=1e3),e)).filter(e=>e.type||e.html&&""!==e.html);return s.sort((e,t)=>e.priority-t.priority),s}return t.sort((e,t)=>e.priority-t.priority),t}addTaskActions(e,t){return t}}class i extends a{constructor(e={}){super(e)}getPopoverId(){const e=this.constructor.popoverId||this.config.popoverId||"";return e?`prpl-popover-${e}`:""}async getTaskDetails(e={}){throw new Error("getTaskDetails() must be implemented by interactive task provider")}addPopoverIdToTaskDetails(e){return(this.constructor.popoverId||this.config.popoverId)&&(e.popover_id=this.getPopoverId()),e}getAllowedInteractiveOptions(){return[]}addTaskActions(e=[],t=[]){return(this.constructor.popoverId||this.config.popoverId)&&t.push({type:"popover",priority:10,popoverId:this.getPopoverId(),label:this.getPopoverActionLabel()}),super.addTaskActions(e,t)}getPopoverActionLabel(){return(0,r.__)("Complete","progress-planner")}}var n=s(8493),o=s(9251);(0,n.nR)(class extends i{static providerId="hello-world";static capability="edit_posts";static isOnboardingTask=!0;static priority=15;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/delete-hello-world-post";static popoverId="hello-world";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("hello_world_post_id");return 0!==e&&null!==e}catch(e){return console.error("Error checking Hello World task condition:",e),!1}}async getTaskDetails(e={}){const t=await(0,o.OJ)("hello_world_post_id"),s=t&&0!==t?this.buildAdminUrl("post.php",{post:t,action:"edit"}):"",a=t&&0!==t?"
"+(0,r.__)('On install, WordPress creates a "Hello World!" post. This post does not add value to your website and solely exists to show what a post can look like. Therefore, "Hello World!" is not needed and should be deleted.',"progress-planner")+"
":(0,r.__)('On install, WordPress creates a "Hello World!" post. This post is not needed and should be deleted.',"progress-planner"),i=this.buildTaskDetails(e,{post_title:(0,r.__)('Delete the "Hello World!" post.',"progress-planner"),description:a,url:s});return this.addPopoverIdToTaskDetails(i)}getPopoverActionLabel(){return(0,r.__)("Delete","progress-planner")}});(0,n.nR)(class extends i{static providerId="sample-page";static capability="edit_pages";static isOnboardingTask=!0;static priority=14;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/delete-sample-page";static popoverId="sample-page";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("sample_page_id");return 0!==e&&null!==e}catch(e){return console.error("Error checking Sample Page task condition:",e),!1}}async getTaskDetails(e={}){const t=await(0,o.OJ)("sample_page_id"),s=t&&0!==t?this.buildAdminUrl("post.php",{post:t,action:"edit"}):"",a=t&&0!==t?"
"+(0,r.__)('On install, WordPress creates a "Sample Page" page. This page does not add value to your website and solely exists to show what a page can look like. Therefore, "Sample Page" is not needed and should be deleted.',"progress-planner")+"
":(0,r.__)('On install, WordPress creates a "Sample Page" page. This page does not add value to your website and solely exists to show what a page can look like. Therefore, "Sample Page" is not needed and should be deleted.',"progress-planner"),i=this.buildTaskDetails(e,{post_title:(0,r.__)('Delete "Sample Page"',"progress-planner"),description:a,url:s});return this.addPopoverIdToTaskDetails(i)}getPopoverActionLabel(){return(0,r.__)("Delete","progress-planner")}});var l=s(5337);(0,n.nR)(class extends i{static providerId="core-blogdescription";static capability="manage_options";static isOnboardingTask=!0;static priority=2;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/set-tagline";static popoverId="core-blogdescription";async shouldAddTask(e={}){try{const e=await(0,l.BJ)({path:"/wp/v2/settings"});return!e?.description||""===e.description}catch(e){return console.error("Error checking Blog Description task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Set tagline","progress-planner"),description:(0,r.__)("Set the tagline to make your website look more professional.","progress-planner"),url:this.buildAdminUrl("options-general.php")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Set tagline","progress-planner")}});(0,n.nR)(class extends i{static providerId="core-siteicon";static capability="manage_options";static isOnboardingTask=!0;static priority=1;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/set-site-icon";static popoverId="core-siteicon";async shouldAddTask(e={}){try{const e=await(0,l.BJ)({path:"/wp/v2/settings"}),t=e?.site_icon;return!t||""===t||"0"===t}catch(e){return console.error("Error checking Site Icon task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Set site icon","progress-planner"),url:this.buildAdminUrl("options-general.php")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Set site icon","progress-planner")}});(0,n.nR)(class extends i{static providerId="core-permalink-structure";static capability="manage_options";static isOnboardingTask=!0;static priority=3;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/change-default-permalink-structure";static popoverId="core-permalink-structure";async shouldAddTask(e={}){try{const e=await(0,l.BJ)({path:"/wp/v2/settings"}),t=e?.permalink_structure||"";return"/%year%/%monthnum%/%day%/%postname%/"===t||"/index.php/%year%/%monthnum%/%day%/%postname%/"===t}catch(e){return console.error("Error checking Permalink Structure task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Set permalink structure","progress-planner"),url:this.buildAdminUrl("options-permalink.php"),link_setting:{hook:"options-permalink.php",iconEl:'label[for="permalink-input-month-name"], label[for="permalink-input-post-name"]'}});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Select permalink structure","progress-planner")}});(0,n.nR)(class extends i{static providerId="select-locale";static capability="install_languages";static isOnboardingTask=!1;static priority=8;static points=1;static isDismissable=!0;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/set-locale";static popoverId="select-locale";async shouldAddTask(e={}){try{const e="undefined"!=typeof window&&window.navigator?.language?window.navigator.language.split("-")[0]:null,t=await(0,l.BJ)({path:"/wp/v2/settings"});return e&&!(t?.language||"en").startsWith(e)}catch(e){return console.error("Error checking Select Locale task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Select your site locale","progress-planner"),url:this.buildAdminUrl("options-general.php"),link_setting:{hook:"options-general.php",iconEl:'label[for="WPLANG"]'}});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Select locale","progress-planner")}});(0,n.nR)(class extends i{static providerId="select-timezone";static capability="manage_options";static isOnboardingTask=!1;static priority=6;static points=1;static isDismissable=!0;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/set-timezone";static popoverId="select-timezone";async shouldAddTask(e={}){try{const e=await(0,l.BJ)({path:"/wp/v2/settings"}),t=e?.timezone_string||"";return!t||"UTC"===t}catch(e){return console.error("Error checking Select Timezone task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Set site timezone","progress-planner"),url:this.buildAdminUrl("options-general.php")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Select timezone","progress-planner")}});(0,n.nR)(class extends i{static providerId="set-date-format";static capability="manage_options";static isOnboardingTask=!1;static priority=7;static points=1;static isDismissable=!0;static isSnoozable=!0;static popoverId="set-date-format";async shouldAddTask(e={}){try{const e=await(0,l.BJ)({path:"/wp/v2/settings"}),t=e?.date_format||"";return!t||"wp_default"===t}catch(e){return console.error("Error checking Set Date Format task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Set site date format","progress-planner"),description:(0,r.__)("Setting the date format correctly on your site is valuable. By setting the correct date format, you ensure the dates are displayed correctly in the admin area and the front end.","progress-planner"),url:this.buildAdminUrl("options-general.php")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Set date format","progress-planner")}});(0,n.nR)(class extends i{static providerId="search-engine-visibility";static capability="manage_options";static isOnboardingTask=!0;static priority=5;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/blog-indexing-settings";static popoverId="search-engine-visibility";async shouldAddTask(e={}){try{const e=await(0,l.BJ)({path:"/wp/v2/settings"});return 0===e?.blog_public||"0"===e?.blog_public}catch(e){return console.error("Error checking Search Engine Visibility task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Allow your site to be indexed by search engines","progress-planner"),url:this.buildAdminUrl("options-reading.php"),link_setting:{hook:"options-reading.php",iconEl:'label[for="blog_public"]'}});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Allow","progress-planner")}});(0,n.nR)(class extends a{static providerId="create-post";static capability="edit_others_posts";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static isRepetitive=!0;static externalLinkUrl="https://prpl.fyi/valuable-content";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("last_published_post_id");return e&&e.post_id,!0}catch(e){return console.error("Error checking Content Create task condition:",e),!1}}async getTaskDetails(e={}){const t=await(0,o.OJ)("last_published_post_id"),s=t?.post_id||null;return this.buildTaskDetails(e,{post_title:(0,r.__)("Create valuable content","progress-planner"),url:"https://prpl.fyi/valuable-content",url_target:"_blank",target_post_id:s})}addTaskActions(e,t){return t.push({type:"link",priority:10,href:this.buildAdminUrl("post-new.php"),label:(0,r.__)("Create new post","progress-planner"),target:"_self"}),t}});(0,n.nR)(class extends a{static providerId="review-post";static capability="edit_others_posts";static isOnboardingTask=!1;static priority=10;static points=1;static isDismissable=!0;static isSnoozable=!0;static isRepetitive=!0;static externalLinkUrl="https://prpl.fyi/review-post";static isMultiTask=!0;async shouldAddTask(e={}){try{const e=await this.getTasksToInject();return e&&e.length>0}catch(e){return console.error("Error checking Content Review task condition:",e),!1}}async getTasksToInject(){try{const e=await(0,o.OJ)("old_posts_for_review");return e&&0!==e.length?e.map(e=>({target_post_id:e.ID,target_post_title:e.post_title,target_post_type:e.post_type})):[]}catch(e){return console.error("Error getting posts for review:",e),[]}}async getTaskDetails(e={}){const t=e?.target_post_id||null,s=e?.target_post_title||null;if(!t)throw new Error("ContentReviewTask requires target_post_id in taskData");const a=s?(0,r.sprintf)(/* translators: %s: post title */ /* translators: %s: post title */
+(0,r.__)("Review: %s","progress-planner"),s):(0,r.sprintf)(/* translators: %d: post ID */ /* translators: %d: post ID */
+(0,r.__)("Review post #%d","progress-planner"),t);return this.buildTaskDetails(e,{post_title:a,url:this.buildAdminUrl("post.php",{post:t,action:"edit"}),url_target:"_blank",target_post_id:t})}addTaskActions(e=[],t=[]){const s=e.target_post_id||e.meta?.target_post_id||null;return s&&t.push({type:"link",priority:10,href:this.buildAdminUrl("post.php",{action:"edit",post:s}),label:(0,r.__)("Review","progress-planner"),target:"_self"}),t}});(0,n.nR)(class extends a{static providerId="unpublished-content";static capability="edit_others_posts";static isOnboardingTask=!1;static priority=55;static points=1;static isDismissable=!0;static isSnoozable=!0;static isRepetitive=!1;static externalLinkUrl="https://prpl.fyi/check-unpublished-content";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("unpublished_content");return e&&Array.isArray(e)&&e.length>0}catch(e){return console.error("Error checking Unpublished Content task condition:",e),!1}}async getTaskDetails(e={}){const t=await(0,o.OJ)("unpublished_content"),s=t&&Array.isArray(t)?t.length:0,a=s>0?(0,r.sprintf)(/* translators: %d: number of unpublished items */ /* translators: %d: number of unpublished items */
+(0,r._n)("You have %d unpublished item that might need attention.","You have %d unpublished items that might need attention.",s,"progress-planner"),s):"";return this.buildTaskDetails(e,{post_title:(0,r.__)("Review unpublished content","progress-planner"),description:a,url:this.buildAdminUrl("edit.php",{post_status:"draft",post_type:"post"})})}addTaskActions(e=[],t=[]){const s=e.meta?.prpl_url||e.url||null;return s&&t.push({type:"link",priority:10,href:s,label:(0,r.__)("Edit","progress-planner"),target:"_self"}),t}});(0,n.nR)(class extends i{static providerId="set-page-about";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static popoverId="set-page-about";async shouldAddTask(e={}){try{const e=await(0,l.BJ)({path:"/progress-planner/v1/page-settings"}).catch(()=>null);return!(!e||!e.about)&&"no"===e.about.isset}catch(e){return console.error("Error checking Set Page About task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Set the About page","progress-planner"),url:this.buildAdminUrl("edit.php",{post_type:"page"})});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Set","progress-planner")}});(0,n.nR)(class extends i{static providerId="set-page-faq";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static popoverId="set-page-faq";async shouldAddTask(e={}){try{const e=await(0,l.BJ)({path:"/progress-planner/v1/page-settings"}).catch(()=>null);return!e||!e.faq||"no"===e.faq.isset}catch(e){return console.error("Error checking Set Page FAQ task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Set the FAQ page","progress-planner"),url:this.buildAdminUrl("edit.php",{post_type:"page"})});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Set","progress-planner")}});(0,n.nR)(class extends i{static providerId="set-page-contact";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static popoverId="set-page-contact";async shouldAddTask(e={}){try{const e=await(0,l.BJ)({path:"/progress-planner/v1/page-settings"}).catch(()=>null);return!e||!e.contact||"no"===e.contact.isset}catch(e){return console.error("Error checking Set Page Contact task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Set the Contact page","progress-planner"),url:this.buildAdminUrl("edit.php",{post_type:"page"})});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Set","progress-planner")}});(0,n.nR)(class extends i{static providerId="set-valuable-post-types";static capability="manage_options";static isOnboardingTask=!1;static priority=70;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/valuable-content";static popoverId="set-valuable-post-types";async shouldAddTask(e={}){return!0}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Set valuable content types","progress-planner"),url:this.buildAdminUrl("admin.php",{page:"progress-planner"})});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Set","progress-planner")}});(0,n.nR)(class extends i{static providerId="rename-uncategorized-category";static capability="manage_categories";static isOnboardingTask=!0;static priority=60;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/rename-uncategorized-category";static popoverId="rename-uncategorized-category";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("uncategorized_category_id");return 0!==e&&null!==e}catch(e){return console.error("Error checking Rename Uncategorized Category task condition:",e),!1}}async getTaskDetails(e={}){const t=await(0,o.OJ)("uncategorized_category_id"),s=this.buildTaskDetails(e,{post_title:(0,r.__)("Rename Uncategorized category","progress-planner"),url:this.buildAdminUrl("term.php",{taxonomy:"category",tag_ID:t})});return this.addPopoverIdToTaskDetails(s)}getPopoverActionLabel(){return(0,r.__)("Rename","progress-planner")}});(0,n.nR)(class extends i{static providerId="fewer-tags";static capability="manage_options";static isOnboardingTask=!0;static priority=32;static points=1;static isDismissable=!0;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/install-fewer-tags";static popoverId="fewer-tags";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("post_tag_count"),t=await(0,o.OJ)("published_post_count");return null!==e&&null!==t&&e>t}catch(e){return console.error("Error checking Fewer Tags task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Install Fewer Tags and clean up your tags","progress-planner"),url:this.buildAdminUrl("plugin-install.php",{tab:"search",s:"fewer tags"})});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Install plugin","progress-planner")}});(0,n.nR)(class extends i{static providerId="remove-terms-without-posts";static capability="edit_others_posts";static isOnboardingTask=!1;static priority=60;static points=1;static isDismissable=!0;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/remove-empty-taxonomy";static popoverId="remove-terms-without-posts";static isMultiTask=!0;async shouldAddTask(e={}){try{const e=await this.getTasksToInject();return e&&e.length>0}catch(e){return console.error("Error checking Remove Terms Without Posts task condition:",e),!1}}async getTasksToInject(){try{const e=await(0,o.OJ)("terms_without_posts");if(!e)return[];const t=Array.isArray(e)?e:[e];return 0===t.length?[]:t.map(e=>({target_term_id:e.term_id,target_taxonomy:e.taxonomy}))}catch(e){return console.error("Error getting tasks to inject for Remove Terms Without Posts:",e),[]}}async getTaskDetails(e={}){const t=e?.target_term_id||null,s=e?.target_taxonomy||null;if(!t||!s)throw new Error("RemoveTermsWithoutPostsTask requires target_term_id and target_taxonomy in taskData");const r=this.buildTaskDetails(e,{post_title:`Remove term #${t}`,url:this.buildAdminUrl("edit-tags.php",{taxonomy:s}),url_target:"_blank",target_term_id:t,target_taxonomy:s});return this.addPopoverIdToTaskDetails(r)}});(0,n.nR)(class extends i{static providerId="update-term-description";static capability="edit_others_posts";static isOnboardingTask=!1;static priority=80;static points=1;static isDismissable=!0;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/taxonomy-terms-description";static popoverId="update-term-description";static isMultiTask=!0;async shouldAddTask(e={}){try{const e=await this.getTasksToInject();return e&&e.length>0}catch(e){return console.error("Error checking Update Term Description task condition:",e),!1}}async getTasksToInject(){try{const e=await(0,o.OJ)("terms_without_description");if(!e)return[];const t=Array.isArray(e)?e:[e];return 0===t.length?[]:t.map(e=>({target_term_id:e.term_id,target_taxonomy:e.taxonomy}))}catch(e){return console.error("Error getting tasks to inject for Update Term Description:",e),[]}}async getTaskDetails(e={}){const t=e?.target_term_id||null,s=e?.target_taxonomy||null;if(!t||!s)throw new Error("UpdateTermDescriptionTask requires target_term_id and target_taxonomy in taskData");const a=this.buildTaskDetails(e,{post_title:(0,r.sprintf)(/* translators: %d: term ID */ /* translators: %d: term ID */
+(0,r.__)("Write description for term #%d","progress-planner"),t),url:this.buildAdminUrl("term.php",{taxonomy:s,tag_ID:t}),url_target:"_blank",target_term_id:t,target_taxonomy:s});return this.addPopoverIdToTaskDetails(a)}addTaskActions(e=[],t=[]){const s=e.target_term_id||e.meta?.target_term_id||null,a=e.target_taxonomy||e.meta?.target_taxonomy||null;if(!s||!a)return super.addTaskActions(e,t);const i={post_title:e.title?.rendered||e.post_title||"",target_term_id:s,target_taxonomy:a,target_term_name:e.meta?.target_term_name||"",target_taxonomy_name:e.meta?.target_taxonomy_name||""};return t.push({type:"popover",priority:10,popoverId:this.getPopoverId(),label:(0,r.__)("Write description","progress-planner"),taskContext:i,eventName:"prpl-interactive-task-action-update-term-description"}),t}getPopoverActionLabel(){return(0,r.__)("Write description","progress-planner")}});(0,n.nR)(class extends i{static providerId="seo-plugin";static capability="manage_options";static isOnboardingTask=!0;static priority=20;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/install-seo-plugin";static popoverId="seo-plugin";async shouldAddTask(e={}){try{return!await(0,o.OJ)("seo_plugin_installed")}catch(e){return console.error("Error checking SEO Plugin task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Install an SEO plugin","progress-planner"),url:this.buildAdminUrl("plugins.php")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Install plugin","progress-planner")}});var p=s(1455),c=s.n(p);(0,n.nR)(class extends a{static providerId="update-core";static capability="update_core";static isOnboardingTask=!1;static priority=20;static points=1;static isDismissable=!1;static isSnoozable=!0;static isRepetitive=!0;static externalLinkUrl="https://prpl.fyi/perform-all-updates";async shouldAddTask(e={}){try{const e=await c()({path:"/wp/v2/updates"}).catch(()=>null);return!e||e.core&&e.core.length>0||e.plugins&&e.plugins.length>0||e.themes&&e.themes.length>0}catch(e){return console.error("Error checking Core Update task condition:",e),!1}}async getTaskDetails(e={}){return this.buildTaskDetails(e,{post_title:(0,r.__)("Perform all updates","progress-planner"),url:this.buildAdminUrl("update-core.php")})}addTaskActions(e,t){return t.push({type:"link",priority:10,href:this.buildAdminUrl("update-core.php"),label:(0,r.__)("Go to the Updates page","progress-planner"),target:"_self"}),t}});(0,n.nR)(class extends a{static providerId="remove-inactive-plugins";static capability="manage_options";static isOnboardingTask=!1;static priority=60;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/remove-inactive-plugins";async shouldAddTask(e={}){try{return await(0,o.OJ)("inactive_plugins_count")>0}catch(e){return console.error("Error checking Remove Inactive Plugins task condition:",e),!1}}async getTaskDetails(e={}){return this.buildTaskDetails(e,{post_title:(0,r.__)("Remove inactive plugins","progress-planner"),url:this.buildAdminUrl("plugins.php",{plugin_status:"inactive"})})}addTaskActions(e,t){return t.push({type:"link",priority:10,href:this.buildAdminUrl("plugins.php",{plugin_status:"inactive"}),label:(0,r.__)('Go to the "Plugins" page',"progress-planner"),target:"_self"}),t}});(0,n.nR)(class extends a{static providerId="wp-debug-display";static capability="manage_options";static isOnboardingTask=!0;static priority=10;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/set-wp-debug";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("wp_debug_status");return!!e&&!0===e.should_fix}catch(e){return console.error("Error checking Debug Display task condition:",e),!1}}async getTaskDetails(e={}){return this.buildTaskDetails(e,{post_title:(0,r.__)("Disable public display of PHP errors","progress-planner")})}});(0,n.nR)(class extends a{static providerId="php-version";static capability="manage_options";static isOnboardingTask=!0;static priority=25;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/update-php-version";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("php_version");return!!e&&this.versionCompare(e,"8.2","<")}catch(e){return console.error("Error checking PHP version task condition:",e),!1}}versionCompare(e,t,s){const r=e.split(".").map(Number),a=t.split(".").map(Number);for(;r.length
a[e]){i=1;break}}switch(s){case"<":return i<0;case"<=":return i<=0;case">":return i>0;case">=":return i>=0;case"==":return 0===i;default:return!1}}async getTaskDetails(e={}){return this.buildTaskDetails(e,{post_title:"Update PHP version"})}});(0,n.nR)(class extends i{static providerId="sending-email";static capability="manage_options";static isOnboardingTask=!1;static priority=4;static points=1;static isDismissable=!0;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/check-if-your-websites-email-system-works";static popoverId="sending-email";async shouldAddTask(e={}){return!0}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Check if your website's email system works","progress-planner"),url:this.buildAdminUrl("admin.php",{page:"progress-planner"})});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Test email sending","progress-planner")}});(0,n.nR)(class extends i{static providerId="disable-comments";static capability="manage_options";static isOnboardingTask=!0;static priority=9;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/disable-comments";static popoverId="disable-comments";async shouldAddTask(e={}){try{const e=await(0,l.BJ)({path:"/wp/v2/settings"});return"open"===(e?.default_comment_status||"open")}catch(e){return console.error("Error checking Disable Comments task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Disable comments","progress-planner"),url:this.buildAdminUrl("options-discussion.php"),link_setting:{hook:"options-discussion.php",iconEl:'label[for="default_comment_status"]'}});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Disable comments","progress-planner")}});(0,n.nR)(class extends i{static providerId="disable-comment-pagination";static capability="manage_options";static isOnboardingTask=!0;static priority=10;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/disable-comment-pagination";static popoverId="disable-comment-pagination";async shouldAddTask(e={}){try{const e=await(0,l.BJ)({path:"/wp/v2/settings"});return!0===e?.page_comments}catch(e){return console.error("Error checking Disable Comment Pagination task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Disable comment pagination","progress-planner"),url:this.buildAdminUrl("options-discussion.php"),link_setting:{hook:"options-discussion.php",iconEl:'label[for="page_comments"]'}});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Disable pagination","progress-planner")}});(0,n.nR)(class extends i{static providerId="improve-pdf-handling";static capability="manage_options";static isOnboardingTask=!1;static priority=1;static points=1;static isDismissable=!0;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/improve-pdf-handling";static popoverId="improve-pdf-handling";async shouldAddTask(e={}){return!0}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Improve PDF handling","progress-planner"),url:this.buildAdminUrl("admin.php",{page:"progress-planner"})});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Improve PDF handling","progress-planner")}});(0,n.nR)(class extends i{static providerId="reduce-autoloaded-options";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!0;static isSnoozable=!0;static popoverId="reduce-autoloaded-options";async shouldAddTask(e={}){return!1}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Reduce number of autoloaded options","progress-planner"),url:this.buildAdminUrl("plugin-install.php",{tab:"search",s:"aaa option optimizer"})});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Reduce","progress-planner")}});(0,n.nR)(class extends a{static providerId="user";static capability="edit_posts";static isOnboardingTask=!1;static priority=999;static points=0;static isDismissable=!0;static isSnoozable=!1;static isRepetitive=!1;static externalLinkUrl="";async shouldAddTask(e={}){return!1}async getTaskDetails(e={}){return this.buildTaskDetails(e,{post_title:e.title?.rendered||e.title||"",description:e.content?.rendered||"",points:this.getPoints(e)})}getPoints(e={}){var t;return("string"==typeof e.excerpt?e.excerpt:null!==(t=e.excerpt?.rendered)&&void 0!==t?t:"").includes("GOLDEN")?1:0}addTaskActions(e={},t=[]){return t.push({type:"link",priority:10,href:"#",label:(0,r.__)("Edit","progress-planner"),inlineEdit:!0}),t}});class d extends i{static providerId="yoast-author-archive";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/yoast-author-archive";static popoverId="yoast-author-archive";static MINIMUM_AUTHOR_WITH_POSTS=1;async shouldAddTask(e={}){try{const e=await(0,o.OJ)("yoast_options");return!!e&&(!(await(0,o.OJ)("post_author_count")>d.MINIMUM_AUTHOR_WITH_POSTS)&&!0!==e.wpseo_titles?.["disable-author"])}catch(e){return console.error("Error checking Yoast Archive Author task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Yoast SEO: disable the author archive","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_page_settings#/author-archives")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Disable","progress-planner")}getFocusTasks(){return[{iconElement:".yst-toggle-field__header",valueElement:{elementSelector:'button[data-id="input-wpseo_titles-disable-author"]',attributeName:"aria-checked",attributeValue:"false",operator:"="}}]}}(0,n.nR)(d);(0,n.nR)(class extends i{static providerId="yoast-date-archive";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/yoast-date-archive";static popoverId="yoast-date-archive";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("yoast_options");return!!e&&(!await(0,o.OJ)("permalink_has_date")&&!0!==e.wpseo_titles?.["disable-date"])}catch(e){return console.error("Error checking Yoast Archive Date task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Yoast SEO: disable the date archive","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_page_settings#/date-archives")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Disable","progress-planner")}getFocusTasks(){return[{iconElement:".yst-toggle-field__header",valueElement:{elementSelector:'button[data-id="input-wpseo_titles-disable-date"]',attributeName:"aria-checked",attributeValue:"false",operator:"="}}]}});class u extends i{static providerId="yoast-format-archive";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/yoast-format-archive";static popoverId="yoast-format-archive";static MINIMUM_POSTS_WITH_FORMAT=3;async shouldAddTask(e={}){try{const e=await(0,o.OJ)("yoast_options");return!!e&&(!(await(0,o.OJ)("archive_format_count")>u.MINIMUM_POSTS_WITH_FORMAT)&&!0!==e.wpseo_titles?.["disable-post_format"])}catch(e){return console.error("Error checking Yoast Archive Format task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Yoast SEO: disable the format archives","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_page_settings#/format-archives")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Disable","progress-planner")}getFocusTasks(){return[{iconElement:".yst-toggle-field__header",valueElement:{elementSelector:'button[data-id="input-wpseo_titles-disable-post_format"]',attributeName:"aria-checked",attributeValue:"false",operator:"="}}]}}(0,n.nR)(u);(0,n.nR)(class extends i{static providerId="yoast-media-pages";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/yoast-media-pages";static popoverId="yoast-media-pages";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("yoast_options");return!!e&&!0!==e.wpseo_titles?.["disable-attachment"]}catch(e){return console.error("Error checking Yoast Media Pages task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Yoast SEO: disable the media pages","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_page_settings#/media-pages")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Disable","progress-planner")}getFocusTasks(){return[{iconElement:".yst-toggle-field__header",valueElement:{elementSelector:'button[data-id="input-wpseo_titles-disable-attachment"]',attributeName:"aria-checked",attributeValue:"false",operator:"="}}]}});(0,n.nR)(class extends i{static providerId="yoast-crawl-settings-emoji-scripts";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/yoast-crawl-optimization-emoji-scripts";static popoverId="yoast-crawl-settings-emoji-scripts";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("yoast_options");return!!e&&!e.wpseo?.remove_emoji_scripts}catch(e){return console.error("Error checking Yoast Crawl Emoji Scripts task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Yoast SEO: remove emoji scripts","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_page_settings#/crawl-optimization#input-wpseo-remove_emoji_scripts")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Remove","progress-planner")}getFocusTasks(){return[{iconElement:".yst-toggle-field__header",valueElement:{elementSelector:'button[data-id="input-wpseo-remove_emoji_scripts"]',attributeName:"aria-checked",attributeValue:"true",operator:"="}}]}});class h extends i{static providerId="yoast-crawl-settings-feed-authors";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/yoast-crawl-optimization-feed-authors";static popoverId="yoast-crawl-settings-feed-authors";static MINIMUM_AUTHOR_WITH_POSTS=1;async shouldAddTask(e={}){try{const e=await(0,o.OJ)("yoast_options");return!!e&&!(await(0,o.OJ)("post_author_count")>h.MINIMUM_AUTHOR_WITH_POSTS||e.wpseo?.remove_feed_authors)}catch(e){return console.error("Error checking Yoast Crawl Feed Authors task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Yoast SEO: remove post authors feeds","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_page_settings#/crawl-optimization#input-wpseo-remove_feed_authors")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Remove","progress-planner")}getFocusTasks(){return[{iconElement:".yst-toggle-field__header",valueElement:{elementSelector:'button[data-id="input-wpseo-remove_feed_authors"]',attributeName:"aria-checked",attributeValue:"true",operator:"="}}]}}(0,n.nR)(h);(0,n.nR)(class extends i{static providerId="yoast-crawl-settings-feed-global-comments";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/yoast-crawl-optimization-feed-global-comments";static popoverId="yoast-crawl-settings-feed-global-comments";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("yoast_options");return!!e&&!e.wpseo?.remove_feed_global_comments}catch(e){return console.error("Error checking Yoast Crawl Feed Comments task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("Yoast SEO: remove global comment feeds","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_page_settings#/crawl-optimization#input-wpseo-remove_feed_global_comments")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Remove","progress-planner")}getFocusTasks(){return[{iconElement:".yst-toggle-field__header",valueElement:{elementSelector:'button[data-id="input-wpseo-remove_feed_global_comments"]',attributeName:"aria-checked",attributeValue:"true",operator:"="}}]}});(0,n.nR)(class extends i{static providerId="yoast-organization-logo";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/yoast-organization-logo";static popoverId="yoast-organization-logo";isPersonMode=!1;checkIsPersonMode(e){return"person"===e?.wpseo_titles?.company_or_person||"person"===e?.wpseo?.company_or_person}async shouldAddTask(e={}){try{const e=await(0,o.OJ)("yoast_options");return!(!e||e.site_logo||(this.isPersonMode=this.checkIsPersonMode(e),this.isPersonMode&&e.wpseo_titles?.person_logo||!this.isPersonMode&&e.wpseo_titles?.company_logo))}catch(e){return console.error("Error checking Yoast Organization Logo task condition:",e),!1}}async getTaskDetails(e={}){const t=await(0,o.OJ)("yoast_options");this.isPersonMode=this.checkIsPersonMode(t);const s=this.isPersonMode?(0,r.__)("Yoast SEO: set your person logo","progress-planner"):(0,r.__)("Yoast SEO: set your organization logo","progress-planner"),a=this.buildTaskDetails(e,{post_title:s,url:this.buildAdminUrl("admin.php?page=wpseo_page_settings#/site-representation")});return this.addPopoverIdToTaskDetails(a)}getExternalLinkUrl(){return this.isPersonMode?"https://prpl.fyi/yoast-person-logo":"https://prpl.fyi/yoast-organization-logo"}getPopoverActionLabel(){return(0,r.__)("Set logo","progress-planner")}getFocusTasks(){return[{iconElement:"legend.yst-label",valueElement:{elementSelector:'input[name="wpseo_titles.company_logo"]',attributeName:"value",attributeValue:"",operator:"!="}},{iconElement:"legend.yst-label",valueElement:{elementSelector:'input[name="wpseo_titles.person_logo"]',attributeName:"value",attributeValue:"",operator:"!="}}]}});(0,n.nR)(class extends a{static providerId="yoast-cornerstone-workout";static capability="edit_others_posts";static isOnboardingTask=!1;static priority=20;static points=3;static isDismissable=!0;static isSnoozable=!0;static isRepetitive=!0;static externalLinkUrl="https://prpl.fyi/run-cornerstone-content-workout";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("yoast_premium_status");return!!e?.active}catch(e){return console.error("Error checking Yoast Cornerstone Workout task condition:",e),!1}}async getTaskDetails(e={}){return this.buildTaskDetails(e,{post_title:(0,r.__)("Yoast SEO: do Yoast SEO's Cornerstone Content Workout","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_workouts#cornerstone")})}addTaskActions(e,t){return t.push({type:"link",priority:10,label:(0,r.__)("Run workout","progress-planner"),href:this.buildAdminUrl("admin.php?page=wpseo_workouts#cornerstone"),target:"_self"}),t}});(0,n.nR)(class extends a{static providerId="yoast-orphaned-content-workout";static capability="edit_others_posts";static isOnboardingTask=!1;static priority=20;static points=3;static isDismissable=!0;static isSnoozable=!0;static isRepetitive=!0;static externalLinkUrl="https://prpl.fyi/run-orphaned-content-workout";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("yoast_premium_status");return!!e?.active}catch(e){return console.error("Error checking Yoast Orphaned Content Workout task condition:",e),!1}}async getTaskDetails(e={}){return this.buildTaskDetails(e,{post_title:(0,r.__)("Yoast SEO: do Yoast SEO's Orphaned Content Workout","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_workouts#orphaned")})}addTaskActions(e,t){return t.push({type:"link",priority:10,label:(0,r.__)("Run workout","progress-planner"),href:this.buildAdminUrl("admin.php?page=wpseo_workouts#orphaned"),target:"_self"}),t}});(0,n.nR)(class extends a{static providerId="yoast-fix-orphaned-content";static capability="edit_others_posts";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!0;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/fix-orphaned-content";static isMultiTask=!0;async shouldAddTask(e={}){try{const e=await this.getTasksToInject();return e&&e.length>0}catch(e){return console.error("Error checking Yoast Fix Orphaned Content task condition:",e),!1}}async getTasksToInject(){try{const e=await(0,o.OJ)("yoast_orphaned_content");if(!e)return[];const t=Array.isArray(e)?e:[e];return 0===t.length?[]:t.map(e=>({target_post_id:e.ID||e.id||e.post_id,target_post_title:e.post_title||e.title||""}))}catch(e){return console.error("Error getting tasks to inject for Yoast Fix Orphaned Content:",e),[]}}async getTaskDetails(e={}){const t=e?.target_post_id||null,s=e?.target_post_title||"";if(!t)throw new Error("YoastFixOrphanedContentTask requires target_post_id in taskData");return this.buildTaskDetails(e,{post_title:(0,r.sprintf)(/* translators: %s: Post title. */ /* translators: %s: Post title. */
+(0,r.__)('Yoast SEO: add internal links to article "%s"!',"progress-planner"),s),url:this.buildAdminUrl("post.php",{post:t,action:"edit"}),url_target:"_blank",target_post_id:t,target_post_title:s})}addTaskActions(e,t){return t.push({type:"link",priority:10,label:(0,r.__)("Learn more about internal linking","progress-planner"),href:"https://prpl.fyi/fix-orphaned-content",target:"_blank"}),t}});(0,n.nR)(class extends a{static providerId="aioseo-organization-logo";static capability="manage_options";static isOnboardingTask=!1;static priority=20;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/aioseo-organization-logo";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("aioseo_options");return!!e&&"person"!==e.schema?.siteRepresents&&""===e.schema?.organizationLogo}catch(e){return console.error("Error checking AIOSEO Organization Logo task condition:",e),!1}}async getTaskDetails(e={}){return this.buildTaskDetails(e,{post_title:(0,r.__)("All in One SEO: set your organization logo","progress-planner"),url:this.buildAdminUrl("admin.php?page=aioseo-search-appearance#/")})}addTaskActions(e,t){return t.push({type:"link",priority:10,label:(0,r.__)("Set logo","progress-planner"),href:this.buildAdminUrl("admin.php?page=aioseo-search-appearance#/"),target:"_self"}),t}});class g extends i{static providerId="aioseo-author-archive";static capability="manage_options";static isOnboardingTask=!1;static priority=20;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/aioseo-author-archive";static popoverId="aioseo-author-archive";static MINIMUM_AUTHOR_WITH_POSTS=1;async shouldAddTask(e={}){try{const e=await(0,o.OJ)("aioseo_options");return!!e&&(!(await(0,o.OJ)("post_author_count")>g.MINIMUM_AUTHOR_WITH_POSTS)&&!0===e.archives?.author?.show)}catch(e){return console.error("Error checking AIOSEO Archive Author task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("All in One SEO: noindex the author archive","progress-planner"),url:this.buildAdminUrl("admin.php?page=aioseo-search-appearance#/archives")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Noindex","progress-planner")}}(0,n.nR)(g);(0,n.nR)(class extends i{static providerId="aioseo-date-archive";static capability="manage_options";static isOnboardingTask=!1;static priority=20;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/aioseo-date-archive";static popoverId="aioseo-date-archive";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("aioseo_options");return!!e&&(!await(0,o.OJ)("permalink_has_date")&&!0===e.archives?.date?.show)}catch(e){return console.error("Error checking AIOSEO Archive Date task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("All in One SEO: noindex the date archive","progress-planner"),url:this.buildAdminUrl("admin.php?page=aioseo-search-appearance#/archives")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Noindex","progress-planner")}});(0,n.nR)(class extends i{static providerId="aioseo-media-pages";static capability="manage_options";static isOnboardingTask=!1;static priority=20;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/aioseo-media-pages";static popoverId="aioseo-media-pages";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("aioseo_options");return!!e&&"attachment"!==e.attachment?.redirectAttachmentUrls}catch(e){return console.error("Error checking AIOSEO Media Pages task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("All in One SEO: redirect media/attachment pages to attachment","progress-planner"),url:this.buildAdminUrl("admin.php?page=aioseo-search-appearance#/media")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Redirect","progress-planner")}});class m extends i{static providerId="aioseo-crawl-settings-feed-authors";static capability="manage_options";static isOnboardingTask=!1;static priority=20;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/aioseo-crawl-optimization-feed-authors";static popoverId="aioseo-crawl-settings-feed-authors";static MINIMUM_AUTHOR_WITH_POSTS=1;async shouldAddTask(e={}){try{const e=await(0,o.OJ)("aioseo_options");return!!e&&(!(await(0,o.OJ)("post_author_count")>m.MINIMUM_AUTHOR_WITH_POSTS)&&!1!==e.crawlCleanup?.feeds?.authors)}catch(e){return console.error("Error checking AIOSEO Crawl Feed Authors task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("All in One SEO: disable author RSS feeds","progress-planner"),url:this.buildAdminUrl("admin.php?page=aioseo-search-appearance#/advanced")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Disable","progress-planner")}}(0,n.nR)(m);(0,n.nR)(class extends i{static providerId="aioseo-crawl-settings-feed-comments";static capability="manage_options";static isOnboardingTask=!1;static priority=20;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/aioseo-crawl-optimization-feed-comments";static popoverId="aioseo-crawl-settings-feed-comments";async shouldAddTask(e={}){try{const e=await(0,o.OJ)("aioseo_options");if(!e)return!1;const t=e.crawlCleanup?.feeds?.globalComments,s=e.crawlCleanup?.feeds?.postComments;return!1!==t||!1!==s}catch(e){return console.error("Error checking AIOSEO Crawl Feed Comments task condition:",e),!1}}async getTaskDetails(e={}){const t=this.buildTaskDetails(e,{post_title:(0,r.__)("All in One SEO: disable comment RSS feeds","progress-planner"),url:this.buildAdminUrl("admin.php?page=aioseo-search-appearance#/advanced")});return this.addPopoverIdToTaskDetails(t)}getPopoverActionLabel(){return(0,r.__)("Disable","progress-planner")}})},790:e=>{e.exports=window.ReactJSXRuntime},1362:(e,t,s)=>{s.d(t,{Cu:()=>i,cr:()=>n});var r=s(2619);const a=[];function i(e){const{id:t,component:s,priority:r=10,width:i=1,forceLastColumn:n=!1,title:o=""}=e;if(!t||!s)return void console.warn("Widget registration failed: id and component are required",e);const l=a.findIndex(e=>e.id===t),p={id:t,component:s,priority:r,width:i,forceLastColumn:n,title:o};l>=0?a[l]=p:a.push(p)}function n(){return[...a].sort((e,t)=>e.priority-t.priority)}(0,r.addAction)("prpl.dashboard.registerWidget","progress-planner/widget-registry",i)},1455:e=>{e.exports=window.wp.apiFetch},1831:(e,t,s)=>{var r=s(1455),a=s.n(r),i=s(6087),n=s(7723),o=s(8864),l=s(790);function p({config:e}){const{licenseKey:t,branding:s={},rangeOptions:r=[],frequencyOptions:a=[]}=e,[o,p]=(0,i.useState)(e.currentRange||"-6 months"),[c,d]=(0,i.useState)(e.currentFrequency||"monthly");return(0,l.jsxs)("div",{className:"prpl-header",style:{marginBottom:"2rem",display:"flex",flexWrap:"wrap",justifyContent:"space-between",alignItems:"center"},children:[(0,l.jsx)("div",{className:"prpl-header-logo",children:s.logoHtml&&(0,l.jsx)("div",{dangerouslySetInnerHTML:{__html:s.logoHtml}})}),(0,l.jsxs)("div",{className:"prpl-header-right",style:{display:"flex",gap:"var(--prpl-padding)",alignItems:"center"},children:[(0,l.jsxs)("button",{className:"prpl-info-icon",id:"prpl-start-tour-icon-button",type:"button",style:{width:"2rem",height:"2rem",display:"inline-flex",alignItems:"center",justifyContent:"center",padding:"0.4em",color:"var(--prpl-color-ui-icon)",cursor:"pointer",backgroundColor:"#fff",border:"1px solid var(--prpl-color-ui-icon)",borderRadius:"var(--prpl-border-radius)"},onMouseEnter:e=>{e.target.style.color="var(--prpl-color-ui-icon-hover)",e.target.style.borderColor="var(--prpl-color-ui-icon-hover)",e.target.style.backgroundColor="var(--prpl-color-ui-icon-hover-fill)"},onMouseLeave:e=>{e.target.style.color="var(--prpl-color-ui-icon)",e.target.style.borderColor="var(--prpl-color-ui-icon)",e.target.style.backgroundColor="#fff"},children:[s.tourIconHtml&&(0,l.jsx)("span",{dangerouslySetInnerHTML:{__html:s.tourIconHtml}}),(0,l.jsx)("span",{className:"screen-reader-text",children:(0,n.__)("Start tour","progress-planner")})]}),"no-license"===t&&(0,l.jsx)(l.Fragment,{children:(0,l.jsxs)("button",{className:"prpl-info-icon",type:"button",style:{width:"2rem",height:"2rem",display:"inline-flex",alignItems:"center",justifyContent:"center",padding:"0.4em",color:"var(--prpl-color-ui-icon)",cursor:"pointer",backgroundColor:"#fff",border:"1px solid var(--prpl-color-ui-icon)",borderRadius:"var(--prpl-border-radius)"},onMouseEnter:e=>{e.target.style.color="var(--prpl-color-ui-icon-hover)",e.target.style.borderColor="var(--prpl-color-ui-icon-hover)",e.target.style.backgroundColor="var(--prpl-color-ui-icon-hover-fill)"},onMouseLeave:e=>{e.target.style.color="var(--prpl-color-ui-icon)",e.target.style.borderColor="var(--prpl-color-ui-icon)",e.target.style.backgroundColor="#fff"},onClick:()=>{if("undefined"!=typeof wp&&wp.hooks&&wp.hooks.doAction){const e={id:"subscribe-form",slug:"subscribe-form",title:(0,n.__)("Subscribe to weekly emails","progress-planner")};wp.hooks.doAction("prpl.popover.open","subscribe-form",e)}else{const e=document.getElementById("prpl-popover-subscribe-form");e&&"function"==typeof e.showPopover&&e.showPopover()}},children:[s.registerIconHtml&&(0,l.jsx)("span",{dangerouslySetInnerHTML:{__html:s.registerIconHtml}}),(0,l.jsx)("span",{className:"screen-reader-text",children:(0,n.__)("Subscribe","progress-planner")})]})}),(0,l.jsxs)("div",{className:"prpl-header-select-range",children:[(0,l.jsx)("label",{htmlFor:"prpl-select-range",className:"screen-reader-text",children:(0,n.__)("Select range:","progress-planner")}),(0,l.jsx)("select",{id:"prpl-select-range",value:o,onChange:e=>{const t=e.target.value;p(t);const s=new URL(window.location.href);s.searchParams.set("range",t),window.location.href=s.href},children:r.map(e=>(0,l.jsx)("option",{value:e.value,children:e.label},e.value))}),(0,l.jsx)("label",{htmlFor:"prpl-select-frequency",className:"screen-reader-text",children:(0,n.__)("Select frequency:","progress-planner")}),(0,l.jsx)("select",{id:"prpl-select-frequency",value:c,onChange:e=>{const t=e.target.value;d(t);const s=new URL(window.location.href);s.searchParams.set("frequency",t),window.location.href=s.href},children:a.map(e=>(0,l.jsx)("option",{value:e.value,children:e.label},e.value))})]})]})]})}var c=s(2619),d=s(1362);const u={container:{padding:"var(--prpl-padding, 1rem)",backgroundColor:"var(--prpl-background-error, #fef2f2)",borderRadius:"var(--prpl-border-radius, 8px)",border:"1px solid var(--prpl-color-error, #ef4444)"},heading:{margin:"0 0 0.5rem 0",fontSize:"var(--prpl-font-size-medium, 1rem)",color:"var(--prpl-color-error, #ef4444)"},message:{margin:0,fontSize:"var(--prpl-font-size-small, 0.875rem)",color:"var(--prpl-color-text-secondary, #6b7280)"},button:{marginTop:"0.75rem",padding:"0.5rem 1rem",backgroundColor:"var(--prpl-color-primary, #3b82f6)",color:"white",border:"none",borderRadius:"var(--prpl-border-radius-small, 4px)",cursor:"pointer",fontSize:"var(--prpl-font-size-small, 0.875rem)"}};class h extends i.Component{constructor(e){super(e),this.state={hasError:!1,error:null,errorInfo:null}}static getDerivedStateFromError(e){return{hasError:!0,error:e}}componentDidCatch(e,t){console.error("ErrorBoundary caught an error:",e,t),this.setState({errorInfo:t}),this.props.onError&&this.props.onError(e,t)}handleRetry=()=>{this.setState({hasError:!1,error:null,errorInfo:null})};render(){const{hasError:e}=this.state,{children:t,fallback:s}=this.props;return e?s||(0,l.jsxs)("div",{style:u.container,children:[(0,l.jsx)("h4",{style:u.heading,children:(0,n.__)("Something went wrong","progress-planner")}),(0,l.jsx)("p",{style:u.message,children:(0,n.__)("This widget failed to load. Try refreshing the page.","progress-planner")}),(0,l.jsx)("button",{type:"button",style:u.button,onClick:this.handleRetry,children:(0,n.__)("Retry","progress-planner")})]}):t}}function g({id:e,width:t=1,forceLastColumn:s=!1,children:r}){const a={},i={};return"todo"===e&&(a.paddingLeft=0,i.paddingLeft="var(--prpl-padding)"),"badge-streak"!==e&&"badge-streak-content"!==e&&"badge-streak-maintenance"!==e||(a.display="flex",a.flexDirection="column",a.justifyContent="space-between"),(0,l.jsx)("div",{className:`prpl-widget-wrapper prpl-${e} prpl-widget-width-${t}`,"data-force-last-column":s?1:0,style:a,children:(0,l.jsx)("div",{className:"widget-inner-container",style:i,children:r})})}function m(){const[e,t]=(0,i.useState)([]);return(0,i.useEffect)(()=>{t((0,d.cr)()),(0,c.addAction)("prpl.dashboard.registerWidget","progress-planner/dashboard-widgets",()=>{t((0,d.cr)())})},[]),(0,l.jsx)(i.Fragment,{children:e.map(e=>(e=>{const t=e.component;return t?(0,l.jsx)(g,{id:e.id,width:e.width||1,forceLastColumn:e.forceLastColumn||!1,children:(0,l.jsx)(h,{widgetName:e.title,children:(0,l.jsx)(t,{config:{title:e.title}})})},e.id):null})(e))})}async function _({url:e,data:t}){const s=new FormData;for(const[e,r]of Object.entries(t))s.append(e,r);const r=await fetch(e,{method:"POST",body:s,credentials:"same-origin"}),a=await r.text();let i;try{i=JSON.parse(a)}catch(e){if(!r.ok)throw console.warn("Failed to parse response:",r,e),new Error(a||"Request failed");throw e}if(r.ok)return i;throw i}var b=s(8493);function y({onNext:e,canProceed:t=()=>!0,wizardState:s,buttonText:r,buttonClass:a="prpl-btn-primary",isLoading:o=!1,wrapInFooter:p=!0}){const c=(0,i.useRef)(null),d=(0,i.useCallback)(()=>{c.current&&(t(s)?c.current.classList.remove("prpl-btn-disabled"):c.current.classList.add("prpl-btn-disabled"))},[t,s]);(0,i.useEffect)(()=>{d()},[d]);const u=(0,l.jsxs)("div",{className:"prpl-tour-next-wrapper",children:[o&&(0,l.jsx)("span",{className:"spinner",style:{visibility:"visible"}}),(0,l.jsx)("button",{ref:c,type:"button",className:`prpl-btn ${a} prpl-tour-next`,onClick:t=>{(e=>{if(c.current?.classList.contains("prpl-btn-disabled")){e.preventDefault(),e.stopPropagation();const t=document.querySelector(".prpl-privacy-checkbox-wrapper .prpl-required-indicator");t&&t.classList.add("prpl-required-indicator-active")}})(t),c.current?.classList.contains("prpl-btn-disabled")||e()},disabled:o,children:r||(0,l.jsxs)(l.Fragment,{children:[(0,n.__)("Next","progress-planner")," →"]})})]});return p?(0,l.jsx)("div",{className:"tour-footer",children:u}):u}function k({wizardState:e,onNext:t,canProceed:s=()=>!0,buttonText:r,buttonClass:a="prpl-btn-primary",isLoading:i=!1,hideFooter:n=!1,children:o}){return(0,l.jsxs)("div",{className:"onboarding-step",children:[o,!n&&(0,l.jsx)(y,{onNext:t,canProceed:s,wizardState:e,buttonText:r,buttonClass:a,isLoading:i})]})}function v({id:e,name:t,value:s,checked:r,onChange:a,label:i,className:n=""}){return(0,l.jsxs)("label",{htmlFor:e,className:`prpl-custom-checkbox ${n}`.trim(),children:[(0,l.jsx)("input",{type:"checkbox",id:e,name:t,value:s,checked:r,onChange:a}),(0,l.jsx)("span",{className:"prpl-custom-control"}),(0,l.jsx)("span",{className:"prpl-custom-control-text",children:i})]})}function f({id:e,name:t,value:s,checked:r,onChange:a,label:i,className:n=""}){return(0,l.jsxs)("label",{htmlFor:e,className:`prpl-custom-radio ${n}`.trim(),children:[(0,l.jsx)("input",{type:"radio",id:e,name:t,value:s,checked:r,onChange:a}),(0,l.jsx)("span",{className:"prpl-custom-control"}),(0,l.jsx)("span",{className:"prpl-custom-control-text",children:i})]})}s(714);var x=s(9061);function w({id:e,name:t,value:s,checked:r,onChange:a,label:i,className:n=""}){return(0,l.jsx)("div",{className:`prpl-post-type-toggle-wrapper ${n}`.trim(),children:(0,l.jsxs)("label",{htmlFor:e,className:"prpl-post-type-toggle-label",children:[(0,l.jsx)("input",{type:"checkbox",id:e,name:t,value:s,checked:r,onChange:a,className:"prpl-post-type-toggle-input"}),(0,l.jsxs)("span",{className:"prpl-post-type-toggle-switch",children:[(0,l.jsx)(x.A,{name:"check",className:"prpl-toggle-icon-check"}),(0,l.jsx)(x.A,{name:"close",className:"prpl-toggle-icon-x"})]}),(0,l.jsx)("span",{className:"prpl-post-type-toggle-text",children:i})]})})}function T(e){const{wizardState:t,updateState:s,config:r}=e,{onboardNonceURL:a,onboardAPIUrl:o,ajaxUrl:p,nonce:c,site:d,timezoneOffset:u,hasLicense:h,l10n:g,baseUrl:m,privacyPolicyUrl:b}=r,{generateLicense:f,isGenerating:x}=function({onboardNonceURL:e,onboardAPIUrl:t,ajaxUrl:s,nonce:r,siteUrl:a,timezoneOffset:n}){const[o,l]=(0,i.useState)(!1),[p,c]=(0,i.useState)(null);return{generateLicense:(0,i.useCallback)(async(i={})=>{l(!0),c(null);try{const o=new FormData;o.append("site",a);const l=await fetch(e,{method:"POST",body:o}).then(e=>e.json());if("ok"!==l.status)throw new Error("Failed to get nonce");const p=new FormData;p.append("nonce",l.nonce),p.append("site",a),p.append("timezone_offset",n.toString()),Object.entries(i).forEach(([e,t])=>{p.append(e,t)});const c=await fetch(t,{method:"POST",body:p}).then(e=>e.json());if(!c.license_key)throw new Error("Failed to generate license");return await _({url:s,data:{action:"progress_planner_save_onboard_data",_ajax_nonce:r,key:c.license_key}}),c.license_key}catch(e){throw c(e.message||"Failed to generate license"),e}finally{l(!1)}},[e,t,s,r,a,n]),isGenerating:o,error:p}}({onboardNonceURL:a,onboardAPIUrl:o,ajaxUrl:p,nonce:c,siteUrl:d,timezoneOffset:u}),[w,T]=(0,i.useState)(t.data.privacyAccepted||!1);return(0,i.useEffect)(()=>{s({data:{...t.data,privacyAccepted:w}})},[w]),(0,l.jsx)(k,{...e,hideFooter:!0,children:(0,l.jsx)("div",{className:"tour-content",children:(0,l.jsxs)("div",{className:"prpl-columns-wrapper-flex prpl-columns-2-1",children:[(0,l.jsxs)("div",{className:"prpl-column",children:[(0,l.jsxs)("div",{className:"prpl-background-content",children:[(0,l.jsx)("h3",{className:"tour-title",children:(0,n.__)("Hi there! Ready to push your website forward? Let's go!","progress-planner")}),(0,l.jsx)("p",{children:(0,n.sprintf)(/* translators: %s: Progress Planner name */ /* translators: %s: Progress Planner name */
+(0,n.__)("%s helps you set clear, focused goals for your website. Let's go through a few simple steps to get everything set up.","progress-planner"),g?.brandingName||"Progress Planner")}),(0,l.jsx)("p",{children:(0,n.__)("This will only take a few minutes.","progress-planner")})]}),!h&&(0,l.jsx)("div",{className:"prpl-privacy-checkbox-wrapper",children:(0,l.jsx)(v,{id:"prpl-privacy-checkbox",checked:w,onChange:e=>{T(e.target.checked);const t=document.querySelector(".prpl-privacy-checkbox-wrapper .prpl-required-indicator");t&&t.classList.remove("prpl-required-indicator-active")},label:(0,l.jsxs)(l.Fragment,{children:[(0,n.__)("I accept the","progress-planner")," ",(0,l.jsx)("a",{href:b||"https://progressplanner.com/privacy-policy/#h-plugin-privacy-policy",target:"_blank",rel:"noopener noreferrer",children:(0,n.__)("privacy policy","progress-planner")})," ",(0,n.__)("and the essential data processing needed for the plugin.","progress-planner")," ",(0,l.jsx)("span",{className:"prpl-required-indicator",children:(0,n.__)("Required","progress-planner")})]})})}),(0,l.jsx)(y,{onNext:async()=>{if(!h&&w)try{await f({"with-email":"no"})}catch(e){return void console.error("Failed to generate license:",e)}e.onNext()},canProceed:()=>!!h||w,wizardState:t,isLoading:x,buttonText:(0,l.jsxs)(l.Fragment,{children:[(0,n.__)("Start onboarding","progress-planner"),(0,l.jsx)("span",{className:"dashicons dashicons-arrow-right-alt2"})]}),buttonClass:"prpl-btn-secondary"})]}),(0,l.jsx)("div",{className:"prpl-column prpl-hide-on-mobile",children:(0,l.jsx)("div",{id:"prpl-welcome-graphic",children:(0,l.jsx)("img",{src:`${m||""}/assets/images/onboarding/thumbs_up_ravi_rtl.svg`,alt:""})})})]})})})}function j(e){return(0,l.jsx)(k,{...e,canProceed:()=>!0,children:(0,l.jsx)("div",{className:"tour-content",children:(0,l.jsxs)("div",{className:"prpl-columns-wrapper-flex",children:[(0,l.jsx)("div",{className:"prpl-column",children:(0,l.jsxs)("div",{className:"prpl-background-content",children:[(0,l.jsx)("h3",{children:(0,n.__)("Recommendations","progress-planner")}),(0,l.jsx)("p",{children:(0,n.__)("Tasks that show you what to work on next.","progress-planner")}),(0,l.jsx)("p",{children:(0,n.__)("These actions help you improve your site step by step, without having to guess where to start. Most recommendations can be completed in under five minutes.","progress-planner")})]})}),(0,l.jsx)("div",{className:"prpl-column",children:(0,l.jsxs)("div",{className:"prpl-background-content",children:[(0,l.jsx)("h3",{children:(0,n.__)("Badges","progress-planner")}),(0,l.jsxs)("p",{children:[(0,l.jsx)("span",{className:"prpl-suggested-task-points",children:"+1"})," ",(0,n.__)("You earn points for every completed task.","progress-planner")]}),(0,l.jsx)("p",{children:(0,n.__)("Collect badges as you make progress, which keeps things fun and helps you stay motivated!","progress-planner")})]})})]})})})}function S({ajaxUrl:e,nonce:t}){const[s,r]=(0,i.useState)(!1),[a,n]=(0,i.useState)(null);return{completeTask:(0,i.useCallback)(async(s,a={})=>{r(!0),n(null);try{const r=await _({url:e,data:{action:"progress_planner_onboarding_complete_task",nonce:t,task_id:s,form_values:JSON.stringify(a)}});if(r.success)return r;throw new Error(r.data?.message||"Failed to complete task")}catch(e){throw n(e.message||"Failed to complete task"),e}finally{r(!1)}},[e,t]),isCompleting:s,error:a}}const I={"core-blogdescription":function({task:e}){return(0,l.jsxs)("div",{className:"prpl-onboarding-task",children:[(0,l.jsxs)("div",{children:[(0,l.jsx)("h3",{className:"prpl-onboarding-task-title",children:e.title}),(0,l.jsx)("p",{children:(0,n.__)("In a few words, explain what this site is about. This information is used in your website's schema and RSS feeds, and can be displayed on your site. The tagline typically is your site's mission statement.","progress-planner")})]}),(0,l.jsx)("input",{type:"text",name:"blogdescription",defaultValue:e.site_description||"",placeholder:(0,n.__)("A catchy phrase to describe your website","progress-planner")})]})},"core-siteicon":function({task:e}){return(0,l.jsxs)("div",{className:"prpl-onboarding-task",children:[(0,l.jsx)("h3",{className:"prpl-onboarding-task-title",children:e.title}),(0,l.jsx)("p",{children:(0,n.__)("Upload an image to make your site stand out.","progress-planner")}),(0,l.jsxs)("div",{className:"prpl-file-drop-zone","data-upload-field":"",children:[(0,l.jsx)("span",{className:"prpl-icon-image",children:(0,l.jsx)("img",{src:(window.prplDashboardConfig?.baseUrl||"")+"/assets/images/onboarding/icon_image.svg",alt:""})}),(0,l.jsxs)("p",{children:[(0,n.__)("Drag and drop a file here or","progress-planner")," ",(0,l.jsx)("label",{htmlFor:`prpl-file-input-${e.task_id}`,className:"prpl-file-browse-link",children:(0,n.__)("upload a file","progress-planner")}),(0,l.jsxs)("span",{className:"prpl-file-upload-hints",children:[(0,l.jsx)("span",{className:"prpl-file-upload-hint prpl-file-upload-hint-dimensions",children:(0,n.__)("Recommended dimensions: 512 x 521 pixels","progress-planner")}),(0,l.jsx)("span",{className:"prpl-file-upload-hint prpl-file-upload-hint-type",children:"PNG, ICO, WEBP"})]})]}),(0,l.jsx)("input",{type:"file",id:`prpl-file-input-${e.task_id}`,"data-task-id":e.task_id,accept:".ico,.png,.jpg,.jpeg,.gif,.webp",hidden:!0}),(0,l.jsx)("input",{type:"hidden",name:"post_id",defaultValue:"","data-validate":"required"}),(0,l.jsx)("div",{className:"prpl-upload-status"}),(0,l.jsx)("div",{className:"prpl-file-preview"}),(0,l.jsx)("button",{type:"button",className:"prpl-file-remove-btn",hidden:!0,children:(0,n.__)("Remove icon","progress-planner")})]})]})},"select-locale":function({task:e}){const[t,s]=(0,i.useState)([]);return(0,i.useEffect)(()=>{a()({path:"/progress-planner/v1/locale-options"}).then(e=>{s(e)})},[]),(0,l.jsxs)("div",{className:"prpl-onboarding-task",children:[(0,l.jsx)("h3",{className:"prpl-onboarding-task-title",children:e.title}),(0,l.jsx)("p",{children:(0,n.__)("Your locale determines the language and formatting your visitors see, such as date structures and currency. Setting this helps your audience feel right at home. Choose your preferred language and region.","progress-planner")}),(0,l.jsx)("select",{name:"WPLANG",children:t.map(e=>(0,l.jsx)("option",{value:e.value,children:e.label},e.value))})]})},"select-timezone":function({task:e}){const[t,s]=(0,i.useState)([]);return(0,i.useEffect)(()=>{a()({path:"/progress-planner/v1/timezone-options"}).then(e=>{s(e)})},[]),(0,l.jsxs)("div",{className:"prpl-onboarding-task",children:[(0,l.jsx)("h3",{className:"prpl-onboarding-task-title",children:e.title}),(0,l.jsx)("p",{children:(0,n.__)("Setting your timezone ensures that scheduled posts and automated updates happen exactly when you expect them to. It keeps your site's clock synced with your local time. Pick your city or offset now!","progress-planner")}),(0,l.jsx)("select",{name:"timezone_string","data-validate":"required",children:t.map(e=>(0,l.jsx)("option",{value:e.value,children:e.label},e.value))})]})}};function D(e){const{wizardState:t,updateState:s,onNext:r,stepData:a,config:o}=e,{ajaxUrl:p,nonce:c}=o,d=o?.l10n?.brandingName||(0,n.__)("Progress Planner","progress-planner"),{completeTask:u}=S({ajaxUrl:p,nonce:c}),[h,g]=(0,i.useState)(!1),m=(0,i.useRef)(null),_=a?.data?.task,b=_?.task_id?I[_.task_id]:null,y=async(e,a={})=>{if(e&&!h){g(!0);try{await u(e,a),s({data:{...t.data,firstTaskCompleted:!0}}),r()}catch(e){console.error("Failed to complete task:",e),g(!1)}}};return(0,i.useEffect)(()=>{if(b)return;if(!m.current)return;const e=m.current.querySelector(".prpl-complete-task-btn");if(!e)return;const t=e=>{e.preventDefault();const t=e.target.closest("button"),s=t?.dataset?.taskId||_?.task_id,r=t?.closest("form");let a={};if(r){const e=new FormData(r);a=Object.fromEntries(e.entries())}y(s,a)};return e.addEventListener("click",t),()=>{e.removeEventListener("click",t)}},[_,b]),(0,i.useEffect)(()=>{_||r()},[_]),_?(0,l.jsx)("div",{className:"onboarding-step",children:(0,l.jsx)("div",{className:"tour-content",children:(0,l.jsxs)("div",{className:"prpl-columns-wrapper-flex",children:[(0,l.jsx)("div",{className:"prpl-column",children:(0,l.jsxs)("div",{className:"prpl-background-content",children:[(0,l.jsx)("h3",{children:(0,n.__)("Ready for your first task and your first point?","progress-planner")}),(0,l.jsx)("p",{children:(0,n.sprintf)(/* translators: %s: Progress Planner name */ /* translators: %s: Progress Planner name */
+(0,n.__)("This is an example of a recommendation in %s. It's a task that helps improve your website. Most recommendations can be completed in under five minutes. Once you've completed a recommendation, we'll celebrate your success together and provide you with a new recommendation.","progress-planner"),d)}),(0,l.jsx)("p",{children:(0,n.__)("Let's give it a try!","progress-planner")})]})}),(0,l.jsx)("div",{className:"prpl-column",ref:m,children:b?(0,l.jsxs)("form",{className:"prpl-onboarding-task-form",onSubmit:e=>{e.preventDefault();const t=new FormData(e.target),s=Object.fromEntries(t.entries());y(_.task_id,s)},children:[(0,l.jsx)(b,{task:_}),(0,l.jsxs)("button",{type:"submit",className:"prpl-complete-task-btn prpl-btn prpl-btn-secondary","data-task-id":_.task_id,disabled:h,children:[h?(0,n.__)("Completing…","progress-planner"):_.action_label||(0,n.__)("Mark as complete","progress-planner"),(0,l.jsx)("span",{className:"dashicons dashicons-arrow-right-alt2"})]})]}):_.template_html?(0,l.jsx)("div",{dangerouslySetInnerHTML:{__html:_.template_html}}):(0,l.jsxs)("div",{className:"prpl-first-task-content",children:[_.title&&(0,l.jsx)("h4",{children:_.title}),(0,l.jsx)("button",{type:"button",className:"prpl-complete-task-btn prpl-btn prpl-btn-secondary","data-task-id":_.task_id,disabled:h,children:h?(0,n.__)("Completing…","progress-planner"):_.action_label||(0,n.__)("Mark as complete","progress-planner")})]})})]})})}):null}var A=s(475),P=s(3971);function N(e){const{wizardState:t,stepData:s}=e,r=(0,i.useMemo)(()=>s?.data||{},[s?.data]),a=r.currentValue||0,[o,p]=(0,i.useState)(a);return(0,i.useEffect)(()=>{if(t.data.firstTaskCompleted&&r.badgeId){const e=setTimeout(()=>{p(e=>e+1)},1500);return()=>clearTimeout(e)}},[t.data.firstTaskCompleted,r.badgeId]),(0,l.jsx)(k,{...e,canProceed:()=>!0,buttonText:(0,n.__)("Got it","progress-planner"),buttonClass:"prpl-btn-secondary",children:(0,l.jsx)("div",{className:"tour-content",children:(0,l.jsxs)("div",{className:"prpl-columns-wrapper-flex prpl-columns-2-1",children:[(0,l.jsx)("div",{className:"prpl-column",children:(0,l.jsxs)("div",{className:"prpl-background-content",children:[(0,l.jsx)("h3",{children:(0,n.__)("Whoohoo, nice one! You just earned your first point!","progress-planner")}),(0,l.jsx)("p",{children:(0,n.__)("Gather ten points this month to unlock your special badge.","progress-planner")}),(0,l.jsx)("p",{children:(0,n.__)("You're off to a great start!","progress-planner")})]})}),(0,l.jsx)("div",{className:"prpl-column",children:(0,l.jsxs)("div",{className:"prpl-gauge-wrapper",children:[r.badgeId&&r.badgeName?(0,l.jsx)(A.A,{value:o,max:r.maxPoints||10,backgroundColor:"#fff",color:"var(--prpl-color-monthly)",color2:"var(--prpl-color-monthly)",contentFontSize:"3rem",children:(0,l.jsx)(P.A,{badgeId:r.badgeId,badgeName:r.badgeName,brandingId:r.brandingId||0,isComplete:!0})}):(0,l.jsx)(A.A,{value:o,max:10,backgroundColor:"#fff",color:"var(--prpl-color-monthly)",color2:"var(--prpl-color-monthly)",contentFontSize:"3rem",children:o}),(0,l.jsx)("p",{style:{textAlign:"center",marginTop:"0"},children:(0,n.__)("Monthly badge","progress-planner")})]})})]})})})}function E(e){const{wizardState:t,updateState:s,config:r,onNext:o}=e,{userFirstName:p="",userEmail:c="",site:d,timezoneOffset:u}=r,[h,g]=(0,i.useState)(()=>{const e=t.data.emailFrequency;return{choice:e?.choice||"weekly",name:e?.name||p,email:e?.email||c}}),[m,_]=(0,i.useState)(!1),[b,y]=(0,i.useState)(null);return(0,i.useEffect)(()=>{s({data:{...t.data,emailFrequency:h}})},[h]),(0,l.jsx)(k,{...e,canProceed:()=>!m&&!!h.choice&&("none"===h.choice||"weekly"===h.choice&&!(!h.name||!h.email)),onNext:async()=>{if("none"!==h.choice){if("weekly"===h.choice){_(!0),y(null);try{const e=d||window.location.origin,t=void 0!==u?u:(new Date).getTimezoneOffset()/-60,s=await a()({path:"/progress-planner/v1/popover/subscribe",method:"POST",data:{name:h.name.trim(),email:h.email.trim(),site:e,timezone_offset:t,with_email:"yes"}});if(!s.success)throw new Error(s.message||(0,n.__)("Failed to subscribe. Please try again.","progress-planner"));o()}catch(e){console.error("Failed to subscribe:",e),y(e.message||(0,n.__)("Failed to subscribe. Please try again.","progress-planner"))}finally{_(!1)}}}else o()},buttonText:(0,n.__)("Got it","progress-planner"),buttonClass:"prpl-btn-secondary",children:(0,l.jsx)("div",{className:"tour-content",children:(0,l.jsxs)("div",{className:"prpl-columns-wrapper-flex prpl-columns-1-2",children:[(0,l.jsx)("div",{className:"prpl-column",children:(0,l.jsxs)("div",{className:"prpl-background-content",children:[(0,l.jsx)("p",{children:(0,n.__)("Stay on track with emails that include recommendations, updates and useful news.","progress-planner")}),(0,l.jsx)("p",{children:(0,n.__)("Choose how often you want a little nudge to keep your site moving forward.","progress-planner")})]})}),(0,l.jsxs)("div",{className:"prpl-column",children:[(0,l.jsx)("h3",{className:"tour-title",children:(0,n.__)("Email Frequency","progress-planner")}),b&&(0,l.jsx)("div",{className:"prpl-error-message",style:{padding:"0.75rem",marginBottom:"1rem",backgroundColor:"#fee",border:"1px solid #fcc",borderRadius:"4px",color:"#c33"},children:b}),(0,l.jsxs)("div",{className:"prpl-email-frequency-options",children:[(0,l.jsx)(f,{id:"prpl-email-weekly",name:"email-frequency",value:"weekly",checked:"weekly"===h.choice,onChange:e=>{g({...h,choice:e.target.value}),y(null)},label:(0,n.__)("Email me weekly","progress-planner")}),(0,l.jsx)(f,{id:"prpl-dont-email",name:"email-frequency",value:"none",checked:"none"===h.choice,onChange:e=>{g({...h,choice:e.target.value}),y(null)},label:(0,n.__)("Don't email me","progress-planner")})]}),"weekly"===h.choice&&(0,l.jsxs)("div",{id:"prpl-email-form",style:{marginTop:"1rem"},children:[(0,l.jsxs)("label",{htmlFor:"prpl-email-name",style:{display:"grid",gridTemplateColumns:"1fr 3fr",marginBottom:"0.5em",gap:"var(--prpl-padding)"},children:[(0,l.jsx)("span",{children:(0,n.__)("First name","progress-planner")}),(0,l.jsx)("input",{id:"prpl-email-name",type:"text",value:h.name,onChange:e=>g({...h,name:e.target.value.trim()})})]}),(0,l.jsxs)("label",{htmlFor:"prpl-email-address",style:{display:"grid",gridTemplateColumns:"1fr 3fr",marginBottom:"0.5em",gap:"var(--prpl-padding)"},children:[(0,l.jsx)("span",{children:(0,n.__)("Email","progress-planner")}),(0,l.jsx)("input",{id:"prpl-email-address",type:"email",value:h.email,onChange:e=>g({...h,email:e.target.value.trim()})})]})]})]})]})})})}const O=["homepage","about","contact","faq","post-types"];function C(e){const{wizardState:t,updateState:s,config:r}=e,{ajaxUrl:a,nonce:o,pages:p=[],postTypes:c=[],pageTypes:d={}}=r,[u,h]=(0,i.useState)(0),[g,m]=(0,i.useState)(()=>{const e={homepage:{hasPage:!0,pageId:null},about:{hasPage:!0,pageId:null},contact:{hasPage:!0,pageId:null},faq:{hasPage:!0,pageId:null},"post-types":{selectedTypes:c.map(e=>e.id)}};return t.data.settings?{...e,...t.data.settings}:e}),[b,f]=(0,i.useState)(!1);(0,i.useEffect)(()=>{s({data:{...t.data,settings:g}})},[g]);const x=async()=>{const t=O[u],s=g[t];await(async(e,t)=>{f(!0);try{m(s=>({...s,[e]:t}))}catch(e){console.error("Failed to save setting:",e)}finally{f(!1)}})(t,s),u===O.length-1?(await(async()=>{f(!0);try{const e={};["homepage","about","contact","faq"].forEach(t=>{g[t]&&(e[t]={id:g[t].pageId||0,have_page:g[t].hasPage?"yes":"not-applicable"})}),await _({url:a,data:{action:"prpl_save_all_onboarding_settings",nonce:o,pages:JSON.stringify(e),"prpl-post-types-include":g["post-types"]?.selectedTypes||[]}})}catch(e){console.error("Failed to save settings:",e)}finally{f(!1)}})(),setTimeout(()=>{e.onNext()},100)):h(u+1)},T=()=>{if(b)return!1;const e=O[u],t=g[e]||{};return["homepage","about","contact","faq"].includes(e)?!t.hasPage||!!t.pageId:"post-types"!==e||t.selectedTypes&&t.selectedTypes.length>0};return(0,l.jsx)(k,{...e,hideFooter:!0,children:(0,l.jsx)("div",{className:"tour-content",children:(()=>{const e=O[u],s=g[e]||{};switch(e){case"homepage":case"about":case"contact":case"faq":{const t=d[e]||{};let r=t.title;r||(r="homepage"===e?(0,n.__)("Home page","progress-planner"):"about"===e?(0,n.__)("About page","progress-planner"):"contact"===e?(0,n.__)("Contact page","progress-planner"):"faq"===e?(0,n.__)("FAQ page","progress-planner"):e);const a=t.description||(0,n.__)("Select a page","progress-planner");return(0,l.jsx)("div",{className:"prpl-setting-item","data-page":e,children:(0,l.jsxs)("div",{className:"prpl-columns-wrapper-flex prpl-columns-1-2",children:[(0,l.jsx)("div",{className:"prpl-column",children:(0,l.jsx)("div",{className:"prpl-background-content",children:(0,l.jsx)("p",{children:a})})}),(0,l.jsxs)("div",{className:"prpl-column",children:[(0,l.jsx)("div",{className:"prpl-setting-header",children:(0,l.jsxs)("h3",{className:"prpl-setting-title",children:[(0,n.__)("Settings:","progress-planner")," ",r,(0,l.jsxs)("span",{className:"prpl-settings-progress",children:[u+1,"/",O.length]})]})}),(0,l.jsxs)("div",{className:"prpl-setting-content",children:[(0,l.jsx)("div",{className:"prpl-select-page"+(s.hasPage?"":" prpl-disabled"),children:(0,l.jsxs)("select",{name:`pages[${e}][id]`,value:s.pageId||"",disabled:!s.hasPage,onChange:t=>m(s=>({...s,[e]:{...s[e],pageId:parseInt(t.target.value,10)||null}})),children:[(0,l.jsx)("option",{value:"",children:(0,n.__)("— Select page —","progress-planner")}),p.map(e=>(0,l.jsx)("option",{value:e.id,children:e.title},e.id))]})}),(0,l.jsx)("div",{className:"prpl-checkbox-wrapper",children:(0,l.jsx)(v,{id:`prpl-no-${e}-page`,checked:!s.hasPage,onChange:t=>{const s=t.target.checked;m(t=>({...t,[e]:{...t[e],hasPage:!s,pageId:s?null:t[e]?.pageId}}))},label:(0,n.sprintf)(/* translators: %s: page type title */ /* translators: %s: page type title */
+(0,n.__)("I don't have a %s yet","progress-planner"),r)})})]}),(0,l.jsxs)("div",{className:"prpl-setting-footer",children:[!s.hasPage&&t.note&&(0,l.jsxs)("div",{className:"prpl-setting-note",children:[(0,l.jsx)("span",{className:"prpl-setting-note-icon",children:(0,l.jsx)("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg",children:(0,l.jsx)("path",{d:"M10 0C4.48 0 0 4.48 0 10s4.48 10 10 10 10-4.48 10-10S15.52 0 10 0zm1 15H9v-6h2v6zm0-8H9V5h2v2z"})})}),(0,l.jsx)("p",{children:t.note})]}),(0,l.jsx)("button",{type:"button",className:"prpl-btn prpl-save-setting-btn"+(T()?"":" prpl-btn-disabled"),onClick:x,disabled:!T(),children:(0,n.__)("Save setting","progress-planner")})]})]})]})})}case"post-types":return(0,l.jsx)("div",{className:"prpl-setting-item","data-page":"post-types",children:(0,l.jsxs)("div",{className:"prpl-columns-wrapper-flex",children:[(0,l.jsx)("div",{className:"prpl-column",children:(0,l.jsx)("div",{className:"prpl-background-content",children:(0,l.jsx)("p",{children:(0,n.__)("Choose the post types you actively use for your content.","progress-planner")})})}),(0,l.jsxs)("div",{className:"prpl-column",children:[(0,l.jsxs)("div",{className:"prpl-setting-header",children:[(0,l.jsxs)("h3",{className:"prpl-setting-title",children:[(0,n.__)("Settings:","progress-planner")," ",(0,n.__)("Valuable post types","progress-planner"),(0,l.jsxs)("span",{className:"prpl-settings-progress",children:[u+1,"/",O.length]})]}),(0,l.jsx)("p",{children:(0,n.__)("We'll track and reward progress only on the ones you select.","progress-planner")})]}),(0,l.jsx)("div",{className:"prpl-setting-content",children:(0,l.jsxs)("div",{className:"prpl-settings-wrapper",children:[(0,l.jsx)("p",{children:(0,n.__)("Which post types do you want us to track?","progress-planner")}),(0,l.jsx)("div",{id:"prpl-post-types-include-wrapper",children:c.map(e=>(0,l.jsx)(w,{id:`prpl-post-type-${e.id}`,name:"prpl-post-types-include[]",value:e.id,checked:s.selectedTypes?.includes(e.id)||!1,onChange:t=>{const s=t.target.checked;m(t=>({...t,"post-types":{selectedTypes:s?[...t["post-types"]?.selectedTypes||[],e.id]:(t["post-types"]?.selectedTypes||[]).filter(t=>t!==e.id)}}))},label:e.title},e.id))})]})}),(0,l.jsx)("div",{className:"prpl-setting-footer",children:(0,l.jsx)(y,{onNext:x,canProceed:T,wizardState:t,isLoading:b})})]})]})});default:return null}})()})})}function L({task:e,config:t,onComplete:s,onOpenChange:r,forceOpen:a=!1,disableActionButton:o=!1}){const{ajaxUrl:p,nonce:c}=t,{completeTask:d}=S({ajaxUrl:p,nonce:c}),[u,h]=(0,i.useState)(a),[g,m]=(0,i.useState)(!1),[_,b]=(0,i.useState)({}),y=(0,i.useRef)(null),[k,v]=(0,i.useState)(e?.template_html||""),[f,x]=(0,i.useState)(!1);(0,i.useEffect)(()=>{e?.task_id&&!e?.template_html&&(async()=>{x(!0);try{const t=new FormData;t.append("action","progress_planner_get_task_template"),t.append("nonce",c),t.append("task_id",e.task_id),t.append("task_data",JSON.stringify(e));const s=await fetch(p,{method:"POST",body:t}).then(e=>e.json());s.success&&s.data?.html&&v(s.data.html)}catch(e){console.error("Failed to fetch task template:",e)}finally{x(!1)}})()},[e?.task_id,e?.template_html,p,c]);const w=async()=>{if(e?.task_id)try{await d(e.task_id,_),m(!0),h(!1),r?.(!1),s?.(e.task_id)}catch(e){console.error("Failed to complete task:",e)}},T=()=>{h(!1),r?.(!1)},j=async(e,s,r)=>{const a=r.querySelector('input[type="file"]');if(!((e,t)=>{if(!t||!t.accept)return!0;const s=t.accept.split(",").map(e=>e.trim()),r=e.name.toLowerCase();return s.some(t=>t.startsWith(".")?r.endsWith(t):!!t.includes("/")&&e.type===t)})(e,a)){const e=a?.accept||"supported file types";return s.textContent=`Invalid file type. Please upload: ${e}`,null}s.textContent=`Uploading ${e.name}...`,s.style.display="";const i=new FormData;i.append("file",e),i.append("prplFileUpload","1");try{const a=await fetch("/wp-json/wp/v2/media",{method:"POST",headers:{"X-WP-Nonce":t.nonceWPAPI},body:i,credentials:"same-origin"});if(201!==a.status)throw new Error("Failed to upload file");const n=await a.json();s.style.display="none";const o=r.querySelector(".prpl-file-preview");o&&(o.innerHTML=`
`,o.style.display="block");const l=r.querySelector(".prpl-file-drop-zone");if(l){l.classList.add("has-image");const e=l.querySelector(".prpl-file-remove-btn");e&&(e.hidden=!1)}return n}catch(e){return console.error("Upload error:",e),s.textContent=`Error: ${e.message}`,null}},D=e=>{const t=e.querySelector("[data-upload-field]");if(!t)return;if(t.dataset.uploadInitialized)return;t.dataset.uploadInitialized="true";const s=t.querySelector('input[type="file"]'),r=t.querySelector(".prpl-upload-status"),a=t.querySelector(".prpl-file-preview");["dragenter","dragover"].forEach(e=>{t.addEventListener(e,e=>{e.preventDefault(),e.stopPropagation(),t.classList.add("dragover")})}),t.addEventListener("dragleave",e=>{e.preventDefault(),e.stopPropagation(),t.classList.remove("dragover")}),t.addEventListener("drop",async a=>{a.preventDefault(),a.stopPropagation(),t.classList.remove("dragover");const i=a.dataTransfer.files[0];if(i){const t=await j(i,r,e);if(t&&s){const e=s.nextElementSibling;e&&"post_id"===e.name&&(e.value=t.id,e.dispatchEvent(new CustomEvent("change",{bubbles:!0})))}}}),s?.addEventListener("change",async t=>{const a=t.target.files[0];if(a){const t=await j(a,r,e);if(t){const e=s.nextElementSibling;e&&"post_id"===e.name&&(e.value=t.id,e.dispatchEvent(new CustomEvent("change",{bubbles:!0})))}}});const i=t.querySelector(".prpl-file-remove-btn");i?.addEventListener("click",()=>{((e,t)=>{t.innerHTML="",t.style.display="none",e.classList.remove("has-image");const s=e.querySelector(".prpl-file-remove-btn");s&&(s.hidden=!0);const r=e.querySelector('input[type="file"]');r&&(r.value="");const a=e.querySelector('input[name="post_id"]');a&&(a.value="",a.dispatchEvent(new CustomEvent("change",{bubbles:!0})));const i=e.querySelector(".prpl-upload-status");i&&(i.style.display="",i.textContent="")})(t,a)})},A=e?.task_id?I[e.task_id]:null;return u?A?(0,l.jsx)("div",{className:"prpl-task-content-active",ref:y,children:(0,l.jsx)("div",{className:"prpl-task-form",children:(0,l.jsxs)("form",{className:"prpl-onboarding-task-form",onSubmit:e=>{e.preventDefault();const t=new FormData(e.target);b(Object.fromEntries(t.entries())),setTimeout(()=>w(),0)},ref:e=>{e&&D(e)},children:[(0,l.jsx)(A,{task:e}),(0,l.jsxs)("div",{className:"prpl-task-buttons",children:[(0,l.jsxs)("button",{type:"button",className:"prpl-btn prpl-task-close-btn",onClick:T,children:[(0,l.jsx)("span",{className:"dashicons dashicons-arrow-left-alt2"})," ",t?.l10n?.backToRecommendations||(0,n.__)("Back to recommendations","progress-planner")]}),(0,l.jsx)("button",{type:"submit",className:"prpl-complete-task-btn prpl-btn prpl-btn-secondary","data-task-id":e.task_id,children:e.action_label||(0,n.__)("Mark as complete","progress-planner")})]})]})})}):(0,l.jsx)("div",{className:"prpl-task-content-active",ref:y,children:(0,l.jsxs)("div",{className:"prpl-task-form",children:[f&&(0,l.jsx)("div",{className:"prpl-spinner",children:(0,l.jsx)("span",{className:"spinner",style:{visibility:"visible"}})}),!f&&k&&(0,l.jsx)("div",{dangerouslySetInnerHTML:{__html:k},role:"presentation",onClick:e=>{if(e.target.classList.contains("prpl-complete-task-btn")){const t=e.target.closest("form");if(t){const e=new FormData(t);b(Object.fromEntries(e.entries())),setTimeout(()=>w(),0)}}},onKeyDown:e=>{if("Enter"===e.key||" "===e.key){e.preventDefault();const t=e.target;if(t.classList.contains("prpl-complete-task-btn")){const e=t.closest("form");if(e){const t=new FormData(e);b(Object.fromEntries(t.entries())),setTimeout(()=>w(),0)}}}},tabIndex:-1,ref:e=>{if(e&&k){if(D(e),e.querySelector(".prpl-task-buttons"))return;const s=e.querySelector(".prpl-complete-task-btn");if(s){const r=document.createElement("div");r.className="prpl-task-buttons";const a=document.createElement("button");if(a.type="button",a.className="prpl-btn prpl-task-close-btn",a.innerHTML=' '+(t?.l10n?.backToRecommendations||"Back to recommendations"),a.addEventListener("click",T),s.parentNode.insertBefore(r,s),r.appendChild(a),r.appendChild(s),o){s.disabled=!0,s.classList.add("prpl-btn-disabled");const t=()=>{s.disabled=!1,s.classList.remove("prpl-btn-disabled")};e.querySelectorAll("input, select, textarea").forEach(e=>{e.addEventListener("change",t),e.addEventListener("input",t)}),e.querySelectorAll('input[type="file"]').forEach(e=>{e.addEventListener("change",t)}),e.addEventListener("prpl-task-input-changed",t)}}}}}),!f&&!k&&(0,l.jsxs)(l.Fragment,{children:[e.title&&(0,l.jsx)("h4",{children:e.title}),e.url&&(0,l.jsx)("a",{href:e.url,target:"_blank",rel:"noopener noreferrer",className:"prpl-button-primary",children:e.action_label||(0,n.__)("Do it","progress-planner")})]})]})}):(0,l.jsx)("div",{className:"prpl-task-item","data-task-id":e?.task_id,children:(0,l.jsxs)("button",{type:"button",className:"prpl-open-task-btn",onClick:()=>{h(!0),r?.(!0)},disabled:g,children:[e?.title||(0,n.__)("Task","progress-planner"),g&&" ✓"]})})}function U(e){const{wizardState:t,updateState:s,stepData:r,config:a}=e,[o,p]=(0,i.useState)(0),[c,d]=(0,i.useState)({}),[u,h]=(0,i.useState)(null),g=r?.data?.tasks||[];(0,i.useEffect)(()=>{t.data.moreTasksCompleted&&d(t.data.moreTasksCompleted)},[]);const m=e=>{d(t=>({...t,[e]:!0})),s({data:{...t.data,moreTasksCompleted:{...c,[e]:!0}}})},_=()=>{p(1)},b=async()=>{s({data:{...t.data,finished:!0}}),window.location.href=a?.lastStepRedirectUrl||"/wp-admin/admin.php?page=progress-planner"};return(0,l.jsxs)(k,{...e,hideFooter:!0,children:[(0,l.jsx)("div",{className:"tour-content",children:(()=>{if(0===o)return(0,l.jsx)("div",{className:"prpl-more-tasks-substep","data-substep":"more-tasks-intro",children:(0,l.jsxs)("div",{className:"prpl-columns-wrapper-flex prpl-columns-2-1",children:[(0,l.jsxs)("div",{className:"prpl-column",children:[(0,l.jsxs)("div",{className:"prpl-background-content",children:[(0,l.jsx)("p",{children:(0,l.jsx)("strong",{children:(0,n.__)("Well done! Great work so far!","progress-planner")})}),(0,l.jsx)("p",{children:(0,n.__)("You can take on a few more recommendations if you feel like it, or jump straight to your dashboard.","progress-planner")})]}),(0,l.jsxs)("div",{className:"prpl-more-tasks-intro-buttons",children:[(0,l.jsx)("a",{href:a?.lastStepRedirectUrl||"/wp-admin/admin.php?page=progress-planner",className:"prpl-finish-onboarding",onClick:e=>{e.preventDefault(),b()},children:(0,n.__)("Take me to the dashboard","progress-planner")}),(0,l.jsxs)("button",{type:"button",className:"prpl-btn prpl-btn-secondary prpl-more-tasks-continue",onClick:_,children:[(0,n.__)("Yes! Let's tackle more tasks","progress-planner")," ","›"]})]})]}),(0,l.jsx)("div",{className:"prpl-column prpl-hide-on-mobile",children:(0,l.jsx)("div",{id:"prpl-success-graphic",children:(0,l.jsx)("img",{src:`${a?.baseUrl||""}/assets/images/onboarding/success_ravi.svg`,alt:""})})})]})});if(u){const e=g.find(e=>e.task_id===u);if(e)return(0,l.jsx)("div",{className:"prpl-more-tasks-substep","data-substep":"more-tasks-tasks",children:(0,l.jsx)(L,{task:e,config:a,onComplete:m,onOpenChange:t=>h(t?e.task_id:null),forceOpen:!0,disableActionButton:!0},e.task_id)})}return(0,l.jsx)("div",{className:"prpl-more-tasks-substep prpl-columns-wrapper-flex","data-substep":"more-tasks-tasks",children:(0,l.jsx)("div",{className:"prpl-column",children:(0,l.jsx)("ul",{className:"prpl-task-list",children:g.map(e=>{const t=c[e.task_id];return(0,l.jsxs)("li",{className:"prpl-complete-task-item",children:[(0,l.jsxs)("span",{className:"task-title",children:[(0,l.jsx)("span",{className:"prpl-task-arrow",children:"→"}),e.title]}),(0,l.jsxs)("div",{className:"prpl-task-item"+(t?" prpl-task-completed":""),children:[(0,l.jsxs)("div",{className:"prpl-task-item-button-wrapper",children:[(0,l.jsx)("button",{type:"button",className:"prpl-complete-task-btn",onClick:()=>h(e.task_id),disabled:t,children:e.action_label||(0,n.__)("Do it","progress-planner")}),(0,l.jsx)("span",{className:"prpl-suggested-task-points",children:"+1"})]}),(0,l.jsx)("span",{className:"prpl-task-completed-icon",children:"✓"})]})]},e.task_id)})})})})})()}),1===o&&!u&&(0,l.jsx)(y,{onNext:b,canProceed:()=>!0,wizardState:t,buttonText:(0,l.jsxs)(l.Fragment,{children:[(0,n.__)("Take me to the dashboard","progress-planner")," ","›"]}),buttonClass:"prpl-btn-secondary"})]})}function z({steps:e,currentStep:t,logoHtml:s}){return(0,l.jsxs)("div",{className:"prpl-onboarding-navigation",children:[(0,l.jsxs)("div",{children:[(0,l.jsx)("div",{id:"prpl-onboarding-mobile-step-label",children:e[t]?.title||""}),(0,l.jsx)("ol",{className:"prpl-step-list",children:e.map((e,s)=>{const r=s===t,a=s{t.preventDefault(),"function"==typeof e&&e()},children:(0,n.__)("Yes, quit the onboarding (for now)","progress-planner")}),(0,l.jsx)("button",{type:"button",id:"prpl-quit-no",className:"prpl-quit-link prpl-quit-link-primary",onClick:e=>{e.preventDefault(),"function"==typeof t&&t()},children:(0,n.__)("No, let's finish the onboarding!","progress-planner")})]})]})}),(0,l.jsx)("div",{className:"prpl-column prpl-hide-on-mobile",children:(0,l.jsx)("div",{id:"prpl-quit-confirmation-graphic",children:(0,l.jsx)("img",{src:`${a||""}/assets/images/onboarding/neglected_site_ravi.svg`,alt:""})})})]})}const M=(0,i.forwardRef)(function({config:e},t){const[s,r]=(0,i.useState)(null),[p,c]=(0,i.useState)(!0),[d,u]=(0,i.useState)(null),h=e.onboardingWizard;(0,i.useEffect)(()=>{(async()=>{try{c(!0),u(null),await(0,b.$G)();const e=await a()({path:"/progress-planner/v1/onboarding-wizard/config"});r(e)}catch(e){h?r(h):u(e)}finally{c(!1)}})()},[h]);const g=s||h,{steps:m,savedProgress:y,ajaxUrl:k,nonce:v}=g||{},f=function({ajaxUrl:e,nonce:t}){const[s,r]=(0,i.useState)(!1),[a,n]=(0,i.useState)(null);return{saveProgress:(0,i.useCallback)(async s=>{r(!0),n(null);try{const r=await _({url:e,data:{action:"progress_planner_onboarding_save_progress",nonce:t,state:JSON.stringify(s)}});if(r.success)return r;throw new Error(r.data?.message||"Failed to save progress")}catch(e){throw n(e.message||"Failed to save progress"),e}finally{r(!1)}},[e,t]),isSaving:s,error:a}}({ajaxUrl:k||"",nonce:v||""}),{wizardState:x,updateState:w,nextStep:S,prevStep:I,currentStep:A,currentStepData:P}=function(e,t){const{steps:s=[],savedProgress:r=null}=e,{saveProgress:a}=t,[n,o]=(0,i.useState)(()=>r?{currentStep:r.currentStep||0,data:r.data||{privacyAccepted:!1,firstTaskCompleted:!1,moreTasksCompleted:{},finished:!1,emailFrequency:{choice:null,name:"",email:""},settings:{}}}:{currentStep:0,data:{privacyAccepted:!1,firstTaskCompleted:!1,moreTasksCompleted:{},finished:!1,emailFrequency:{choice:null,name:"",email:""},settings:{}}}),l=(0,i.useCallback)(e=>{o(t=>({...t,...e,data:{...t.data,...e.data||{}}}))},[]),p=(0,i.useCallback)(()=>{o(e=>{const t=Math.min(e.currentStep+1,s.length-1);return{...e,currentStep:t}})},[s.length]),c=(0,i.useCallback)(()=>{o(e=>{const t=Math.max(e.currentStep-1,0);return{...e,currentStep:t}})},[]),d=(0,i.useCallback)(e=>{o(t=>({...t,currentStep:Math.max(0,Math.min(e,s.length-1))}))},[s.length]);return(0,i.useEffect)(()=>{const e=setTimeout(()=>{a(n).catch(()=>{})},500);return()=>clearTimeout(e)},[n,a]),{wizardState:n,updateState:l,nextStep:p,prevStep:c,goToStep:d,currentStep:n.currentStep,currentStepData:s[n.currentStep]||null,totalSteps:s.length}}(g||{},f),[O,L]=(0,i.useState)(!1),[M,F]=(0,i.useState)(!1),q=(0,i.useRef)(null),$=(0,i.useRef)(!1),J=(0,o.fX)(e=>e.shouldAutoStartWizard),W=(0,o.fX)(e=>e.setShouldAutoStartWizard);(0,i.useImperativeHandle)(t,()=>({startOnboarding(){!x.data.finished&&g?.enabled&&q.current&&("function"==typeof q.current.showPopover&&q.current.showPopover(),F(!0),setTimeout(()=>{q.current&&q.current.focus()},0))}}));const H=(0,i.useCallback)(e=>{const t=q.current;if(q.current=e,t&&t!==e){const e=t.__prplToggleHandler;e&&(t.removeEventListener("toggle",e),delete t.__prplToggleHandler)}if(!e)return;if(!e.__prplToggleHandler){const t=e=>{F("open"===e.newState)};e.addEventListener("toggle",t),e.__prplToggleHandler=t}if(!g?.enabled)return;if(x.data.finished)return;if(e.matches(":popover-open"))return void F(!0);if($.current)return;const s=y&&Object.keys(y).length>0;if(J&&!s&&!$.current&&"function"==typeof e.showPopover)try{e.showPopover(),F(!0),J&&W(!1),setTimeout(()=>{e&&e.focus()},0)}catch(e){console.error("[OnboardingWizard] Ref callback: Error calling showPopover()",e)}},[g?.enabled,x.data.finished,y,J,W]);(0,i.useEffect)(()=>{if(!M)return;const e=e=>{"Escape"!==e.key||O||L(!0)};return document.addEventListener("keydown",e),()=>{document.removeEventListener("keydown",e)}},[M,O]);const B=()=>{$.current=!0,L(!1);const e=q.current;e&&"function"==typeof e.hidePopover&&e.hidePopover(),F(!1),f.saveProgress(x).catch(()=>{})},Y=()=>{L(!1)};return p||d&&!h?null:g?.enabled?(0,l.jsx)(l.Fragment,{children:(0,l.jsxs)("div",{ref:H,id:"prpl-popover-onboarding",className:"prpl-popover-onboarding",popover:"manual",tabIndex:-1,"data-prpl-step":A,role:"dialog","aria-modal":"true","aria-labelledby":"prpl-onboarding-title",children:[(0,l.jsxs)("div",{className:"prpl-onboarding-layout",children:[!O&&(0,l.jsx)(z,{steps:m,currentStep:A,logoHtml:g.logoHtml}),(0,l.jsx)("div",{className:"prpl-onboarding-content",children:(0,l.jsx)("div",{className:"tour-content-wrapper",children:(()=>{if(O)return(0,l.jsx)(R,{onConfirm:B,onCancel:Y,config:g});if(!P)return null;const e={wizardState:x,updateState:w,onNext:S,onBack:A>0?I:null,config:g,stepData:P};switch(P.id){case"onboarding-step-welcome":return(0,l.jsx)(T,{...e});case"onboarding-step-whats-what":return(0,l.jsx)(j,{...e});case"onboarding-step-first-task":return(0,l.jsx)(D,{...e});case"onboarding-step-badges":return(0,l.jsx)(N,{...e});case"onboarding-step-email-frequency":return(0,l.jsx)(E,{...e});case"onboarding-step-settings":return(0,l.jsx)(C,{...e});case"onboarding-step-more-tasks":return(0,l.jsx)(U,{...e});default:return null}})()})})]}),!O&&(0,l.jsx)("button",{id:"prpl-tour-close-btn",className:"prpl-popover-close",onClick:()=>{L(!0)},"aria-label":(0,n.__)("Close","progress-planner"),children:(0,l.jsx)("span",{className:"dashicons dashicons-no-alt"})})]})}):null}),F={skipLink:{position:"absolute",top:"-40px",left:0,background:"var(--prpl-color-button-primary)",color:"var(--prpl-color-button-primary-text)",padding:"8px 16px",textDecoration:"none",borderRadius:"var(--prpl-border-radius)",zIndex:1e5},widgetsContainer:{display:"grid",gridTemplateColumns:"repeat(auto-fit, minmax(var(--prpl-column-min-width), 1fr))",columnGap:"var(--prpl-gap)",gridAutoRows:"var(--prpl-gap)",gridAutoFlow:"dense"}};function q({config:e}){const{privacyPolicyAccepted:t=!1}=e,s=(0,i.useRef)(null),r=(0,o.fX)(e=>e.setShouldAutoStartWizard);(0,i.useEffect)(()=>{t||r(!0)},[t,r]);return t?(0,l.jsxs)(i.Fragment,{children:[(0,l.jsx)("a",{href:"#prpl-main-content",className:"screen-reader-text prpl-skip-link",style:F.skipLink,onFocus:e=>{e.target.style.top="10px",e.target.style.left="10px"},onBlur:e=>{e.target.style.top="-40px",e.target.style.left="0"},children:(0,n.__)("Skip to main content","progress-planner")}),(0,l.jsx)("h1",{className:"screen-reader-text",children:(0,n.__)("Progress Planner","progress-planner")}),(0,l.jsx)(p,{config:e}),(0,l.jsx)("div",{id:"prpl-main-content",className:"prpl-widgets-container",style:F.widgetsContainer,children:(0,l.jsx)(m,{})}),(0,l.jsx)(M,{config:e,ref:s})]}):(0,l.jsxs)(i.Fragment,{children:[(0,l.jsxs)("div",{className:"prpl-start-onboarding-container",children:[(0,l.jsx)("div",{className:"prpl-start-onboarding-graphic",children:(0,l.jsx)("img",{src:`${e.baseUrl||""}/assets/images/onboarding/thumbs_up_ravi_rtl.svg`,alt:"",style:{maxWidth:"100%",height:"auto"}})}),(0,l.jsx)("button",{className:"prpl-button-primary",id:"prpl-start-onboarding-button",onClick:()=>{s.current&&"function"==typeof s.current.startOnboarding&&s.current.startOnboarding()},children:(0,n.__)("Are you ready to work on your site?","progress-planner")})]}),(0,l.jsx)(M,{config:e,ref:s})]})}const $={maybeComplete:function(e){return new Promise((t,s)=>{try{const r=document.querySelector(`.prpl-suggested-task[data-post-id="${e}"]`);if(!r)return console.warn(`prplSuggestedTask.maybeComplete: Task element not found for post ID ${e}`),void s(new Error(`Task element not found for post ID ${e}`));const a=r.querySelector('[data-action="complete"]');if(a){const s=a.getAttribute("onclick");a.removeAttribute("onclick"),setTimeout(()=>{a.click(),s&&a.setAttribute("onclick",s),t({postId:e})},0)}else console.warn(`prplSuggestedTask.maybeComplete: Complete button not found for post ID ${e}`),s(new Error(`Complete button not found for post ID ${e}`))}catch(e){console.error("prplSuggestedTask.maybeComplete: Error completing task",e),s(e)}})},snooze:function(e,t){return new Promise((s,r)=>{try{const a=document.querySelector(`.prpl-suggested-task[data-post-id="${e}"]`);if(!a)return console.warn(`prplSuggestedTask.snooze: Task element not found for post ID ${e}`),void r(new Error(`Task element not found for post ID ${e}`));const i=a.querySelector(`.prpl-snooze-duration-radio-group input[type="radio"][value="${t}"]`);if(i){const r=i.getAttribute("onchange");i.removeAttribute("onchange"),setTimeout(()=>{i.checked=!0,i.dispatchEvent(new Event("change",{bubbles:!0})),r&&i.setAttribute("onchange",r),s({postId:e,snoozeDuration:t})},0)}else console.warn(`prplSuggestedTask.snooze: Snooze radio button not found for post ID ${e} with duration ${t}`),r(new Error(`Snooze radio button not found for post ID ${e} with duration ${t}`))}catch(e){console.error("prplSuggestedTask.snooze: Error snoozing task",e),r(e)}})}};function J(e){if(!e)return"";try{const t=new URL(e,"http://example.com");t.searchParams.sort();let s=t.pathname+t.search;return s.length>1&&s.endsWith("/")&&(s=s.slice(0,-1)),s}catch(t){return e}}if("sessionStorage"in window)try{for(const e in window.sessionStorage)if(e.indexOf("wp-api-schema-model")>-1&&-1===window.sessionStorage.getItem(e).indexOf("/wp/v2/prpl_recommendations")){window.sessionStorage.removeItem(e);break}}catch(e){}function W(){const e=document.getElementById("prpl-dashboard-root");if(e){const t=(0,i.createRoot)(e),s=window.prplDashboardConfig||{};t.render((0,l.jsx)(q,{config:s}))}}window.prplPreloadedData&&a().use(function(e){const t=new Map;return e&&"object"==typeof e&&Object.entries(e).forEach(([e,s])=>{t.set(J(e),s)}),(e,s)=>{if(e.method&&"GET"!==e.method.toUpperCase())return s(e);if(!1===e.parse)return s(e);const r=J(e.path||e.url);if(t.has(r)){const e=t.get(r);return t.delete(r),Promise.resolve(e.body)}return s(e)}}(window.prplPreloadedData)),window.prplSuggestedTask=$,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",W):W()},2619:e=>{e.exports=window.wp.hooks},3971:(e,t,s)=>{s.d(t,{A:()=>a});var r=s(790);function a({badgeId:e,badgeName:t,brandingId:s=0,isComplete:a=!0}){const i=window.progressPlannerBadge||{};let n=i.remoteServerRootUrl||"https://progressplanner.com";const o=i.placeholderImageUrl||"";(n.includes("localhost")||n.includes("127.0.0.1"))&&(n="https://progressplanner.com");let l=`${n}/wp-json/progress-planner-saas/v1/badge-svg/?badge_id=${e}`;s&&(l+=`&branding_id=${s}`);const p=t&&"null"!==t?t:"Badge",c={maxWidth:"100%",height:"auto",verticalAlign:"bottom",transition:"opacity 0.3s ease-in-out, filter 0.3s ease-in-out",...!a&&{opacity:.25,filter:"grayscale(1)"}};return(0,r.jsx)("img",{src:l,alt:p,onError:e=>{o&&e.target.src!==o&&(e.target.onerror=null,e.target.src=o)},style:c})}},5337:(e,t,s)=>{s.d(t,{BJ:()=>l,IL:()=>p,Wz:()=>c});var r=s(1455),a=s.n(r);const i=new Map,n=new Map,o=3e5;async function l(e,t={}){const{skipCache:s=!1,ttl:r=o}=t,l=function(e){if("GET"!==(e.method||"GET").toUpperCase())return null;let t=e.path||e.url||"";if(e.data&&"object"==typeof e.data){const s=new URLSearchParams(e.data).toString();s&&(t+=(t.includes("?")?"&":"?")+s)}return`GET:${t}`}(e);if(!l)return a()(e);if(!s&&i.has(l))return i.get(l);if(!s){const e=n.get(l);if(e&&Date.now()-e.timestamp(n.set(l,{data:e,timestamp:Date.now()}),i.delete(l),e)).catch(e=>{throw i.delete(l),e});return i.set(l,p),p}function p(){n.clear(),i.clear()}function c(e,t){const s=`GET:${e}`;n.set(s,{data:t,timestamp:Date.now()})}},6087:e=>{e.exports=window.wp.element},7723:e=>{e.exports=window.wp.i18n},8493:(e,t,s)=>{s.d(t,{$G:()=>T,CI:()=>f,DF:()=>v,Sm:()=>b,_C:()=>x,nR:()=>g,wA:()=>k});var r=s(2619),a=s(1455),i=s.n(a),n=s(9251);const o=["hello_world_post_id","sample_page_id","inactive_plugins_count","uncategorized_category_id","post_author_count","last_published_post_id","archive_format_count","terms_without_posts","terms_without_description","post_tag_count","published_post_count","unpublished_content","seo_plugin_installed","php_version","wp_debug_status","old_posts_for_review"],l=new Map;let p=new Map,c=[];const d={isPreFetchComplete:!1,isEvaluating:!1,currentIndex:0},u=3,h=5;function g(e){const t=e.providerId;if(!t)return void console.warn("Task class missing providerId, skipping:",e);const s=e.priority||50;(0,r.addFilter)("prpl.tasks.classes",`prpl/task/${t}`,r=>(r.has(t)||r.set(t,{TaskClass:e,priority:s}),r),s),l.set(t,e)}async function m(){try{const e=await i()({path:"/wp/v2/prpl_recommendations?status=publish,trash,future&per_page=100&_embed=true"}),t=new Map;return Array.isArray(e)&&e.forEach(e=>{e.slug&&t.set(e.slug,{...e,_existsInDb:!0,_isActive:"publish"===e.status})}),t}catch(e){return console.error("Error pre-fetching existing tasks:",e),new Map}}function _(){const e=(0,r.applyFilters)("prpl.tasks.classes",new Map);c=Array.from(e.entries()).map(([e,{TaskClass:t,priority:s}])=>({TaskClass:t,priority:s,providerId:e})).sort((e,t)=>e.priority-t.priority)}async function b(e,t){if(!d.isPreFetchComplete){const[e]=await Promise.all([m(),...o.map(e=>(0,n.OJ)(e).catch(()=>null))]);p=e,d.isPreFetchComplete=!0,_()}if(d.isEvaluating)return{complete:!1,tasksAdded:0};d.isEvaluating=!0;let s=0;try{const e=[],r=[];for(;d.currentIndexe.priority-t.priority),r.sort((e,t)=>e.priority-t.priority);for(const{task:r,priority:a}of e)t(r,a),s++;for(let e=0;ee.taskDetails);try{const e=await(0,n.J1)(i);e.success&&e.tasks&&e.tasks.forEach((e,r)=>{if(e.success&&e.task){const{priority:i,taskId:n}=a[r];void 0===e.task.prpl_priority&&(e.task.prpl_priority=i),p.set(n,e.task),t(e.task,i),s++}})}catch(e){409!==e?.data?.status&&console.error("Error creating task batch:",e)}}}finally{d.isEvaluating=!1}return{complete:d.currentIndex>=c.length,tasksAdded:s}}async function y(e,t){const s=e.providerId;try{const r=new e,a=e.isMultiTask||!1,i=r.getTasksToInject&&"function"==typeof r.getTasksToInject;if(a||i)return await async function(e,t,s){const r=t.providerId,a=[],i=[];try{if(e.shouldAddTask&&!await e.shouldAddTask())return{};const t=await e.getTasksToInject();if(!Array.isArray(t))return{};for(const n of t){const t=e.getTaskId?.(n)||r,o=p.get(t);if(o)o._isActive&&(void 0===o.prpl_priority&&(o.prpl_priority=s),a.push({task:o,priority:s}));else if(e.getTaskDetails){const a=await e.getTaskDetails(n);a&&(a.task_id=a.task_id||t,a.provider_id=a.provider_id||r,i.push({taskDetails:a,priority:s,taskId:t}))}}return 1===a.length&&0===i.length?{existing:a[0]}:0===a.length&&1===i.length?{toCreate:i[0]}:a.length>0?{existing:a[0]}:i.length>0?{toCreate:i[0]}:{}}catch(e){return console.error(`Error evaluating multi-task provider "${r}":`,e),{}}}(r,e,t);const n=r.getTaskId?.()||s,o=p.get(n);if(o&&!o._isActive)return{};if(o&&o._isActive)return void 0===o.prpl_priority&&(o.prpl_priority=t),{existing:{task:o,priority:t}};if(!r.shouldAddTask)return{};if(!await r.shouldAddTask())return{};if(!r.getTaskDetails)return{};const l=await r.getTaskDetails();return l?(l.task_id=l.task_id||n,l.provider_id=l.provider_id||s,{toCreate:{taskDetails:l,priority:t,taskId:n}}):{}}catch(e){return console.error(`Error evaluating task "${s}":`,e),{}}}function k(){return!d.isPreFetchComplete||d.currentIndex0)try{await(0,n.J1)(e)}catch(e){409!==e?.data?.status&&console.error("Error creating onboarding tasks:",e)}}},8864:(e,t,s)=>{s.d(t,{fX:()=>c});const r=window.React,a=e=>{let t;const s=new Set,r=(e,r)=>{const a="function"==typeof e?e(t):e;if(!Object.is(a,t)){const e=t;t=(null!=r?r:"object"!=typeof a||null===a)?a:Object.assign({},t,a),s.forEach(s=>s(t,e))}},a=()=>t,i={setState:r,getState:a,getInitialState:()=>n,subscribe:e=>(s.add(e),()=>s.delete(e))},n=t=e(r,a,i);return i},i=e=>e,n=e=>{const t=(e=>e?a(e):a)(e),s=e=>function(e,t=i){const s=r.useSyncExternalStore(e.subscribe,r.useCallback(()=>t(e.getState()),[e,t]),r.useCallback(()=>t(e.getInitialState()),[e,t]));return r.useDebugValue(s),s}(t,e);return Object.assign(s,t),s};var o=s(1455),l=s.n(o),p=s(5337);const c=(d=(e,t)=>({sessionPoints:0,totalPoints:0,lastCompletionTime:null,lastCompletedTask:null,activityScore:{current:0,target:100},badgeProgress:{},cacheInvalidatedAt:null,shouldAutoStartWizard:!1,providerTerms:{},termsLoading:!1,termsLoaded:!1,onTaskCompleted:(t,s=0)=>e(e=>({sessionPoints:e.sessionPoints+s,lastCompletionTime:Date.now(),lastCompletedTask:t})),onTaskUncompleted:(t,s=0)=>e(e=>({sessionPoints:Math.max(0,e.sessionPoints-s)})),updateActivityScore:t=>e(e=>({activityScore:{...e.activityScore,...t}})),updateBadgeProgress:(t,s)=>e(e=>({badgeProgress:{...e.badgeProgress,[t]:s}})),invalidateCache:()=>{(0,p.IL)(),e({cacheInvalidatedAt:Date.now()})},setShouldAutoStartWizard:t=>{e({shouldAutoStartWizard:t})},getProviderTermId:e=>{const s=t();return s.providerTerms[e]?.id||null},fetchProviderTerms:async()=>{const s=t();if(s.termsLoaded||s.termsLoading)return s.providerTerms;e({termsLoading:!0});try{const t=await l()({path:"/wp/v2/prpl_recommendations_provider?per_page=100"}),s={};let r=!1;if(t.forEach(e=>{s[e.slug]=e,"user"===e.slug&&(r=!0)}),!r)try{const e=await l()({path:"/wp/v2/prpl_recommendations_provider",method:"POST",data:{slug:"user",name:"user"}});s.user=e}catch(e){if("term_exists"===e.code&&e.data?.term_id)try{const t=await l()({path:`/wp/v2/prpl_recommendations_provider/${e.data.term_id}`});s.user=t}catch(e){console.error("Error fetching existing user term:",e)}else console.error("Error creating user term:",e)}return e({providerTerms:s,termsLoading:!1,termsLoaded:!0}),s}catch(t){return console.error("Error fetching provider terms:",t),e({termsLoading:!1}),{}}}}))?n(d):n;var d},9061:(e,t,s)=>{s.d(t,{A:()=>i});var r=s(790);const a={arrow:{viewBox:"0 0 20 17",paths:[{d:"M19.92 8.12c-.05-.12-.12-.23-.22-.33L12.21.29A.996.996 0 1 0 10.8 1.7l5.79 5.79H1c-.55 0-1 .45-1 1s.45 1 1 1h15.59l-5.79 5.79a.996.996 0 0 0 .71 1.7c.26 0 .51-.1.71-.29l7.5-7.5c.1-.1.17-.21.22-.33.05-.12.07-.24.08-.38 0-.14-.03-.27-.08-.38Z"}]},trash:{viewBox:"0 0 48 48",paths:[{d:"M32.99 47.88H15.01c-3.46 0-6.38-2.7-6.64-6.15L6.04 11.49l-.72.12c-.82.14-1.59-.41-1.73-1.22-.14-.82.41-1.59 1.22-1.73.79-.14 1.57-.26 2.37-.38h.02c2.21-.33 4.46-.6 6.69-.81v-.72c0-3.56 2.74-6.44 6.25-6.55 2.56-.08 5.15-.08 7.71 0 3.5.11 6.25 2.99 6.25 6.55v.72c2.24.2 4.48.47 6.7.81.79.12 1.59.25 2.38.39.82.14 1.36.92 1.22 1.73-.14.82-.92 1.36-1.73 1.22l-.72-.12-2.33 30.24c-.27 3.45-3.18 6.15-6.64 6.15Zm-17.98-3h17.97c1.9 0 3.51-1.48 3.65-3.38l2.34-30.46c-2.15-.3-4.33-.53-6.48-.7h-.03c-5.62-.43-11.32-.43-16.95 0h-.03c-2.15.17-4.33.4-6.48.7l2.34 30.46c.15 1.9 1.75 3.38 3.65 3.38ZM24 7.01c2.37 0 4.74.07 7.11.22v-.49c0-1.93-1.47-3.49-3.34-3.55-2.5-.08-5.03-.08-7.52 0-1.88.06-3.34 1.62-3.34 3.55v.49c2.36-.15 4.73-.22 7.11-.22Zm5.49 32.26h-.06c-.83-.03-1.47-.73-1.44-1.56l.79-20.65c.03-.83.75-1.45 1.56-1.44.83.03 1.47.73 1.44 1.56l-.79 20.65c-.03.81-.7 1.44-1.5 1.44Zm-10.98 0c-.8 0-1.47-.63-1.5-1.44l-.79-20.65c-.03-.83.61-1.52 1.44-1.56.84 0 1.52.61 1.56 1.44l.79 20.65c.03.83-.61 1.52-1.44 1.56h-.06Z"}]},check:{viewBox:"0 0 20 20",paths:[{d:"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",fillRule:"evenodd",clipRule:"evenodd"}]},close:{viewBox:"0 0 20 20",paths:[{d:"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",fillRule:"evenodd",clipRule:"evenodd"}]},chevronDown:{viewBox:"0 0 24 24",stroke:!0,paths:[{d:"m19.5 8.25-7.5 7.5-7.5-7.5",strokeLinecap:"round",strokeLinejoin:"round"}]},info:{viewBox:"0 0 64 64",paths:[{d:"M32 63.73C14.51 63.73.27 49.49.27 32S14.51.27 32 .27 63.73 14.5 63.73 32 49.5 63.73 32 63.73Zm0-58C17.51 5.73 5.73 17.52 5.73 32S17.52 58.27 32 58.27 58.27 46.48 58.27 32 46.49 5.73 32 5.73Zm1.2 41.4c-.42 0-.83-.05-1.24-.15-1.33-.33-2.46-1.17-3.16-2.34-.71-1.18-.91-2.56-.58-3.9l2.13-8.54c-1.25.36-2.62-.21-3.21-1.42-.66-1.35-.1-2.99 1.25-3.65l.13-.06c1.21-.6 2.6-.7 3.91-.27 1.3.44 2.36 1.35 2.97 2.58.55 1.1.69 2.36.39 3.54l-2.13 8.54c1.22-.36 2.58.19 3.19 1.37.69 1.34.16 2.98-1.18 3.67l-.13.07c-.74.37-1.54.56-2.34.56Zm-2.26-15.17Zm1.09-9.03c-1.65 0-3.02-1.34-3.02-2.99s1.34-3.01 2.99-3.01h.03c1.65 0 2.99 1.34 2.99 2.99s-1.34 3.01-2.99 3.01Z"}]},warning:{viewBox:"0 0 24 24",paths:[{d:"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003ZM12 8.25a.75.75 0 0 1 .75.75v3.75a.75.75 0 0 1-1.5 0V9a.75.75 0 0 1 .75-.75Zm0 8.25a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Z",fillRule:"evenodd",clipRule:"evenodd"}]}};function i({name:e,...t}){const s=a[e];if(!s)return null;const i=s.stroke;return(0,r.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:s.viewBox,fill:i?"none":"currentColor",stroke:i?"currentColor":void 0,strokeWidth:i?"1.5":void 0,"aria-hidden":"true",focusable:"false",...t,children:s.paths.map((e,t)=>(0,r.jsx)("path",{...e},t))})}},9251:(e,t,s)=>{s.d(t,{J1:()=>g,OJ:()=>m,Rt:()=>p,UT:()=>l,cy:()=>c,e4:()=>h,j:()=>o,lC:()=>u,vq:()=>d});var r=s(1455),a=s.n(r),i=s(5337);const n={"1-week":7,"2-weeks":14,"1-month":30,"3-months":90,"6-months":180,"1-year":365,forever:3650};async function o({status:e="publish",perPage:t=5,page:s=1,excludeProvider:r,provider:i,excludeIds:n=[],needsPagination:o=!0}={}){const l={status:e,per_page:t,page:s,_embed:!0,"filter[orderby]":"menu_order","filter[order]":"ASC"};r&&(l.exclude_provider=r),i&&(l.provider=i),n.length>0&&(l.exclude=n.join(","));const p=function(e){const t=new URLSearchParams;return Object.entries(e).forEach(([e,s])=>{Array.isArray(s)?s.forEach(s=>t.append(e,s)):null!=s&&""!==s&&t.append(e,s)}),t.toString()}(l);try{if(!o)return{tasks:await a()({path:`/wp/v2/prpl_recommendations?${p}`})||[],totalPages:1,hasMore:!1};const e=await a()({path:`/wp/v2/prpl_recommendations?${p}`,parse:!1}),t=await e.json(),r=parseInt(e.headers.get("X-WP-TotalPages")||"1",10);return{tasks:t||[],totalPages:r,hasMore:s{e(e.s=1831)}]);
\ No newline at end of file
diff --git a/build/editor.asset.php b/build/editor.asset.php
new file mode 100644
index 0000000000..b3cc9e6203
--- /dev/null
+++ b/build/editor.asset.php
@@ -0,0 +1 @@
+ array('react-jsx-runtime', 'wp-components', 'wp-data', 'wp-edit-post', 'wp-element', 'wp-i18n', 'wp-plugins'), 'version' => '1ea649f2424d6b9b7dae', 'handle' => 'undefined-editor');
diff --git a/build/editor.js b/build/editor.js
new file mode 100644
index 0000000000..58aef10ae6
--- /dev/null
+++ b/build/editor.js
@@ -0,0 +1 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[8],{790:e=>{e.exports=window.ReactJSXRuntime},5738:(e,s,n)=>{const t=window.wp.plugins;var r=n(6087);const o=window.wp.editPost;var i=n(7723),l=n(790);function d(){return(0,l.jsx)("span",{className:"progress-planner-icon",style:{display:"inline-flex",width:"20px",height:"20px"},dangerouslySetInnerHTML:{__html:progressPlannerEditor.adminMenuIconSvg}})}const a=window.wp.components,p=window.wp.data,c="progress_planner_page_types";function g({pageTypes:e,defaultPageType:s}){const n=(0,p.useSelect)(e=>{const n=e("core/editor").getEditedPostAttribute(c);return n&&0({label:e.title,value:e.id}));return(0,l.jsx)(a.SelectControl,{label:(0,i.__)("Page type","progress-planner"),value:n,options:r,onChange:e=>{const s={};s[c]=e,t(s)}})}function u({lessonSection:e}){const[s,n]=(0,r.useState)(!1);return(0,l.jsx)("div",{title:(0,i.__)("Video","progress-planner"),children:(0,l.jsxs)("div",{children:[(0,l.jsx)(a.Button,{onClick:()=>n(!0),icon:"video-alt3",variant:"secondary",style:{width:"100%",margin:"15px 0",color:"#38296D",boxShadow:"inset 0 0 0 1px #38296D"},children:e.video_button_label?e.video_button_text:(0,i.__)("Watch video","progress-planner")}),s&&(0,l.jsx)(a.Modal,{title:(0,i.__)("Video","progress-planner"),onRequestClose:()=>n(!1),shouldCloseOnClickOutside:!0,shouldCloseOnEsc:!0,size:"large",children:(0,l.jsx)("div",{children:(0,l.jsx)("div",{dangerouslySetInnerHTML:{__html:e.video}})})})]})})}function h({lesson:e,sectionId:s,wrapperEl:n="div"}){if(!e||!e[s])return(0,l.jsx)("div",{});const t=e[s],r=n,o="string"==typeof n?{}:{title:t.heading,initialOpen:!1};return(0,l.jsxs)(r,{...o,children:[t.video?(0,l.jsx)(u,{lessonSection:t}):(0,l.jsx)("div",{}),t.text?(0,l.jsx)("div",{dangerouslySetInnerHTML:{__html:t.text}}):(0,l.jsx)("div",{})]})}function x({lessonSection:e,pageTodos:s}){const n=[];e.todos&&e.todos.forEach(e=>{e.group_todos.forEach(e=>{e.todo_required&&n.push(e.id)})});const t=(s||"").split(",").filter(e=>e&&n.includes(e)),r=n.length>0?Math.round(t.length/n.length*100):0;return(0,l.jsxs)("div",{children:[(0,l.jsxs)("div",{style:{width:"100%",display:"flex",alignItems:"center"},children:[(0,l.jsx)("div",{style:{width:"100%",backgroundColor:"#e1e3e7",height:"15px",borderRadius:"5px"},children:(0,l.jsx)("div",{style:{width:`${r}%`,backgroundColor:"#14b8a6",height:"15px",borderRadius:"5px"}})}),(0,l.jsx)("div",{style:{margin:"0 5px",fontSize:"12px",color:"#38296D"},children:`${r}%`})]}),(0,l.jsx)("div",{dangerouslySetInnerHTML:{__html:window.prplL10nStrings?.checklistProgressDescription||""}})]})}function _({item:e,pageTodos:s}){const{editPost:n}=(0,p.useDispatch)("core/editor"),t=(s||"").split(",").filter(e=>e).includes(e.id);return(0,l.jsx)("div",{children:(0,l.jsx)(a.CheckboxControl,{checked:t,label:e.todo_name,className:e.todo_required?"progress-planner-todo-item required":"progress-planner-todo-item",help:(0,l.jsx)("div",{dangerouslySetInnerHTML:{__html:e.todo_description}}),onChange:t=>{const r=(s||"").split(",").filter(e=>e);if(t)r.includes(e.id)||r.push(e.id);else{const s=r.indexOf(e.id);s>-1&&r.splice(s,1)}n({meta:{progress_planner_page_todos:r.join(",")}})}})})}function j({lessonSection:e,pageTodos:s}){return e.todos?(0,l.jsx)(l.Fragment,{children:e.todos.map(e=>(0,l.jsx)(a.PanelBody,{title:e.group_heading,initialOpen:!1,children:(0,l.jsx)("div",{children:e.group_todos.map(e=>(0,l.jsx)(_,{item:e,pageTodos:s},e.id))})},`progress-planner-sidebar-lesson-section-${e.group_heading}`))}):null}function y({lessons:e,pageTypes:s,defaultPageType:n}){const t=(0,p.useSelect)(e=>e("core/editor").getEditedPostAttribute("progress_planner_page_types")),o=(0,p.useSelect)(e=>{const s=e("core/editor").getEditedPostAttribute("meta");return s?s.progress_planner_page_todos:""},[])||"",i=function(e,s,n){return Array.isArray(e)?e=e.length>0?e[0]:0:e?"string"==typeof e?e=parseInt(e):"number"!=typeof e&&(e=0):e=0,e||(e=parseInt(n)),s.find(s=>parseInt(s.id)===parseInt(e))?.slug}(t,s,n);if(!i||!e||0===e.length)return(0,l.jsx)("div",{});const d=e.find(e=>e.settings.id===i);if(!d)return(0,l.jsx)("div",{});const c={...d};return c.content_update_cycle?.text&&(c.content_update_cycle.text=c.content_update_cycle.text.replace(/\{page_type\}/g,c.name).replace(/\{update_cycle\}/g,c.content_update_cycle.update_cycle)),(0,l.jsxs)(r.Fragment,{children:[(0,l.jsx)(h,{lesson:c,sectionId:"content_update_cycle",wrapperEl:"div"}),(0,l.jsx)(h,{lesson:c,sectionId:"intro",wrapperEl:a.PanelBody}),c.checklist?(0,l.jsx)(a.PanelBody,{title:c.checklist.heading,initialOpen:!1,children:(0,l.jsxs)("div",{children:[c.checklist.video?(0,l.jsx)(u,{lessonSection:c.checklist}):(0,l.jsx)("div",{}),(0,l.jsx)(x,{lessonSection:c.checklist,pageTodos:o}),(0,l.jsx)(j,{lessonSection:c.checklist,pageTodos:o})]})}):(0,l.jsx)("div",{}),(0,l.jsx)(h,{lesson:c,sectionId:"writers_block",wrapperEl:a.PanelBody})]})}function f({lessons:e,pageTypes:s,defaultPageType:n}){return(0,l.jsxs)(r.Fragment,{children:[(0,l.jsx)(o.PluginSidebarMoreMenuItem,{target:"progress-planner-sidebar",children:(0,i.__)("Progress Planner Sidebar","progress-planner")}),(0,l.jsx)(o.PluginSidebar,{name:"progress-planner-sidebar",title:(0,i.__)("Progress Planner Sidebar","progress-planner"),icon:(0,l.jsx)(d,{}),children:(0,l.jsxs)("div",{style:{padding:"15px",borderBottom:"1px solid #ddd"},children:[(0,l.jsx)(g,{pageTypes:s,defaultPageType:n}),(0,l.jsx)(y,{lessons:e,pageTypes:s,defaultPageType:n})]})})]})}const v=window.progressPlannerEditor||{lessons:[],pageTypes:[],defaultPageType:0};(0,t.registerPlugin)("progress-planner-sidebar",{render:()=>(0,l.jsx)(f,{lessons:v.lessons,pageTypes:v.pageTypes,defaultPageType:v.defaultPageType})}),(0,t.registerPlugin)("progress-planner-post-status",{render:function(){const{openGeneralSidebar:e}=(0,p.useDispatch)("core/edit-post");return(0,l.jsxs)("div",{children:[(0,l.jsx)(o.PluginPostStatusInfo,{children:(0,l.jsx)(a.Button,{icon:(0,l.jsx)(d,{}),style:{width:"100%",margin:"15px 0",color:"#38296D",boxShadow:"inset 0 0 0 1px #38296D",fontWeight:"bold"},variant:"secondary",href:"#",onClick:()=>{e("progress-planner-sidebar/progress-planner-sidebar")},children:(0,i.__)("Progress Planner","progress-planner")})}),(0,l.jsx)(o.PluginPostStatusInfo,{})]})}})},6087:e=>{e.exports=window.wp.element},7723:e=>{e.exports=window.wp.i18n}},e=>{e(e.s=5738)}]);
\ No newline at end of file
diff --git a/build/plugin-deactivation-rtl.css b/build/plugin-deactivation-rtl.css
new file mode 100644
index 0000000000..ef75f7654f
--- /dev/null
+++ b/build/plugin-deactivation-rtl.css
@@ -0,0 +1 @@
+.prpl-deactivation-modal{align-items:center;display:flex;height:100%;justify-content:center;right:0;position:fixed;top:0;width:100%;z-index:100000}.prpl-deactivation-backdrop{background-color:rgba(0,0,0,.5);height:100%;right:0;position:fixed;top:0;width:100%}.prpl-deactivation-content{background:#fff;border:1px solid #ccc;border-radius:8px;max-height:80vh;max-width:600px;overflow-y:auto;padding:2rem;position:relative;width:90%;z-index:1}.prpl-deactivation-content .reason-wrapper,.prpl-deactivation-content form{display:flex;flex-direction:column;gap:1rem}.prpl-deactivation-content .feedback-wrapper{display:none}.prpl-deactivation-content .feedback-visible{display:block}.prpl-deactivation-content .feedback-wrapper input,.prpl-deactivation-content .feedback-wrapper textarea{border:1px solid #ccc;border-radius:4px;padding:.5rem;width:100%}.prpl-deactivation-content .actions{display:flex;gap:1rem}.prpl-deactivation-content button{border:1px solid #ccc;border-radius:4px;cursor:pointer;margin:0;padding:.5rem 1rem}.prpl-deactivation-content button.submit{background-color:green;color:#fff}.prpl-deactivation-content button.dismiss{background-color:#fff;color:#000}
diff --git a/build/plugin-deactivation.asset.php b/build/plugin-deactivation.asset.php
new file mode 100644
index 0000000000..9f07ce8c1b
--- /dev/null
+++ b/build/plugin-deactivation.asset.php
@@ -0,0 +1 @@
+ array('react-jsx-runtime', 'wp-element', 'wp-i18n'), 'version' => '52a4da450d026bdbf821', 'handle' => 'undefined-plugin-deactivation');
diff --git a/build/plugin-deactivation.css b/build/plugin-deactivation.css
new file mode 100644
index 0000000000..13853267be
--- /dev/null
+++ b/build/plugin-deactivation.css
@@ -0,0 +1 @@
+.prpl-deactivation-modal{align-items:center;display:flex;height:100%;justify-content:center;left:0;position:fixed;top:0;width:100%;z-index:100000}.prpl-deactivation-backdrop{background-color:rgba(0,0,0,.5);height:100%;left:0;position:fixed;top:0;width:100%}.prpl-deactivation-content{background:#fff;border:1px solid #ccc;border-radius:8px;max-height:80vh;max-width:600px;overflow-y:auto;padding:2rem;position:relative;width:90%;z-index:1}.prpl-deactivation-content .reason-wrapper,.prpl-deactivation-content form{display:flex;flex-direction:column;gap:1rem}.prpl-deactivation-content .feedback-wrapper{display:none}.prpl-deactivation-content .feedback-visible{display:block}.prpl-deactivation-content .feedback-wrapper input,.prpl-deactivation-content .feedback-wrapper textarea{border:1px solid #ccc;border-radius:4px;padding:.5rem;width:100%}.prpl-deactivation-content .actions{display:flex;gap:1rem}.prpl-deactivation-content button{border:1px solid #ccc;border-radius:4px;cursor:pointer;margin:0;padding:.5rem 1rem}.prpl-deactivation-content button.submit{background-color:green;color:#fff}.prpl-deactivation-content button.dismiss{background-color:#fff;color:#000}
diff --git a/build/plugin-deactivation.js b/build/plugin-deactivation.js
new file mode 100644
index 0000000000..25f0c7c28a
--- /dev/null
+++ b/build/plugin-deactivation.js
@@ -0,0 +1 @@
+(()=>{"use strict";const e=window.wp.element,t=window.wp.i18n,n=window.ReactJSXRuntime;function a({config:a,isOpen:i,onDismiss:s}){const[o,r]=(0,e.useState)(""),[c,d]=(0,e.useState)(""),[l,p]=(0,e.useState)(!1);if(!i)return null;const{reasons:u,remoteServerUrl:v,pluginSlug:h,siteUrl:m,deactivateUrl:f}=a;return(0,n.jsxs)("div",{className:"prpl-deactivation-modal",children:[(0,n.jsx)("div",{className:"prpl-deactivation-backdrop"}),(0,n.jsxs)("div",{className:"prpl-deactivation-content",children:[(0,n.jsx)("h1",{children:(0,t.__)("We're sorry to see you go","progress-planner")}),(0,n.jsx)("p",{children:(0,t.__)("If you have a moment, please let us know why you are deactivating this plugin:","progress-planner")}),(0,n.jsxs)("form",{onSubmit:e=>e.preventDefault(),children:[u.map(e=>(0,n.jsxs)("div",{className:"reason-wrapper","data-reason":e.id,children:[(0,n.jsxs)("span",{className:"radio-wrapper",children:[(0,n.jsx)("input",{id:`deactivate-plugin-reason-${e.id}`,type:"radio",name:"reason",value:e.id,checked:o===e.id,onChange:()=>{r(e.id),d("")}}),(0,n.jsx)("label",{htmlFor:`deactivate-plugin-reason-${e.id}`,children:e.label})]}),o===e.id&&e.feedback_type&&(0,n.jsx)("div",{className:"feedback-wrapper feedback-visible",children:"textarea"===e.feedback_type?(0,n.jsx)("textarea",{placeholder:e.feedback_placeholder,value:c,onChange:e=>d(e.target.value)}):(0,n.jsx)("input",{type:"text",placeholder:e.feedback_placeholder,value:c,onChange:e=>d(e.target.value)})})]},e.id)),(0,n.jsxs)("div",{className:"actions",children:[(0,n.jsx)("button",{type:"button",className:"submit",onClick:async()=>{p(!0);const e={action:"plugin_deactivation",plugin:h,site:m};try{const t=new FormData;Object.entries(e).forEach(([e,n])=>{t.append(e,n)});const n=await fetch(`${v}/?rest_route=/deactivation-feedback-server/v1/get-nonce`,{method:"POST",body:t}).then(e=>e.json()),a=new FormData;Object.entries({...e,nonce:n?.nonce||"",reason:o,feedback:c}).forEach(([e,t])=>{a.append(e,t)}),await fetch(`${v}/?rest_route=/deactivation-feedback-server/v1/submit-feedback`,{method:"POST",body:a})}catch{}s?s():window.location.href=f},disabled:l,children:(0,t.__)("Submit & Deactivate","progress-planner")}),(0,n.jsx)("button",{type:"button",className:"dismiss",onClick:()=>{s?s():window.location.href=f},children:(0,t.__)("Skip & Deactivate","progress-planner")})]})]})]})]})}function i(){const[t,i]=(0,e.useState)(!1),s=window.prplDeactivationConfig||{};return(0,e.useEffect)(()=>{const e=document.getElementById(`deactivate-${s.pluginSlug}`);if(!e)return;const t=e=>{e.preventDefault(),i(!0)};return e.addEventListener("click",t),()=>{e.removeEventListener("click",t)}},[s.pluginSlug]),(0,n.jsx)(a,{config:s,isOpen:t,onDismiss:()=>{i(!1);const e=document.getElementById(`deactivate-${s.pluginSlug}`);e&&(window.location.href=e.href)}})}const s=document.getElementById("prpl-deactivation-root");s&&(0,e.createRoot)(s).render((0,n.jsx)(i,{}))})();
\ No newline at end of file
diff --git a/build/runtime.asset.php b/build/runtime.asset.php
new file mode 100644
index 0000000000..c0727e6e6b
--- /dev/null
+++ b/build/runtime.asset.php
@@ -0,0 +1 @@
+ array(), 'version' => '02758cdb5ff917b9a8c8', 'handle' => 'undefined-runtime');
diff --git a/build/runtime.js b/build/runtime.js
new file mode 100644
index 0000000000..e3d24f550f
--- /dev/null
+++ b/build/runtime.js
@@ -0,0 +1 @@
+(()=>{"use strict";var e,r,t,o={},n={};function a(e){var r=n[e];if(void 0!==r)return r.exports;var t=n[e]={exports:{}};return o[e](t,t.exports,a),t.exports}a.m=o,e=[],a.O=(r,t,o,n)=>{if(!t){var i=1/0;for(u=0;u=n)&&Object.keys(a.O).every(e=>a.O[e](t[s]))?t.splice(s--,1):(l=!1,n0&&e[u-1][2]>n;u--)e[u]=e[u-1];e[u]=[t,o,n]},a.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return a.d(r,{a:r}),r},a.d=(e,r)=>{for(var t in r)a.o(r,t)&&!a.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},a.f={},a.e=e=>Promise.all(Object.keys(a.f).reduce((r,t)=>(a.f[t](e,r),r),[])),a.u=e=>({4:"SiteIconPopover",152:"LocalePopover",393:"MonthlyBadgesPopover",426:"AIOSEOPopover",454:"DisableCommentsPopover",496:"EmailSendingPopover",510:"BlogDescriptionPopover",529:"TimezonePopover",624:"PermalinkStructurePopover",648:"YoastPopover",717:"CustomPopover",770:"SubscribeFormPopover",869:"ImprovePdfHandlingPopover",880:"UpgradeTasksPopover",937:"BadgeStreakPopover",941:"DateFormatPopover"}[e]+".chunk.js"),a.miniCssF=e=>"ImprovePdfHandlingPopover.css",a.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),a.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r={},t="progress-planner:",a.l=(e,o,n,i)=>{if(r[e])r[e].push(o);else{var l,s;if(void 0!==n)for(var p=document.getElementsByTagName("script"),u=0;u{l.onerror=l.onload=null,clearTimeout(v);var n=r[e];if(delete r[e],l.parentNode&&l.parentNode.removeChild(l),n&&n.forEach(e=>e(o)),t)return t(o)},v=setTimeout(c.bind(null,void 0,{type:"timeout",target:l}),12e4);l.onerror=c.bind(null,l.onerror),l.onload=c.bind(null,l.onload),s&&document.head.appendChild(l)}},a.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;a.g.importScripts&&(e=a.g.location+"");var r=a.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var o=t.length-1;o>-1&&(!e||!/^http(s?):/.test(e));)e=t[o--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),a.p=e})(),(()=>{if("undefined"!=typeof document){var e={121:0};a.f.miniCss=(r,t)=>{e[r]?t.push(e[r]):0!==e[r]&&{869:1}[r]&&t.push(e[r]=(e=>new Promise((r,t)=>{var o=a.miniCssF(e),n=a.p+o;if(((e,r)=>{for(var t=document.getElementsByTagName("link"),o=0;o{var i=document.createElement("link");i.rel="stylesheet",i.type="text/css",a.nc&&(i.nonce=a.nc),i.onerror=i.onload=t=>{if(i.onerror=i.onload=null,"load"===t.type)o();else{var a=t&&t.type,l=t&&t.target&&t.target.href||r,s=new Error("Loading CSS chunk "+e+" failed.\n("+a+": "+l+")");s.name="ChunkLoadError",s.code="CSS_CHUNK_LOAD_FAILED",s.type=a,s.request=l,i.parentNode&&i.parentNode.removeChild(i),n(s)}},i.href=r,document.head.appendChild(i)})(e,n,0,r,t)}))(r).then(()=>{e[r]=0},t=>{throw delete e[r],t}))}}})(),(()=>{var e={121:0};a.f.j=(r,t)=>{var o=a.o(e,r)?e[r]:void 0;if(0!==o)if(o)t.push(o[2]);else if(121!=r){var n=new Promise((t,n)=>o=e[r]=[t,n]);t.push(o[2]=n);var i=a.p+a.u(r),l=new Error;a.l(i,t=>{if(a.o(e,r)&&(0!==(o=e[r])&&(e[r]=void 0),o)){var n=t&&("load"===t.type?"missing":t.type),i=t&&t.target&&t.target.src;l.message="Loading chunk "+r+" failed.\n("+n+": "+i+")",l.name="ChunkLoadError",l.type=n,l.request=i,o[1](l)}},"chunk-"+r,r)}else e[r]=0},a.O.j=r=>0===e[r];var r=(r,t)=>{var o,n,[i,l,s]=t,p=0;if(i.some(r=>0!==e[r])){for(o in l)a.o(l,o)&&(a.m[o]=l[o]);if(s)var u=s(a)}for(r&&r(t);p array('react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '5378b7a6e1c709f1b936', 'handle' => 'undefined-widget-activity-scores');
diff --git a/build/widget-activity-scores.css b/build/widget-activity-scores.css
new file mode 100644
index 0000000000..b83e7450bc
--- /dev/null
+++ b/build/widget-activity-scores.css
@@ -0,0 +1 @@
+.prpl-tooltip-wrapper .prpl-tooltip p{margin-bottom:0}.prpl-tooltip-wrapper .prpl-tooltip p:first-child{margin-top:0}
diff --git a/build/widget-activity-scores.js b/build/widget-activity-scores.js
new file mode 100644
index 0000000000..073ff09b59
--- /dev/null
+++ b/build/widget-activity-scores.js
@@ -0,0 +1,10 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[825],{475:(e,t,r)=>{r.d(t,{A:()=>o});var n=r(6087),a=r(790);function o({value:e=0,max:t=10,backgroundColor:r="var(--prpl-background-monthly)",color:o="var(--prpl-color-monthly)",color2:s="var(--prpl-color-monthly-2)",contentFontSize:i="var(--prpl-font-size-6xl)",children:l}){const c="180deg",d={padding:"var(--prpl-padding) var(--prpl-padding) calc(var(--prpl-padding) * 2) var(--prpl-padding)",background:r,borderRadius:"var(--prpl-border-radius-big)",aspectRatio:"2 / 1",overflow:"hidden",position:"relative",marginBottom:"var(--prpl-padding)"},p={width:"100%",aspectRatio:"1 / 1",borderRadius:"100%",position:"relative",background:`radial-gradient(${r} 0 57%, transparent 57% 100%), conic-gradient(from 270deg, ${(0,n.useMemo)(()=>{const r=t>0?e/t:0;let n;return r<=.5?n=`${o} calc(${c} * ${r})`:(n=`${o} calc(${c} * 0.5)`,n+=`, ${s} calc(${c} * ${r})`),n+=`, var(--prpl-color-gauge-remain) calc(${c} * ${r}) ${c}`,n},[e,t,o,s])}, transparent ${c})`,textAlign:"center"},u={fontSize:"var(--prpl-font-size-small)",position:"absolute",top:"50%",color:"var(--prpl-color-text)",width:"10%",textAlign:"center"},g={...u,left:0},h={...u,right:0},m={fontSize:i,bottom:"50%",display:"block",fontWeight:600,textAlign:"center",position:"absolute",color:"var(--prpl-color-text)",width:"100%",lineHeight:1.2};return(0,a.jsx)("div",{className:"prpl-gauge",style:d,children:(0,a.jsxs)("div",{className:"prpl-gauge__ring",style:p,children:[(0,a.jsx)("span",{className:"prpl-gauge__label prpl-gauge__label--min",style:g,children:"0"}),(0,a.jsx)("span",{className:"prpl-gauge__content",style:m,children:(0,a.jsx)("span",{className:"prpl-gauge__content-inner",style:{display:"inline-block",width:"50%"},children:l})}),(0,a.jsx)("span",{className:"prpl-gauge__label prpl-gauge__label--max",style:h,children:t})]})})}},790:e=>{e.exports=window.ReactJSXRuntime},1059:(e,t,r)=>{r.d(t,{A:()=>g});var n=r(6087),a=r(7723),o=r(790);const s={position:"absolute",top:0,right:0,transform:"translate(-10px, -10px) rotate(90deg)",width:0,height:0,borderStyle:"solid",borderWidth:"7.5px 10px 7.5px 0",borderColor:"transparent var(--prpl-background-activity) transparent transparent"},i={padding:0,lineHeight:1,background:"none",border:"none",cursor:"pointer",fontSize:"var(--prpl-font-size-small)",color:"var(--prpl-color-link)"},l={display:"inline-flex",alignItems:"center",position:"relative"},c={display:"block",position:"absolute",bottom:0,left:"100%",transform:"translate(-100%, calc(100% + 10px))",padding:"0.75rem 1.5rem 0.75rem 0.75rem",width:150,background:"var(--prpl-background-activity)",borderRadius:"var(--prpl-border-radius)",zIndex:2,visibility:"hidden",fontSize:"1rem",fontWeight:400,color:"var(--prpl-color-text)"},d={visibility:"visible",zIndex:10},p={position:"absolute",top:0,right:0,padding:"0.1rem",lineHeight:0,margin:0,background:"none",border:"none",cursor:"pointer"},u={display:"block",position:"fixed",top:0,left:0,width:"100%",height:"100%",zIndex:9,backgroundColor:"rgba(0, 0, 0, 0.5)"};function g({triggerContent:e,children:t,tooltipStyle:r,arrowStyle:g,onClose:h}){const[m,f]=(0,n.useState)(!1),[v,x]=(0,n.useState)(!1),b=(0,n.useRef)(null),y=(0,n.useId)(),w=(0,n.useCallback)(()=>{f(!1),h?.()},[h]);(0,n.useEffect)(()=>{if(!m)return;const e=e=>{"Escape"===e.key&&w()};return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)},[m,w]);const k={...i,textDecoration:v?"underline":"none"};return(0,o.jsxs)("span",{className:"prpl-tooltip-wrapper",style:l,children:[(0,o.jsx)("button",{type:"button",className:"prpl-info-icon","aria-describedby":y,onClick:()=>f(!0),style:k,onMouseEnter:()=>x(!0),onMouseLeave:()=>x(!1),children:e}),m&&(0,o.jsx)("span",{role:"presentation",onClick:w,style:u}),(0,o.jsxs)("span",{ref:b,id:y,className:"prpl-tooltip",role:"tooltip","aria-hidden":!m,style:{...c,...m?d:{},...r},children:[(0,o.jsx)("span",{"data-testid":"tooltip-arrow",style:{...s,...g}}),t,(0,o.jsxs)("button",{type:"button",onClick:w,style:p,children:[(0,o.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,o.jsx)("span",{className:"screen-reader-text",children:(0,a.__)("Close","progress-planner")})]})]})]})}},1362:(e,t,r)=>{r.d(t,{Cu:()=>o,cr:()=>s});var n=r(2619);const a=[];function o(e){const{id:t,component:r,priority:n=10,width:o=1,forceLastColumn:s=!1,title:i=""}=e;if(!t||!r)return void console.warn("Widget registration failed: id and component are required",e);const l=a.findIndex(e=>e.id===t),c={id:t,component:r,priority:n,width:o,forceLastColumn:s,title:i};l>=0?a[l]=c:a.push(c)}function s(){return[...a].sort((e,t)=>e.priority-t.priority)}(0,n.addAction)("prpl.dashboard.registerWidget","progress-planner/widget-registry",o)},1455:e=>{e.exports=window.wp.apiFetch},2619:e=>{e.exports=window.wp.hooks},5262:(e,t,r)=>{r.d(t,{A:()=>o});var n=r(6087),a=r(790);function o({number:e,label:t,backgroundColor:r="var(--prpl-background-content)"}){const o=(0,n.useRef)(null),s=(0,n.useRef)(null),i=(0,n.useCallback)(()=>{const e=s.current,t=o.current;if(!e||!t)return;e.style.fontSize="100%",e.style.width="max-content";const r=t.clientWidth;let n=100;for(;e.clientWidth>r&&n>80;)n-=1,e.style.fontSize=n+"%";n<=80&&(e.style.fontSize="80%",e.style.width="100%")},[]);(0,n.useEffect)(()=>(i(),window.addEventListener("resize",i),()=>{window.removeEventListener("resize",i)}),[i,t]);const l={backgroundColor:r,padding:"var(--prpl-padding)",borderRadius:"var(--prpl-border-radius-big)",display:"flex",flexDirection:"column",alignItems:"center",textAlign:"center",alignContent:"center",justifyContent:"center",height:"calc(var(--prpl-font-size-5xl) + var(--prpl-font-size-2xl) + var(--prpl-padding) * 2)",marginBottom:"var(--prpl-padding)"};return(0,a.jsxs)("div",{className:"prpl-big-counter",style:l,children:[(0,a.jsx)("div",{className:"prpl-big-counter__width-reference",ref:o,style:{width:"100%"}}),(0,a.jsx)("span",{className:"prpl-big-counter__number",style:{fontSize:"var(--prpl-font-size-5xl)",lineHeight:1,fontWeight:600},children:e}),(0,a.jsx)("span",{className:"prpl-big-counter__label-wrapper",style:{fontSize:"var(--prpl-font-size-2xl)"},children:(0,a.jsx)("span",{className:"prpl-big-counter__label",ref:s,style:{fontSize:"100%",display:"inline-block",width:"max-content"},children:t})})]})}},5337:(e,t,r)=>{r.d(t,{BJ:()=>l,IL:()=>c,Wz:()=>d});var n=r(1455),a=r.n(n);const o=new Map,s=new Map,i=3e5;async function l(e,t={}){const{skipCache:r=!1,ttl:n=i}=t,l=function(e){if("GET"!==(e.method||"GET").toUpperCase())return null;let t=e.path||e.url||"";if(e.data&&"object"==typeof e.data){const r=new URLSearchParams(e.data).toString();r&&(t+=(t.includes("?")?"&":"?")+r)}return`GET:${t}`}(e);if(!l)return a()(e);if(!r&&o.has(l))return o.get(l);if(!r){const e=s.get(l);if(e&&Date.now()-e.timestamp(s.set(l,{data:e,timestamp:Date.now()}),o.delete(l),e)).catch(e=>{throw o.delete(l),e});return o.set(l,c),c}function c(){s.clear(),o.clear()}function d(e,t){const r=`GET:${e}`;s.set(r,{data:t,timestamp:Date.now()})}},5815:(e,t,r)=>{r.d(t,{Q8:()=>d,iA:()=>c,rr:()=>p});var n=r(6087),a=r(790);const o="\n@keyframes prpl-shimmer {\n\t0% { background-position: 200% 0; }\n\t100% { background-position: -200% 0; }\n}\n";let s=!1;function i(){if(s||"undefined"==typeof document)return;const e=document.createElement("style");e.id="prpl-skeleton-keyframes",e.textContent=o,document.head.appendChild(e),s=!0}const l={background:"linear-gradient(\n\t\t90deg,\n\t\tvar(--prpl-color-gauge-remain, #f0f0f0) 25%,\n\t\tvar(--prpl-color-border, #e0e0e0) 50%,\n\t\tvar(--prpl-color-gauge-remain, #f0f0f0) 75%\n\t)",backgroundSize:"200% 100%",animation:"prpl-shimmer 1.5s ease-in-out infinite",borderRadius:"var(--prpl-border-radius, 8px)"};function c({width:e="100%",height:t="1em",className:r="",style:o={}}){return(0,n.useEffect)(()=>{i()},[]),(0,a.jsx)("div",{className:r||void 0,style:{...l,width:e,height:t,...o}})}function d({size:e="40px",className:t="",style:r={}}){return(0,n.useEffect)(()=>{i()},[]),(0,a.jsx)("div",{className:t||void 0,style:{...l,width:e,height:e,borderRadius:"50%",...r}})}function p({width:e="100%",lines:t=1,className:r="",style:o={},lastShort:s=!0}){return(0,n.useEffect)(()=>{i()},[]),1===t?(0,a.jsx)(c,{width:e,height:"1em",className:r,style:o}):(0,a.jsx)("div",{style:{display:"flex",flexDirection:"column",...o},children:Array.from({length:t}).map((n,o)=>(0,a.jsx)(c,{width:s&&o===t-1?"70%":e,height:"1em",className:r,style:{marginBottom:o{e.exports=window.wp.element},7421:(e,t,r)=>{r.d(t,{A:()=>o});var n=r(5815),a=r(790);function o({backgroundColor:e="var(--prpl-background-content)"}){const t={backgroundColor:e,padding:"var(--prpl-padding)",borderRadius:"var(--prpl-border-radius-big)",display:"flex",flexDirection:"column",alignItems:"center",textAlign:"center",alignContent:"center",justifyContent:"center",height:"calc(var(--prpl-font-size-5xl) + var(--prpl-font-size-2xl) + var(--prpl-padding) * 2)",marginBottom:"var(--prpl-padding)",gap:"0.5rem"};return(0,a.jsxs)("div",{style:t,children:[(0,a.jsx)(n.iA,{width:"3rem",height:"var(--prpl-font-size-5xl)",style:{borderRadius:"8px"}}),(0,a.jsx)(n.iA,{width:"8rem",height:"var(--prpl-font-size-2xl)",style:{borderRadius:"4px"}})]})}},7723:e=>{e.exports=window.wp.i18n},8691:(e,t,r)=>{r.d(t,{KS:()=>s});var n=r(6087),a=r(5337);const o=3e5;function s(e,t=[],r="Failed to load data",s={}){const{cache:i=!0,cacheTtl:l=o,skipCache:c=!1}=s,[d,p]=(0,n.useState)(!0),[u,g]=(0,n.useState)(null),[h,m]=(0,n.useState)(null),f=(0,n.useCallback)(async(t=!1)=>{if(e){p(!0),g(null);try{const r=await(0,a.BJ)({path:e},{skipCache:t||c||!i,ttl:l});m(r)}catch(e){const t=e.message||("string"==typeof r?r:r.message||"Failed to load data");g(t)}finally{p(!1)}}else p(!1)},[e,i,l,c,r]);return(0,n.useEffect)(()=>{f()},[e,...t]),{isLoading:d,error:u,data:h,refetch:(0,n.useCallback)((e=!0)=>{f(e)},[f])}}},8864:(e,t,r)=>{r.d(t,{fX:()=>d});const n=window.React,a=e=>{let t;const r=new Set,n=(e,n)=>{const a="function"==typeof e?e(t):e;if(!Object.is(a,t)){const e=t;t=(null!=n?n:"object"!=typeof a||null===a)?a:Object.assign({},t,a),r.forEach(r=>r(t,e))}},a=()=>t,o={setState:n,getState:a,getInitialState:()=>s,subscribe:e=>(r.add(e),()=>r.delete(e))},s=t=e(n,a,o);return o},o=e=>e,s=e=>{const t=(e=>e?a(e):a)(e),r=e=>function(e,t=o){const r=n.useSyncExternalStore(e.subscribe,n.useCallback(()=>t(e.getState()),[e,t]),n.useCallback(()=>t(e.getInitialState()),[e,t]));return n.useDebugValue(r),r}(t,e);return Object.assign(r,t),r};var i=r(1455),l=r.n(i),c=r(5337);const d=(p=(e,t)=>({sessionPoints:0,totalPoints:0,lastCompletionTime:null,lastCompletedTask:null,activityScore:{current:0,target:100},badgeProgress:{},cacheInvalidatedAt:null,shouldAutoStartWizard:!1,providerTerms:{},termsLoading:!1,termsLoaded:!1,onTaskCompleted:(t,r=0)=>e(e=>({sessionPoints:e.sessionPoints+r,lastCompletionTime:Date.now(),lastCompletedTask:t})),onTaskUncompleted:(t,r=0)=>e(e=>({sessionPoints:Math.max(0,e.sessionPoints-r)})),updateActivityScore:t=>e(e=>({activityScore:{...e.activityScore,...t}})),updateBadgeProgress:(t,r)=>e(e=>({badgeProgress:{...e.badgeProgress,[t]:r}})),invalidateCache:()=>{(0,c.IL)(),e({cacheInvalidatedAt:Date.now()})},setShouldAutoStartWizard:t=>{e({shouldAutoStartWizard:t})},getProviderTermId:e=>{const r=t();return r.providerTerms[e]?.id||null},fetchProviderTerms:async()=>{const r=t();if(r.termsLoaded||r.termsLoading)return r.providerTerms;e({termsLoading:!0});try{const t=await l()({path:"/wp/v2/prpl_recommendations_provider?per_page=100"}),r={};let n=!1;if(t.forEach(e=>{r[e.slug]=e,"user"===e.slug&&(n=!0)}),!n)try{const e=await l()({path:"/wp/v2/prpl_recommendations_provider",method:"POST",data:{slug:"user",name:"user"}});r.user=e}catch(e){if("term_exists"===e.code&&e.data?.term_id)try{const t=await l()({path:`/wp/v2/prpl_recommendations_provider/${e.data.term_id}`});r.user=t}catch(e){console.error("Error fetching existing user term:",e)}else console.error("Error creating user term:",e)}return e({providerTerms:r,termsLoading:!1,termsLoaded:!0}),r}catch(t){return console.error("Error fetching provider terms:",t),e({termsLoading:!1}),{}}}}))?s(p):s;var p},8982:(e,t,r)=>{r.d(t,{W5:()=>s,pp:()=>i});var n=r(7723),a=r(790);const o={padding:"1em",backgroundColor:"var(--prpl-color-error-background, #fee)",color:"var(--prpl-color-error, #c00)",borderRadius:"var(--prpl-border-radius)"};function s({message:e=(0,n.__)("An error occurred.","progress-planner"),className:t="",style:r={},simple:s=!1}){return s?(0,a.jsx)("p",{className:t||void 0,children:e}):(0,a.jsx)("div",{className:"prpl-widget-error"+(t?` ${t}`:""),style:{...o,...r},children:e})}function i({message:e=(0,n.__)("No data available.","progress-planner"),className:t=""}){return(0,a.jsx)("p",{className:t||void 0,children:e})}},9061:(e,t,r)=>{r.d(t,{A:()=>o});var n=r(790);const a={arrow:{viewBox:"0 0 20 17",paths:[{d:"M19.92 8.12c-.05-.12-.12-.23-.22-.33L12.21.29A.996.996 0 1 0 10.8 1.7l5.79 5.79H1c-.55 0-1 .45-1 1s.45 1 1 1h15.59l-5.79 5.79a.996.996 0 0 0 .71 1.7c.26 0 .51-.1.71-.29l7.5-7.5c.1-.1.17-.21.22-.33.05-.12.07-.24.08-.38 0-.14-.03-.27-.08-.38Z"}]},trash:{viewBox:"0 0 48 48",paths:[{d:"M32.99 47.88H15.01c-3.46 0-6.38-2.7-6.64-6.15L6.04 11.49l-.72.12c-.82.14-1.59-.41-1.73-1.22-.14-.82.41-1.59 1.22-1.73.79-.14 1.57-.26 2.37-.38h.02c2.21-.33 4.46-.6 6.69-.81v-.72c0-3.56 2.74-6.44 6.25-6.55 2.56-.08 5.15-.08 7.71 0 3.5.11 6.25 2.99 6.25 6.55v.72c2.24.2 4.48.47 6.7.81.79.12 1.59.25 2.38.39.82.14 1.36.92 1.22 1.73-.14.82-.92 1.36-1.73 1.22l-.72-.12-2.33 30.24c-.27 3.45-3.18 6.15-6.64 6.15Zm-17.98-3h17.97c1.9 0 3.51-1.48 3.65-3.38l2.34-30.46c-2.15-.3-4.33-.53-6.48-.7h-.03c-5.62-.43-11.32-.43-16.95 0h-.03c-2.15.17-4.33.4-6.48.7l2.34 30.46c.15 1.9 1.75 3.38 3.65 3.38ZM24 7.01c2.37 0 4.74.07 7.11.22v-.49c0-1.93-1.47-3.49-3.34-3.55-2.5-.08-5.03-.08-7.52 0-1.88.06-3.34 1.62-3.34 3.55v.49c2.36-.15 4.73-.22 7.11-.22Zm5.49 32.26h-.06c-.83-.03-1.47-.73-1.44-1.56l.79-20.65c.03-.83.75-1.45 1.56-1.44.83.03 1.47.73 1.44 1.56l-.79 20.65c-.03.81-.7 1.44-1.5 1.44Zm-10.98 0c-.8 0-1.47-.63-1.5-1.44l-.79-20.65c-.03-.83.61-1.52 1.44-1.56.84 0 1.52.61 1.56 1.44l.79 20.65c.03.83-.61 1.52-1.44 1.56h-.06Z"}]},check:{viewBox:"0 0 20 20",paths:[{d:"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",fillRule:"evenodd",clipRule:"evenodd"}]},close:{viewBox:"0 0 20 20",paths:[{d:"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",fillRule:"evenodd",clipRule:"evenodd"}]},chevronDown:{viewBox:"0 0 24 24",stroke:!0,paths:[{d:"m19.5 8.25-7.5 7.5-7.5-7.5",strokeLinecap:"round",strokeLinejoin:"round"}]},info:{viewBox:"0 0 64 64",paths:[{d:"M32 63.73C14.51 63.73.27 49.49.27 32S14.51.27 32 .27 63.73 14.5 63.73 32 49.5 63.73 32 63.73Zm0-58C17.51 5.73 5.73 17.52 5.73 32S17.52 58.27 32 58.27 58.27 46.48 58.27 32 46.49 5.73 32 5.73Zm1.2 41.4c-.42 0-.83-.05-1.24-.15-1.33-.33-2.46-1.17-3.16-2.34-.71-1.18-.91-2.56-.58-3.9l2.13-8.54c-1.25.36-2.62-.21-3.21-1.42-.66-1.35-.1-2.99 1.25-3.65l.13-.06c1.21-.6 2.6-.7 3.91-.27 1.3.44 2.36 1.35 2.97 2.58.55 1.1.69 2.36.39 3.54l-2.13 8.54c1.22-.36 2.58.19 3.19 1.37.69 1.34.16 2.98-1.18 3.67l-.13.07c-.74.37-1.54.56-2.34.56Zm-2.26-15.17Zm1.09-9.03c-1.65 0-3.02-1.34-3.02-2.99s1.34-3.01 2.99-3.01h.03c1.65 0 2.99 1.34 2.99 2.99s-1.34 3.01-2.99 3.01Z"}]},warning:{viewBox:"0 0 24 24",paths:[{d:"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003ZM12 8.25a.75.75 0 0 1 .75.75v3.75a.75.75 0 0 1-1.5 0V9a.75.75 0 0 1 .75-.75Zm0 8.25a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Z",fillRule:"evenodd",clipRule:"evenodd"}]}};function o({name:e,...t}){const r=a[e];if(!r)return null;const o=r.stroke;return(0,n.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:r.viewBox,fill:o?"none":"currentColor",stroke:o?"currentColor":void 0,strokeWidth:o?"1.5":void 0,"aria-hidden":"true",focusable:"false",...t,children:r.paths.map((e,t)=>(0,n.jsx)("path",{...e},t))})}},9235:(e,t,r)=>{r.d(t,{A:()=>o});var n=r(5815),a=r(790);function o({backgroundColor:e="var(--prpl-background-monthly)"}){const t={padding:"var(--prpl-padding) var(--prpl-padding) calc(var(--prpl-padding) * 2) var(--prpl-padding)",background:e,borderRadius:"var(--prpl-border-radius-big)",aspectRatio:"2 / 1",overflow:"hidden",position:"relative",marginBottom:"var(--prpl-padding)",display:"flex",justifyContent:"center",alignItems:"flex-start"};return(0,a.jsx)("div",{style:t,children:(0,a.jsxs)("div",{style:{width:"100%",aspectRatio:"1 / 1",position:"relative",display:"flex",justifyContent:"center",alignItems:"center"},children:[(0,a.jsx)(n.Q8,{size:"100%",style:{position:"absolute",opacity:.3}}),(0,a.jsx)("div",{style:{position:"absolute",top:"35%",display:"flex",flexDirection:"column",alignItems:"center",gap:"0.5em"},children:(0,a.jsx)(n.iA,{width:"3em",height:"2.5em",style:{borderRadius:"8px"}})})]})})}},9277:(e,t,r)=>{r.d(t,{A:()=>c});var n=r(7723),a=r(1059),o=r(9061),s=r(790);const i={display:"flex",justifyContent:"flex-start",flexWrap:"wrap",position:"relative"},l={width:"1.25rem",height:"1.25rem",display:"inline-block",verticalAlign:"bottom",color:"#6b7280"};function c({title:e,tooltipContent:t="",className:r=""}){return(0,s.jsxs)("h2",{className:"prpl-widget-title"+(r?` ${r}`:""),children:[e,t&&(0,s.jsx)("div",{style:i,children:(0,s.jsx)(a.A,{triggerContent:(0,s.jsxs)("span",{style:l,children:[(0,s.jsx)(o.A,{name:"info"}),(0,s.jsx)("span",{className:"screen-reader-text",children:(0,n.__)("More info","progress-planner")})]}),children:t})})]})}},9458:(e,t,r)=>{var n=r(6087),a=r(7723),o=r(1362),s=r(475),i=r(790);function l({data:e=[]}){const t=(0,n.useRef)(null),r=e.length>6?Math.floor(e.length/6):1;(0,n.useEffect)(()=>{if(!t.current)return;if(0===t.current.querySelectorAll(".label.invisible").length)return;const e=t.current.querySelectorAll(".label-container"),r=t.current.querySelector(".chart-bar");e.forEach(e=>{const t=e.querySelector(".label");if(!t)return;const r=t.offsetWidth;t.style.display="block",t.style.width="0";const n=(e.offsetWidth-r)/2;t.classList.contains("visible")&&(t.style.marginLeft=`${n}px`)});const n=t.current.querySelector(".label");if(n&&r){const e=Math.max(n.offsetWidth/4,1);r.style.gap=`${Math.floor(e)}px`}},[e]);const a={flex:"auto",display:"flex",flexDirection:"column",justifyContent:"flex-end",height:"100%"},o={height:"1rem",overflow:"visible",textAlign:"center",display:"block",width:"100%",fontSize:"0.75em"};return(0,i.jsx)("div",{className:"prpl-bar-chart",ref:t,children:(0,i.jsx)("div",{className:"chart-bar",style:{display:"flex",maxWidth:"600px",height:"200px",width:"100%",alignItems:"flex-end",gap:"5px",margin:"1rem 0"},children:e.map((e,t)=>{const n={display:"block",width:"100%",height:`${e.score}%`,background:e.color},s=t%r===0,l=s?"label visible":"label invisible",c=s?{}:{visibility:"hidden"};return(0,i.jsxs)("div",{className:"prpl-bar-chart__bar-container",style:a,children:[(0,i.jsx)("div",{className:"prpl-bar-chart__bar",style:n,title:`${e.label} - ${e.score}%`}),(0,i.jsx)("span",{className:"label-container",style:o,children:(0,i.jsx)("span",{className:l,style:c,children:e.label})})]},t)})})})}var c=r(5262),d=r(9277),p=r(8982),u=r(9235),g=r(5815);function h({bars:e=6}){const t={flex:"auto",display:"flex",flexDirection:"column",justifyContent:"flex-end",height:"100%"},r={height:"1rem",overflow:"visible",textAlign:"center",display:"block",width:"100%",marginTop:"0.25rem"},n=Array.from({length:e}).map((e,t)=>30+17*t%50);return(0,i.jsx)("div",{children:(0,i.jsx)("div",{style:{display:"flex",maxWidth:"600px",height:"200px",width:"100%",alignItems:"flex-end",gap:"5px",margin:"1rem 0"},children:n.map((e,n)=>(0,i.jsxs)("div",{style:t,children:[(0,i.jsx)(g.iA,{width:"100%",height:`${e}%`,style:{borderRadius:"4px 4px 0 0"}}),(0,i.jsx)("span",{style:r,children:(0,i.jsx)(g.iA,{width:"80%",height:"0.75em",style:{margin:"0 auto"}})})]},n))})})}var m=r(7421);function f(){return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)("div",{style:{"--background":"var(--prpl-background-monthly)"},children:(0,i.jsx)(u.A,{backgroundColor:"var(--prpl-background-activity)"})}),(0,i.jsx)("hr",{}),(0,i.jsx)(g.rr,{width:"80%",style:{marginBottom:"0.5rem"}}),(0,i.jsx)("div",{className:"prpl-graph-wrapper",style:{maxHeight:"300px"},children:(0,i.jsx)(h,{bars:6})}),(0,i.jsx)("hr",{}),(0,i.jsx)(m.A,{backgroundColor:"var(--prpl-background-activity)"}),(0,i.jsx)("div",{className:"prpl-widget-content",children:(0,i.jsx)(g.rr,{lines:2})})]})}var v=r(8691),x=r(8864);function b(e,t,r){const n=new Date;if("monthly"===r&&t===n.toLocaleString("default",{month:"short"}))return"var(--prpl-color-border)";if("weekly"===r)try{const e=new Date(t);if(!isNaN(e.getTime())){const t=new Date(n);t.setDate(n.getDate()-n.getDay()),t.setHours(0,0,0,0);const r=new Date(t);if(r.setDate(t.getDate()+6),r.setHours(23,59,59,999),e>=t&&e<=r)return"var(--prpl-color-border)"}}catch(e){}return e>90?"var(--prpl-graph-color-3)":e>30?"var(--prpl-color-monthly)":"var(--prpl-graph-color-1)"}(0,o.Cu)({id:"activity-scores",component:function({config:e={}}){const t=(0,x.fX)(e=>e.sessionPoints),r=window.prplDashboardConfig||{},o=r.currentRange||"-6 months",u=r.currentFrequency||"monthly",g=`/progress-planner/v1/widgets/activity-scores?range=${encodeURIComponent(o)}&frequency=${encodeURIComponent(u)}`,{isLoading:h,error:m,data:y}=(0,v.KS)(g,[],"Failed to load activity data"),w=e?.title||(0,a.__)("Your website activity score","progress-planner"),k=(0,n.useMemo)(()=>y?.score?Math.min(100,y.score+t):0,[y?.score,t]);if(h)return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(d.A,{title:w}),(0,i.jsx)(f,{})]});if(m)return(0,i.jsx)(p.W5,{message:m,simple:!0});if(!y)return(0,i.jsx)(p.pp,{});const{chartData:j,personalRecord:C}=y,_=(S=k)>=75?"var(--prpl-graph-color-3)":S>=50?"var(--prpl-color-monthly)":"var(--prpl-graph-color-1)";var S;const N=j.map(e=>({...e,color:b(e.score,e.label,u)})),A=function(e,t){if(0===e)return(0,a.__)("This is the start of your first streak! Add content to your site every week and set a personal record!","progress-planner");if(e<=t)return(0,a.sprintf)(
+// translators: %s: number of weeks.
+// translators: %s: number of weeks.
+(0,a._n)("Congratulations! You're on a streak! You've consistently maintained your website for the past %s week! 🎉","Congratulations! You're on a streak! You've consistently maintained your website for the past %s weeks! 🎉",t,"progress-planner"),t);if(t>=1){const r=e-t;return(0,a.sprintf)(
+// translators: %1$s: number of weeks for current streak. %2$s: number of weeks for max streak. %3$s: weeks to go.
+// translators: %1$s: number of weeks for current streak. %2$s: number of weeks for max streak. %3$s: weeks to go.
+(0,a._n)("Keep it up! You've consistently maintained your website for the past %1$s week. Your longest streak was %2$s weeks, %3$s more to go to break your record!","Keep it up! You've consistently maintained your website for the past %1$s weeks. Your longest streak was %2$s weeks, %3$s more to go to break your record!",t,"progress-planner"),t,e,r)}return(0,a.sprintf)(
+// translators: %s: number of weeks for max streak.
+// translators: %s: number of weeks for max streak.
+(0,a._n)("Get back to your streak! Your longest streak was %s week. Keep working on those website maintenance tasks every week and break your record!","Get back to your streak! Your longest streak was %s weeks. Keep working on those website maintenance tasks every week and break your record!",e,"progress-planner"),e)}(C.maxStreak,C.currentStreak);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(d.A,{title:w,tooltipContent:(0,a.__)("Your website activity score is based on the amount of website maintenance work you have done over the past 30 days.","progress-planner")}),(0,i.jsx)("div",{style:{"--background":"var(--prpl-background-monthly)"},children:(0,i.jsx)(s.A,{value:k,max:100,backgroundColor:"var(--prpl-background-activity)",color:_,color2:_,contentFontSize:"var(--prpl-font-size-6xl)",children:k})}),(0,i.jsx)("hr",{}),(0,i.jsx)("p",{children:(0,a.__)("Check out your website activity in the past months:","progress-planner")}),(0,i.jsx)("div",{className:"prpl-graph-wrapper",style:{maxHeight:"300px"},children:(0,i.jsx)(l,{data:N})}),(0,i.jsx)("hr",{}),(0,i.jsx)(c.A,{number:String(C.maxStreak),label:(0,a.__)("personal record","progress-planner"),backgroundColor:"var(--prpl-background-activity)"}),(0,i.jsx)("div",{className:"prpl-widget-content",children:A})]})},priority:4,width:1,forceLastColumn:!1,title:(0,a.__)("Your website activity score","progress-planner")})}},e=>{e(e.s=9458)}]);
\ No newline at end of file
diff --git a/build/widget-content-activity-rtl.css b/build/widget-content-activity-rtl.css
new file mode 100644
index 0000000000..b83e7450bc
--- /dev/null
+++ b/build/widget-content-activity-rtl.css
@@ -0,0 +1 @@
+.prpl-tooltip-wrapper .prpl-tooltip p{margin-bottom:0}.prpl-tooltip-wrapper .prpl-tooltip p:first-child{margin-top:0}
diff --git a/build/widget-content-activity.asset.php b/build/widget-content-activity.asset.php
new file mode 100644
index 0000000000..224f27f733
--- /dev/null
+++ b/build/widget-content-activity.asset.php
@@ -0,0 +1 @@
+ array('react-jsx-runtime', 'wp-api-fetch', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '2561b0883f75c3e3c9c9', 'handle' => 'undefined-widget-content-activity');
diff --git a/build/widget-content-activity.css b/build/widget-content-activity.css
new file mode 100644
index 0000000000..b83e7450bc
--- /dev/null
+++ b/build/widget-content-activity.css
@@ -0,0 +1 @@
+.prpl-tooltip-wrapper .prpl-tooltip p{margin-bottom:0}.prpl-tooltip-wrapper .prpl-tooltip p:first-child{margin-top:0}
diff --git a/build/widget-content-activity.js b/build/widget-content-activity.js
new file mode 100644
index 0000000000..14d0e46ac0
--- /dev/null
+++ b/build/widget-content-activity.js
@@ -0,0 +1 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[951],{539:(e,t,r)=>{var s=r(7723),n=r(1362),a=r(5262),i=r(6087),l=r(790);function o({dataArgs:e,visibleSeries:t,filtersLabel:r,onToggle:s}){const n={display:"flex",alignItems:"center",gap:"0.25em",cursor:"pointer"},a=r=>({backgroundColor:t.includes(r)?e[r].color:"transparent",width:"1em",height:"1em",borderRadius:"0.25em",outline:`1px solid ${e[r].color}`,border:"1px solid #fff"}),i={display:"none"};return(0,l.jsxs)("div",{className:"prpl-line-chart__filters",style:{display:"flex",gap:"1em",marginBottom:"1em",justifyContent:"space-between",fontSize:"0.85rem"},children:[r&&(0,l.jsx)("span",{className:"prpl-line-chart__filters-label",dangerouslySetInnerHTML:{__html:r}}),Object.keys(e).map(r=>(0,l.jsxs)("label",{htmlFor:`prpl-chart-filter-${r}`,className:`prpl-line-chart__filter prpl-line-chart__filter--${r}`,style:n,children:[(0,l.jsx)("span",{className:"prpl-line-chart__filter-color",style:a(r)}),(0,l.jsx)("input",{type:"checkbox",id:`prpl-chart-filter-${r}`,name:r,value:r,checked:t.includes(r),onChange:()=>s(r),style:i}),e[r].label]},r))]})}const c={aspectRatio:2,height:300,axisOffset:16,strokeWidth:4,dataArgs:{},axisColor:"var(--prpl-color-border)",rulersColor:"var(--prpl-color-border)",filtersLabel:""};function d({data:e,options:t}){const r=(0,i.useMemo)(()=>({...c,...t}),[t]),[s,n]=(0,i.useState)(()=>Object.keys(r.dataArgs)),a=(0,i.useCallback)(e=>{n(t=>t.includes(e)?t.filter(t=>t!==e):[...t,e])},[]),d=(0,i.useCallback)(()=>Object.keys(e).reduce((t,r)=>s.includes(r)?Math.max(t,e[r].reduce((e,t)=>Math.max(e,t.score),0)):t,0),[e,s]),p=(0,i.useCallback)(()=>{const e=d(),t=100>e&&70{const e=p(),t={4:e%4,5:e%5,3:e%3},r=Math.min(...Object.values(t));return parseInt(Object.keys(t).find(e=>t[e]===r),10)},[p]),u=(0,i.useCallback)(()=>{const e=p(),t=h(),r=e/t,s=[];if(100===e||15>e)for(let e=0;e<=t;e++)s.push(parseInt(r*e,10));else for(let n=0;n<=t;n++)s.push(Math.min(e,Math.round(r*n)));return s},[p,h]),x=(0,i.useCallback)(e=>{const t=p();return(t-e*((r.height-2*r.axisOffset)/r.height))*(r.height/t)-r.axisOffset-r.strokeWidth/2},[p,r.height,r.axisOffset,r.strokeWidth]),g=(0,i.useCallback)(()=>{const t=Object.keys(e)[0];return t&&e[t]?Math.round((r.height*r.aspectRatio-3*r.axisOffset)/(e[t].length-1)):0},[e,r.height,r.aspectRatio,r.axisOffset]),m=parseInt(r.height*r.aspectRatio+2*r.axisOffset,10),f=parseInt(r.height+2*r.axisOffset,10),y=Object.keys(e)[0],b=y?e[y]:[],v=b.length,j=Math.max(1,Math.round(v/6));return(0,l.jsxs)("div",{className:"prpl-line-chart",style:{width:"100%"},children:[Object.keys(r.dataArgs).length>1&&(0,l.jsx)(o,{dataArgs:r.dataArgs,visibleSeries:s,filtersLabel:r.filtersLabel,onToggle:a}),(0,l.jsx)("div",{className:"prpl-line-chart__svg-container",style:{width:"100%"},children:(0,l.jsxs)("svg",{className:"prpl-line-chart__svg",viewBox:`0 0 ${m} ${f}`,children:[(0,l.jsx)("g",{className:"prpl-line-chart__x-axis",children:(0,l.jsx)("line",{x1:3*r.axisOffset,x2:r.aspectRatio*r.height,y1:r.height-r.axisOffset,y2:r.height-r.axisOffset,stroke:r.axisColor,strokeWidth:"1"})}),(0,l.jsx)("g",{className:"prpl-line-chart__y-axis",children:(0,l.jsx)("line",{x1:3*r.axisOffset,x2:3*r.axisOffset,y1:r.axisOffset,y2:r.height-r.axisOffset,stroke:r.axisColor,strokeWidth:"1"})}),b.map((e,t)=>{const s=g()*t+2*r.axisOffset;return v>6&&0!==t&&t%j!==0?null:(0,l.jsxs)("g",{className:"prpl-line-chart__x-label",children:[(0,l.jsx)("text",{x:s,y:r.height+r.axisOffset,children:e.label}),0!==t&&(0,l.jsx)("line",{x1:s+r.axisOffset,x2:s+r.axisOffset,y1:r.axisOffset,y2:r.height-r.axisOffset,stroke:r.rulersColor,strokeWidth:"1"})]},`x-label-${t}`)}),u().map((e,t)=>{const s=x(e);return(0,l.jsxs)("g",{className:"prpl-line-chart__y-label",children:[(0,l.jsx)("text",{x:"0",y:s+r.axisOffset/2,children:e}),0!==t&&(0,l.jsx)("line",{x1:3*r.axisOffset,x2:r.aspectRatio*r.height,y1:s,y2:s,stroke:r.rulersColor,strokeWidth:"1"})]},`y-label-${t}`)}),Object.keys(e).map(t=>{if(!s.includes(t))return null;const n=e[t].map((e,t)=>`${3*r.axisOffset+g()*t},${x(e.score)}`).join(" ");return(0,l.jsx)("g",{className:`prpl-line-chart__series prpl-line-chart__series--${t}`,children:(0,l.jsx)("polyline",{fill:"none",stroke:r.dataArgs[t]?.color,strokeWidth:r.strokeWidth,points:n})},`series-${t}`)})]})})]})}function p({activityTypes:e,weeklyActivity:t,totalCount:r}){const n={border:"none",padding:"0.5em"},a={...n,fontWeight:400},i={...n,textAlign:"center"},o={...n,borderTop:"1px solid var(--prpl-color-border)"},c={...i,borderTop:"1px solid var(--prpl-color-border)"};return(0,l.jsxs)("table",{className:"prpl-content-activity__table",style:{width:"100%",marginBottom:"1em",borderSpacing:"6px 0"},children:[(0,l.jsx)("thead",{className:"prpl-content-activity__table-head",children:(0,l.jsxs)("tr",{className:"prpl-content-activity__table-row",children:[(0,l.jsx)("th",{className:"prpl-content-activity__table-header",style:n,children:(0,s.__)("Content managed","progress-planner")}),(0,l.jsx)("th",{className:"prpl-content-activity__table-header",style:i,children:(0,s.__)("Last week","progress-planner")})]})}),(0,l.jsx)("tbody",{className:"prpl-content-activity__table-body",children:Object.keys(e).map((r,s)=>{const n={backgroundColor:s%2==0?"var(--prpl-background-table)":"transparent"};return(0,l.jsxs)("tr",{className:`prpl-content-activity__table-row prpl-content-activity__table-row--${r}`,style:n,children:[(0,l.jsx)("th",{className:"prpl-content-activity__table-cell",style:a,children:e[r].label}),(0,l.jsx)("td",{className:"prpl-content-activity__table-cell",style:i,children:t[r]||0})]},r)})}),(0,l.jsx)("tfoot",{className:"prpl-content-activity__table-foot",children:(0,l.jsxs)("tr",{className:"prpl-content-activity__table-row prpl-content-activity__table-row--total",children:[(0,l.jsx)("th",{className:"prpl-content-activity__table-cell",style:o,children:(0,s.__)("Total","progress-planner")}),(0,l.jsx)("td",{className:"prpl-content-activity__table-cell",style:c,children:r})]})})]})}var h=r(8982),u=r(8691),x=r(9277),g=r(5815),m=r(7421);function f(){return(0,l.jsxs)("div",{style:{width:"100%",height:"200px",marginBottom:"var(--prpl-padding)",position:"relative"},children:[(0,l.jsx)(g.iA,{width:"100%",height:"100%",style:{opacity:.3,borderRadius:"var(--prpl-border-radius)"}}),(0,l.jsx)("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:"20px",display:"flex",alignItems:"flex-end",justifyContent:"space-around",padding:"10px"},children:[40,60,45,75,50,80].map((e,t)=>(0,l.jsx)(g.iA,{width:"4px",height:`${e}%`,style:{borderRadius:"2px"}},t))})]})}function y({rows:e=3}){const t={border:"none",padding:"0.5em"},r={...t,textAlign:"center"},s={...t,borderTop:"1px solid var(--prpl-color-border)"};return(0,l.jsxs)("table",{style:{width:"100%",marginBottom:"1em",borderSpacing:"6px 0"},children:[(0,l.jsx)("thead",{children:(0,l.jsxs)("tr",{children:[(0,l.jsx)("th",{style:t,children:(0,l.jsx)(g.iA,{width:"8rem",height:"1em"})}),(0,l.jsx)("th",{style:r,children:(0,l.jsx)(g.iA,{width:"5rem",height:"1em",style:{marginLeft:"auto"}})})]})}),(0,l.jsx)("tbody",{children:Array.from({length:e}).map((e,s)=>{const n={backgroundColor:s%2==0?"var(--prpl-background-table)":"transparent"};return(0,l.jsxs)("tr",{style:n,children:[(0,l.jsx)("th",{style:t,children:(0,l.jsx)(g.iA,{width:60+10*s%30+"%",height:"1em"})}),(0,l.jsx)("td",{style:r,children:(0,l.jsx)(g.iA,{width:"2rem",height:"1em",style:{marginLeft:"auto"}})})]},s)})}),(0,l.jsx)("tfoot",{children:(0,l.jsxs)("tr",{children:[(0,l.jsx)("th",{style:s,children:(0,l.jsx)(g.iA,{width:"3rem",height:"1em"})}),(0,l.jsx)("td",{style:{...r,borderTop:"1px solid var(--prpl-color-border)"},children:(0,l.jsx)(g.iA,{width:"2rem",height:"1em",style:{marginLeft:"auto"}})})]})})]})}function b(){return(0,l.jsxs)("div",{className:"prpl-content-activity",children:[(0,l.jsx)("div",{style:{marginBottom:"1rem"},children:(0,l.jsx)(g.rr,{lines:3})}),(0,l.jsx)(m.A,{backgroundColor:"var(--prpl-background-content)"}),(0,l.jsx)("div",{style:{marginBottom:"var(--prpl-padding)"},children:(0,l.jsx)(f,{})}),(0,l.jsx)(y,{rows:3})]})}(0,n.Cu)({id:"content-activity",component:function({config:e={}}){const t=window.prplDashboardConfig||{},r=t.currentRange||"-6 months",n=t.currentFrequency||"monthly",i=`/progress-planner/v1/widgets/content-activity?range=${encodeURIComponent(r)}&frequency=${encodeURIComponent(n)}`,{isLoading:o,error:c,data:g}=(0,u.KS)(i,[],(0,s.__)("Failed to load content activity data.","progress-planner")),m=e?.title||(0,s.__)("Content activity","progress-planner");return o?(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(x.A,{title:m}),(0,l.jsx)(b,{})]}):c?(0,l.jsx)(h.W5,{message:c,className:"prpl-content-activity__error"}):g?(0,l.jsxs)("div",{className:"prpl-content-activity",children:[(0,l.jsx)(x.A,{title:m}),(0,l.jsx)("p",{children:g.i18n?.description||(0,s.__)("Here are the updates you made to your content last week. Whether you published something new, updated an existing post, or removed outdated content, it all helps you stay on top of your site!","progress-planner")}),(0,l.jsx)(a.A,{number:g.totalCount,label:g.i18n?.piecesOfContentManaged||(0,s.__)("pieces of content managed","progress-planner"),backgroundColor:"var(--prpl-background-content)"}),(0,l.jsx)("div",{className:"prpl-graph-wrapper",style:{marginBottom:"var(--prpl-padding)"},children:(0,l.jsx)(d,{data:g.chartData,options:g.chartOptions})}),(0,l.jsx)(p,{activityTypes:g.activityTypes,weeklyActivity:g.weeklyActivity,totalCount:g.weeklyTotalCount})]}):null},priority:5,width:1,forceLastColumn:!1,title:(0,s.__)("Content activity","progress-planner")})},790:e=>{e.exports=window.ReactJSXRuntime},1059:(e,t,r)=>{r.d(t,{A:()=>u});var s=r(6087),n=r(7723),a=r(790);const i={position:"absolute",top:0,right:0,transform:"translate(-10px, -10px) rotate(90deg)",width:0,height:0,borderStyle:"solid",borderWidth:"7.5px 10px 7.5px 0",borderColor:"transparent var(--prpl-background-activity) transparent transparent"},l={padding:0,lineHeight:1,background:"none",border:"none",cursor:"pointer",fontSize:"var(--prpl-font-size-small)",color:"var(--prpl-color-link)"},o={display:"inline-flex",alignItems:"center",position:"relative"},c={display:"block",position:"absolute",bottom:0,left:"100%",transform:"translate(-100%, calc(100% + 10px))",padding:"0.75rem 1.5rem 0.75rem 0.75rem",width:150,background:"var(--prpl-background-activity)",borderRadius:"var(--prpl-border-radius)",zIndex:2,visibility:"hidden",fontSize:"1rem",fontWeight:400,color:"var(--prpl-color-text)"},d={visibility:"visible",zIndex:10},p={position:"absolute",top:0,right:0,padding:"0.1rem",lineHeight:0,margin:0,background:"none",border:"none",cursor:"pointer"},h={display:"block",position:"fixed",top:0,left:0,width:"100%",height:"100%",zIndex:9,backgroundColor:"rgba(0, 0, 0, 0.5)"};function u({triggerContent:e,children:t,tooltipStyle:r,arrowStyle:u,onClose:x}){const[g,m]=(0,s.useState)(!1),[f,y]=(0,s.useState)(!1),b=(0,s.useRef)(null),v=(0,s.useId)(),j=(0,s.useCallback)(()=>{m(!1),x?.()},[x]);(0,s.useEffect)(()=>{if(!g)return;const e=e=>{"Escape"===e.key&&j()};return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)},[g,j]);const w={...l,textDecoration:f?"underline":"none"};return(0,a.jsxs)("span",{className:"prpl-tooltip-wrapper",style:o,children:[(0,a.jsx)("button",{type:"button",className:"prpl-info-icon","aria-describedby":v,onClick:()=>m(!0),style:w,onMouseEnter:()=>y(!0),onMouseLeave:()=>y(!1),children:e}),g&&(0,a.jsx)("span",{role:"presentation",onClick:j,style:h}),(0,a.jsxs)("span",{ref:b,id:v,className:"prpl-tooltip",role:"tooltip","aria-hidden":!g,style:{...c,...g?d:{},...r},children:[(0,a.jsx)("span",{"data-testid":"tooltip-arrow",style:{...i,...u}}),t,(0,a.jsxs)("button",{type:"button",onClick:j,style:p,children:[(0,a.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,a.jsx)("span",{className:"screen-reader-text",children:(0,n.__)("Close","progress-planner")})]})]})]})}},1362:(e,t,r)=>{r.d(t,{Cu:()=>a,cr:()=>i});var s=r(2619);const n=[];function a(e){const{id:t,component:r,priority:s=10,width:a=1,forceLastColumn:i=!1,title:l=""}=e;if(!t||!r)return void console.warn("Widget registration failed: id and component are required",e);const o=n.findIndex(e=>e.id===t),c={id:t,component:r,priority:s,width:a,forceLastColumn:i,title:l};o>=0?n[o]=c:n.push(c)}function i(){return[...n].sort((e,t)=>e.priority-t.priority)}(0,s.addAction)("prpl.dashboard.registerWidget","progress-planner/widget-registry",a)},1455:e=>{e.exports=window.wp.apiFetch},2619:e=>{e.exports=window.wp.hooks},5262:(e,t,r)=>{r.d(t,{A:()=>a});var s=r(6087),n=r(790);function a({number:e,label:t,backgroundColor:r="var(--prpl-background-content)"}){const a=(0,s.useRef)(null),i=(0,s.useRef)(null),l=(0,s.useCallback)(()=>{const e=i.current,t=a.current;if(!e||!t)return;e.style.fontSize="100%",e.style.width="max-content";const r=t.clientWidth;let s=100;for(;e.clientWidth>r&&s>80;)s-=1,e.style.fontSize=s+"%";s<=80&&(e.style.fontSize="80%",e.style.width="100%")},[]);(0,s.useEffect)(()=>(l(),window.addEventListener("resize",l),()=>{window.removeEventListener("resize",l)}),[l,t]);const o={backgroundColor:r,padding:"var(--prpl-padding)",borderRadius:"var(--prpl-border-radius-big)",display:"flex",flexDirection:"column",alignItems:"center",textAlign:"center",alignContent:"center",justifyContent:"center",height:"calc(var(--prpl-font-size-5xl) + var(--prpl-font-size-2xl) + var(--prpl-padding) * 2)",marginBottom:"var(--prpl-padding)"};return(0,n.jsxs)("div",{className:"prpl-big-counter",style:o,children:[(0,n.jsx)("div",{className:"prpl-big-counter__width-reference",ref:a,style:{width:"100%"}}),(0,n.jsx)("span",{className:"prpl-big-counter__number",style:{fontSize:"var(--prpl-font-size-5xl)",lineHeight:1,fontWeight:600},children:e}),(0,n.jsx)("span",{className:"prpl-big-counter__label-wrapper",style:{fontSize:"var(--prpl-font-size-2xl)"},children:(0,n.jsx)("span",{className:"prpl-big-counter__label",ref:i,style:{fontSize:"100%",display:"inline-block",width:"max-content"},children:t})})]})}},5337:(e,t,r)=>{r.d(t,{BJ:()=>o,IL:()=>c,Wz:()=>d});var s=r(1455),n=r.n(s);const a=new Map,i=new Map,l=3e5;async function o(e,t={}){const{skipCache:r=!1,ttl:s=l}=t,o=function(e){if("GET"!==(e.method||"GET").toUpperCase())return null;let t=e.path||e.url||"";if(e.data&&"object"==typeof e.data){const r=new URLSearchParams(e.data).toString();r&&(t+=(t.includes("?")?"&":"?")+r)}return`GET:${t}`}(e);if(!o)return n()(e);if(!r&&a.has(o))return a.get(o);if(!r){const e=i.get(o);if(e&&Date.now()-e.timestamp(i.set(o,{data:e,timestamp:Date.now()}),a.delete(o),e)).catch(e=>{throw a.delete(o),e});return a.set(o,c),c}function c(){i.clear(),a.clear()}function d(e,t){const r=`GET:${e}`;i.set(r,{data:t,timestamp:Date.now()})}},5815:(e,t,r)=>{r.d(t,{Q8:()=>d,iA:()=>c,rr:()=>p});var s=r(6087),n=r(790);const a="\n@keyframes prpl-shimmer {\n\t0% { background-position: 200% 0; }\n\t100% { background-position: -200% 0; }\n}\n";let i=!1;function l(){if(i||"undefined"==typeof document)return;const e=document.createElement("style");e.id="prpl-skeleton-keyframes",e.textContent=a,document.head.appendChild(e),i=!0}const o={background:"linear-gradient(\n\t\t90deg,\n\t\tvar(--prpl-color-gauge-remain, #f0f0f0) 25%,\n\t\tvar(--prpl-color-border, #e0e0e0) 50%,\n\t\tvar(--prpl-color-gauge-remain, #f0f0f0) 75%\n\t)",backgroundSize:"200% 100%",animation:"prpl-shimmer 1.5s ease-in-out infinite",borderRadius:"var(--prpl-border-radius, 8px)"};function c({width:e="100%",height:t="1em",className:r="",style:a={}}){return(0,s.useEffect)(()=>{l()},[]),(0,n.jsx)("div",{className:r||void 0,style:{...o,width:e,height:t,...a}})}function d({size:e="40px",className:t="",style:r={}}){return(0,s.useEffect)(()=>{l()},[]),(0,n.jsx)("div",{className:t||void 0,style:{...o,width:e,height:e,borderRadius:"50%",...r}})}function p({width:e="100%",lines:t=1,className:r="",style:a={},lastShort:i=!0}){return(0,s.useEffect)(()=>{l()},[]),1===t?(0,n.jsx)(c,{width:e,height:"1em",className:r,style:a}):(0,n.jsx)("div",{style:{display:"flex",flexDirection:"column",...a},children:Array.from({length:t}).map((s,a)=>(0,n.jsx)(c,{width:i&&a===t-1?"70%":e,height:"1em",className:r,style:{marginBottom:a{e.exports=window.wp.element},7421:(e,t,r)=>{r.d(t,{A:()=>a});var s=r(5815),n=r(790);function a({backgroundColor:e="var(--prpl-background-content)"}){const t={backgroundColor:e,padding:"var(--prpl-padding)",borderRadius:"var(--prpl-border-radius-big)",display:"flex",flexDirection:"column",alignItems:"center",textAlign:"center",alignContent:"center",justifyContent:"center",height:"calc(var(--prpl-font-size-5xl) + var(--prpl-font-size-2xl) + var(--prpl-padding) * 2)",marginBottom:"var(--prpl-padding)",gap:"0.5rem"};return(0,n.jsxs)("div",{style:t,children:[(0,n.jsx)(s.iA,{width:"3rem",height:"var(--prpl-font-size-5xl)",style:{borderRadius:"8px"}}),(0,n.jsx)(s.iA,{width:"8rem",height:"var(--prpl-font-size-2xl)",style:{borderRadius:"4px"}})]})}},7723:e=>{e.exports=window.wp.i18n},8691:(e,t,r)=>{r.d(t,{KS:()=>i});var s=r(6087),n=r(5337);const a=3e5;function i(e,t=[],r="Failed to load data",i={}){const{cache:l=!0,cacheTtl:o=a,skipCache:c=!1}=i,[d,p]=(0,s.useState)(!0),[h,u]=(0,s.useState)(null),[x,g]=(0,s.useState)(null),m=(0,s.useCallback)(async(t=!1)=>{if(e){p(!0),u(null);try{const r=await(0,n.BJ)({path:e},{skipCache:t||c||!l,ttl:o});g(r)}catch(e){const t=e.message||("string"==typeof r?r:r.message||"Failed to load data");u(t)}finally{p(!1)}}else p(!1)},[e,l,o,c,r]);return(0,s.useEffect)(()=>{m()},[e,...t]),{isLoading:d,error:h,data:x,refetch:(0,s.useCallback)((e=!0)=>{m(e)},[m])}}},8982:(e,t,r)=>{r.d(t,{W5:()=>i,pp:()=>l});var s=r(7723),n=r(790);const a={padding:"1em",backgroundColor:"var(--prpl-color-error-background, #fee)",color:"var(--prpl-color-error, #c00)",borderRadius:"var(--prpl-border-radius)"};function i({message:e=(0,s.__)("An error occurred.","progress-planner"),className:t="",style:r={},simple:i=!1}){return i?(0,n.jsx)("p",{className:t||void 0,children:e}):(0,n.jsx)("div",{className:"prpl-widget-error"+(t?` ${t}`:""),style:{...a,...r},children:e})}function l({message:e=(0,s.__)("No data available.","progress-planner"),className:t=""}){return(0,n.jsx)("p",{className:t||void 0,children:e})}},9061:(e,t,r)=>{r.d(t,{A:()=>a});var s=r(790);const n={arrow:{viewBox:"0 0 20 17",paths:[{d:"M19.92 8.12c-.05-.12-.12-.23-.22-.33L12.21.29A.996.996 0 1 0 10.8 1.7l5.79 5.79H1c-.55 0-1 .45-1 1s.45 1 1 1h15.59l-5.79 5.79a.996.996 0 0 0 .71 1.7c.26 0 .51-.1.71-.29l7.5-7.5c.1-.1.17-.21.22-.33.05-.12.07-.24.08-.38 0-.14-.03-.27-.08-.38Z"}]},trash:{viewBox:"0 0 48 48",paths:[{d:"M32.99 47.88H15.01c-3.46 0-6.38-2.7-6.64-6.15L6.04 11.49l-.72.12c-.82.14-1.59-.41-1.73-1.22-.14-.82.41-1.59 1.22-1.73.79-.14 1.57-.26 2.37-.38h.02c2.21-.33 4.46-.6 6.69-.81v-.72c0-3.56 2.74-6.44 6.25-6.55 2.56-.08 5.15-.08 7.71 0 3.5.11 6.25 2.99 6.25 6.55v.72c2.24.2 4.48.47 6.7.81.79.12 1.59.25 2.38.39.82.14 1.36.92 1.22 1.73-.14.82-.92 1.36-1.73 1.22l-.72-.12-2.33 30.24c-.27 3.45-3.18 6.15-6.64 6.15Zm-17.98-3h17.97c1.9 0 3.51-1.48 3.65-3.38l2.34-30.46c-2.15-.3-4.33-.53-6.48-.7h-.03c-5.62-.43-11.32-.43-16.95 0h-.03c-2.15.17-4.33.4-6.48.7l2.34 30.46c.15 1.9 1.75 3.38 3.65 3.38ZM24 7.01c2.37 0 4.74.07 7.11.22v-.49c0-1.93-1.47-3.49-3.34-3.55-2.5-.08-5.03-.08-7.52 0-1.88.06-3.34 1.62-3.34 3.55v.49c2.36-.15 4.73-.22 7.11-.22Zm5.49 32.26h-.06c-.83-.03-1.47-.73-1.44-1.56l.79-20.65c.03-.83.75-1.45 1.56-1.44.83.03 1.47.73 1.44 1.56l-.79 20.65c-.03.81-.7 1.44-1.5 1.44Zm-10.98 0c-.8 0-1.47-.63-1.5-1.44l-.79-20.65c-.03-.83.61-1.52 1.44-1.56.84 0 1.52.61 1.56 1.44l.79 20.65c.03.83-.61 1.52-1.44 1.56h-.06Z"}]},check:{viewBox:"0 0 20 20",paths:[{d:"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",fillRule:"evenodd",clipRule:"evenodd"}]},close:{viewBox:"0 0 20 20",paths:[{d:"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",fillRule:"evenodd",clipRule:"evenodd"}]},chevronDown:{viewBox:"0 0 24 24",stroke:!0,paths:[{d:"m19.5 8.25-7.5 7.5-7.5-7.5",strokeLinecap:"round",strokeLinejoin:"round"}]},info:{viewBox:"0 0 64 64",paths:[{d:"M32 63.73C14.51 63.73.27 49.49.27 32S14.51.27 32 .27 63.73 14.5 63.73 32 49.5 63.73 32 63.73Zm0-58C17.51 5.73 5.73 17.52 5.73 32S17.52 58.27 32 58.27 58.27 46.48 58.27 32 46.49 5.73 32 5.73Zm1.2 41.4c-.42 0-.83-.05-1.24-.15-1.33-.33-2.46-1.17-3.16-2.34-.71-1.18-.91-2.56-.58-3.9l2.13-8.54c-1.25.36-2.62-.21-3.21-1.42-.66-1.35-.1-2.99 1.25-3.65l.13-.06c1.21-.6 2.6-.7 3.91-.27 1.3.44 2.36 1.35 2.97 2.58.55 1.1.69 2.36.39 3.54l-2.13 8.54c1.22-.36 2.58.19 3.19 1.37.69 1.34.16 2.98-1.18 3.67l-.13.07c-.74.37-1.54.56-2.34.56Zm-2.26-15.17Zm1.09-9.03c-1.65 0-3.02-1.34-3.02-2.99s1.34-3.01 2.99-3.01h.03c1.65 0 2.99 1.34 2.99 2.99s-1.34 3.01-2.99 3.01Z"}]},warning:{viewBox:"0 0 24 24",paths:[{d:"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003ZM12 8.25a.75.75 0 0 1 .75.75v3.75a.75.75 0 0 1-1.5 0V9a.75.75 0 0 1 .75-.75Zm0 8.25a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Z",fillRule:"evenodd",clipRule:"evenodd"}]}};function a({name:e,...t}){const r=n[e];if(!r)return null;const a=r.stroke;return(0,s.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:r.viewBox,fill:a?"none":"currentColor",stroke:a?"currentColor":void 0,strokeWidth:a?"1.5":void 0,"aria-hidden":"true",focusable:"false",...t,children:r.paths.map((e,t)=>(0,s.jsx)("path",{...e},t))})}},9277:(e,t,r)=>{r.d(t,{A:()=>c});var s=r(7723),n=r(1059),a=r(9061),i=r(790);const l={display:"flex",justifyContent:"flex-start",flexWrap:"wrap",position:"relative"},o={width:"1.25rem",height:"1.25rem",display:"inline-block",verticalAlign:"bottom",color:"#6b7280"};function c({title:e,tooltipContent:t="",className:r=""}){return(0,i.jsxs)("h2",{className:"prpl-widget-title"+(r?` ${r}`:""),children:[e,t&&(0,i.jsx)("div",{style:l,children:(0,i.jsx)(n.A,{triggerContent:(0,i.jsxs)("span",{style:o,children:[(0,i.jsx)(a.A,{name:"info"}),(0,i.jsx)("span",{className:"screen-reader-text",children:(0,s.__)("More info","progress-planner")})]}),children:t})})]})}}},e=>{e(e.s=539)}]);
\ No newline at end of file
diff --git a/build/widget-content-badges-rtl.css b/build/widget-content-badges-rtl.css
new file mode 100644
index 0000000000..b83e7450bc
--- /dev/null
+++ b/build/widget-content-badges-rtl.css
@@ -0,0 +1 @@
+.prpl-tooltip-wrapper .prpl-tooltip p{margin-bottom:0}.prpl-tooltip-wrapper .prpl-tooltip p:first-child{margin-top:0}
diff --git a/build/widget-content-badges.asset.php b/build/widget-content-badges.asset.php
new file mode 100644
index 0000000000..814f99d184
--- /dev/null
+++ b/build/widget-content-badges.asset.php
@@ -0,0 +1 @@
+ array('react-jsx-runtime', 'wp-api-fetch', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '7e081ca68cefb51101b8', 'handle' => 'undefined-widget-content-badges');
diff --git a/build/widget-content-badges.css b/build/widget-content-badges.css
new file mode 100644
index 0000000000..b83e7450bc
--- /dev/null
+++ b/build/widget-content-badges.css
@@ -0,0 +1 @@
+.prpl-tooltip-wrapper .prpl-tooltip p{margin-bottom:0}.prpl-tooltip-wrapper .prpl-tooltip p:first-child{margin-top:0}
diff --git a/build/widget-content-badges.js b/build/widget-content-badges.js
new file mode 100644
index 0000000000..5f40157bf2
--- /dev/null
+++ b/build/widget-content-badges.js
@@ -0,0 +1,3 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[115],{475:(e,t,r)=>{r.d(t,{A:()=>s});var n=r(6087),a=r(790);function s({value:e=0,max:t=10,backgroundColor:r="var(--prpl-background-monthly)",color:s="var(--prpl-color-monthly)",color2:o="var(--prpl-color-monthly-2)",contentFontSize:i="var(--prpl-font-size-6xl)",children:l}){const c="180deg",d={padding:"var(--prpl-padding) var(--prpl-padding) calc(var(--prpl-padding) * 2) var(--prpl-padding)",background:r,borderRadius:"var(--prpl-border-radius-big)",aspectRatio:"2 / 1",overflow:"hidden",position:"relative",marginBottom:"var(--prpl-padding)"},p={width:"100%",aspectRatio:"1 / 1",borderRadius:"100%",position:"relative",background:`radial-gradient(${r} 0 57%, transparent 57% 100%), conic-gradient(from 270deg, ${(0,n.useMemo)(()=>{const r=t>0?e/t:0;let n;return r<=.5?n=`${s} calc(${c} * ${r})`:(n=`${s} calc(${c} * 0.5)`,n+=`, ${o} calc(${c} * ${r})`),n+=`, var(--prpl-color-gauge-remain) calc(${c} * ${r}) ${c}`,n},[e,t,s,o])}, transparent ${c})`,textAlign:"center"},g={fontSize:"var(--prpl-font-size-small)",position:"absolute",top:"50%",color:"var(--prpl-color-text)",width:"10%",textAlign:"center"},u={...g,left:0},m={...g,right:0},h={fontSize:i,bottom:"50%",display:"block",fontWeight:600,textAlign:"center",position:"absolute",color:"var(--prpl-color-text)",width:"100%",lineHeight:1.2};return(0,a.jsx)("div",{className:"prpl-gauge",style:d,children:(0,a.jsxs)("div",{className:"prpl-gauge__ring",style:p,children:[(0,a.jsx)("span",{className:"prpl-gauge__label prpl-gauge__label--min",style:u,children:"0"}),(0,a.jsx)("span",{className:"prpl-gauge__content",style:h,children:(0,a.jsx)("span",{className:"prpl-gauge__content-inner",style:{display:"inline-block",width:"50%"},children:l})}),(0,a.jsx)("span",{className:"prpl-gauge__label prpl-gauge__label--max",style:m,children:t})]})})}},645:(e,t,r)=>{r.d(t,{Ge:()=>i,HY:()=>n,TV:()=>s,Tn:()=>a,cs:()=>o,et:()=>l});const n=[{id:"content-curator",name:"Content Curator",description:"20 existing posts/pages, or 10 new posts/pages",type:"content",background:"var(--prpl-background-content-badge)",thresholds:{existingPosts:20,newPosts:10}},{id:"revision-ranger",name:"Revision Ranger",description:"Write 30 new posts or pages",type:"content",background:"var(--prpl-background-content-badge)",thresholds:{newPosts:30}},{id:"purposeful-publisher",name:"Purposeful Publisher",description:"Write 50 new posts or pages",type:"content",background:"var(--prpl-background-content-badge)",thresholds:{newPosts:50}}],a=[{id:"progress-padawan",name:"Progress Padawan",description:"6 weeks streak",type:"maintenance",background:"var(--prpl-background-streak)",thresholds:{weeks:6}},{id:"maintenance-maniac",name:"Maintenance Maniac",description:"26 weeks streak",type:"maintenance",background:"var(--prpl-background-streak)",thresholds:{weeks:26}},{id:"super-site-specialist",name:"Super Site Specialist",description:"52 weeks streak",type:"maintenance",background:"var(--prpl-background-streak)",thresholds:{weeks:52}}],s={targetPoints:10,months:{m1:"Jack January",m2:"Felix February",m3:"Mary March",m4:"Avery April",m5:"Matteo May",m6:"Jasmine June",m7:"Joey July",m8:"Abed August",m9:"Sam September",m10:"Oksana October",m11:"Noah November",m12:"Daisy December"}};function o(e){return`monthly-${e.getFullYear()}-m${e.getMonth()+1}`}function i(e){const t=`m${e.getMonth()+1}`;return s.months[t]||""}function l(e){const t=n.find(t=>t.id===e);if(t)return t;const r=a.find(t=>t.id===e);if(r)return r;if(e.startsWith("monthly-")){const t=e.split("-");if(3===t.length){const r=parseInt(t[1],10),n=t[2].replace("m",""),a=parseInt(n,10);if(r&&a>=1&&a<=12){const t=new Date(r,a-1,1);return{id:e,name:i(t),description:"",type:"monthly",background:"var(--prpl-background-content-badge)",thresholds:{points:s.targetPoints}}}}}return null}},790:e=>{e.exports=window.ReactJSXRuntime},1059:(e,t,r)=>{r.d(t,{A:()=>u});var n=r(6087),a=r(7723),s=r(790);const o={position:"absolute",top:0,right:0,transform:"translate(-10px, -10px) rotate(90deg)",width:0,height:0,borderStyle:"solid",borderWidth:"7.5px 10px 7.5px 0",borderColor:"transparent var(--prpl-background-activity) transparent transparent"},i={padding:0,lineHeight:1,background:"none",border:"none",cursor:"pointer",fontSize:"var(--prpl-font-size-small)",color:"var(--prpl-color-link)"},l={display:"inline-flex",alignItems:"center",position:"relative"},c={display:"block",position:"absolute",bottom:0,left:"100%",transform:"translate(-100%, calc(100% + 10px))",padding:"0.75rem 1.5rem 0.75rem 0.75rem",width:150,background:"var(--prpl-background-activity)",borderRadius:"var(--prpl-border-radius)",zIndex:2,visibility:"hidden",fontSize:"1rem",fontWeight:400,color:"var(--prpl-color-text)"},d={visibility:"visible",zIndex:10},p={position:"absolute",top:0,right:0,padding:"0.1rem",lineHeight:0,margin:0,background:"none",border:"none",cursor:"pointer"},g={display:"block",position:"fixed",top:0,left:0,width:"100%",height:"100%",zIndex:9,backgroundColor:"rgba(0, 0, 0, 0.5)"};function u({triggerContent:e,children:t,tooltipStyle:r,arrowStyle:u,onClose:m}){const[h,f]=(0,n.useState)(!1),[b,v]=(0,n.useState)(!1),x=(0,n.useRef)(null),y=(0,n.useId)(),w=(0,n.useCallback)(()=>{f(!1),m?.()},[m]);(0,n.useEffect)(()=>{if(!h)return;const e=e=>{"Escape"===e.key&&w()};return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)},[h,w]);const k={...i,textDecoration:b?"underline":"none"};return(0,s.jsxs)("span",{className:"prpl-tooltip-wrapper",style:l,children:[(0,s.jsx)("button",{type:"button",className:"prpl-info-icon","aria-describedby":y,onClick:()=>f(!0),style:k,onMouseEnter:()=>v(!0),onMouseLeave:()=>v(!1),children:e}),h&&(0,s.jsx)("span",{role:"presentation",onClick:w,style:g}),(0,s.jsxs)("span",{ref:x,id:y,className:"prpl-tooltip",role:"tooltip","aria-hidden":!h,style:{...c,...h?d:{},...r},children:[(0,s.jsx)("span",{"data-testid":"tooltip-arrow",style:{...o,...u}}),t,(0,s.jsxs)("button",{type:"button",onClick:w,style:p,children:[(0,s.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,s.jsx)("span",{className:"screen-reader-text",children:(0,a.__)("Close","progress-planner")})]})]})]})}},1362:(e,t,r)=>{r.d(t,{Cu:()=>s,cr:()=>o});var n=r(2619);const a=[];function s(e){const{id:t,component:r,priority:n=10,width:s=1,forceLastColumn:o=!1,title:i=""}=e;if(!t||!r)return void console.warn("Widget registration failed: id and component are required",e);const l=a.findIndex(e=>e.id===t),c={id:t,component:r,priority:n,width:s,forceLastColumn:o,title:i};l>=0?a[l]=c:a.push(c)}function o(){return[...a].sort((e,t)=>e.priority-t.priority)}(0,n.addAction)("prpl.dashboard.registerWidget","progress-planner/widget-registry",s)},1455:e=>{e.exports=window.wp.apiFetch},2381:(e,t,r)=>{r.d(t,{Ek:()=>l,jx:()=>i,mZ:()=>o});var n=r(1455),a=r.n(n),s=r(5337);async function o(e=!1){try{const t=await(0,s.BJ)({path:"/progress-planner/v1/activities"},{skipCache:e});return{activities:t.activities||[],totalPostsCount:t.totalPostsCount||0,activationDate:t.activationDate?new Date(t.activationDate):new Date,config:t.config||{brandingId:0,remoteServerUrl:"",placeholderUrl:""}}}catch(e){throw new Error(e.message||"Failed to fetch activities")}}async function i(e=!1){try{return(await(0,s.BJ)({path:"/progress-planner/v1/badge-stats"},{skipCache:e})).badges||{}}catch(e){throw new Error(e.message||"Failed to fetch badge stats")}}async function l(e){try{const t=await a()({path:"/progress-planner/v1/badge-stats",method:"POST",data:{badges:e}});return(0,s.Wz)("/progress-planner/v1/badge-stats",t),t.badges||{}}catch(e){throw new Error(e.message||"Failed to save badge stats")}}},2619:e=>{e.exports=window.wp.hooks},3971:(e,t,r)=>{r.d(t,{A:()=>a});var n=r(790);function a({badgeId:e,badgeName:t,brandingId:r=0,isComplete:a=!0}){const s=window.progressPlannerBadge||{};let o=s.remoteServerRootUrl||"https://progressplanner.com";const i=s.placeholderImageUrl||"";(o.includes("localhost")||o.includes("127.0.0.1"))&&(o="https://progressplanner.com");let l=`${o}/wp-json/progress-planner-saas/v1/badge-svg/?badge_id=${e}`;r&&(l+=`&branding_id=${r}`);const c=t&&"null"!==t?t:"Badge",d={maxWidth:"100%",height:"auto",verticalAlign:"bottom",transition:"opacity 0.3s ease-in-out, filter 0.3s ease-in-out",...!a&&{opacity:.25,filter:"grayscale(1)"}};return(0,n.jsx)("img",{src:l,alt:c,onError:e=>{i&&e.target.src!==i&&(e.target.onerror=null,e.target.src=i)},style:d})}},4272:(e,t,r)=>{r.d(t,{A:()=>y});var n=r(7723),a=r(6087),s=r(7440),o=r(8300),i=r(8650),l=r(645),c=r(475),d=r(3971),p=r(790);function g({badge:e,config:t,backgroundColor:r="var(--prpl-background-content-badge)",getRemainingText:a}){return(0,p.jsxs)("div",{className:"prpl-latest-badges-wrapper",children:[(0,p.jsx)(c.A,{value:e.progress,max:100,backgroundColor:e.background||r,color:"var(--prpl-color-monthly)",color2:"var(--prpl-color-monthly-2)",children:(0,p.jsx)(d.A,{badgeId:e.id,badgeName:e.name,brandingId:t.brandingId,isComplete:!0})}),(0,p.jsxs)("div",{className:"prpl-badge-content-wrapper",children:[(0,p.jsxs)("p",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:"1rem",marginBottom:0},children:[(0,p.jsx)("span",{children:(0,n.sprintf)(/* translators: %s: The badge name. */ /* translators: %s: The badge name. */
+(0,n.__)("Progress %s","progress-planner"),e.name)}),(0,p.jsxs)("span",{style:{fontWeight:600,fontSize:"var(--prpl-font-size-3xl)"},children:[e.progress,"%"]})]}),(0,p.jsx)("p",{style:{marginTop:0},children:a(e.remaining)})]})]})}function u({badges:e,config:t,backgroundColor:r="var(--prpl-background-content-badge)",className:n=""}){const a={display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:"calc(var(--prpl-gap) / 4)",background:r,padding:"calc(var(--prpl-padding) / 2)",borderRadius:"var(--prpl-border-radius-big)"},s={display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"flex-start",flexWrap:"wrap",minWidth:0},o={margin:0,fontSize:"var(--prpl-font-size-small)",textAlign:"center",lineHeight:1.2};return(0,p.jsx)("div",{className:`progress-wrapper ${n}`.trim(),style:a,children:e.map(e=>(0,p.jsxs)("span",{className:"prpl-badge",style:s,"data-value":e.progress,children:[(0,p.jsx)(d.A,{badgeId:e.id,badgeName:e.name,brandingId:t.brandingId,isComplete:e.isComplete}),(0,p.jsx)("p",{style:o,children:e.name})]},e.id))})}var m=r(8982),h=r(5815),f=r(9235);function b({backgroundColor:e="var(--prpl-background-content-badge)"}){return(0,p.jsxs)("div",{className:"prpl-latest-badges-wrapper",style:{display:"flex",flexDirection:"row",gap:"1rem"},children:[(0,p.jsx)("div",{style:{flex:"0 0 auto",width:"140px"},children:(0,p.jsx)(f.A,{backgroundColor:e})}),(0,p.jsxs)("div",{className:"prpl-badge-content-wrapper",style:{flex:1,display:"flex",flexDirection:"column",justifyContent:"center"},children:[(0,p.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:"1rem",marginBottom:"0.5rem"},children:[(0,p.jsx)(h.iA,{width:"8rem",height:"1em"}),(0,p.jsx)(h.iA,{width:"3rem",height:"1.5em"})]}),(0,p.jsx)(h.rr,{lines:1})]})]})}function v({count:e=6,backgroundColor:t="var(--prpl-background-content-badge)"}){const r={display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:"calc(var(--prpl-gap) / 4)",background:t,padding:"calc(var(--prpl-padding) / 2)",borderRadius:"var(--prpl-border-radius-big)"},n={display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"flex-start",gap:"0.25rem",minWidth:0},a={fontSize:"var(--prpl-font-size-small)",textAlign:"center"};return(0,p.jsx)("div",{className:"progress-wrapper",style:r,children:Array.from({length:e}).map((e,t)=>(0,p.jsxs)("span",{className:"prpl-badge",style:n,children:[(0,p.jsx)(h.Q8,{size:"50px",style:{opacity:.5}}),(0,p.jsx)("div",{style:a,children:(0,p.jsx)(h.iA,{width:"4rem",height:"0.75em",style:{margin:"0 auto"}})})]},t))})}function x({backgroundColor:e="var(--prpl-background-content-badge)"}){return(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)("div",{style:{marginBottom:"1rem"},children:(0,p.jsx)(h.rr,{lines:2})}),(0,p.jsx)(b,{backgroundColor:e}),(0,p.jsx)("hr",{}),(0,p.jsx)("div",{className:"prpl-badges-container-achievements",children:(0,p.jsx)(v,{count:6,backgroundColor:e})})]})}function y({badgeType:e,introText:t,backgroundColor:r,badgeGroupClass:c="",getRemainingText:d}){const{isLoading:h,error:f,data:b}=(0,s.H)(),v=(0,o._)({activities:b?.activities||[],savedStats:b?.savedStats||{},totalPostsCount:b?.totalPostsCount||0,activationDate:b?.activationDate?new Date(b.activationDate):null});(0,i.t)(v,b?.savedStats||{});const y=(0,a.useMemo)(()=>"content"===e?l.HY:l.Tn,[e]),w=(0,a.useMemo)(()=>{for(const e of y){const t=v[e.id];if(t&&t.progress<100)return{id:e.id,name:e.name,background:e.background,progress:t.progress,remaining:t.remaining}}return null},[y,v]),k=(0,a.useMemo)(()=>y.map(e=>{const t=v[e.id]||{progress:0,remaining:0};return{id:e.id,name:e.name,progress:t.progress,isComplete:t.progress>=100}}),[y,v]);return h?(0,p.jsx)(x,{backgroundColor:r}):f?(0,p.jsx)(m.W5,{message:f,simple:!0}):w?(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)("p",{children:t}),(0,p.jsx)(g,{badge:w,config:b?.config||{},backgroundColor:r,getRemainingText:d}),(0,p.jsx)("hr",{}),(0,p.jsx)("div",{className:"prpl-badges-container-achievements",children:(0,p.jsx)(u,{badges:k,config:b?.config||{},backgroundColor:r,className:c})})]}):(0,p.jsx)(m.pp,{message:(0,n.__)("No badge data available.","progress-planner")})}},5337:(e,t,r)=>{r.d(t,{BJ:()=>l,IL:()=>c,Wz:()=>d});var n=r(1455),a=r.n(n);const s=new Map,o=new Map,i=3e5;async function l(e,t={}){const{skipCache:r=!1,ttl:n=i}=t,l=function(e){if("GET"!==(e.method||"GET").toUpperCase())return null;let t=e.path||e.url||"";if(e.data&&"object"==typeof e.data){const r=new URLSearchParams(e.data).toString();r&&(t+=(t.includes("?")?"&":"?")+r)}return`GET:${t}`}(e);if(!l)return a()(e);if(!r&&s.has(l))return s.get(l);if(!r){const e=o.get(l);if(e&&Date.now()-e.timestamp(o.set(l,{data:e,timestamp:Date.now()}),s.delete(l),e)).catch(e=>{throw s.delete(l),e});return s.set(l,c),c}function c(){o.clear(),s.clear()}function d(e,t){const r=`GET:${e}`;o.set(r,{data:t,timestamp:Date.now()})}},5815:(e,t,r)=>{r.d(t,{Q8:()=>d,iA:()=>c,rr:()=>p});var n=r(6087),a=r(790);const s="\n@keyframes prpl-shimmer {\n\t0% { background-position: 200% 0; }\n\t100% { background-position: -200% 0; }\n}\n";let o=!1;function i(){if(o||"undefined"==typeof document)return;const e=document.createElement("style");e.id="prpl-skeleton-keyframes",e.textContent=s,document.head.appendChild(e),o=!0}const l={background:"linear-gradient(\n\t\t90deg,\n\t\tvar(--prpl-color-gauge-remain, #f0f0f0) 25%,\n\t\tvar(--prpl-color-border, #e0e0e0) 50%,\n\t\tvar(--prpl-color-gauge-remain, #f0f0f0) 75%\n\t)",backgroundSize:"200% 100%",animation:"prpl-shimmer 1.5s ease-in-out infinite",borderRadius:"var(--prpl-border-radius, 8px)"};function c({width:e="100%",height:t="1em",className:r="",style:s={}}){return(0,n.useEffect)(()=>{i()},[]),(0,a.jsx)("div",{className:r||void 0,style:{...l,width:e,height:t,...s}})}function d({size:e="40px",className:t="",style:r={}}){return(0,n.useEffect)(()=>{i()},[]),(0,a.jsx)("div",{className:t||void 0,style:{...l,width:e,height:e,borderRadius:"50%",...r}})}function p({width:e="100%",lines:t=1,className:r="",style:s={},lastShort:o=!0}){return(0,n.useEffect)(()=>{i()},[]),1===t?(0,a.jsx)(c,{width:e,height:"1em",className:r,style:s}):(0,a.jsx)("div",{style:{display:"flex",flexDirection:"column",...s},children:Array.from({length:t}).map((n,s)=>(0,a.jsx)(c,{width:o&&s===t-1?"70%":e,height:"1em",className:r,style:{marginBottom:s{e.exports=window.wp.element},7440:(e,t,r)=>{r.d(t,{H:()=>s});var n=r(6087),a=r(2381);function s(){const[e,t]=(0,n.useState)(!0),[r,s]=(0,n.useState)(null),[o,i]=(0,n.useState)(null),l=(0,n.useCallback)(async()=>{try{t(!0),s(null);const[e,r]=await Promise.all([(0,a.mZ)(),(0,a.jx)()]);i({activities:e.activities||[],totalPostsCount:e.totalPostsCount||0,activationDate:e.activationDate,savedStats:r,config:e.config||{brandingId:0,remoteServerUrl:"",placeholderUrl:""}})}catch(e){s(e.message||"Failed to load badge data")}finally{t(!1)}},[]);return(0,n.useEffect)(()=>{l()},[l]),{isLoading:e,error:r,data:o,refetch:l}}},7723:e=>{e.exports=window.wp.i18n},8300:(e,t,r)=>{r.d(t,{_:()=>o});var n=r(6087);function a(e){const t=new Date(e),r=t.getDay(),n=t.getDate()-r+(0===r?-6:1);return t.setDate(n),t.setHours(0,0,0,0),t}var s=r(645);function o({activities:e=[],savedStats:t={},totalPostsCount:r=0,activationDate:o=null,getMonthlyBadgeDateRange:i=null}){return(0,n.useMemo)(()=>{if(!o)return{};const n={};if(["content-curator","revision-ranger","purposeful-publisher"].forEach(a=>{const i=(0,s.et)(a);if(!i)return;const l=t[a];if(l&&l.progress&&void 0!==l.remaining&&l.progress>=100)return void(n[a]={progress:l.progress,remaining:l.remaining});const c=function(e,t,r,n){const{thresholds:a}=e;if("content-curator"===e.id){const e=Math.max(0,a.existingPosts-Math.min(a.existingPosts,r));if(0===e)return{progress:100,remaining:0};const s=new Date(n);s.setHours(0,0,0,0);const o=t.filter(e=>{if("content"!==e.category||"publish"!==e.type)return!1;const t=new Date(e.date);return t.setHours(0,0,0,0),t>=s}).length,i=Math.max(0,a.newPosts-Math.min(a.newPosts,o));return{progress:Math.max(Math.min(100,Math.floor(r/2)),Math.min(100,Math.floor(10*o))),remaining:Math.min(e,i)}}const s=new Date(n);s.setHours(0,0,0,0);const o=t.filter(e=>{if("content"!==e.category||"publish"!==e.type)return!1;const t=new Date(e.date);return t.setHours(0,0,0,0),t>=s}).length,i=a.newPosts;return{progress:Math.min(100,Math.floor(o/i*100)),remaining:Math.max(0,i-Math.min(i,o))}}(i,e,r,o);n[a]=c}),["progress-padawan","maintenance-maniac","super-site-specialist"].forEach(r=>{const i=(0,s.et)(r);if(!i)return;const l=t[r];if(l&&l.progress&&void 0!==l.remaining){if(l.progress>=100)return void(n[r]={progress:l.progress,remaining:l.remaining});if(l.date){const e=new Date(l.date);if((new Date-e)/864e5<=2)return void(n[r]={progress:l.progress,remaining:l.remaining})}}const c=function(e,t,r){const{thresholds:n}=e,s=n.weeks,o=function(e,t,r=1){const n=new Map;e.forEach(e=>{const r=new Date(e.date);r.setHours(0,0,0,0);const s=new Date(t);if(s.setHours(0,0,0,0),r0}),o.setDate(o.getDate()+7)}let l=0,c=0,d=r;for(const e of s)if(e.hasActivity)l++,c=Math.max(c,l);else{if(d>0){d--;continue}l=0}return{max_streak:c,current_streak:l}}(t.filter(e=>"maintenance"===e.category),r,1),i=o.max_streak;return{progress:Math.min(100,Math.floor(i/s*100)),remaining:Math.max(0,s-Math.min(s,i))}}(i,e,o);n[r]=c}),i){const r=new Set;Object.keys(t).forEach(e=>{e.startsWith("monthly-")&&r.add(e)});const a=new Date,o=`monthly-${a.getFullYear()}-m${a.getMonth()+1}`;r.add(o);for(let e=1;e<=2;e++){const t=new Date(a.getFullYear(),a.getMonth()-e,1),n=`monthly-${t.getFullYear()}-m${t.getMonth()+1}`;r.add(n)}r.forEach(r=>{if(!(0,s.et)(r))return;const a=i(r);if(!a)return;const{startDate:o,endDate:l}=a,c=t[r];if(c&&c.progress&&void 0!==c.remaining&&void 0!==c.points&&c.progress>=100)return void(n[r]={progress:c.progress,remaining:c.remaining,points:c.points});const d=function(e,t,r,n,a=10,s={}){const o=new Date(r);o.setHours(0,0,0,0);const i=new Date(n);i.setHours(23,59,59,999);const l=t.filter(e=>{const t=new Date(e.date);return t>=o&&t<=i});let c=0;l.forEach(e=>{e.points&&"number"==typeof e.points&&(c+=e.points)});const d={progress:Math.max(0,Math.min(100,Math.floor(c/a*100))),remaining:Math.max(0,Math.min(a-c,a)),points:c};if(c>=a||s.noNextBadgePoints)return d;const p=function(e,t,r){let n=0,a=0,s=0,o=0;const i=new Date(t);i.setMonth(i.getMonth()+1),i.setDate(1),i.setHours(0,0,0,0);const l=new Date(i);l.setMonth(l.getMonth()+1),l.setDate(0),l.setHours(23,59,59,999),e.filter(e=>{const t=new Date(e.date);return t>=i&&t<=l}).forEach(e=>{e.points&&"number"==typeof e.points&&(n+=e.points)});{const r=new Date(t);r.setMonth(r.getMonth()+2),r.setDate(1),r.setHours(0,0,0,0);const n=new Date(r);n.setMonth(n.getMonth()+1),n.setDate(0),n.setHours(23,59,59,999),e.filter(e=>{const t=new Date(e.date);return t>=r&&t<=n}).forEach(e=>{e.points&&"number"==typeof e.points&&(a+=e.points)})}return n>r&&(s=Math.max(0,n-r)),a>r&&(o=Math.max(0,a-r),n0){const e=c+p;return{progress:Math.max(0,Math.min(100,Math.floor(e/a*100))),remaining:Math.max(0,Math.min(a-e,a)),points:e}}return d}(0,e,o,l,10,{noNextBadgePoints:!1});n[r]=d})}return n},[e,t,r,o,i])}},8334:(e,t,r)=>{var n=r(6087),a=r(7723),s=r(1362),o=r(4272),i=r(9277),l=r(790);function c(e){return(0,a.sprintf)(/* translators: %s: The remaining number of posts or pages to write. */ /* translators: %s: The remaining number of posts or pages to write. */
+(0,a._n)("Write %s new post or page and earn your next badge!","Write %s new posts or pages and earn your next badge!",e,"progress-planner"),e)}(0,s.Cu)({id:"badge-streak-content",component:function({config:e={}}){const t=e?.title||(0,a.__)("Your content badges","progress-planner");return(0,l.jsxs)(n.Fragment,{children:[(0,l.jsx)(i.A,{title:t,tooltipContent:(0,a.__)("Your content badges are based on the amount of content you have created over the past 30 days.","progress-planner")}),(0,l.jsx)(o.A,{badgeType:"content",introText:(0,a.__)("The more you work on meaningful content, the sooner you unlock new badges.","progress-planner"),backgroundColor:"var(--prpl-background-content-badge)",badgeGroupClass:"badge-group-content",getRemainingText:c})]})},priority:6,width:1,forceLastColumn:!0,title:(0,a.__)("Your content badges","progress-planner")})},8650:(e,t,r)=>{r.d(t,{t:()=>s});var n=r(6087),a=r(2381);function s(e,t){const r=(0,n.useRef)({}),s=(0,n.useRef)(!1);(0,n.useEffect)(()=>{if(s.current||!e||0===Object.keys(e).length)return;const n={};let o=!1;Object.keys(e).forEach(a=>{var s;const i=e[a],l=r.current[a],c=t[a],d=!l||l.progress!==i.progress||l.remaining!==i.remaining,p=i.progress>=100&&(!c||(null!==(s=c.progress)&&void 0!==s?s:0)<100),g=!c||c.progress!==i.progress||c.remaining!==i.remaining;(d||p||g)&&(n[a]={progress:i.progress,remaining:i.remaining,...void 0!==i.points&&{points:i.points}},o=!0)}),o&&Object.keys(n).length>0&&(s.current=!0,(0,a.Ek)(n).catch(e=>{console.warn("Failed to save badge progress:",e)}).finally(()=>{s.current=!1})),r.current={...e}},[e,t])}},8982:(e,t,r)=>{r.d(t,{W5:()=>o,pp:()=>i});var n=r(7723),a=r(790);const s={padding:"1em",backgroundColor:"var(--prpl-color-error-background, #fee)",color:"var(--prpl-color-error, #c00)",borderRadius:"var(--prpl-border-radius)"};function o({message:e=(0,n.__)("An error occurred.","progress-planner"),className:t="",style:r={},simple:o=!1}){return o?(0,a.jsx)("p",{className:t||void 0,children:e}):(0,a.jsx)("div",{className:"prpl-widget-error"+(t?` ${t}`:""),style:{...s,...r},children:e})}function i({message:e=(0,n.__)("No data available.","progress-planner"),className:t=""}){return(0,a.jsx)("p",{className:t||void 0,children:e})}},9061:(e,t,r)=>{r.d(t,{A:()=>s});var n=r(790);const a={arrow:{viewBox:"0 0 20 17",paths:[{d:"M19.92 8.12c-.05-.12-.12-.23-.22-.33L12.21.29A.996.996 0 1 0 10.8 1.7l5.79 5.79H1c-.55 0-1 .45-1 1s.45 1 1 1h15.59l-5.79 5.79a.996.996 0 0 0 .71 1.7c.26 0 .51-.1.71-.29l7.5-7.5c.1-.1.17-.21.22-.33.05-.12.07-.24.08-.38 0-.14-.03-.27-.08-.38Z"}]},trash:{viewBox:"0 0 48 48",paths:[{d:"M32.99 47.88H15.01c-3.46 0-6.38-2.7-6.64-6.15L6.04 11.49l-.72.12c-.82.14-1.59-.41-1.73-1.22-.14-.82.41-1.59 1.22-1.73.79-.14 1.57-.26 2.37-.38h.02c2.21-.33 4.46-.6 6.69-.81v-.72c0-3.56 2.74-6.44 6.25-6.55 2.56-.08 5.15-.08 7.71 0 3.5.11 6.25 2.99 6.25 6.55v.72c2.24.2 4.48.47 6.7.81.79.12 1.59.25 2.38.39.82.14 1.36.92 1.22 1.73-.14.82-.92 1.36-1.73 1.22l-.72-.12-2.33 30.24c-.27 3.45-3.18 6.15-6.64 6.15Zm-17.98-3h17.97c1.9 0 3.51-1.48 3.65-3.38l2.34-30.46c-2.15-.3-4.33-.53-6.48-.7h-.03c-5.62-.43-11.32-.43-16.95 0h-.03c-2.15.17-4.33.4-6.48.7l2.34 30.46c.15 1.9 1.75 3.38 3.65 3.38ZM24 7.01c2.37 0 4.74.07 7.11.22v-.49c0-1.93-1.47-3.49-3.34-3.55-2.5-.08-5.03-.08-7.52 0-1.88.06-3.34 1.62-3.34 3.55v.49c2.36-.15 4.73-.22 7.11-.22Zm5.49 32.26h-.06c-.83-.03-1.47-.73-1.44-1.56l.79-20.65c.03-.83.75-1.45 1.56-1.44.83.03 1.47.73 1.44 1.56l-.79 20.65c-.03.81-.7 1.44-1.5 1.44Zm-10.98 0c-.8 0-1.47-.63-1.5-1.44l-.79-20.65c-.03-.83.61-1.52 1.44-1.56.84 0 1.52.61 1.56 1.44l.79 20.65c.03.83-.61 1.52-1.44 1.56h-.06Z"}]},check:{viewBox:"0 0 20 20",paths:[{d:"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",fillRule:"evenodd",clipRule:"evenodd"}]},close:{viewBox:"0 0 20 20",paths:[{d:"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",fillRule:"evenodd",clipRule:"evenodd"}]},chevronDown:{viewBox:"0 0 24 24",stroke:!0,paths:[{d:"m19.5 8.25-7.5 7.5-7.5-7.5",strokeLinecap:"round",strokeLinejoin:"round"}]},info:{viewBox:"0 0 64 64",paths:[{d:"M32 63.73C14.51 63.73.27 49.49.27 32S14.51.27 32 .27 63.73 14.5 63.73 32 49.5 63.73 32 63.73Zm0-58C17.51 5.73 5.73 17.52 5.73 32S17.52 58.27 32 58.27 58.27 46.48 58.27 32 46.49 5.73 32 5.73Zm1.2 41.4c-.42 0-.83-.05-1.24-.15-1.33-.33-2.46-1.17-3.16-2.34-.71-1.18-.91-2.56-.58-3.9l2.13-8.54c-1.25.36-2.62-.21-3.21-1.42-.66-1.35-.1-2.99 1.25-3.65l.13-.06c1.21-.6 2.6-.7 3.91-.27 1.3.44 2.36 1.35 2.97 2.58.55 1.1.69 2.36.39 3.54l-2.13 8.54c1.22-.36 2.58.19 3.19 1.37.69 1.34.16 2.98-1.18 3.67l-.13.07c-.74.37-1.54.56-2.34.56Zm-2.26-15.17Zm1.09-9.03c-1.65 0-3.02-1.34-3.02-2.99s1.34-3.01 2.99-3.01h.03c1.65 0 2.99 1.34 2.99 2.99s-1.34 3.01-2.99 3.01Z"}]},warning:{viewBox:"0 0 24 24",paths:[{d:"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003ZM12 8.25a.75.75 0 0 1 .75.75v3.75a.75.75 0 0 1-1.5 0V9a.75.75 0 0 1 .75-.75Zm0 8.25a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Z",fillRule:"evenodd",clipRule:"evenodd"}]}};function s({name:e,...t}){const r=a[e];if(!r)return null;const s=r.stroke;return(0,n.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:r.viewBox,fill:s?"none":"currentColor",stroke:s?"currentColor":void 0,strokeWidth:s?"1.5":void 0,"aria-hidden":"true",focusable:"false",...t,children:r.paths.map((e,t)=>(0,n.jsx)("path",{...e},t))})}},9235:(e,t,r)=>{r.d(t,{A:()=>s});var n=r(5815),a=r(790);function s({backgroundColor:e="var(--prpl-background-monthly)"}){const t={padding:"var(--prpl-padding) var(--prpl-padding) calc(var(--prpl-padding) * 2) var(--prpl-padding)",background:e,borderRadius:"var(--prpl-border-radius-big)",aspectRatio:"2 / 1",overflow:"hidden",position:"relative",marginBottom:"var(--prpl-padding)",display:"flex",justifyContent:"center",alignItems:"flex-start"};return(0,a.jsx)("div",{style:t,children:(0,a.jsxs)("div",{style:{width:"100%",aspectRatio:"1 / 1",position:"relative",display:"flex",justifyContent:"center",alignItems:"center"},children:[(0,a.jsx)(n.Q8,{size:"100%",style:{position:"absolute",opacity:.3}}),(0,a.jsx)("div",{style:{position:"absolute",top:"35%",display:"flex",flexDirection:"column",alignItems:"center",gap:"0.5em"},children:(0,a.jsx)(n.iA,{width:"3em",height:"2.5em",style:{borderRadius:"8px"}})})]})})}},9277:(e,t,r)=>{r.d(t,{A:()=>c});var n=r(7723),a=r(1059),s=r(9061),o=r(790);const i={display:"flex",justifyContent:"flex-start",flexWrap:"wrap",position:"relative"},l={width:"1.25rem",height:"1.25rem",display:"inline-block",verticalAlign:"bottom",color:"#6b7280"};function c({title:e,tooltipContent:t="",className:r=""}){return(0,o.jsxs)("h2",{className:"prpl-widget-title"+(r?` ${r}`:""),children:[e,t&&(0,o.jsx)("div",{style:i,children:(0,o.jsx)(a.A,{triggerContent:(0,o.jsxs)("span",{style:l,children:[(0,o.jsx)(s.A,{name:"info"}),(0,o.jsx)("span",{className:"screen-reader-text",children:(0,n.__)("More info","progress-planner")})]}),children:t})})]})}}},e=>{e(e.s=8334)}]);
\ No newline at end of file
diff --git a/build/widget-monthly-badges-rtl.css b/build/widget-monthly-badges-rtl.css
new file mode 100644
index 0000000000..b83e7450bc
--- /dev/null
+++ b/build/widget-monthly-badges-rtl.css
@@ -0,0 +1 @@
+.prpl-tooltip-wrapper .prpl-tooltip p{margin-bottom:0}.prpl-tooltip-wrapper .prpl-tooltip p:first-child{margin-top:0}
diff --git a/build/widget-monthly-badges.asset.php b/build/widget-monthly-badges.asset.php
new file mode 100644
index 0000000000..41b12d7847
--- /dev/null
+++ b/build/widget-monthly-badges.asset.php
@@ -0,0 +1 @@
+ array('react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '9262ec148d6a49f0f231', 'handle' => 'undefined-widget-monthly-badges');
diff --git a/build/widget-monthly-badges.css b/build/widget-monthly-badges.css
new file mode 100644
index 0000000000..b83e7450bc
--- /dev/null
+++ b/build/widget-monthly-badges.css
@@ -0,0 +1 @@
+.prpl-tooltip-wrapper .prpl-tooltip p{margin-bottom:0}.prpl-tooltip-wrapper .prpl-tooltip p:first-child{margin-top:0}
diff --git a/build/widget-monthly-badges.js b/build/widget-monthly-badges.js
new file mode 100644
index 0000000000..fff705a9b1
--- /dev/null
+++ b/build/widget-monthly-badges.js
@@ -0,0 +1,2 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[208],{475:(e,t,r)=>{r.d(t,{A:()=>a});var n=r(6087),s=r(790);function a({value:e=0,max:t=10,backgroundColor:r="var(--prpl-background-monthly)",color:a="var(--prpl-color-monthly)",color2:o="var(--prpl-color-monthly-2)",contentFontSize:i="var(--prpl-font-size-6xl)",children:l}){const c="180deg",d={padding:"var(--prpl-padding) var(--prpl-padding) calc(var(--prpl-padding) * 2) var(--prpl-padding)",background:r,borderRadius:"var(--prpl-border-radius-big)",aspectRatio:"2 / 1",overflow:"hidden",position:"relative",marginBottom:"var(--prpl-padding)"},p={width:"100%",aspectRatio:"1 / 1",borderRadius:"100%",position:"relative",background:`radial-gradient(${r} 0 57%, transparent 57% 100%), conic-gradient(from 270deg, ${(0,n.useMemo)(()=>{const r=t>0?e/t:0;let n;return r<=.5?n=`${a} calc(${c} * ${r})`:(n=`${a} calc(${c} * 0.5)`,n+=`, ${o} calc(${c} * ${r})`),n+=`, var(--prpl-color-gauge-remain) calc(${c} * ${r}) ${c}`,n},[e,t,a,o])}, transparent ${c})`,textAlign:"center"},g={fontSize:"var(--prpl-font-size-small)",position:"absolute",top:"50%",color:"var(--prpl-color-text)",width:"10%",textAlign:"center"},u={...g,left:0},m={...g,right:0},h={fontSize:i,bottom:"50%",display:"block",fontWeight:600,textAlign:"center",position:"absolute",color:"var(--prpl-color-text)",width:"100%",lineHeight:1.2};return(0,s.jsx)("div",{className:"prpl-gauge",style:d,children:(0,s.jsxs)("div",{className:"prpl-gauge__ring",style:p,children:[(0,s.jsx)("span",{className:"prpl-gauge__label prpl-gauge__label--min",style:u,children:"0"}),(0,s.jsx)("span",{className:"prpl-gauge__content",style:h,children:(0,s.jsx)("span",{className:"prpl-gauge__content-inner",style:{display:"inline-block",width:"50%"},children:l})}),(0,s.jsx)("span",{className:"prpl-gauge__label prpl-gauge__label--max",style:m,children:t})]})})}},645:(e,t,r)=>{r.d(t,{Ge:()=>i,HY:()=>n,TV:()=>a,Tn:()=>s,cs:()=>o,et:()=>l});const n=[{id:"content-curator",name:"Content Curator",description:"20 existing posts/pages, or 10 new posts/pages",type:"content",background:"var(--prpl-background-content-badge)",thresholds:{existingPosts:20,newPosts:10}},{id:"revision-ranger",name:"Revision Ranger",description:"Write 30 new posts or pages",type:"content",background:"var(--prpl-background-content-badge)",thresholds:{newPosts:30}},{id:"purposeful-publisher",name:"Purposeful Publisher",description:"Write 50 new posts or pages",type:"content",background:"var(--prpl-background-content-badge)",thresholds:{newPosts:50}}],s=[{id:"progress-padawan",name:"Progress Padawan",description:"6 weeks streak",type:"maintenance",background:"var(--prpl-background-streak)",thresholds:{weeks:6}},{id:"maintenance-maniac",name:"Maintenance Maniac",description:"26 weeks streak",type:"maintenance",background:"var(--prpl-background-streak)",thresholds:{weeks:26}},{id:"super-site-specialist",name:"Super Site Specialist",description:"52 weeks streak",type:"maintenance",background:"var(--prpl-background-streak)",thresholds:{weeks:52}}],a={targetPoints:10,months:{m1:"Jack January",m2:"Felix February",m3:"Mary March",m4:"Avery April",m5:"Matteo May",m6:"Jasmine June",m7:"Joey July",m8:"Abed August",m9:"Sam September",m10:"Oksana October",m11:"Noah November",m12:"Daisy December"}};function o(e){return`monthly-${e.getFullYear()}-m${e.getMonth()+1}`}function i(e){const t=`m${e.getMonth()+1}`;return a.months[t]||""}function l(e){const t=n.find(t=>t.id===e);if(t)return t;const r=s.find(t=>t.id===e);if(r)return r;if(e.startsWith("monthly-")){const t=e.split("-");if(3===t.length){const r=parseInt(t[1],10),n=t[2].replace("m",""),s=parseInt(n,10);if(r&&s>=1&&s<=12){const t=new Date(r,s-1,1);return{id:e,name:i(t),description:"",type:"monthly",background:"var(--prpl-background-content-badge)",thresholds:{points:a.targetPoints}}}}}return null}},790:e=>{e.exports=window.ReactJSXRuntime},1059:(e,t,r)=>{r.d(t,{A:()=>u});var n=r(6087),s=r(7723),a=r(790);const o={position:"absolute",top:0,right:0,transform:"translate(-10px, -10px) rotate(90deg)",width:0,height:0,borderStyle:"solid",borderWidth:"7.5px 10px 7.5px 0",borderColor:"transparent var(--prpl-background-activity) transparent transparent"},i={padding:0,lineHeight:1,background:"none",border:"none",cursor:"pointer",fontSize:"var(--prpl-font-size-small)",color:"var(--prpl-color-link)"},l={display:"inline-flex",alignItems:"center",position:"relative"},c={display:"block",position:"absolute",bottom:0,left:"100%",transform:"translate(-100%, calc(100% + 10px))",padding:"0.75rem 1.5rem 0.75rem 0.75rem",width:150,background:"var(--prpl-background-activity)",borderRadius:"var(--prpl-border-radius)",zIndex:2,visibility:"hidden",fontSize:"1rem",fontWeight:400,color:"var(--prpl-color-text)"},d={visibility:"visible",zIndex:10},p={position:"absolute",top:0,right:0,padding:"0.1rem",lineHeight:0,margin:0,background:"none",border:"none",cursor:"pointer"},g={display:"block",position:"fixed",top:0,left:0,width:"100%",height:"100%",zIndex:9,backgroundColor:"rgba(0, 0, 0, 0.5)"};function u({triggerContent:e,children:t,tooltipStyle:r,arrowStyle:u,onClose:m}){const[h,f]=(0,n.useState)(!1),[b,v]=(0,n.useState)(!1),y=(0,n.useRef)(null),x=(0,n.useId)(),w=(0,n.useCallback)(()=>{f(!1),m?.()},[m]);(0,n.useEffect)(()=>{if(!h)return;const e=e=>{"Escape"===e.key&&w()};return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)},[h,w]);const k={...i,textDecoration:b?"underline":"none"};return(0,a.jsxs)("span",{className:"prpl-tooltip-wrapper",style:l,children:[(0,a.jsx)("button",{type:"button",className:"prpl-info-icon","aria-describedby":x,onClick:()=>f(!0),style:k,onMouseEnter:()=>v(!0),onMouseLeave:()=>v(!1),children:e}),h&&(0,a.jsx)("span",{role:"presentation",onClick:w,style:g}),(0,a.jsxs)("span",{ref:y,id:x,className:"prpl-tooltip",role:"tooltip","aria-hidden":!h,style:{...c,...h?d:{},...r},children:[(0,a.jsx)("span",{"data-testid":"tooltip-arrow",style:{...o,...u}}),t,(0,a.jsxs)("button",{type:"button",onClick:w,style:p,children:[(0,a.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,a.jsx)("span",{className:"screen-reader-text",children:(0,s.__)("Close","progress-planner")})]})]})]})}},1362:(e,t,r)=>{r.d(t,{Cu:()=>a,cr:()=>o});var n=r(2619);const s=[];function a(e){const{id:t,component:r,priority:n=10,width:a=1,forceLastColumn:o=!1,title:i=""}=e;if(!t||!r)return void console.warn("Widget registration failed: id and component are required",e);const l=s.findIndex(e=>e.id===t),c={id:t,component:r,priority:n,width:a,forceLastColumn:o,title:i};l>=0?s[l]=c:s.push(c)}function o(){return[...s].sort((e,t)=>e.priority-t.priority)}(0,n.addAction)("prpl.dashboard.registerWidget","progress-planner/widget-registry",a)},1455:e=>{e.exports=window.wp.apiFetch},2381:(e,t,r)=>{r.d(t,{Ek:()=>l,jx:()=>i,mZ:()=>o});var n=r(1455),s=r.n(n),a=r(5337);async function o(e=!1){try{const t=await(0,a.BJ)({path:"/progress-planner/v1/activities"},{skipCache:e});return{activities:t.activities||[],totalPostsCount:t.totalPostsCount||0,activationDate:t.activationDate?new Date(t.activationDate):new Date,config:t.config||{brandingId:0,remoteServerUrl:"",placeholderUrl:""}}}catch(e){throw new Error(e.message||"Failed to fetch activities")}}async function i(e=!1){try{return(await(0,a.BJ)({path:"/progress-planner/v1/badge-stats"},{skipCache:e})).badges||{}}catch(e){throw new Error(e.message||"Failed to fetch badge stats")}}async function l(e){try{const t=await s()({path:"/progress-planner/v1/badge-stats",method:"POST",data:{badges:e}});return(0,a.Wz)("/progress-planner/v1/badge-stats",t),t.badges||{}}catch(e){throw new Error(e.message||"Failed to save badge stats")}}},2619:e=>{e.exports=window.wp.hooks},3971:(e,t,r)=>{r.d(t,{A:()=>s});var n=r(790);function s({badgeId:e,badgeName:t,brandingId:r=0,isComplete:s=!0}){const a=window.progressPlannerBadge||{};let o=a.remoteServerRootUrl||"https://progressplanner.com";const i=a.placeholderImageUrl||"";(o.includes("localhost")||o.includes("127.0.0.1"))&&(o="https://progressplanner.com");let l=`${o}/wp-json/progress-planner-saas/v1/badge-svg/?badge_id=${e}`;r&&(l+=`&branding_id=${r}`);const c=t&&"null"!==t?t:"Badge",d={maxWidth:"100%",height:"auto",verticalAlign:"bottom",transition:"opacity 0.3s ease-in-out, filter 0.3s ease-in-out",...!s&&{opacity:.25,filter:"grayscale(1)"}};return(0,n.jsx)("img",{src:l,alt:c,onError:e=>{i&&e.target.src!==i&&(e.target.onerror=null,e.target.src=i)},style:d})}},5337:(e,t,r)=>{r.d(t,{BJ:()=>l,IL:()=>c,Wz:()=>d});var n=r(1455),s=r.n(n);const a=new Map,o=new Map,i=3e5;async function l(e,t={}){const{skipCache:r=!1,ttl:n=i}=t,l=function(e){if("GET"!==(e.method||"GET").toUpperCase())return null;let t=e.path||e.url||"";if(e.data&&"object"==typeof e.data){const r=new URLSearchParams(e.data).toString();r&&(t+=(t.includes("?")?"&":"?")+r)}return`GET:${t}`}(e);if(!l)return s()(e);if(!r&&a.has(l))return a.get(l);if(!r){const e=o.get(l);if(e&&Date.now()-e.timestamp(o.set(l,{data:e,timestamp:Date.now()}),a.delete(l),e)).catch(e=>{throw a.delete(l),e});return a.set(l,c),c}function c(){o.clear(),a.clear()}function d(e,t){const r=`GET:${e}`;o.set(r,{data:t,timestamp:Date.now()})}},5815:(e,t,r)=>{r.d(t,{Q8:()=>d,iA:()=>c,rr:()=>p});var n=r(6087),s=r(790);const a="\n@keyframes prpl-shimmer {\n\t0% { background-position: 200% 0; }\n\t100% { background-position: -200% 0; }\n}\n";let o=!1;function i(){if(o||"undefined"==typeof document)return;const e=document.createElement("style");e.id="prpl-skeleton-keyframes",e.textContent=a,document.head.appendChild(e),o=!0}const l={background:"linear-gradient(\n\t\t90deg,\n\t\tvar(--prpl-color-gauge-remain, #f0f0f0) 25%,\n\t\tvar(--prpl-color-border, #e0e0e0) 50%,\n\t\tvar(--prpl-color-gauge-remain, #f0f0f0) 75%\n\t)",backgroundSize:"200% 100%",animation:"prpl-shimmer 1.5s ease-in-out infinite",borderRadius:"var(--prpl-border-radius, 8px)"};function c({width:e="100%",height:t="1em",className:r="",style:a={}}){return(0,n.useEffect)(()=>{i()},[]),(0,s.jsx)("div",{className:r||void 0,style:{...l,width:e,height:t,...a}})}function d({size:e="40px",className:t="",style:r={}}){return(0,n.useEffect)(()=>{i()},[]),(0,s.jsx)("div",{className:t||void 0,style:{...l,width:e,height:e,borderRadius:"50%",...r}})}function p({width:e="100%",lines:t=1,className:r="",style:a={},lastShort:o=!0}){return(0,n.useEffect)(()=>{i()},[]),1===t?(0,s.jsx)(c,{width:e,height:"1em",className:r,style:a}):(0,s.jsx)("div",{style:{display:"flex",flexDirection:"column",...a},children:Array.from({length:t}).map((n,a)=>(0,s.jsx)(c,{width:o&&a===t-1?"70%":e,height:"1em",className:r,style:{marginBottom:a{var n=r(6087),s=r(7723),a=r(1362),o=r(7440),i=r(8300),l=r(8650),c=r(645),d=r(475),p=r(3971),g=r(790);const u={container:{padding:"1rem 0"},bar:{width:"100%",height:"1rem",backgroundColor:"var(--prpl-color-gauge-remain)",borderRadius:"0.5rem",position:"relative"},progressBase:{height:"100%",backgroundColor:"var(--prpl-color-monthly)",borderRadius:"0.5rem",transition:"width 0.4s ease"},badgeWrapperBase:{display:"flex",width:"7.5rem",height:"auto",position:"absolute",top:"-2.5rem",transition:"left 0.4s ease"},alertIndicator:{content:'"!"',display:"flex",alignItems:"center",justifyContent:"center",width:"20px",height:"20px",backgroundColor:"var(--prpl-color-alert-error)",border:"2px solid #fff",borderRadius:"50%",position:"absolute",top:"10%",right:"25%",color:"#fff",fontSize:"12px",fontWeight:"bold"},pointsContainer:{display:"flex",justifyContent:"flex-start",gap:"1rem"},pointsNumber:{fontSize:"var(--prpl-font-size-3xl)",fontWeight:600},remainingText:{display:"flex",alignItems:"center"}};function m({badgeId:e,badgeName:t,points:r=0,maxPoints:a=10,accumulatedRemaining:o=0,daysRemaining:i=0,brandingId:l=0}){const c=(0,n.useMemo)(()=>0===a?0:r/a*100,[r,a]),d=(0,n.useMemo)(()=>({...u.progressBase,width:`${c}%`}),[c]),m=(0,n.useMemo)(()=>({...u.badgeWrapperBase,left:`calc(${c}% - 3.75rem)`}),[c]),h=r>=a,f="prpl-badge-progress-bar"+(h?" prpl-badge-progress-bar--complete":"");return(0,g.jsxs)("div",{className:f,style:u.container,children:[(0,g.jsxs)("div",{className:"prpl-badge-progress-bar__bar",style:u.bar,children:[(0,g.jsx)("div",{className:"prpl-badge-progress-bar__progress",style:d}),(0,g.jsxs)("div",{className:"prpl-badge-progress-bar__badge-wrapper",style:m,children:[(0,g.jsx)(p.A,{badgeId:e,badgeName:t,brandingId:l}),!h&&(0,g.jsx)("span",{className:"prpl-badge-progress-bar__alert",style:u.alertIndicator,children:"!"})]})]}),(0,g.jsxs)("div",{className:"prpl-widget-content-points",style:u.pointsContainer,children:[(0,g.jsxs)("span",{className:"prpl-widget-previous-ravi-points-number",style:u.pointsNumber,children:[r,"pt"]}),o>0&&(0,g.jsx)("span",{className:"prpl-previous-month-badge-progress-bar-remaining",style:u.remainingText,dangerouslySetInnerHTML:{__html:(0,s.sprintf)(/* translators: %1$s: The number of points. %2$d: The number of days. */ /* translators: %1$s: The number of points. %2$d: The number of days. */
+(0,s._n)("%1$s more points to go - %2$d day left","%1$s more points to go - %2$d days left",i,"progress-planner"),(0,s.sprintf)('%d',o),i)}})]})]})}function h({points:e,label:t=(0,s.__)("Progress monthly badge","progress-planner"),showUnit:r=!0}){return(0,g.jsxs)("div",{className:"prpl-monthly-badges__points-counter",style:{display:"flex",justifyContent:"space-between",alignItems:"center"},children:[(0,g.jsx)("span",{className:"prpl-monthly-badges__points-label",children:t}),(0,g.jsxs)("span",{className:"prpl-monthly-badges__points-number",style:{fontSize:"var(--prpl-font-size-3xl)",fontWeight:600},children:[e,r&&"pt"]})]})}var f=r(8982),b=r(9235),v=r(5815);function y({size:e="100%"}){return(0,g.jsx)("div",{style:{maxWidth:"100%",display:"flex",justifyContent:"center",alignItems:"center"},children:(0,g.jsx)(v.Q8,{size:e,style:{maxWidth:"100%",aspectRatio:"1 / 1",opacity:.5}})})}function x(){return(0,g.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"0.5rem",justifyContent:"center"},children:[(0,g.jsx)(v.iA,{width:"2rem",height:"1.5rem",style:{borderRadius:"4px"}}),(0,g.jsx)(v.iA,{width:"8rem",height:"1rem"})]})}function w(){return(0,g.jsxs)("div",{style:{display:"flex",flexDirection:"column",gap:"1rem"},children:[(0,g.jsxs)("div",{style:{position:"relative"},children:[(0,g.jsx)(b.A,{}),(0,g.jsx)("div",{style:{position:"absolute",top:"25%",left:"50%",transform:"translateX(-50%)",width:"40%"},children:(0,g.jsx)(y,{})})]}),(0,g.jsx)(x,{})]})}var k=r(9277),j=r(8864);(0,a.Cu)({id:"monthly-badges",component:function({config:e={}}){const t=(0,j.fX)(e=>e.sessionPoints),{isLoading:r,error:a,data:u}=(0,o.H)(),b=(0,n.useCallback)(e=>{if(!e.startsWith("monthly-"))return null;const t=e.split("-");if(3!==t.length)return null;const r=parseInt(t[1],10),n=t[2].replace("m",""),s=parseInt(n,10);if(!r||s<1||s>12)return null;const a=new Date(r,s-1,1);a.setHours(0,0,0,0);const o=new Date(r,s,0);return o.setHours(23,59,59,999),{startDate:a,endDate:o}},[]),v=(0,i._)({activities:u?.activities||[],savedStats:u?.savedStats||{},totalPostsCount:u?.totalPostsCount||0,activationDate:u?.activationDate?new Date(u.activationDate):null,getMonthlyBadgeDateRange:b});(0,l.t)(v,u?.savedStats||{});const y=(0,n.useMemo)(()=>{const e=new Date,t=(0,c.cs)(e);return{id:t,name:(0,c.Ge)(e),progress:v[t]||{progress:0,remaining:10,points:0}}},[v]),x=(0,n.useMemo)(()=>{const e=new Date,t=e.getMonth(),r=e.getFullYear(),n=[],s=u?.activationDate?new Date(u.activationDate):null;for(let e=1;e<=2;e++){const a=new Date(r,t-e,1);if(s&&a=D,S=(0,n.useMemo)(()=>{if(0===x.length)return[];let e=Math.max(0,D-M);const t=x.map(t=>{const r=Math.max(0,(t.maxPoints||10)-t.points);return e+=r,{...t,remaining:r,accumulatedRemaining:e}}),r=new Date,n=new Date(r.getFullYear(),r.getMonth()+1,0).getDate()-r.getDate();return t.map(e=>({...e,daysRemaining:n}))},[x,D,M]),N=e?.title||(0,s.__)("Your monthly badge","progress-planner");return r?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(k.A,{title:N}),(0,g.jsx)(w,{})]}):a?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(k.A,{title:N}),(0,g.jsx)(f.W5,{message:a,className:"prpl-monthly-badges prpl-monthly-badges--error",style:{minHeight:"200px",backgroundColor:"transparent",color:"var(--prpl-color-alert-error)"}})]}):(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(k.A,{title:N}),(0,g.jsxs)("div",{className:"prpl-monthly-badges",style:{display:"flex",flexDirection:"column",gap:"1rem"},children:[(0,g.jsx)(d.A,{value:M,max:D,children:y&&(0,g.jsx)(p.A,{badgeId:y.id,badgeName:y.name,brandingId:_.brandingId,isComplete:C})}),(0,g.jsx)(h,{points:M,label:(0,s.__)("Progress monthly badge","progress-planner")}),x.length>0&&(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)("hr",{}),(0,g.jsxs)("div",{className:"prpl-previous-month-badge-progress-bars-wrapper",children:[(0,g.jsx)("h3",{children:(0,s.__)("Oh no! You missed the previous monthly badge!","progress-planner")}),(0,g.jsx)("p",{className:"prpl-previous-month-badge-progress-bars-wrapper-description",dangerouslySetInnerHTML:{__html:(0,s.__)("No worries though! Collect the surplus of points you earn, and get your badge!","progress-planner")}}),S.map(e=>(0,g.jsx)("div",{className:"prpl-previous-month-badge-progress-bar-wrapper",style:{borderRadius:"0.5rem",padding:"0.75rem 1rem 1.25rem 1rem"},"data-badge-id":e.id,children:(0,g.jsx)(m,{badgeId:e.id,badgeName:e.name,points:e.points,maxPoints:e.maxPoints||10,remaining:e.remaining,accumulatedRemaining:e.accumulatedRemaining,daysRemaining:e.daysRemaining,brandingId:_.brandingId})},e.id))]})]})]})]})},priority:2,width:1,forceLastColumn:!1,title:(0,s.__)("Your monthly badge","progress-planner")})},6087:e=>{e.exports=window.wp.element},7440:(e,t,r)=>{r.d(t,{H:()=>a});var n=r(6087),s=r(2381);function a(){const[e,t]=(0,n.useState)(!0),[r,a]=(0,n.useState)(null),[o,i]=(0,n.useState)(null),l=(0,n.useCallback)(async()=>{try{t(!0),a(null);const[e,r]=await Promise.all([(0,s.mZ)(),(0,s.jx)()]);i({activities:e.activities||[],totalPostsCount:e.totalPostsCount||0,activationDate:e.activationDate,savedStats:r,config:e.config||{brandingId:0,remoteServerUrl:"",placeholderUrl:""}})}catch(e){a(e.message||"Failed to load badge data")}finally{t(!1)}},[]);return(0,n.useEffect)(()=>{l()},[l]),{isLoading:e,error:r,data:o,refetch:l}}},7723:e=>{e.exports=window.wp.i18n},8300:(e,t,r)=>{r.d(t,{_:()=>o});var n=r(6087);function s(e){const t=new Date(e),r=t.getDay(),n=t.getDate()-r+(0===r?-6:1);return t.setDate(n),t.setHours(0,0,0,0),t}var a=r(645);function o({activities:e=[],savedStats:t={},totalPostsCount:r=0,activationDate:o=null,getMonthlyBadgeDateRange:i=null}){return(0,n.useMemo)(()=>{if(!o)return{};const n={};if(["content-curator","revision-ranger","purposeful-publisher"].forEach(s=>{const i=(0,a.et)(s);if(!i)return;const l=t[s];if(l&&l.progress&&void 0!==l.remaining&&l.progress>=100)return void(n[s]={progress:l.progress,remaining:l.remaining});const c=function(e,t,r,n){const{thresholds:s}=e;if("content-curator"===e.id){const e=Math.max(0,s.existingPosts-Math.min(s.existingPosts,r));if(0===e)return{progress:100,remaining:0};const a=new Date(n);a.setHours(0,0,0,0);const o=t.filter(e=>{if("content"!==e.category||"publish"!==e.type)return!1;const t=new Date(e.date);return t.setHours(0,0,0,0),t>=a}).length,i=Math.max(0,s.newPosts-Math.min(s.newPosts,o));return{progress:Math.max(Math.min(100,Math.floor(r/2)),Math.min(100,Math.floor(10*o))),remaining:Math.min(e,i)}}const a=new Date(n);a.setHours(0,0,0,0);const o=t.filter(e=>{if("content"!==e.category||"publish"!==e.type)return!1;const t=new Date(e.date);return t.setHours(0,0,0,0),t>=a}).length,i=s.newPosts;return{progress:Math.min(100,Math.floor(o/i*100)),remaining:Math.max(0,i-Math.min(i,o))}}(i,e,r,o);n[s]=c}),["progress-padawan","maintenance-maniac","super-site-specialist"].forEach(r=>{const i=(0,a.et)(r);if(!i)return;const l=t[r];if(l&&l.progress&&void 0!==l.remaining){if(l.progress>=100)return void(n[r]={progress:l.progress,remaining:l.remaining});if(l.date){const e=new Date(l.date);if((new Date-e)/864e5<=2)return void(n[r]={progress:l.progress,remaining:l.remaining})}}const c=function(e,t,r){const{thresholds:n}=e,a=n.weeks,o=function(e,t,r=1){const n=new Map;e.forEach(e=>{const r=new Date(e.date);r.setHours(0,0,0,0);const a=new Date(t);if(a.setHours(0,0,0,0),r0}),o.setDate(o.getDate()+7)}let l=0,c=0,d=r;for(const e of a)if(e.hasActivity)l++,c=Math.max(c,l);else{if(d>0){d--;continue}l=0}return{max_streak:c,current_streak:l}}(t.filter(e=>"maintenance"===e.category),r,1),i=o.max_streak;return{progress:Math.min(100,Math.floor(i/a*100)),remaining:Math.max(0,a-Math.min(a,i))}}(i,e,o);n[r]=c}),i){const r=new Set;Object.keys(t).forEach(e=>{e.startsWith("monthly-")&&r.add(e)});const s=new Date,o=`monthly-${s.getFullYear()}-m${s.getMonth()+1}`;r.add(o);for(let e=1;e<=2;e++){const t=new Date(s.getFullYear(),s.getMonth()-e,1),n=`monthly-${t.getFullYear()}-m${t.getMonth()+1}`;r.add(n)}r.forEach(r=>{if(!(0,a.et)(r))return;const s=i(r);if(!s)return;const{startDate:o,endDate:l}=s,c=t[r];if(c&&c.progress&&void 0!==c.remaining&&void 0!==c.points&&c.progress>=100)return void(n[r]={progress:c.progress,remaining:c.remaining,points:c.points});const d=function(e,t,r,n,s=10,a={}){const o=new Date(r);o.setHours(0,0,0,0);const i=new Date(n);i.setHours(23,59,59,999);const l=t.filter(e=>{const t=new Date(e.date);return t>=o&&t<=i});let c=0;l.forEach(e=>{e.points&&"number"==typeof e.points&&(c+=e.points)});const d={progress:Math.max(0,Math.min(100,Math.floor(c/s*100))),remaining:Math.max(0,Math.min(s-c,s)),points:c};if(c>=s||a.noNextBadgePoints)return d;const p=function(e,t,r){let n=0,s=0,a=0,o=0;const i=new Date(t);i.setMonth(i.getMonth()+1),i.setDate(1),i.setHours(0,0,0,0);const l=new Date(i);l.setMonth(l.getMonth()+1),l.setDate(0),l.setHours(23,59,59,999),e.filter(e=>{const t=new Date(e.date);return t>=i&&t<=l}).forEach(e=>{e.points&&"number"==typeof e.points&&(n+=e.points)});{const r=new Date(t);r.setMonth(r.getMonth()+2),r.setDate(1),r.setHours(0,0,0,0);const n=new Date(r);n.setMonth(n.getMonth()+1),n.setDate(0),n.setHours(23,59,59,999),e.filter(e=>{const t=new Date(e.date);return t>=r&&t<=n}).forEach(e=>{e.points&&"number"==typeof e.points&&(s+=e.points)})}return n>r&&(a=Math.max(0,n-r)),s>r&&(o=Math.max(0,s-r),n0){const e=c+p;return{progress:Math.max(0,Math.min(100,Math.floor(e/s*100))),remaining:Math.max(0,Math.min(s-e,s)),points:e}}return d}(0,e,o,l,10,{noNextBadgePoints:!1});n[r]=d})}return n},[e,t,r,o,i])}},8650:(e,t,r)=>{r.d(t,{t:()=>a});var n=r(6087),s=r(2381);function a(e,t){const r=(0,n.useRef)({}),a=(0,n.useRef)(!1);(0,n.useEffect)(()=>{if(a.current||!e||0===Object.keys(e).length)return;const n={};let o=!1;Object.keys(e).forEach(s=>{var a;const i=e[s],l=r.current[s],c=t[s],d=!l||l.progress!==i.progress||l.remaining!==i.remaining,p=i.progress>=100&&(!c||(null!==(a=c.progress)&&void 0!==a?a:0)<100),g=!c||c.progress!==i.progress||c.remaining!==i.remaining;(d||p||g)&&(n[s]={progress:i.progress,remaining:i.remaining,...void 0!==i.points&&{points:i.points}},o=!0)}),o&&Object.keys(n).length>0&&(a.current=!0,(0,s.Ek)(n).catch(e=>{console.warn("Failed to save badge progress:",e)}).finally(()=>{a.current=!1})),r.current={...e}},[e,t])}},8864:(e,t,r)=>{r.d(t,{fX:()=>d});const n=window.React,s=e=>{let t;const r=new Set,n=(e,n)=>{const s="function"==typeof e?e(t):e;if(!Object.is(s,t)){const e=t;t=(null!=n?n:"object"!=typeof s||null===s)?s:Object.assign({},t,s),r.forEach(r=>r(t,e))}},s=()=>t,a={setState:n,getState:s,getInitialState:()=>o,subscribe:e=>(r.add(e),()=>r.delete(e))},o=t=e(n,s,a);return a},a=e=>e,o=e=>{const t=(e=>e?s(e):s)(e),r=e=>function(e,t=a){const r=n.useSyncExternalStore(e.subscribe,n.useCallback(()=>t(e.getState()),[e,t]),n.useCallback(()=>t(e.getInitialState()),[e,t]));return n.useDebugValue(r),r}(t,e);return Object.assign(r,t),r};var i=r(1455),l=r.n(i),c=r(5337);const d=(p=(e,t)=>({sessionPoints:0,totalPoints:0,lastCompletionTime:null,lastCompletedTask:null,activityScore:{current:0,target:100},badgeProgress:{},cacheInvalidatedAt:null,shouldAutoStartWizard:!1,providerTerms:{},termsLoading:!1,termsLoaded:!1,onTaskCompleted:(t,r=0)=>e(e=>({sessionPoints:e.sessionPoints+r,lastCompletionTime:Date.now(),lastCompletedTask:t})),onTaskUncompleted:(t,r=0)=>e(e=>({sessionPoints:Math.max(0,e.sessionPoints-r)})),updateActivityScore:t=>e(e=>({activityScore:{...e.activityScore,...t}})),updateBadgeProgress:(t,r)=>e(e=>({badgeProgress:{...e.badgeProgress,[t]:r}})),invalidateCache:()=>{(0,c.IL)(),e({cacheInvalidatedAt:Date.now()})},setShouldAutoStartWizard:t=>{e({shouldAutoStartWizard:t})},getProviderTermId:e=>{const r=t();return r.providerTerms[e]?.id||null},fetchProviderTerms:async()=>{const r=t();if(r.termsLoaded||r.termsLoading)return r.providerTerms;e({termsLoading:!0});try{const t=await l()({path:"/wp/v2/prpl_recommendations_provider?per_page=100"}),r={};let n=!1;if(t.forEach(e=>{r[e.slug]=e,"user"===e.slug&&(n=!0)}),!n)try{const e=await l()({path:"/wp/v2/prpl_recommendations_provider",method:"POST",data:{slug:"user",name:"user"}});r.user=e}catch(e){if("term_exists"===e.code&&e.data?.term_id)try{const t=await l()({path:`/wp/v2/prpl_recommendations_provider/${e.data.term_id}`});r.user=t}catch(e){console.error("Error fetching existing user term:",e)}else console.error("Error creating user term:",e)}return e({providerTerms:r,termsLoading:!1,termsLoaded:!0}),r}catch(t){return console.error("Error fetching provider terms:",t),e({termsLoading:!1}),{}}}}))?o(p):o;var p},8982:(e,t,r)=>{r.d(t,{W5:()=>o,pp:()=>i});var n=r(7723),s=r(790);const a={padding:"1em",backgroundColor:"var(--prpl-color-error-background, #fee)",color:"var(--prpl-color-error, #c00)",borderRadius:"var(--prpl-border-radius)"};function o({message:e=(0,n.__)("An error occurred.","progress-planner"),className:t="",style:r={},simple:o=!1}){return o?(0,s.jsx)("p",{className:t||void 0,children:e}):(0,s.jsx)("div",{className:"prpl-widget-error"+(t?` ${t}`:""),style:{...a,...r},children:e})}function i({message:e=(0,n.__)("No data available.","progress-planner"),className:t=""}){return(0,s.jsx)("p",{className:t||void 0,children:e})}},9061:(e,t,r)=>{r.d(t,{A:()=>a});var n=r(790);const s={arrow:{viewBox:"0 0 20 17",paths:[{d:"M19.92 8.12c-.05-.12-.12-.23-.22-.33L12.21.29A.996.996 0 1 0 10.8 1.7l5.79 5.79H1c-.55 0-1 .45-1 1s.45 1 1 1h15.59l-5.79 5.79a.996.996 0 0 0 .71 1.7c.26 0 .51-.1.71-.29l7.5-7.5c.1-.1.17-.21.22-.33.05-.12.07-.24.08-.38 0-.14-.03-.27-.08-.38Z"}]},trash:{viewBox:"0 0 48 48",paths:[{d:"M32.99 47.88H15.01c-3.46 0-6.38-2.7-6.64-6.15L6.04 11.49l-.72.12c-.82.14-1.59-.41-1.73-1.22-.14-.82.41-1.59 1.22-1.73.79-.14 1.57-.26 2.37-.38h.02c2.21-.33 4.46-.6 6.69-.81v-.72c0-3.56 2.74-6.44 6.25-6.55 2.56-.08 5.15-.08 7.71 0 3.5.11 6.25 2.99 6.25 6.55v.72c2.24.2 4.48.47 6.7.81.79.12 1.59.25 2.38.39.82.14 1.36.92 1.22 1.73-.14.82-.92 1.36-1.73 1.22l-.72-.12-2.33 30.24c-.27 3.45-3.18 6.15-6.64 6.15Zm-17.98-3h17.97c1.9 0 3.51-1.48 3.65-3.38l2.34-30.46c-2.15-.3-4.33-.53-6.48-.7h-.03c-5.62-.43-11.32-.43-16.95 0h-.03c-2.15.17-4.33.4-6.48.7l2.34 30.46c.15 1.9 1.75 3.38 3.65 3.38ZM24 7.01c2.37 0 4.74.07 7.11.22v-.49c0-1.93-1.47-3.49-3.34-3.55-2.5-.08-5.03-.08-7.52 0-1.88.06-3.34 1.62-3.34 3.55v.49c2.36-.15 4.73-.22 7.11-.22Zm5.49 32.26h-.06c-.83-.03-1.47-.73-1.44-1.56l.79-20.65c.03-.83.75-1.45 1.56-1.44.83.03 1.47.73 1.44 1.56l-.79 20.65c-.03.81-.7 1.44-1.5 1.44Zm-10.98 0c-.8 0-1.47-.63-1.5-1.44l-.79-20.65c-.03-.83.61-1.52 1.44-1.56.84 0 1.52.61 1.56 1.44l.79 20.65c.03.83-.61 1.52-1.44 1.56h-.06Z"}]},check:{viewBox:"0 0 20 20",paths:[{d:"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",fillRule:"evenodd",clipRule:"evenodd"}]},close:{viewBox:"0 0 20 20",paths:[{d:"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",fillRule:"evenodd",clipRule:"evenodd"}]},chevronDown:{viewBox:"0 0 24 24",stroke:!0,paths:[{d:"m19.5 8.25-7.5 7.5-7.5-7.5",strokeLinecap:"round",strokeLinejoin:"round"}]},info:{viewBox:"0 0 64 64",paths:[{d:"M32 63.73C14.51 63.73.27 49.49.27 32S14.51.27 32 .27 63.73 14.5 63.73 32 49.5 63.73 32 63.73Zm0-58C17.51 5.73 5.73 17.52 5.73 32S17.52 58.27 32 58.27 58.27 46.48 58.27 32 46.49 5.73 32 5.73Zm1.2 41.4c-.42 0-.83-.05-1.24-.15-1.33-.33-2.46-1.17-3.16-2.34-.71-1.18-.91-2.56-.58-3.9l2.13-8.54c-1.25.36-2.62-.21-3.21-1.42-.66-1.35-.1-2.99 1.25-3.65l.13-.06c1.21-.6 2.6-.7 3.91-.27 1.3.44 2.36 1.35 2.97 2.58.55 1.1.69 2.36.39 3.54l-2.13 8.54c1.22-.36 2.58.19 3.19 1.37.69 1.34.16 2.98-1.18 3.67l-.13.07c-.74.37-1.54.56-2.34.56Zm-2.26-15.17Zm1.09-9.03c-1.65 0-3.02-1.34-3.02-2.99s1.34-3.01 2.99-3.01h.03c1.65 0 2.99 1.34 2.99 2.99s-1.34 3.01-2.99 3.01Z"}]},warning:{viewBox:"0 0 24 24",paths:[{d:"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003ZM12 8.25a.75.75 0 0 1 .75.75v3.75a.75.75 0 0 1-1.5 0V9a.75.75 0 0 1 .75-.75Zm0 8.25a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Z",fillRule:"evenodd",clipRule:"evenodd"}]}};function a({name:e,...t}){const r=s[e];if(!r)return null;const a=r.stroke;return(0,n.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:r.viewBox,fill:a?"none":"currentColor",stroke:a?"currentColor":void 0,strokeWidth:a?"1.5":void 0,"aria-hidden":"true",focusable:"false",...t,children:r.paths.map((e,t)=>(0,n.jsx)("path",{...e},t))})}},9235:(e,t,r)=>{r.d(t,{A:()=>a});var n=r(5815),s=r(790);function a({backgroundColor:e="var(--prpl-background-monthly)"}){const t={padding:"var(--prpl-padding) var(--prpl-padding) calc(var(--prpl-padding) * 2) var(--prpl-padding)",background:e,borderRadius:"var(--prpl-border-radius-big)",aspectRatio:"2 / 1",overflow:"hidden",position:"relative",marginBottom:"var(--prpl-padding)",display:"flex",justifyContent:"center",alignItems:"flex-start"};return(0,s.jsx)("div",{style:t,children:(0,s.jsxs)("div",{style:{width:"100%",aspectRatio:"1 / 1",position:"relative",display:"flex",justifyContent:"center",alignItems:"center"},children:[(0,s.jsx)(n.Q8,{size:"100%",style:{position:"absolute",opacity:.3}}),(0,s.jsx)("div",{style:{position:"absolute",top:"35%",display:"flex",flexDirection:"column",alignItems:"center",gap:"0.5em"},children:(0,s.jsx)(n.iA,{width:"3em",height:"2.5em",style:{borderRadius:"8px"}})})]})})}},9277:(e,t,r)=>{r.d(t,{A:()=>c});var n=r(7723),s=r(1059),a=r(9061),o=r(790);const i={display:"flex",justifyContent:"flex-start",flexWrap:"wrap",position:"relative"},l={width:"1.25rem",height:"1.25rem",display:"inline-block",verticalAlign:"bottom",color:"#6b7280"};function c({title:e,tooltipContent:t="",className:r=""}){return(0,o.jsxs)("h2",{className:"prpl-widget-title"+(r?` ${r}`:""),children:[e,t&&(0,o.jsx)("div",{style:i,children:(0,o.jsx)(s.A,{triggerContent:(0,o.jsxs)("span",{style:l,children:[(0,o.jsx)(a.A,{name:"info"}),(0,o.jsx)("span",{className:"screen-reader-text",children:(0,n.__)("More info","progress-planner")})]}),children:t})})]})}}},e=>{e(e.s=5989)}]);
\ No newline at end of file
diff --git a/build/widget-streak-badges-rtl.css b/build/widget-streak-badges-rtl.css
new file mode 100644
index 0000000000..b83e7450bc
--- /dev/null
+++ b/build/widget-streak-badges-rtl.css
@@ -0,0 +1 @@
+.prpl-tooltip-wrapper .prpl-tooltip p{margin-bottom:0}.prpl-tooltip-wrapper .prpl-tooltip p:first-child{margin-top:0}
diff --git a/build/widget-streak-badges.asset.php b/build/widget-streak-badges.asset.php
new file mode 100644
index 0000000000..16f9bbfb76
--- /dev/null
+++ b/build/widget-streak-badges.asset.php
@@ -0,0 +1 @@
+ array('react-jsx-runtime', 'wp-api-fetch', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '845873ba05d7ac56f610', 'handle' => 'undefined-widget-streak-badges');
diff --git a/build/widget-streak-badges.css b/build/widget-streak-badges.css
new file mode 100644
index 0000000000..b83e7450bc
--- /dev/null
+++ b/build/widget-streak-badges.css
@@ -0,0 +1 @@
+.prpl-tooltip-wrapper .prpl-tooltip p{margin-bottom:0}.prpl-tooltip-wrapper .prpl-tooltip p:first-child{margin-top:0}
diff --git a/build/widget-streak-badges.js b/build/widget-streak-badges.js
new file mode 100644
index 0000000000..c7d8362048
--- /dev/null
+++ b/build/widget-streak-badges.js
@@ -0,0 +1,3 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[883],{75:(e,t,r)=>{var n=r(6087),a=r(7723),s=r(1362),o=r(4272),i=r(9277),l=r(790);function c(e){return(0,a.sprintf)(/* translators: %s: The remaining number of weeks. */ /* translators: %s: The remaining number of weeks. */
+(0,a._n)("%s week to go to complete this streak!","%s weeks to go to complete this streak!",e,"progress-planner"),e)}(0,s.Cu)({id:"badge-streak-maintenance",component:function({config:e={}}){const t=e?.title||(0,a.__)("Your streak badges","progress-planner");return(0,l.jsxs)(n.Fragment,{children:[(0,l.jsx)(i.A,{title:t,tooltipContent:(0,a.__)("Your streak badges are based on the amount of website maintenance work you have done over the past 30 days.","progress-planner")}),(0,l.jsx)(o.A,{badgeType:"maintenance",introText:(0,a.__)("Execute at least one website maintenance task every week.","progress-planner"),backgroundColor:"var(--prpl-background-streak)",badgeGroupClass:"badge-group-maintenance",getRemainingText:c})]})},priority:7,width:1,forceLastColumn:!0,title:(0,a.__)("Your streak badges","progress-planner")})},475:(e,t,r)=>{r.d(t,{A:()=>s});var n=r(6087),a=r(790);function s({value:e=0,max:t=10,backgroundColor:r="var(--prpl-background-monthly)",color:s="var(--prpl-color-monthly)",color2:o="var(--prpl-color-monthly-2)",contentFontSize:i="var(--prpl-font-size-6xl)",children:l}){const c="180deg",p={padding:"var(--prpl-padding) var(--prpl-padding) calc(var(--prpl-padding) * 2) var(--prpl-padding)",background:r,borderRadius:"var(--prpl-border-radius-big)",aspectRatio:"2 / 1",overflow:"hidden",position:"relative",marginBottom:"var(--prpl-padding)"},d={width:"100%",aspectRatio:"1 / 1",borderRadius:"100%",position:"relative",background:`radial-gradient(${r} 0 57%, transparent 57% 100%), conic-gradient(from 270deg, ${(0,n.useMemo)(()=>{const r=t>0?e/t:0;let n;return r<=.5?n=`${s} calc(${c} * ${r})`:(n=`${s} calc(${c} * 0.5)`,n+=`, ${o} calc(${c} * ${r})`),n+=`, var(--prpl-color-gauge-remain) calc(${c} * ${r}) ${c}`,n},[e,t,s,o])}, transparent ${c})`,textAlign:"center"},g={fontSize:"var(--prpl-font-size-small)",position:"absolute",top:"50%",color:"var(--prpl-color-text)",width:"10%",textAlign:"center"},u={...g,left:0},m={...g,right:0},h={fontSize:i,bottom:"50%",display:"block",fontWeight:600,textAlign:"center",position:"absolute",color:"var(--prpl-color-text)",width:"100%",lineHeight:1.2};return(0,a.jsx)("div",{className:"prpl-gauge",style:p,children:(0,a.jsxs)("div",{className:"prpl-gauge__ring",style:d,children:[(0,a.jsx)("span",{className:"prpl-gauge__label prpl-gauge__label--min",style:u,children:"0"}),(0,a.jsx)("span",{className:"prpl-gauge__content",style:h,children:(0,a.jsx)("span",{className:"prpl-gauge__content-inner",style:{display:"inline-block",width:"50%"},children:l})}),(0,a.jsx)("span",{className:"prpl-gauge__label prpl-gauge__label--max",style:m,children:t})]})})}},645:(e,t,r)=>{r.d(t,{Ge:()=>i,HY:()=>n,TV:()=>s,Tn:()=>a,cs:()=>o,et:()=>l});const n=[{id:"content-curator",name:"Content Curator",description:"20 existing posts/pages, or 10 new posts/pages",type:"content",background:"var(--prpl-background-content-badge)",thresholds:{existingPosts:20,newPosts:10}},{id:"revision-ranger",name:"Revision Ranger",description:"Write 30 new posts or pages",type:"content",background:"var(--prpl-background-content-badge)",thresholds:{newPosts:30}},{id:"purposeful-publisher",name:"Purposeful Publisher",description:"Write 50 new posts or pages",type:"content",background:"var(--prpl-background-content-badge)",thresholds:{newPosts:50}}],a=[{id:"progress-padawan",name:"Progress Padawan",description:"6 weeks streak",type:"maintenance",background:"var(--prpl-background-streak)",thresholds:{weeks:6}},{id:"maintenance-maniac",name:"Maintenance Maniac",description:"26 weeks streak",type:"maintenance",background:"var(--prpl-background-streak)",thresholds:{weeks:26}},{id:"super-site-specialist",name:"Super Site Specialist",description:"52 weeks streak",type:"maintenance",background:"var(--prpl-background-streak)",thresholds:{weeks:52}}],s={targetPoints:10,months:{m1:"Jack January",m2:"Felix February",m3:"Mary March",m4:"Avery April",m5:"Matteo May",m6:"Jasmine June",m7:"Joey July",m8:"Abed August",m9:"Sam September",m10:"Oksana October",m11:"Noah November",m12:"Daisy December"}};function o(e){return`monthly-${e.getFullYear()}-m${e.getMonth()+1}`}function i(e){const t=`m${e.getMonth()+1}`;return s.months[t]||""}function l(e){const t=n.find(t=>t.id===e);if(t)return t;const r=a.find(t=>t.id===e);if(r)return r;if(e.startsWith("monthly-")){const t=e.split("-");if(3===t.length){const r=parseInt(t[1],10),n=t[2].replace("m",""),a=parseInt(n,10);if(r&&a>=1&&a<=12){const t=new Date(r,a-1,1);return{id:e,name:i(t),description:"",type:"monthly",background:"var(--prpl-background-content-badge)",thresholds:{points:s.targetPoints}}}}}return null}},790:e=>{e.exports=window.ReactJSXRuntime},1059:(e,t,r)=>{r.d(t,{A:()=>u});var n=r(6087),a=r(7723),s=r(790);const o={position:"absolute",top:0,right:0,transform:"translate(-10px, -10px) rotate(90deg)",width:0,height:0,borderStyle:"solid",borderWidth:"7.5px 10px 7.5px 0",borderColor:"transparent var(--prpl-background-activity) transparent transparent"},i={padding:0,lineHeight:1,background:"none",border:"none",cursor:"pointer",fontSize:"var(--prpl-font-size-small)",color:"var(--prpl-color-link)"},l={display:"inline-flex",alignItems:"center",position:"relative"},c={display:"block",position:"absolute",bottom:0,left:"100%",transform:"translate(-100%, calc(100% + 10px))",padding:"0.75rem 1.5rem 0.75rem 0.75rem",width:150,background:"var(--prpl-background-activity)",borderRadius:"var(--prpl-border-radius)",zIndex:2,visibility:"hidden",fontSize:"1rem",fontWeight:400,color:"var(--prpl-color-text)"},p={visibility:"visible",zIndex:10},d={position:"absolute",top:0,right:0,padding:"0.1rem",lineHeight:0,margin:0,background:"none",border:"none",cursor:"pointer"},g={display:"block",position:"fixed",top:0,left:0,width:"100%",height:"100%",zIndex:9,backgroundColor:"rgba(0, 0, 0, 0.5)"};function u({triggerContent:e,children:t,tooltipStyle:r,arrowStyle:u,onClose:m}){const[h,f]=(0,n.useState)(!1),[v,b]=(0,n.useState)(!1),x=(0,n.useRef)(null),y=(0,n.useId)(),w=(0,n.useCallback)(()=>{f(!1),m?.()},[m]);(0,n.useEffect)(()=>{if(!h)return;const e=e=>{"Escape"===e.key&&w()};return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)},[h,w]);const k={...i,textDecoration:v?"underline":"none"};return(0,s.jsxs)("span",{className:"prpl-tooltip-wrapper",style:l,children:[(0,s.jsx)("button",{type:"button",className:"prpl-info-icon","aria-describedby":y,onClick:()=>f(!0),style:k,onMouseEnter:()=>b(!0),onMouseLeave:()=>b(!1),children:e}),h&&(0,s.jsx)("span",{role:"presentation",onClick:w,style:g}),(0,s.jsxs)("span",{ref:x,id:y,className:"prpl-tooltip",role:"tooltip","aria-hidden":!h,style:{...c,...h?p:{},...r},children:[(0,s.jsx)("span",{"data-testid":"tooltip-arrow",style:{...o,...u}}),t,(0,s.jsxs)("button",{type:"button",onClick:w,style:d,children:[(0,s.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,s.jsx)("span",{className:"screen-reader-text",children:(0,a.__)("Close","progress-planner")})]})]})]})}},1362:(e,t,r)=>{r.d(t,{Cu:()=>s,cr:()=>o});var n=r(2619);const a=[];function s(e){const{id:t,component:r,priority:n=10,width:s=1,forceLastColumn:o=!1,title:i=""}=e;if(!t||!r)return void console.warn("Widget registration failed: id and component are required",e);const l=a.findIndex(e=>e.id===t),c={id:t,component:r,priority:n,width:s,forceLastColumn:o,title:i};l>=0?a[l]=c:a.push(c)}function o(){return[...a].sort((e,t)=>e.priority-t.priority)}(0,n.addAction)("prpl.dashboard.registerWidget","progress-planner/widget-registry",s)},1455:e=>{e.exports=window.wp.apiFetch},2381:(e,t,r)=>{r.d(t,{Ek:()=>l,jx:()=>i,mZ:()=>o});var n=r(1455),a=r.n(n),s=r(5337);async function o(e=!1){try{const t=await(0,s.BJ)({path:"/progress-planner/v1/activities"},{skipCache:e});return{activities:t.activities||[],totalPostsCount:t.totalPostsCount||0,activationDate:t.activationDate?new Date(t.activationDate):new Date,config:t.config||{brandingId:0,remoteServerUrl:"",placeholderUrl:""}}}catch(e){throw new Error(e.message||"Failed to fetch activities")}}async function i(e=!1){try{return(await(0,s.BJ)({path:"/progress-planner/v1/badge-stats"},{skipCache:e})).badges||{}}catch(e){throw new Error(e.message||"Failed to fetch badge stats")}}async function l(e){try{const t=await a()({path:"/progress-planner/v1/badge-stats",method:"POST",data:{badges:e}});return(0,s.Wz)("/progress-planner/v1/badge-stats",t),t.badges||{}}catch(e){throw new Error(e.message||"Failed to save badge stats")}}},2619:e=>{e.exports=window.wp.hooks},3971:(e,t,r)=>{r.d(t,{A:()=>a});var n=r(790);function a({badgeId:e,badgeName:t,brandingId:r=0,isComplete:a=!0}){const s=window.progressPlannerBadge||{};let o=s.remoteServerRootUrl||"https://progressplanner.com";const i=s.placeholderImageUrl||"";(o.includes("localhost")||o.includes("127.0.0.1"))&&(o="https://progressplanner.com");let l=`${o}/wp-json/progress-planner-saas/v1/badge-svg/?badge_id=${e}`;r&&(l+=`&branding_id=${r}`);const c=t&&"null"!==t?t:"Badge",p={maxWidth:"100%",height:"auto",verticalAlign:"bottom",transition:"opacity 0.3s ease-in-out, filter 0.3s ease-in-out",...!a&&{opacity:.25,filter:"grayscale(1)"}};return(0,n.jsx)("img",{src:l,alt:c,onError:e=>{i&&e.target.src!==i&&(e.target.onerror=null,e.target.src=i)},style:p})}},4272:(e,t,r)=>{r.d(t,{A:()=>y});var n=r(7723),a=r(6087),s=r(7440),o=r(8300),i=r(8650),l=r(645),c=r(475),p=r(3971),d=r(790);function g({badge:e,config:t,backgroundColor:r="var(--prpl-background-content-badge)",getRemainingText:a}){return(0,d.jsxs)("div",{className:"prpl-latest-badges-wrapper",children:[(0,d.jsx)(c.A,{value:e.progress,max:100,backgroundColor:e.background||r,color:"var(--prpl-color-monthly)",color2:"var(--prpl-color-monthly-2)",children:(0,d.jsx)(p.A,{badgeId:e.id,badgeName:e.name,brandingId:t.brandingId,isComplete:!0})}),(0,d.jsxs)("div",{className:"prpl-badge-content-wrapper",children:[(0,d.jsxs)("p",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:"1rem",marginBottom:0},children:[(0,d.jsx)("span",{children:(0,n.sprintf)(/* translators: %s: The badge name. */ /* translators: %s: The badge name. */
+(0,n.__)("Progress %s","progress-planner"),e.name)}),(0,d.jsxs)("span",{style:{fontWeight:600,fontSize:"var(--prpl-font-size-3xl)"},children:[e.progress,"%"]})]}),(0,d.jsx)("p",{style:{marginTop:0},children:a(e.remaining)})]})]})}function u({badges:e,config:t,backgroundColor:r="var(--prpl-background-content-badge)",className:n=""}){const a={display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:"calc(var(--prpl-gap) / 4)",background:r,padding:"calc(var(--prpl-padding) / 2)",borderRadius:"var(--prpl-border-radius-big)"},s={display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"flex-start",flexWrap:"wrap",minWidth:0},o={margin:0,fontSize:"var(--prpl-font-size-small)",textAlign:"center",lineHeight:1.2};return(0,d.jsx)("div",{className:`progress-wrapper ${n}`.trim(),style:a,children:e.map(e=>(0,d.jsxs)("span",{className:"prpl-badge",style:s,"data-value":e.progress,children:[(0,d.jsx)(p.A,{badgeId:e.id,badgeName:e.name,brandingId:t.brandingId,isComplete:e.isComplete}),(0,d.jsx)("p",{style:o,children:e.name})]},e.id))})}var m=r(8982),h=r(5815),f=r(9235);function v({backgroundColor:e="var(--prpl-background-content-badge)"}){return(0,d.jsxs)("div",{className:"prpl-latest-badges-wrapper",style:{display:"flex",flexDirection:"row",gap:"1rem"},children:[(0,d.jsx)("div",{style:{flex:"0 0 auto",width:"140px"},children:(0,d.jsx)(f.A,{backgroundColor:e})}),(0,d.jsxs)("div",{className:"prpl-badge-content-wrapper",style:{flex:1,display:"flex",flexDirection:"column",justifyContent:"center"},children:[(0,d.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:"1rem",marginBottom:"0.5rem"},children:[(0,d.jsx)(h.iA,{width:"8rem",height:"1em"}),(0,d.jsx)(h.iA,{width:"3rem",height:"1.5em"})]}),(0,d.jsx)(h.rr,{lines:1})]})]})}function b({count:e=6,backgroundColor:t="var(--prpl-background-content-badge)"}){const r={display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:"calc(var(--prpl-gap) / 4)",background:t,padding:"calc(var(--prpl-padding) / 2)",borderRadius:"var(--prpl-border-radius-big)"},n={display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"flex-start",gap:"0.25rem",minWidth:0},a={fontSize:"var(--prpl-font-size-small)",textAlign:"center"};return(0,d.jsx)("div",{className:"progress-wrapper",style:r,children:Array.from({length:e}).map((e,t)=>(0,d.jsxs)("span",{className:"prpl-badge",style:n,children:[(0,d.jsx)(h.Q8,{size:"50px",style:{opacity:.5}}),(0,d.jsx)("div",{style:a,children:(0,d.jsx)(h.iA,{width:"4rem",height:"0.75em",style:{margin:"0 auto"}})})]},t))})}function x({backgroundColor:e="var(--prpl-background-content-badge)"}){return(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)("div",{style:{marginBottom:"1rem"},children:(0,d.jsx)(h.rr,{lines:2})}),(0,d.jsx)(v,{backgroundColor:e}),(0,d.jsx)("hr",{}),(0,d.jsx)("div",{className:"prpl-badges-container-achievements",children:(0,d.jsx)(b,{count:6,backgroundColor:e})})]})}function y({badgeType:e,introText:t,backgroundColor:r,badgeGroupClass:c="",getRemainingText:p}){const{isLoading:h,error:f,data:v}=(0,s.H)(),b=(0,o._)({activities:v?.activities||[],savedStats:v?.savedStats||{},totalPostsCount:v?.totalPostsCount||0,activationDate:v?.activationDate?new Date(v.activationDate):null});(0,i.t)(b,v?.savedStats||{});const y=(0,a.useMemo)(()=>"content"===e?l.HY:l.Tn,[e]),w=(0,a.useMemo)(()=>{for(const e of y){const t=b[e.id];if(t&&t.progress<100)return{id:e.id,name:e.name,background:e.background,progress:t.progress,remaining:t.remaining}}return null},[y,b]),k=(0,a.useMemo)(()=>y.map(e=>{const t=b[e.id]||{progress:0,remaining:0};return{id:e.id,name:e.name,progress:t.progress,isComplete:t.progress>=100}}),[y,b]);return h?(0,d.jsx)(x,{backgroundColor:r}):f?(0,d.jsx)(m.W5,{message:f,simple:!0}):w?(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)("p",{children:t}),(0,d.jsx)(g,{badge:w,config:v?.config||{},backgroundColor:r,getRemainingText:p}),(0,d.jsx)("hr",{}),(0,d.jsx)("div",{className:"prpl-badges-container-achievements",children:(0,d.jsx)(u,{badges:k,config:v?.config||{},backgroundColor:r,className:c})})]}):(0,d.jsx)(m.pp,{message:(0,n.__)("No badge data available.","progress-planner")})}},5337:(e,t,r)=>{r.d(t,{BJ:()=>l,IL:()=>c,Wz:()=>p});var n=r(1455),a=r.n(n);const s=new Map,o=new Map,i=3e5;async function l(e,t={}){const{skipCache:r=!1,ttl:n=i}=t,l=function(e){if("GET"!==(e.method||"GET").toUpperCase())return null;let t=e.path||e.url||"";if(e.data&&"object"==typeof e.data){const r=new URLSearchParams(e.data).toString();r&&(t+=(t.includes("?")?"&":"?")+r)}return`GET:${t}`}(e);if(!l)return a()(e);if(!r&&s.has(l))return s.get(l);if(!r){const e=o.get(l);if(e&&Date.now()-e.timestamp(o.set(l,{data:e,timestamp:Date.now()}),s.delete(l),e)).catch(e=>{throw s.delete(l),e});return s.set(l,c),c}function c(){o.clear(),s.clear()}function p(e,t){const r=`GET:${e}`;o.set(r,{data:t,timestamp:Date.now()})}},5815:(e,t,r)=>{r.d(t,{Q8:()=>p,iA:()=>c,rr:()=>d});var n=r(6087),a=r(790);const s="\n@keyframes prpl-shimmer {\n\t0% { background-position: 200% 0; }\n\t100% { background-position: -200% 0; }\n}\n";let o=!1;function i(){if(o||"undefined"==typeof document)return;const e=document.createElement("style");e.id="prpl-skeleton-keyframes",e.textContent=s,document.head.appendChild(e),o=!0}const l={background:"linear-gradient(\n\t\t90deg,\n\t\tvar(--prpl-color-gauge-remain, #f0f0f0) 25%,\n\t\tvar(--prpl-color-border, #e0e0e0) 50%,\n\t\tvar(--prpl-color-gauge-remain, #f0f0f0) 75%\n\t)",backgroundSize:"200% 100%",animation:"prpl-shimmer 1.5s ease-in-out infinite",borderRadius:"var(--prpl-border-radius, 8px)"};function c({width:e="100%",height:t="1em",className:r="",style:s={}}){return(0,n.useEffect)(()=>{i()},[]),(0,a.jsx)("div",{className:r||void 0,style:{...l,width:e,height:t,...s}})}function p({size:e="40px",className:t="",style:r={}}){return(0,n.useEffect)(()=>{i()},[]),(0,a.jsx)("div",{className:t||void 0,style:{...l,width:e,height:e,borderRadius:"50%",...r}})}function d({width:e="100%",lines:t=1,className:r="",style:s={},lastShort:o=!0}){return(0,n.useEffect)(()=>{i()},[]),1===t?(0,a.jsx)(c,{width:e,height:"1em",className:r,style:s}):(0,a.jsx)("div",{style:{display:"flex",flexDirection:"column",...s},children:Array.from({length:t}).map((n,s)=>(0,a.jsx)(c,{width:o&&s===t-1?"70%":e,height:"1em",className:r,style:{marginBottom:s{e.exports=window.wp.element},7440:(e,t,r)=>{r.d(t,{H:()=>s});var n=r(6087),a=r(2381);function s(){const[e,t]=(0,n.useState)(!0),[r,s]=(0,n.useState)(null),[o,i]=(0,n.useState)(null),l=(0,n.useCallback)(async()=>{try{t(!0),s(null);const[e,r]=await Promise.all([(0,a.mZ)(),(0,a.jx)()]);i({activities:e.activities||[],totalPostsCount:e.totalPostsCount||0,activationDate:e.activationDate,savedStats:r,config:e.config||{brandingId:0,remoteServerUrl:"",placeholderUrl:""}})}catch(e){s(e.message||"Failed to load badge data")}finally{t(!1)}},[]);return(0,n.useEffect)(()=>{l()},[l]),{isLoading:e,error:r,data:o,refetch:l}}},7723:e=>{e.exports=window.wp.i18n},8300:(e,t,r)=>{r.d(t,{_:()=>o});var n=r(6087);function a(e){const t=new Date(e),r=t.getDay(),n=t.getDate()-r+(0===r?-6:1);return t.setDate(n),t.setHours(0,0,0,0),t}var s=r(645);function o({activities:e=[],savedStats:t={},totalPostsCount:r=0,activationDate:o=null,getMonthlyBadgeDateRange:i=null}){return(0,n.useMemo)(()=>{if(!o)return{};const n={};if(["content-curator","revision-ranger","purposeful-publisher"].forEach(a=>{const i=(0,s.et)(a);if(!i)return;const l=t[a];if(l&&l.progress&&void 0!==l.remaining&&l.progress>=100)return void(n[a]={progress:l.progress,remaining:l.remaining});const c=function(e,t,r,n){const{thresholds:a}=e;if("content-curator"===e.id){const e=Math.max(0,a.existingPosts-Math.min(a.existingPosts,r));if(0===e)return{progress:100,remaining:0};const s=new Date(n);s.setHours(0,0,0,0);const o=t.filter(e=>{if("content"!==e.category||"publish"!==e.type)return!1;const t=new Date(e.date);return t.setHours(0,0,0,0),t>=s}).length,i=Math.max(0,a.newPosts-Math.min(a.newPosts,o));return{progress:Math.max(Math.min(100,Math.floor(r/2)),Math.min(100,Math.floor(10*o))),remaining:Math.min(e,i)}}const s=new Date(n);s.setHours(0,0,0,0);const o=t.filter(e=>{if("content"!==e.category||"publish"!==e.type)return!1;const t=new Date(e.date);return t.setHours(0,0,0,0),t>=s}).length,i=a.newPosts;return{progress:Math.min(100,Math.floor(o/i*100)),remaining:Math.max(0,i-Math.min(i,o))}}(i,e,r,o);n[a]=c}),["progress-padawan","maintenance-maniac","super-site-specialist"].forEach(r=>{const i=(0,s.et)(r);if(!i)return;const l=t[r];if(l&&l.progress&&void 0!==l.remaining){if(l.progress>=100)return void(n[r]={progress:l.progress,remaining:l.remaining});if(l.date){const e=new Date(l.date);if((new Date-e)/864e5<=2)return void(n[r]={progress:l.progress,remaining:l.remaining})}}const c=function(e,t,r){const{thresholds:n}=e,s=n.weeks,o=function(e,t,r=1){const n=new Map;e.forEach(e=>{const r=new Date(e.date);r.setHours(0,0,0,0);const s=new Date(t);if(s.setHours(0,0,0,0),r0}),o.setDate(o.getDate()+7)}let l=0,c=0,p=r;for(const e of s)if(e.hasActivity)l++,c=Math.max(c,l);else{if(p>0){p--;continue}l=0}return{max_streak:c,current_streak:l}}(t.filter(e=>"maintenance"===e.category),r,1),i=o.max_streak;return{progress:Math.min(100,Math.floor(i/s*100)),remaining:Math.max(0,s-Math.min(s,i))}}(i,e,o);n[r]=c}),i){const r=new Set;Object.keys(t).forEach(e=>{e.startsWith("monthly-")&&r.add(e)});const a=new Date,o=`monthly-${a.getFullYear()}-m${a.getMonth()+1}`;r.add(o);for(let e=1;e<=2;e++){const t=new Date(a.getFullYear(),a.getMonth()-e,1),n=`monthly-${t.getFullYear()}-m${t.getMonth()+1}`;r.add(n)}r.forEach(r=>{if(!(0,s.et)(r))return;const a=i(r);if(!a)return;const{startDate:o,endDate:l}=a,c=t[r];if(c&&c.progress&&void 0!==c.remaining&&void 0!==c.points&&c.progress>=100)return void(n[r]={progress:c.progress,remaining:c.remaining,points:c.points});const p=function(e,t,r,n,a=10,s={}){const o=new Date(r);o.setHours(0,0,0,0);const i=new Date(n);i.setHours(23,59,59,999);const l=t.filter(e=>{const t=new Date(e.date);return t>=o&&t<=i});let c=0;l.forEach(e=>{e.points&&"number"==typeof e.points&&(c+=e.points)});const p={progress:Math.max(0,Math.min(100,Math.floor(c/a*100))),remaining:Math.max(0,Math.min(a-c,a)),points:c};if(c>=a||s.noNextBadgePoints)return p;const d=function(e,t,r){let n=0,a=0,s=0,o=0;const i=new Date(t);i.setMonth(i.getMonth()+1),i.setDate(1),i.setHours(0,0,0,0);const l=new Date(i);l.setMonth(l.getMonth()+1),l.setDate(0),l.setHours(23,59,59,999),e.filter(e=>{const t=new Date(e.date);return t>=i&&t<=l}).forEach(e=>{e.points&&"number"==typeof e.points&&(n+=e.points)});{const r=new Date(t);r.setMonth(r.getMonth()+2),r.setDate(1),r.setHours(0,0,0,0);const n=new Date(r);n.setMonth(n.getMonth()+1),n.setDate(0),n.setHours(23,59,59,999),e.filter(e=>{const t=new Date(e.date);return t>=r&&t<=n}).forEach(e=>{e.points&&"number"==typeof e.points&&(a+=e.points)})}return n>r&&(s=Math.max(0,n-r)),a>r&&(o=Math.max(0,a-r),n0){const e=c+d;return{progress:Math.max(0,Math.min(100,Math.floor(e/a*100))),remaining:Math.max(0,Math.min(a-e,a)),points:e}}return p}(0,e,o,l,10,{noNextBadgePoints:!1});n[r]=p})}return n},[e,t,r,o,i])}},8650:(e,t,r)=>{r.d(t,{t:()=>s});var n=r(6087),a=r(2381);function s(e,t){const r=(0,n.useRef)({}),s=(0,n.useRef)(!1);(0,n.useEffect)(()=>{if(s.current||!e||0===Object.keys(e).length)return;const n={};let o=!1;Object.keys(e).forEach(a=>{var s;const i=e[a],l=r.current[a],c=t[a],p=!l||l.progress!==i.progress||l.remaining!==i.remaining,d=i.progress>=100&&(!c||(null!==(s=c.progress)&&void 0!==s?s:0)<100),g=!c||c.progress!==i.progress||c.remaining!==i.remaining;(p||d||g)&&(n[a]={progress:i.progress,remaining:i.remaining,...void 0!==i.points&&{points:i.points}},o=!0)}),o&&Object.keys(n).length>0&&(s.current=!0,(0,a.Ek)(n).catch(e=>{console.warn("Failed to save badge progress:",e)}).finally(()=>{s.current=!1})),r.current={...e}},[e,t])}},8982:(e,t,r)=>{r.d(t,{W5:()=>o,pp:()=>i});var n=r(7723),a=r(790);const s={padding:"1em",backgroundColor:"var(--prpl-color-error-background, #fee)",color:"var(--prpl-color-error, #c00)",borderRadius:"var(--prpl-border-radius)"};function o({message:e=(0,n.__)("An error occurred.","progress-planner"),className:t="",style:r={},simple:o=!1}){return o?(0,a.jsx)("p",{className:t||void 0,children:e}):(0,a.jsx)("div",{className:"prpl-widget-error"+(t?` ${t}`:""),style:{...s,...r},children:e})}function i({message:e=(0,n.__)("No data available.","progress-planner"),className:t=""}){return(0,a.jsx)("p",{className:t||void 0,children:e})}},9061:(e,t,r)=>{r.d(t,{A:()=>s});var n=r(790);const a={arrow:{viewBox:"0 0 20 17",paths:[{d:"M19.92 8.12c-.05-.12-.12-.23-.22-.33L12.21.29A.996.996 0 1 0 10.8 1.7l5.79 5.79H1c-.55 0-1 .45-1 1s.45 1 1 1h15.59l-5.79 5.79a.996.996 0 0 0 .71 1.7c.26 0 .51-.1.71-.29l7.5-7.5c.1-.1.17-.21.22-.33.05-.12.07-.24.08-.38 0-.14-.03-.27-.08-.38Z"}]},trash:{viewBox:"0 0 48 48",paths:[{d:"M32.99 47.88H15.01c-3.46 0-6.38-2.7-6.64-6.15L6.04 11.49l-.72.12c-.82.14-1.59-.41-1.73-1.22-.14-.82.41-1.59 1.22-1.73.79-.14 1.57-.26 2.37-.38h.02c2.21-.33 4.46-.6 6.69-.81v-.72c0-3.56 2.74-6.44 6.25-6.55 2.56-.08 5.15-.08 7.71 0 3.5.11 6.25 2.99 6.25 6.55v.72c2.24.2 4.48.47 6.7.81.79.12 1.59.25 2.38.39.82.14 1.36.92 1.22 1.73-.14.82-.92 1.36-1.73 1.22l-.72-.12-2.33 30.24c-.27 3.45-3.18 6.15-6.64 6.15Zm-17.98-3h17.97c1.9 0 3.51-1.48 3.65-3.38l2.34-30.46c-2.15-.3-4.33-.53-6.48-.7h-.03c-5.62-.43-11.32-.43-16.95 0h-.03c-2.15.17-4.33.4-6.48.7l2.34 30.46c.15 1.9 1.75 3.38 3.65 3.38ZM24 7.01c2.37 0 4.74.07 7.11.22v-.49c0-1.93-1.47-3.49-3.34-3.55-2.5-.08-5.03-.08-7.52 0-1.88.06-3.34 1.62-3.34 3.55v.49c2.36-.15 4.73-.22 7.11-.22Zm5.49 32.26h-.06c-.83-.03-1.47-.73-1.44-1.56l.79-20.65c.03-.83.75-1.45 1.56-1.44.83.03 1.47.73 1.44 1.56l-.79 20.65c-.03.81-.7 1.44-1.5 1.44Zm-10.98 0c-.8 0-1.47-.63-1.5-1.44l-.79-20.65c-.03-.83.61-1.52 1.44-1.56.84 0 1.52.61 1.56 1.44l.79 20.65c.03.83-.61 1.52-1.44 1.56h-.06Z"}]},check:{viewBox:"0 0 20 20",paths:[{d:"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",fillRule:"evenodd",clipRule:"evenodd"}]},close:{viewBox:"0 0 20 20",paths:[{d:"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",fillRule:"evenodd",clipRule:"evenodd"}]},chevronDown:{viewBox:"0 0 24 24",stroke:!0,paths:[{d:"m19.5 8.25-7.5 7.5-7.5-7.5",strokeLinecap:"round",strokeLinejoin:"round"}]},info:{viewBox:"0 0 64 64",paths:[{d:"M32 63.73C14.51 63.73.27 49.49.27 32S14.51.27 32 .27 63.73 14.5 63.73 32 49.5 63.73 32 63.73Zm0-58C17.51 5.73 5.73 17.52 5.73 32S17.52 58.27 32 58.27 58.27 46.48 58.27 32 46.49 5.73 32 5.73Zm1.2 41.4c-.42 0-.83-.05-1.24-.15-1.33-.33-2.46-1.17-3.16-2.34-.71-1.18-.91-2.56-.58-3.9l2.13-8.54c-1.25.36-2.62-.21-3.21-1.42-.66-1.35-.1-2.99 1.25-3.65l.13-.06c1.21-.6 2.6-.7 3.91-.27 1.3.44 2.36 1.35 2.97 2.58.55 1.1.69 2.36.39 3.54l-2.13 8.54c1.22-.36 2.58.19 3.19 1.37.69 1.34.16 2.98-1.18 3.67l-.13.07c-.74.37-1.54.56-2.34.56Zm-2.26-15.17Zm1.09-9.03c-1.65 0-3.02-1.34-3.02-2.99s1.34-3.01 2.99-3.01h.03c1.65 0 2.99 1.34 2.99 2.99s-1.34 3.01-2.99 3.01Z"}]},warning:{viewBox:"0 0 24 24",paths:[{d:"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003ZM12 8.25a.75.75 0 0 1 .75.75v3.75a.75.75 0 0 1-1.5 0V9a.75.75 0 0 1 .75-.75Zm0 8.25a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Z",fillRule:"evenodd",clipRule:"evenodd"}]}};function s({name:e,...t}){const r=a[e];if(!r)return null;const s=r.stroke;return(0,n.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:r.viewBox,fill:s?"none":"currentColor",stroke:s?"currentColor":void 0,strokeWidth:s?"1.5":void 0,"aria-hidden":"true",focusable:"false",...t,children:r.paths.map((e,t)=>(0,n.jsx)("path",{...e},t))})}},9235:(e,t,r)=>{r.d(t,{A:()=>s});var n=r(5815),a=r(790);function s({backgroundColor:e="var(--prpl-background-monthly)"}){const t={padding:"var(--prpl-padding) var(--prpl-padding) calc(var(--prpl-padding) * 2) var(--prpl-padding)",background:e,borderRadius:"var(--prpl-border-radius-big)",aspectRatio:"2 / 1",overflow:"hidden",position:"relative",marginBottom:"var(--prpl-padding)",display:"flex",justifyContent:"center",alignItems:"flex-start"};return(0,a.jsx)("div",{style:t,children:(0,a.jsxs)("div",{style:{width:"100%",aspectRatio:"1 / 1",position:"relative",display:"flex",justifyContent:"center",alignItems:"center"},children:[(0,a.jsx)(n.Q8,{size:"100%",style:{position:"absolute",opacity:.3}}),(0,a.jsx)("div",{style:{position:"absolute",top:"35%",display:"flex",flexDirection:"column",alignItems:"center",gap:"0.5em"},children:(0,a.jsx)(n.iA,{width:"3em",height:"2.5em",style:{borderRadius:"8px"}})})]})})}},9277:(e,t,r)=>{r.d(t,{A:()=>c});var n=r(7723),a=r(1059),s=r(9061),o=r(790);const i={display:"flex",justifyContent:"flex-start",flexWrap:"wrap",position:"relative"},l={width:"1.25rem",height:"1.25rem",display:"inline-block",verticalAlign:"bottom",color:"#6b7280"};function c({title:e,tooltipContent:t="",className:r=""}){return(0,o.jsxs)("h2",{className:"prpl-widget-title"+(r?` ${r}`:""),children:[e,t&&(0,o.jsx)("div",{style:i,children:(0,o.jsx)(a.A,{triggerContent:(0,o.jsxs)("span",{style:l,children:[(0,o.jsx)(s.A,{name:"info"}),(0,o.jsx)("span",{className:"screen-reader-text",children:(0,n.__)("More info","progress-planner")})]}),children:t})})]})}}},e=>{e(e.s=75)}]);
\ No newline at end of file
diff --git a/build/widget-suggested-tasks-rtl.css b/build/widget-suggested-tasks-rtl.css
new file mode 100644
index 0000000000..b83e7450bc
--- /dev/null
+++ b/build/widget-suggested-tasks-rtl.css
@@ -0,0 +1 @@
+.prpl-tooltip-wrapper .prpl-tooltip p{margin-bottom:0}.prpl-tooltip-wrapper .prpl-tooltip p:first-child{margin-top:0}
diff --git a/build/widget-suggested-tasks.asset.php b/build/widget-suggested-tasks.asset.php
new file mode 100644
index 0000000000..c59e1414c3
--- /dev/null
+++ b/build/widget-suggested-tasks.asset.php
@@ -0,0 +1 @@
+ array('react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n'), 'version' => '020c6cdd72752cfb9191', 'handle' => 'undefined-widget-suggested-tasks');
diff --git a/build/widget-suggested-tasks.css b/build/widget-suggested-tasks.css
new file mode 100644
index 0000000000..b83e7450bc
--- /dev/null
+++ b/build/widget-suggested-tasks.css
@@ -0,0 +1 @@
+.prpl-tooltip-wrapper .prpl-tooltip p{margin-bottom:0}.prpl-tooltip-wrapper .prpl-tooltip p:first-child{margin-top:0}
diff --git a/build/widget-suggested-tasks.js b/build/widget-suggested-tasks.js
new file mode 100644
index 0000000000..af1499ced7
--- /dev/null
+++ b/build/widget-suggested-tasks.js
@@ -0,0 +1,8 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[196],{714:(t,e,s)=>{var r=s(7723);class a{constructor(t={}){const e=this.constructor;let s=!0;void 0!==e.isSnoozable?s=e.isSnoozable:void 0!==t.isSnoozable&&(s=t.isSnoozable),this.config={providerId:e.providerId||t.providerId||"",capability:e.capability||t.capability||"manage_options",isOnboardingTask:void 0!==e.isOnboardingTask?e.isOnboardingTask:t.isOnboardingTask||!1,priority:void 0!==e.priority?e.priority:t.priority||50,points:void 0!==e.points?e.points:t.points||1,parent:void 0!==e.parent?e.parent:t.parent||0,isDismissable:void 0!==e.isDismissable?e.isDismissable:t.isDismissable||!1,isSnoozable:s,isRepetitive:void 0!==e.isRepetitive?e.isRepetitive:t.isRepetitive||!1,dependencies:e.dependencies||t.dependencies||[],externalLinkUrl:e.externalLinkUrl||t.externalLinkUrl||"",popoverId:e.popoverId||t.popoverId||"",isMultiTask:void 0!==e.isMultiTask?e.isMultiTask:t.isMultiTask||!1,...t}}static getStaticConfig(){return{providerId:this.providerId||"",capability:this.capability||"manage_options",isOnboardingTask:this.isOnboardingTask||!1,priority:void 0!==this.priority?this.priority:50,points:void 0!==this.points?this.points:1,parent:this.parent||0,isDismissable:this.isDismissable||!1,isSnoozable:void 0===this.isSnoozable||this.isSnoozable,isRepetitive:this.isRepetitive||!1,dependencies:this.dependencies||[],externalLinkUrl:this.externalLinkUrl||"",popoverId:this.popoverId||"",isMultiTask:this.isMultiTask||!1}}getProviderId(){return this.constructor.providerId||this.config.providerId||""}getPriority(){const t=this.constructor;return void 0!==t.priority?t.priority:this.config.priority||50}getPoints(){const t=this.constructor;return void 0!==t.points?t.points:this.config.points||1}buildAdminUrl(t="",e={}){const s=window.prplDashboardConfig?.adminUrl||"/wp-admin/",r=s.endsWith("/")?"":"/";let a=t?`${s}${r}${t}`:s;const i=Object.entries(e).filter(([,t])=>null!=t).map(([t,e])=>`${encodeURIComponent(t)}=${encodeURIComponent(e)}`).join("&");return i&&(a+=(a.includes("?")?"&":"?")+i),a}buildTaskDetails(t={},e={}){const s=this.constructor;return{task_id:this.getTaskId(t),provider_id:this.getProviderId(),post_title:"",description:"",priority:this.getPriority(),points:this.getPoints(),parent:s.parent||0,url:"",url_target:"_self",dismissable:void 0!==s.isDismissable?s.isDismissable:this.config.isDismissable,external_link_url:s.externalLinkUrl||this.config.externalLinkUrl,...e}}capabilityRequired(){return!0}async shouldAddTask(t={}){throw new Error("shouldAddTask() must be implemented by task provider")}async getTaskDetails(t={}){throw new Error("getTaskDetails() must be implemented by task provider")}getTaskId(t={}){const e=this.constructor,s=[e.providerId||this.config.providerId||""];if(t.targetPostId&&s.push(t.targetPostId),t.targetTermId&&s.push(t.targetTermId),t.targetTaxonomy&&s.push(t.targetTaxonomy),t.target_post_id&&s.push(t.target_post_id),t.target_term_id&&s.push(t.target_term_id),t.target_taxonomy&&s.push(t.target_taxonomy),void 0!==e.isRepetitive?e.isRepetitive:this.config.isRepetitive){const t=new Date,e=t.getFullYear(),r=this.getWeekNumber(t);s.push(`${e}${r.toString().padStart(2,"0")}`)}return s.join("-")}getWeekNumber(t){const e=new Date(Date.UTC(t.getFullYear(),t.getMonth(),t.getDate())),s=e.getUTCDay()||7;e.setUTCDate(e.getUTCDate()+4-s);const r=new Date(Date.UTC(e.getUTCFullYear(),0,1));return Math.ceil(((e-r)/864e5+1)/7)}async areDependenciesSatisfied(t){const e=this.constructor.dependencies||this.config.dependencies||[];if(!e||0===e.length)return!0;for(const s of e){const e="string"==typeof s?s:s.taskId,r="object"==typeof s?s.status:"completed";if(await t(e)!==r)return!1}return!0}getTaskActions(t={}){const e=[],s=this.constructor;t&&"object"==typeof t||(t={});const r=this.getProviderId(),a=t.slug||t.id||"",i=t.title?.rendered||t.title||t.post_title||"";this.capabilityRequired()&&this.config.isDismissable&&"user"!==r&&e.push({type:"complete",priority:20,taskId:a,taskTitle:i}),this.capabilityRequired()&&this.config.isSnoozable&&e.push({type:"snooze",priority:30,taskId:a,taskTitle:i});const n=!(!this.config.popoverId&&!s.popoverId);if(this.config.externalLinkUrl?e.push({type:"info",priority:40,externalUrl:this.config.externalLinkUrl}):!n&&t.content?.rendered&&""!==t.content.rendered&&e.push({type:"info",priority:40,taskId:a,taskTitle:i,content:t.content.rendered}),this.capabilityRequired()){const s=this.addTaskActions(t,e).map(t=>(t.priority||(t.priority=1e3),t)).filter(t=>t.type||t.html&&""!==t.html);return s.sort((t,e)=>t.priority-e.priority),s}return e.sort((t,e)=>t.priority-e.priority),e}addTaskActions(t,e){return e}}class i extends a{constructor(t={}){super(t)}getPopoverId(){const t=this.constructor.popoverId||this.config.popoverId||"";return t?`prpl-popover-${t}`:""}async getTaskDetails(t={}){throw new Error("getTaskDetails() must be implemented by interactive task provider")}addPopoverIdToTaskDetails(t){return(this.constructor.popoverId||this.config.popoverId)&&(t.popover_id=this.getPopoverId()),t}getAllowedInteractiveOptions(){return[]}addTaskActions(t=[],e=[]){return(this.constructor.popoverId||this.config.popoverId)&&e.push({type:"popover",priority:10,popoverId:this.getPopoverId(),label:this.getPopoverActionLabel()}),super.addTaskActions(t,e)}getPopoverActionLabel(){return(0,r.__)("Complete","progress-planner")}}var n=s(8493),o=s(9251);(0,n.nR)(class extends i{static providerId="hello-world";static capability="edit_posts";static isOnboardingTask=!0;static priority=15;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/delete-hello-world-post";static popoverId="hello-world";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("hello_world_post_id");return 0!==t&&null!==t}catch(t){return console.error("Error checking Hello World task condition:",t),!1}}async getTaskDetails(t={}){const e=await(0,o.OJ)("hello_world_post_id"),s=e&&0!==e?this.buildAdminUrl("post.php",{post:e,action:"edit"}):"",a=e&&0!==e?""+(0,r.__)('On install, WordPress creates a "Hello World!" post. This post does not add value to your website and solely exists to show what a post can look like. Therefore, "Hello World!" is not needed and should be deleted.',"progress-planner")+"
":(0,r.__)('On install, WordPress creates a "Hello World!" post. This post is not needed and should be deleted.',"progress-planner"),i=this.buildTaskDetails(t,{post_title:(0,r.__)('Delete the "Hello World!" post.',"progress-planner"),description:a,url:s});return this.addPopoverIdToTaskDetails(i)}getPopoverActionLabel(){return(0,r.__)("Delete","progress-planner")}});(0,n.nR)(class extends i{static providerId="sample-page";static capability="edit_pages";static isOnboardingTask=!0;static priority=14;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/delete-sample-page";static popoverId="sample-page";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("sample_page_id");return 0!==t&&null!==t}catch(t){return console.error("Error checking Sample Page task condition:",t),!1}}async getTaskDetails(t={}){const e=await(0,o.OJ)("sample_page_id"),s=e&&0!==e?this.buildAdminUrl("post.php",{post:e,action:"edit"}):"",a=e&&0!==e?""+(0,r.__)('On install, WordPress creates a "Sample Page" page. This page does not add value to your website and solely exists to show what a page can look like. Therefore, "Sample Page" is not needed and should be deleted.',"progress-planner")+"
":(0,r.__)('On install, WordPress creates a "Sample Page" page. This page does not add value to your website and solely exists to show what a page can look like. Therefore, "Sample Page" is not needed and should be deleted.',"progress-planner"),i=this.buildTaskDetails(t,{post_title:(0,r.__)('Delete "Sample Page"',"progress-planner"),description:a,url:s});return this.addPopoverIdToTaskDetails(i)}getPopoverActionLabel(){return(0,r.__)("Delete","progress-planner")}});var l=s(5337);(0,n.nR)(class extends i{static providerId="core-blogdescription";static capability="manage_options";static isOnboardingTask=!0;static priority=2;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/set-tagline";static popoverId="core-blogdescription";async shouldAddTask(t={}){try{const t=await(0,l.BJ)({path:"/wp/v2/settings"});return!t?.description||""===t.description}catch(t){return console.error("Error checking Blog Description task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Set tagline","progress-planner"),description:(0,r.__)("Set the tagline to make your website look more professional.","progress-planner"),url:this.buildAdminUrl("options-general.php")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Set tagline","progress-planner")}});(0,n.nR)(class extends i{static providerId="core-siteicon";static capability="manage_options";static isOnboardingTask=!0;static priority=1;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/set-site-icon";static popoverId="core-siteicon";async shouldAddTask(t={}){try{const t=await(0,l.BJ)({path:"/wp/v2/settings"}),e=t?.site_icon;return!e||""===e||"0"===e}catch(t){return console.error("Error checking Site Icon task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Set site icon","progress-planner"),url:this.buildAdminUrl("options-general.php")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Set site icon","progress-planner")}});(0,n.nR)(class extends i{static providerId="core-permalink-structure";static capability="manage_options";static isOnboardingTask=!0;static priority=3;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/change-default-permalink-structure";static popoverId="core-permalink-structure";async shouldAddTask(t={}){try{const t=await(0,l.BJ)({path:"/wp/v2/settings"}),e=t?.permalink_structure||"";return"/%year%/%monthnum%/%day%/%postname%/"===e||"/index.php/%year%/%monthnum%/%day%/%postname%/"===e}catch(t){return console.error("Error checking Permalink Structure task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Set permalink structure","progress-planner"),url:this.buildAdminUrl("options-permalink.php"),link_setting:{hook:"options-permalink.php",iconEl:'label[for="permalink-input-month-name"], label[for="permalink-input-post-name"]'}});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Select permalink structure","progress-planner")}});(0,n.nR)(class extends i{static providerId="select-locale";static capability="install_languages";static isOnboardingTask=!1;static priority=8;static points=1;static isDismissable=!0;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/set-locale";static popoverId="select-locale";async shouldAddTask(t={}){try{const t="undefined"!=typeof window&&window.navigator?.language?window.navigator.language.split("-")[0]:null,e=await(0,l.BJ)({path:"/wp/v2/settings"});return t&&!(e?.language||"en").startsWith(t)}catch(t){return console.error("Error checking Select Locale task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Select your site locale","progress-planner"),url:this.buildAdminUrl("options-general.php"),link_setting:{hook:"options-general.php",iconEl:'label[for="WPLANG"]'}});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Select locale","progress-planner")}});(0,n.nR)(class extends i{static providerId="select-timezone";static capability="manage_options";static isOnboardingTask=!1;static priority=6;static points=1;static isDismissable=!0;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/set-timezone";static popoverId="select-timezone";async shouldAddTask(t={}){try{const t=await(0,l.BJ)({path:"/wp/v2/settings"}),e=t?.timezone_string||"";return!e||"UTC"===e}catch(t){return console.error("Error checking Select Timezone task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Set site timezone","progress-planner"),url:this.buildAdminUrl("options-general.php")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Select timezone","progress-planner")}});(0,n.nR)(class extends i{static providerId="set-date-format";static capability="manage_options";static isOnboardingTask=!1;static priority=7;static points=1;static isDismissable=!0;static isSnoozable=!0;static popoverId="set-date-format";async shouldAddTask(t={}){try{const t=await(0,l.BJ)({path:"/wp/v2/settings"}),e=t?.date_format||"";return!e||"wp_default"===e}catch(t){return console.error("Error checking Set Date Format task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Set site date format","progress-planner"),description:(0,r.__)("Setting the date format correctly on your site is valuable. By setting the correct date format, you ensure the dates are displayed correctly in the admin area and the front end.","progress-planner"),url:this.buildAdminUrl("options-general.php")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Set date format","progress-planner")}});(0,n.nR)(class extends i{static providerId="search-engine-visibility";static capability="manage_options";static isOnboardingTask=!0;static priority=5;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/blog-indexing-settings";static popoverId="search-engine-visibility";async shouldAddTask(t={}){try{const t=await(0,l.BJ)({path:"/wp/v2/settings"});return 0===t?.blog_public||"0"===t?.blog_public}catch(t){return console.error("Error checking Search Engine Visibility task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Allow your site to be indexed by search engines","progress-planner"),url:this.buildAdminUrl("options-reading.php"),link_setting:{hook:"options-reading.php",iconEl:'label[for="blog_public"]'}});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Allow","progress-planner")}});(0,n.nR)(class extends a{static providerId="create-post";static capability="edit_others_posts";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static isRepetitive=!0;static externalLinkUrl="https://prpl.fyi/valuable-content";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("last_published_post_id");return t&&t.post_id,!0}catch(t){return console.error("Error checking Content Create task condition:",t),!1}}async getTaskDetails(t={}){const e=await(0,o.OJ)("last_published_post_id"),s=e?.post_id||null;return this.buildTaskDetails(t,{post_title:(0,r.__)("Create valuable content","progress-planner"),url:"https://prpl.fyi/valuable-content",url_target:"_blank",target_post_id:s})}addTaskActions(t,e){return e.push({type:"link",priority:10,href:this.buildAdminUrl("post-new.php"),label:(0,r.__)("Create new post","progress-planner"),target:"_self"}),e}});(0,n.nR)(class extends a{static providerId="review-post";static capability="edit_others_posts";static isOnboardingTask=!1;static priority=10;static points=1;static isDismissable=!0;static isSnoozable=!0;static isRepetitive=!0;static externalLinkUrl="https://prpl.fyi/review-post";static isMultiTask=!0;async shouldAddTask(t={}){try{const t=await this.getTasksToInject();return t&&t.length>0}catch(t){return console.error("Error checking Content Review task condition:",t),!1}}async getTasksToInject(){try{const t=await(0,o.OJ)("old_posts_for_review");return t&&0!==t.length?t.map(t=>({target_post_id:t.ID,target_post_title:t.post_title,target_post_type:t.post_type})):[]}catch(t){return console.error("Error getting posts for review:",t),[]}}async getTaskDetails(t={}){const e=t?.target_post_id||null,s=t?.target_post_title||null;if(!e)throw new Error("ContentReviewTask requires target_post_id in taskData");const a=s?(0,r.sprintf)(/* translators: %s: post title */ /* translators: %s: post title */
+(0,r.__)("Review: %s","progress-planner"),s):(0,r.sprintf)(/* translators: %d: post ID */ /* translators: %d: post ID */
+(0,r.__)("Review post #%d","progress-planner"),e);return this.buildTaskDetails(t,{post_title:a,url:this.buildAdminUrl("post.php",{post:e,action:"edit"}),url_target:"_blank",target_post_id:e})}addTaskActions(t=[],e=[]){const s=t.target_post_id||t.meta?.target_post_id||null;return s&&e.push({type:"link",priority:10,href:this.buildAdminUrl("post.php",{action:"edit",post:s}),label:(0,r.__)("Review","progress-planner"),target:"_self"}),e}});(0,n.nR)(class extends a{static providerId="unpublished-content";static capability="edit_others_posts";static isOnboardingTask=!1;static priority=55;static points=1;static isDismissable=!0;static isSnoozable=!0;static isRepetitive=!1;static externalLinkUrl="https://prpl.fyi/check-unpublished-content";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("unpublished_content");return t&&Array.isArray(t)&&t.length>0}catch(t){return console.error("Error checking Unpublished Content task condition:",t),!1}}async getTaskDetails(t={}){const e=await(0,o.OJ)("unpublished_content"),s=e&&Array.isArray(e)?e.length:0,a=s>0?(0,r.sprintf)(/* translators: %d: number of unpublished items */ /* translators: %d: number of unpublished items */
+(0,r._n)("You have %d unpublished item that might need attention.","You have %d unpublished items that might need attention.",s,"progress-planner"),s):"";return this.buildTaskDetails(t,{post_title:(0,r.__)("Review unpublished content","progress-planner"),description:a,url:this.buildAdminUrl("edit.php",{post_status:"draft",post_type:"post"})})}addTaskActions(t=[],e=[]){const s=t.meta?.prpl_url||t.url||null;return s&&e.push({type:"link",priority:10,href:s,label:(0,r.__)("Edit","progress-planner"),target:"_self"}),e}});(0,n.nR)(class extends i{static providerId="set-page-about";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static popoverId="set-page-about";async shouldAddTask(t={}){try{const t=await(0,l.BJ)({path:"/progress-planner/v1/page-settings"}).catch(()=>null);return!(!t||!t.about)&&"no"===t.about.isset}catch(t){return console.error("Error checking Set Page About task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Set the About page","progress-planner"),url:this.buildAdminUrl("edit.php",{post_type:"page"})});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Set","progress-planner")}});(0,n.nR)(class extends i{static providerId="set-page-faq";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static popoverId="set-page-faq";async shouldAddTask(t={}){try{const t=await(0,l.BJ)({path:"/progress-planner/v1/page-settings"}).catch(()=>null);return!t||!t.faq||"no"===t.faq.isset}catch(t){return console.error("Error checking Set Page FAQ task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Set the FAQ page","progress-planner"),url:this.buildAdminUrl("edit.php",{post_type:"page"})});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Set","progress-planner")}});(0,n.nR)(class extends i{static providerId="set-page-contact";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static popoverId="set-page-contact";async shouldAddTask(t={}){try{const t=await(0,l.BJ)({path:"/progress-planner/v1/page-settings"}).catch(()=>null);return!t||!t.contact||"no"===t.contact.isset}catch(t){return console.error("Error checking Set Page Contact task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Set the Contact page","progress-planner"),url:this.buildAdminUrl("edit.php",{post_type:"page"})});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Set","progress-planner")}});(0,n.nR)(class extends i{static providerId="set-valuable-post-types";static capability="manage_options";static isOnboardingTask=!1;static priority=70;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/valuable-content";static popoverId="set-valuable-post-types";async shouldAddTask(t={}){return!0}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Set valuable content types","progress-planner"),url:this.buildAdminUrl("admin.php",{page:"progress-planner"})});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Set","progress-planner")}});(0,n.nR)(class extends i{static providerId="rename-uncategorized-category";static capability="manage_categories";static isOnboardingTask=!0;static priority=60;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/rename-uncategorized-category";static popoverId="rename-uncategorized-category";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("uncategorized_category_id");return 0!==t&&null!==t}catch(t){return console.error("Error checking Rename Uncategorized Category task condition:",t),!1}}async getTaskDetails(t={}){const e=await(0,o.OJ)("uncategorized_category_id"),s=this.buildTaskDetails(t,{post_title:(0,r.__)("Rename Uncategorized category","progress-planner"),url:this.buildAdminUrl("term.php",{taxonomy:"category",tag_ID:e})});return this.addPopoverIdToTaskDetails(s)}getPopoverActionLabel(){return(0,r.__)("Rename","progress-planner")}});(0,n.nR)(class extends i{static providerId="fewer-tags";static capability="manage_options";static isOnboardingTask=!0;static priority=32;static points=1;static isDismissable=!0;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/install-fewer-tags";static popoverId="fewer-tags";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("post_tag_count"),e=await(0,o.OJ)("published_post_count");return null!==t&&null!==e&&t>e}catch(t){return console.error("Error checking Fewer Tags task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Install Fewer Tags and clean up your tags","progress-planner"),url:this.buildAdminUrl("plugin-install.php",{tab:"search",s:"fewer tags"})});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Install plugin","progress-planner")}});(0,n.nR)(class extends i{static providerId="remove-terms-without-posts";static capability="edit_others_posts";static isOnboardingTask=!1;static priority=60;static points=1;static isDismissable=!0;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/remove-empty-taxonomy";static popoverId="remove-terms-without-posts";static isMultiTask=!0;async shouldAddTask(t={}){try{const t=await this.getTasksToInject();return t&&t.length>0}catch(t){return console.error("Error checking Remove Terms Without Posts task condition:",t),!1}}async getTasksToInject(){try{const t=await(0,o.OJ)("terms_without_posts");if(!t)return[];const e=Array.isArray(t)?t:[t];return 0===e.length?[]:e.map(t=>({target_term_id:t.term_id,target_taxonomy:t.taxonomy}))}catch(t){return console.error("Error getting tasks to inject for Remove Terms Without Posts:",t),[]}}async getTaskDetails(t={}){const e=t?.target_term_id||null,s=t?.target_taxonomy||null;if(!e||!s)throw new Error("RemoveTermsWithoutPostsTask requires target_term_id and target_taxonomy in taskData");const r=this.buildTaskDetails(t,{post_title:`Remove term #${e}`,url:this.buildAdminUrl("edit-tags.php",{taxonomy:s}),url_target:"_blank",target_term_id:e,target_taxonomy:s});return this.addPopoverIdToTaskDetails(r)}});(0,n.nR)(class extends i{static providerId="update-term-description";static capability="edit_others_posts";static isOnboardingTask=!1;static priority=80;static points=1;static isDismissable=!0;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/taxonomy-terms-description";static popoverId="update-term-description";static isMultiTask=!0;async shouldAddTask(t={}){try{const t=await this.getTasksToInject();return t&&t.length>0}catch(t){return console.error("Error checking Update Term Description task condition:",t),!1}}async getTasksToInject(){try{const t=await(0,o.OJ)("terms_without_description");if(!t)return[];const e=Array.isArray(t)?t:[t];return 0===e.length?[]:e.map(t=>({target_term_id:t.term_id,target_taxonomy:t.taxonomy}))}catch(t){return console.error("Error getting tasks to inject for Update Term Description:",t),[]}}async getTaskDetails(t={}){const e=t?.target_term_id||null,s=t?.target_taxonomy||null;if(!e||!s)throw new Error("UpdateTermDescriptionTask requires target_term_id and target_taxonomy in taskData");const a=this.buildTaskDetails(t,{post_title:(0,r.sprintf)(/* translators: %d: term ID */ /* translators: %d: term ID */
+(0,r.__)("Write description for term #%d","progress-planner"),e),url:this.buildAdminUrl("term.php",{taxonomy:s,tag_ID:e}),url_target:"_blank",target_term_id:e,target_taxonomy:s});return this.addPopoverIdToTaskDetails(a)}addTaskActions(t=[],e=[]){const s=t.target_term_id||t.meta?.target_term_id||null,a=t.target_taxonomy||t.meta?.target_taxonomy||null;if(!s||!a)return super.addTaskActions(t,e);const i={post_title:t.title?.rendered||t.post_title||"",target_term_id:s,target_taxonomy:a,target_term_name:t.meta?.target_term_name||"",target_taxonomy_name:t.meta?.target_taxonomy_name||""};return e.push({type:"popover",priority:10,popoverId:this.getPopoverId(),label:(0,r.__)("Write description","progress-planner"),taskContext:i,eventName:"prpl-interactive-task-action-update-term-description"}),e}getPopoverActionLabel(){return(0,r.__)("Write description","progress-planner")}});(0,n.nR)(class extends i{static providerId="seo-plugin";static capability="manage_options";static isOnboardingTask=!0;static priority=20;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/install-seo-plugin";static popoverId="seo-plugin";async shouldAddTask(t={}){try{return!await(0,o.OJ)("seo_plugin_installed")}catch(t){return console.error("Error checking SEO Plugin task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Install an SEO plugin","progress-planner"),url:this.buildAdminUrl("plugins.php")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Install plugin","progress-planner")}});var c=s(1455),p=s.n(c);(0,n.nR)(class extends a{static providerId="update-core";static capability="update_core";static isOnboardingTask=!1;static priority=20;static points=1;static isDismissable=!1;static isSnoozable=!0;static isRepetitive=!0;static externalLinkUrl="https://prpl.fyi/perform-all-updates";async shouldAddTask(t={}){try{const t=await p()({path:"/wp/v2/updates"}).catch(()=>null);return!t||t.core&&t.core.length>0||t.plugins&&t.plugins.length>0||t.themes&&t.themes.length>0}catch(t){return console.error("Error checking Core Update task condition:",t),!1}}async getTaskDetails(t={}){return this.buildTaskDetails(t,{post_title:(0,r.__)("Perform all updates","progress-planner"),url:this.buildAdminUrl("update-core.php")})}addTaskActions(t,e){return e.push({type:"link",priority:10,href:this.buildAdminUrl("update-core.php"),label:(0,r.__)("Go to the Updates page","progress-planner"),target:"_self"}),e}});(0,n.nR)(class extends a{static providerId="remove-inactive-plugins";static capability="manage_options";static isOnboardingTask=!1;static priority=60;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/remove-inactive-plugins";async shouldAddTask(t={}){try{return await(0,o.OJ)("inactive_plugins_count")>0}catch(t){return console.error("Error checking Remove Inactive Plugins task condition:",t),!1}}async getTaskDetails(t={}){return this.buildTaskDetails(t,{post_title:(0,r.__)("Remove inactive plugins","progress-planner"),url:this.buildAdminUrl("plugins.php",{plugin_status:"inactive"})})}addTaskActions(t,e){return e.push({type:"link",priority:10,href:this.buildAdminUrl("plugins.php",{plugin_status:"inactive"}),label:(0,r.__)('Go to the "Plugins" page',"progress-planner"),target:"_self"}),e}});(0,n.nR)(class extends a{static providerId="wp-debug-display";static capability="manage_options";static isOnboardingTask=!0;static priority=10;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/set-wp-debug";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("wp_debug_status");return!!t&&!0===t.should_fix}catch(t){return console.error("Error checking Debug Display task condition:",t),!1}}async getTaskDetails(t={}){return this.buildTaskDetails(t,{post_title:(0,r.__)("Disable public display of PHP errors","progress-planner")})}});(0,n.nR)(class extends a{static providerId="php-version";static capability="manage_options";static isOnboardingTask=!0;static priority=25;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/update-php-version";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("php_version");return!!t&&this.versionCompare(t,"8.2","<")}catch(t){return console.error("Error checking PHP version task condition:",t),!1}}versionCompare(t,e,s){const r=t.split(".").map(Number),a=e.split(".").map(Number);for(;r.lengtha[t]){i=1;break}}switch(s){case"<":return i<0;case"<=":return i<=0;case">":return i>0;case">=":return i>=0;case"==":return 0===i;default:return!1}}async getTaskDetails(t={}){return this.buildTaskDetails(t,{post_title:"Update PHP version"})}});(0,n.nR)(class extends i{static providerId="sending-email";static capability="manage_options";static isOnboardingTask=!1;static priority=4;static points=1;static isDismissable=!0;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/check-if-your-websites-email-system-works";static popoverId="sending-email";async shouldAddTask(t={}){return!0}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Check if your website's email system works","progress-planner"),url:this.buildAdminUrl("admin.php",{page:"progress-planner"})});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Test email sending","progress-planner")}});(0,n.nR)(class extends i{static providerId="disable-comments";static capability="manage_options";static isOnboardingTask=!0;static priority=9;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/disable-comments";static popoverId="disable-comments";async shouldAddTask(t={}){try{const t=await(0,l.BJ)({path:"/wp/v2/settings"});return"open"===(t?.default_comment_status||"open")}catch(t){return console.error("Error checking Disable Comments task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Disable comments","progress-planner"),url:this.buildAdminUrl("options-discussion.php"),link_setting:{hook:"options-discussion.php",iconEl:'label[for="default_comment_status"]'}});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Disable comments","progress-planner")}});(0,n.nR)(class extends i{static providerId="disable-comment-pagination";static capability="manage_options";static isOnboardingTask=!0;static priority=10;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/disable-comment-pagination";static popoverId="disable-comment-pagination";async shouldAddTask(t={}){try{const t=await(0,l.BJ)({path:"/wp/v2/settings"});return!0===t?.page_comments}catch(t){return console.error("Error checking Disable Comment Pagination task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Disable comment pagination","progress-planner"),url:this.buildAdminUrl("options-discussion.php"),link_setting:{hook:"options-discussion.php",iconEl:'label[for="page_comments"]'}});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Disable pagination","progress-planner")}});(0,n.nR)(class extends i{static providerId="improve-pdf-handling";static capability="manage_options";static isOnboardingTask=!1;static priority=1;static points=1;static isDismissable=!0;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/improve-pdf-handling";static popoverId="improve-pdf-handling";async shouldAddTask(t={}){return!0}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Improve PDF handling","progress-planner"),url:this.buildAdminUrl("admin.php",{page:"progress-planner"})});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Improve PDF handling","progress-planner")}});(0,n.nR)(class extends i{static providerId="reduce-autoloaded-options";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!0;static isSnoozable=!0;static popoverId="reduce-autoloaded-options";async shouldAddTask(t={}){return!1}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Reduce number of autoloaded options","progress-planner"),url:this.buildAdminUrl("plugin-install.php",{tab:"search",s:"aaa option optimizer"})});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Reduce","progress-planner")}});(0,n.nR)(class extends a{static providerId="user";static capability="edit_posts";static isOnboardingTask=!1;static priority=999;static points=0;static isDismissable=!0;static isSnoozable=!1;static isRepetitive=!1;static externalLinkUrl="";async shouldAddTask(t={}){return!1}async getTaskDetails(t={}){return this.buildTaskDetails(t,{post_title:t.title?.rendered||t.title||"",description:t.content?.rendered||"",points:this.getPoints(t)})}getPoints(t={}){var e;return("string"==typeof t.excerpt?t.excerpt:null!==(e=t.excerpt?.rendered)&&void 0!==e?e:"").includes("GOLDEN")?1:0}addTaskActions(t={},e=[]){return e.push({type:"link",priority:10,href:"#",label:(0,r.__)("Edit","progress-planner"),inlineEdit:!0}),e}});class d extends i{static providerId="yoast-author-archive";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/yoast-author-archive";static popoverId="yoast-author-archive";static MINIMUM_AUTHOR_WITH_POSTS=1;async shouldAddTask(t={}){try{const t=await(0,o.OJ)("yoast_options");return!!t&&(!(await(0,o.OJ)("post_author_count")>d.MINIMUM_AUTHOR_WITH_POSTS)&&!0!==t.wpseo_titles?.["disable-author"])}catch(t){return console.error("Error checking Yoast Archive Author task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Yoast SEO: disable the author archive","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_page_settings#/author-archives")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Disable","progress-planner")}getFocusTasks(){return[{iconElement:".yst-toggle-field__header",valueElement:{elementSelector:'button[data-id="input-wpseo_titles-disable-author"]',attributeName:"aria-checked",attributeValue:"false",operator:"="}}]}}(0,n.nR)(d);(0,n.nR)(class extends i{static providerId="yoast-date-archive";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/yoast-date-archive";static popoverId="yoast-date-archive";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("yoast_options");return!!t&&(!await(0,o.OJ)("permalink_has_date")&&!0!==t.wpseo_titles?.["disable-date"])}catch(t){return console.error("Error checking Yoast Archive Date task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Yoast SEO: disable the date archive","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_page_settings#/date-archives")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Disable","progress-planner")}getFocusTasks(){return[{iconElement:".yst-toggle-field__header",valueElement:{elementSelector:'button[data-id="input-wpseo_titles-disable-date"]',attributeName:"aria-checked",attributeValue:"false",operator:"="}}]}});class u extends i{static providerId="yoast-format-archive";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/yoast-format-archive";static popoverId="yoast-format-archive";static MINIMUM_POSTS_WITH_FORMAT=3;async shouldAddTask(t={}){try{const t=await(0,o.OJ)("yoast_options");return!!t&&(!(await(0,o.OJ)("archive_format_count")>u.MINIMUM_POSTS_WITH_FORMAT)&&!0!==t.wpseo_titles?.["disable-post_format"])}catch(t){return console.error("Error checking Yoast Archive Format task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Yoast SEO: disable the format archives","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_page_settings#/format-archives")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Disable","progress-planner")}getFocusTasks(){return[{iconElement:".yst-toggle-field__header",valueElement:{elementSelector:'button[data-id="input-wpseo_titles-disable-post_format"]',attributeName:"aria-checked",attributeValue:"false",operator:"="}}]}}(0,n.nR)(u);(0,n.nR)(class extends i{static providerId="yoast-media-pages";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/yoast-media-pages";static popoverId="yoast-media-pages";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("yoast_options");return!!t&&!0!==t.wpseo_titles?.["disable-attachment"]}catch(t){return console.error("Error checking Yoast Media Pages task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Yoast SEO: disable the media pages","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_page_settings#/media-pages")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Disable","progress-planner")}getFocusTasks(){return[{iconElement:".yst-toggle-field__header",valueElement:{elementSelector:'button[data-id="input-wpseo_titles-disable-attachment"]',attributeName:"aria-checked",attributeValue:"false",operator:"="}}]}});(0,n.nR)(class extends i{static providerId="yoast-crawl-settings-emoji-scripts";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/yoast-crawl-optimization-emoji-scripts";static popoverId="yoast-crawl-settings-emoji-scripts";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("yoast_options");return!!t&&!t.wpseo?.remove_emoji_scripts}catch(t){return console.error("Error checking Yoast Crawl Emoji Scripts task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Yoast SEO: remove emoji scripts","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_page_settings#/crawl-optimization#input-wpseo-remove_emoji_scripts")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Remove","progress-planner")}getFocusTasks(){return[{iconElement:".yst-toggle-field__header",valueElement:{elementSelector:'button[data-id="input-wpseo-remove_emoji_scripts"]',attributeName:"aria-checked",attributeValue:"true",operator:"="}}]}});class g extends i{static providerId="yoast-crawl-settings-feed-authors";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/yoast-crawl-optimization-feed-authors";static popoverId="yoast-crawl-settings-feed-authors";static MINIMUM_AUTHOR_WITH_POSTS=1;async shouldAddTask(t={}){try{const t=await(0,o.OJ)("yoast_options");return!!t&&!(await(0,o.OJ)("post_author_count")>g.MINIMUM_AUTHOR_WITH_POSTS||t.wpseo?.remove_feed_authors)}catch(t){return console.error("Error checking Yoast Crawl Feed Authors task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Yoast SEO: remove post authors feeds","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_page_settings#/crawl-optimization#input-wpseo-remove_feed_authors")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Remove","progress-planner")}getFocusTasks(){return[{iconElement:".yst-toggle-field__header",valueElement:{elementSelector:'button[data-id="input-wpseo-remove_feed_authors"]',attributeName:"aria-checked",attributeValue:"true",operator:"="}}]}}(0,n.nR)(g);(0,n.nR)(class extends i{static providerId="yoast-crawl-settings-feed-global-comments";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/yoast-crawl-optimization-feed-global-comments";static popoverId="yoast-crawl-settings-feed-global-comments";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("yoast_options");return!!t&&!t.wpseo?.remove_feed_global_comments}catch(t){return console.error("Error checking Yoast Crawl Feed Comments task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("Yoast SEO: remove global comment feeds","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_page_settings#/crawl-optimization#input-wpseo-remove_feed_global_comments")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Remove","progress-planner")}getFocusTasks(){return[{iconElement:".yst-toggle-field__header",valueElement:{elementSelector:'button[data-id="input-wpseo-remove_feed_global_comments"]',attributeName:"aria-checked",attributeValue:"true",operator:"="}}]}});(0,n.nR)(class extends i{static providerId="yoast-organization-logo";static capability="manage_options";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/yoast-organization-logo";static popoverId="yoast-organization-logo";isPersonMode=!1;checkIsPersonMode(t){return"person"===t?.wpseo_titles?.company_or_person||"person"===t?.wpseo?.company_or_person}async shouldAddTask(t={}){try{const t=await(0,o.OJ)("yoast_options");return!(!t||t.site_logo||(this.isPersonMode=this.checkIsPersonMode(t),this.isPersonMode&&t.wpseo_titles?.person_logo||!this.isPersonMode&&t.wpseo_titles?.company_logo))}catch(t){return console.error("Error checking Yoast Organization Logo task condition:",t),!1}}async getTaskDetails(t={}){const e=await(0,o.OJ)("yoast_options");this.isPersonMode=this.checkIsPersonMode(e);const s=this.isPersonMode?(0,r.__)("Yoast SEO: set your person logo","progress-planner"):(0,r.__)("Yoast SEO: set your organization logo","progress-planner"),a=this.buildTaskDetails(t,{post_title:s,url:this.buildAdminUrl("admin.php?page=wpseo_page_settings#/site-representation")});return this.addPopoverIdToTaskDetails(a)}getExternalLinkUrl(){return this.isPersonMode?"https://prpl.fyi/yoast-person-logo":"https://prpl.fyi/yoast-organization-logo"}getPopoverActionLabel(){return(0,r.__)("Set logo","progress-planner")}getFocusTasks(){return[{iconElement:"legend.yst-label",valueElement:{elementSelector:'input[name="wpseo_titles.company_logo"]',attributeName:"value",attributeValue:"",operator:"!="}},{iconElement:"legend.yst-label",valueElement:{elementSelector:'input[name="wpseo_titles.person_logo"]',attributeName:"value",attributeValue:"",operator:"!="}}]}});(0,n.nR)(class extends a{static providerId="yoast-cornerstone-workout";static capability="edit_others_posts";static isOnboardingTask=!1;static priority=20;static points=3;static isDismissable=!0;static isSnoozable=!0;static isRepetitive=!0;static externalLinkUrl="https://prpl.fyi/run-cornerstone-content-workout";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("yoast_premium_status");return!!t?.active}catch(t){return console.error("Error checking Yoast Cornerstone Workout task condition:",t),!1}}async getTaskDetails(t={}){return this.buildTaskDetails(t,{post_title:(0,r.__)("Yoast SEO: do Yoast SEO's Cornerstone Content Workout","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_workouts#cornerstone")})}addTaskActions(t,e){return e.push({type:"link",priority:10,label:(0,r.__)("Run workout","progress-planner"),href:this.buildAdminUrl("admin.php?page=wpseo_workouts#cornerstone"),target:"_self"}),e}});(0,n.nR)(class extends a{static providerId="yoast-orphaned-content-workout";static capability="edit_others_posts";static isOnboardingTask=!1;static priority=20;static points=3;static isDismissable=!0;static isSnoozable=!0;static isRepetitive=!0;static externalLinkUrl="https://prpl.fyi/run-orphaned-content-workout";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("yoast_premium_status");return!!t?.active}catch(t){return console.error("Error checking Yoast Orphaned Content Workout task condition:",t),!1}}async getTaskDetails(t={}){return this.buildTaskDetails(t,{post_title:(0,r.__)("Yoast SEO: do Yoast SEO's Orphaned Content Workout","progress-planner"),url:this.buildAdminUrl("admin.php?page=wpseo_workouts#orphaned")})}addTaskActions(t,e){return e.push({type:"link",priority:10,label:(0,r.__)("Run workout","progress-planner"),href:this.buildAdminUrl("admin.php?page=wpseo_workouts#orphaned"),target:"_self"}),e}});(0,n.nR)(class extends a{static providerId="yoast-fix-orphaned-content";static capability="edit_others_posts";static isOnboardingTask=!1;static priority=50;static points=1;static isDismissable=!0;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/fix-orphaned-content";static isMultiTask=!0;async shouldAddTask(t={}){try{const t=await this.getTasksToInject();return t&&t.length>0}catch(t){return console.error("Error checking Yoast Fix Orphaned Content task condition:",t),!1}}async getTasksToInject(){try{const t=await(0,o.OJ)("yoast_orphaned_content");if(!t)return[];const e=Array.isArray(t)?t:[t];return 0===e.length?[]:e.map(t=>({target_post_id:t.ID||t.id||t.post_id,target_post_title:t.post_title||t.title||""}))}catch(t){return console.error("Error getting tasks to inject for Yoast Fix Orphaned Content:",t),[]}}async getTaskDetails(t={}){const e=t?.target_post_id||null,s=t?.target_post_title||"";if(!e)throw new Error("YoastFixOrphanedContentTask requires target_post_id in taskData");return this.buildTaskDetails(t,{post_title:(0,r.sprintf)(/* translators: %s: Post title. */ /* translators: %s: Post title. */
+(0,r.__)('Yoast SEO: add internal links to article "%s"!',"progress-planner"),s),url:this.buildAdminUrl("post.php",{post:e,action:"edit"}),url_target:"_blank",target_post_id:e,target_post_title:s})}addTaskActions(t,e){return e.push({type:"link",priority:10,label:(0,r.__)("Learn more about internal linking","progress-planner"),href:"https://prpl.fyi/fix-orphaned-content",target:"_blank"}),e}});(0,n.nR)(class extends a{static providerId="aioseo-organization-logo";static capability="manage_options";static isOnboardingTask=!1;static priority=20;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/aioseo-organization-logo";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("aioseo_options");return!!t&&"person"!==t.schema?.siteRepresents&&""===t.schema?.organizationLogo}catch(t){return console.error("Error checking AIOSEO Organization Logo task condition:",t),!1}}async getTaskDetails(t={}){return this.buildTaskDetails(t,{post_title:(0,r.__)("All in One SEO: set your organization logo","progress-planner"),url:this.buildAdminUrl("admin.php?page=aioseo-search-appearance#/")})}addTaskActions(t,e){return e.push({type:"link",priority:10,label:(0,r.__)("Set logo","progress-planner"),href:this.buildAdminUrl("admin.php?page=aioseo-search-appearance#/"),target:"_self"}),e}});class h extends i{static providerId="aioseo-author-archive";static capability="manage_options";static isOnboardingTask=!1;static priority=20;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/aioseo-author-archive";static popoverId="aioseo-author-archive";static MINIMUM_AUTHOR_WITH_POSTS=1;async shouldAddTask(t={}){try{const t=await(0,o.OJ)("aioseo_options");return!!t&&(!(await(0,o.OJ)("post_author_count")>h.MINIMUM_AUTHOR_WITH_POSTS)&&!0===t.archives?.author?.show)}catch(t){return console.error("Error checking AIOSEO Archive Author task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("All in One SEO: noindex the author archive","progress-planner"),url:this.buildAdminUrl("admin.php?page=aioseo-search-appearance#/archives")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Noindex","progress-planner")}}(0,n.nR)(h);(0,n.nR)(class extends i{static providerId="aioseo-date-archive";static capability="manage_options";static isOnboardingTask=!1;static priority=20;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/aioseo-date-archive";static popoverId="aioseo-date-archive";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("aioseo_options");return!!t&&(!await(0,o.OJ)("permalink_has_date")&&!0===t.archives?.date?.show)}catch(t){return console.error("Error checking AIOSEO Archive Date task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("All in One SEO: noindex the date archive","progress-planner"),url:this.buildAdminUrl("admin.php?page=aioseo-search-appearance#/archives")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Noindex","progress-planner")}});(0,n.nR)(class extends i{static providerId="aioseo-media-pages";static capability="manage_options";static isOnboardingTask=!1;static priority=20;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/aioseo-media-pages";static popoverId="aioseo-media-pages";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("aioseo_options");return!!t&&"attachment"!==t.attachment?.redirectAttachmentUrls}catch(t){return console.error("Error checking AIOSEO Media Pages task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("All in One SEO: redirect media/attachment pages to attachment","progress-planner"),url:this.buildAdminUrl("admin.php?page=aioseo-search-appearance#/media")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Redirect","progress-planner")}});class m extends i{static providerId="aioseo-crawl-settings-feed-authors";static capability="manage_options";static isOnboardingTask=!1;static priority=20;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/aioseo-crawl-optimization-feed-authors";static popoverId="aioseo-crawl-settings-feed-authors";static MINIMUM_AUTHOR_WITH_POSTS=1;async shouldAddTask(t={}){try{const t=await(0,o.OJ)("aioseo_options");return!!t&&(!(await(0,o.OJ)("post_author_count")>m.MINIMUM_AUTHOR_WITH_POSTS)&&!1!==t.crawlCleanup?.feeds?.authors)}catch(t){return console.error("Error checking AIOSEO Crawl Feed Authors task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("All in One SEO: disable author RSS feeds","progress-planner"),url:this.buildAdminUrl("admin.php?page=aioseo-search-appearance#/advanced")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Disable","progress-planner")}}(0,n.nR)(m);(0,n.nR)(class extends i{static providerId="aioseo-crawl-settings-feed-comments";static capability="manage_options";static isOnboardingTask=!1;static priority=20;static points=1;static isDismissable=!1;static isSnoozable=!0;static externalLinkUrl="https://prpl.fyi/aioseo-crawl-optimization-feed-comments";static popoverId="aioseo-crawl-settings-feed-comments";async shouldAddTask(t={}){try{const t=await(0,o.OJ)("aioseo_options");if(!t)return!1;const e=t.crawlCleanup?.feeds?.globalComments,s=t.crawlCleanup?.feeds?.postComments;return!1!==e||!1!==s}catch(t){return console.error("Error checking AIOSEO Crawl Feed Comments task condition:",t),!1}}async getTaskDetails(t={}){const e=this.buildTaskDetails(t,{post_title:(0,r.__)("All in One SEO: disable comment RSS feeds","progress-planner"),url:this.buildAdminUrl("admin.php?page=aioseo-search-appearance#/advanced")});return this.addPopoverIdToTaskDetails(e)}getPopoverActionLabel(){return(0,r.__)("Disable","progress-planner")}})},790:t=>{t.exports=window.ReactJSXRuntime},1059:(t,e,s)=>{s.d(e,{A:()=>g});var r=s(6087),a=s(7723),i=s(790);const n={position:"absolute",top:0,right:0,transform:"translate(-10px, -10px) rotate(90deg)",width:0,height:0,borderStyle:"solid",borderWidth:"7.5px 10px 7.5px 0",borderColor:"transparent var(--prpl-background-activity) transparent transparent"},o={padding:0,lineHeight:1,background:"none",border:"none",cursor:"pointer",fontSize:"var(--prpl-font-size-small)",color:"var(--prpl-color-link)"},l={display:"inline-flex",alignItems:"center",position:"relative"},c={display:"block",position:"absolute",bottom:0,left:"100%",transform:"translate(-100%, calc(100% + 10px))",padding:"0.75rem 1.5rem 0.75rem 0.75rem",width:150,background:"var(--prpl-background-activity)",borderRadius:"var(--prpl-border-radius)",zIndex:2,visibility:"hidden",fontSize:"1rem",fontWeight:400,color:"var(--prpl-color-text)"},p={visibility:"visible",zIndex:10},d={position:"absolute",top:0,right:0,padding:"0.1rem",lineHeight:0,margin:0,background:"none",border:"none",cursor:"pointer"},u={display:"block",position:"fixed",top:0,left:0,width:"100%",height:"100%",zIndex:9,backgroundColor:"rgba(0, 0, 0, 0.5)"};function g({triggerContent:t,children:e,tooltipStyle:s,arrowStyle:g,onClose:h}){const[m,y]=(0,r.useState)(!1),[b,k]=(0,r.useState)(!1),_=(0,r.useRef)(null),f=(0,r.useId)(),v=(0,r.useCallback)(()=>{y(!1),h?.()},[h]);(0,r.useEffect)(()=>{if(!m)return;const t=t=>{"Escape"===t.key&&v()};return document.addEventListener("keydown",t),()=>document.removeEventListener("keydown",t)},[m,v]);const w={...o,textDecoration:b?"underline":"none"};return(0,i.jsxs)("span",{className:"prpl-tooltip-wrapper",style:l,children:[(0,i.jsx)("button",{type:"button",className:"prpl-info-icon","aria-describedby":f,onClick:()=>y(!0),style:w,onMouseEnter:()=>k(!0),onMouseLeave:()=>k(!1),children:t}),m&&(0,i.jsx)("span",{role:"presentation",onClick:v,style:u}),(0,i.jsxs)("span",{ref:_,id:f,className:"prpl-tooltip",role:"tooltip","aria-hidden":!m,style:{...c,...m?p:{},...s},children:[(0,i.jsx)("span",{"data-testid":"tooltip-arrow",style:{...n,...g}}),e,(0,i.jsxs)("button",{type:"button",onClick:v,style:d,children:[(0,i.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,i.jsx)("span",{className:"screen-reader-text",children:(0,a.__)("Close","progress-planner")})]})]})]})}},1362:(t,e,s)=>{s.d(e,{Cu:()=>i,cr:()=>n});var r=s(2619);const a=[];function i(t){const{id:e,component:s,priority:r=10,width:i=1,forceLastColumn:n=!1,title:o=""}=t;if(!e||!s)return void console.warn("Widget registration failed: id and component are required",t);const l=a.findIndex(t=>t.id===e),c={id:e,component:s,priority:r,width:i,forceLastColumn:n,title:o};l>=0?a[l]=c:a.push(c)}function n(){return[...a].sort((t,e)=>t.priority-e.priority)}(0,r.addAction)("prpl.dashboard.registerWidget","progress-planner/widget-registry",i)},1455:t=>{t.exports=window.wp.apiFetch},1971:(t,e,s)=>{function r(t,e=null){return t||e?t?.slug?t.slug:t?.prpl_provider?.slug?t.prpl_provider.slug:e||null:null}s.d(e,{p:()=>r})},2619:t=>{t.exports=window.wp.hooks},3572:(t,e,s)=>{s.d(e,{h:()=>a});var r=s(6087);function a(){(0,r.useEffect)(()=>{const t=()=>{document.querySelectorAll(".prpl-widget-wrapper").forEach(t=>{if(!t||t.classList.contains("in-popover"))return;const e=t.querySelector(".widget-inner-container");if(!e)return;const s=document.querySelector(".prpl-widgets-container");if(!s)return;const r=parseInt(window.getComputedStyle(s).getPropertyValue("grid-auto-rows")),a=parseInt(window.getComputedStyle(t).getPropertyValue("padding-top")),i=parseInt(window.getComputedStyle(t).getPropertyValue("padding-bottom")),n=Math.ceil((e.getBoundingClientRect().height+a+i)/r);t.style.gridRowEnd="span "+(n+1)})},e=()=>{setTimeout(t,0)};return window.addEventListener("prpl/grid/resize",t),window.addEventListener("resize",e),window.addEventListener("load",e),e(),setTimeout(e,1e3),()=>{window.removeEventListener("prpl/grid/resize",t),window.removeEventListener("resize",e),window.removeEventListener("load",e)}},[])}},4333:(t,e,s)=>{s.d(e,{nM:()=>p,nO:()=>d,ys:()=>u});var r=s(1455),a=s.n(r),i=s(7723);function n(t){let e=t.querySelector('button[type="submit"]');if(e||(e=t.querySelector('button[data-action="completeTask"]')),e){e.disabled=!0;const t=document.createElement("span");t.classList.add("prpl-spinner"),t.innerHTML='',e.after(t)}}function o(t){let e=t.querySelector('button[type="submit"]');e||(e=t.querySelector('button[data-action="completeTask"]')),e&&(e.disabled=!1);const s=t.querySelector("span.prpl-spinner");s&&s.remove()}function l(t){const e=document.querySelector(`#${t} form`);if(e&&!e.parentNode.querySelector("p.prpl-interactive-task-error-message")){const t=document.createElement("p");t.classList.add("prpl-note","prpl-note-error","prpl-interactive-task-error-message"),t.textContent=(0,i.__)("Something went wrong. Please try again.","progress-planner"),e.insertAdjacentElement("afterend",t)}}function c(t){const e=document.querySelector(`#${t} form`);if(!e)return;const s=e.parentNode.querySelector("p.prpl-interactive-task-error-message");s&&s.remove()}async function p({settingAPIKey:t,setting:e,popoverId:s,settingCallbackValue:r=t=>t,value:i=null}){const p=document.querySelector(`#${s} form`);if(!p&&null===i)throw new Error("Form not found and no value provided");p&&n(p),c(s);try{const s=r(null!==i?i:new FormData(p).get(e)),n=await a()({path:"/wp/v2/settings",method:"POST",data:{[t]:s}});return p&&o(p),n}catch(t){throw p&&o(p),l(s),t}}async function d({setting:t,settingPath:e=!1,popoverId:s,settingCallbackValue:r=t=>t,value:i=null}){const p=document.querySelector(`#${s} form`);if(!p&&null===i)throw new Error("Form not found and no value provided");p&&n(p),c(s);try{const n=r(null!==i?i:new FormData(p).get(t));let c="";e&&(Array.isArray(e)?c=JSON.stringify(e):"string"==typeof e&&(c=e));const d=await a()({path:"/progress-planner/v1/popover/submit",method:"POST",data:{setting:t,value:n,setting_path:c}});if(p&&o(p),!0!==d.success)throw l(s),new Error("Settings update failed");return d}catch(t){throw p&&o(p),l(s),t}}async function u(t,e="posts"){return a()({path:`/wp/v2/${e}/${t}?force=true`,method:"DELETE"})}},5337:(t,e,s)=>{s.d(e,{BJ:()=>l,IL:()=>c,Wz:()=>p});var r=s(1455),a=s.n(r);const i=new Map,n=new Map,o=3e5;async function l(t,e={}){const{skipCache:s=!1,ttl:r=o}=e,l=function(t){if("GET"!==(t.method||"GET").toUpperCase())return null;let e=t.path||t.url||"";if(t.data&&"object"==typeof t.data){const s=new URLSearchParams(t.data).toString();s&&(e+=(e.includes("?")?"&":"?")+s)}return`GET:${e}`}(t);if(!l)return a()(t);if(!s&&i.has(l))return i.get(l);if(!s){const t=n.get(l);if(t&&Date.now()-t.timestamp(n.set(l,{data:t,timestamp:Date.now()}),i.delete(l),t)).catch(t=>{throw i.delete(l),t});return i.set(l,c),c}function c(){n.clear(),i.clear()}function p(t,e){const s=`GET:${t}`;n.set(s,{data:e,timestamp:Date.now()})}},5815:(t,e,s)=>{s.d(e,{Q8:()=>p,iA:()=>c,rr:()=>d});var r=s(6087),a=s(790);const i="\n@keyframes prpl-shimmer {\n\t0% { background-position: 200% 0; }\n\t100% { background-position: -200% 0; }\n}\n";let n=!1;function o(){if(n||"undefined"==typeof document)return;const t=document.createElement("style");t.id="prpl-skeleton-keyframes",t.textContent=i,document.head.appendChild(t),n=!0}const l={background:"linear-gradient(\n\t\t90deg,\n\t\tvar(--prpl-color-gauge-remain, #f0f0f0) 25%,\n\t\tvar(--prpl-color-border, #e0e0e0) 50%,\n\t\tvar(--prpl-color-gauge-remain, #f0f0f0) 75%\n\t)",backgroundSize:"200% 100%",animation:"prpl-shimmer 1.5s ease-in-out infinite",borderRadius:"var(--prpl-border-radius, 8px)"};function c({width:t="100%",height:e="1em",className:s="",style:i={}}){return(0,r.useEffect)(()=>{o()},[]),(0,a.jsx)("div",{className:s||void 0,style:{...l,width:t,height:e,...i}})}function p({size:t="40px",className:e="",style:s={}}){return(0,r.useEffect)(()=>{o()},[]),(0,a.jsx)("div",{className:e||void 0,style:{...l,width:t,height:t,borderRadius:"50%",...s}})}function d({width:t="100%",lines:e=1,className:s="",style:i={},lastShort:n=!0}){return(0,r.useEffect)(()=>{o()},[]),1===e?(0,a.jsx)(c,{width:t,height:"1em",className:s,style:i}):(0,a.jsx)("div",{style:{display:"flex",flexDirection:"column",...i},children:Array.from({length:e}).map((r,i)=>(0,a.jsx)(c,{width:n&&i===e-1?"70%":t,height:"1em",className:s,style:{marginBottom:i{t.exports=window.wp.element},6174:(t,e,s)=>{var r=s(6087),a=s(7723),i=s(8537),n=s(1362),o=s(2619),l=s(1455),c=s.n(l),p=s(4333);const d={"hello-world":async function(t){const e=t.prpl_task_data?.postId||t.postId||window.helloWorldData?.postId;return e&&await(0,p.ys)(e,"posts"),{success:!0}},"sample-page":async function(t){const e=t.prpl_task_data?.pageId||t.pageId||window.samplePageData?.postId;return e&&await(0,p.ys)(e,"pages"),{success:!0}},"remove-terms-without-posts":async function(t){const e=t.prpl_task_data?.termIds||t.termIds||window.removeTermsWithoutPostsData?.termIds||[],s=t.prpl_task_data?.taxonomy||t.taxonomy||window.removeTermsWithoutPostsData?.taxonomy||"category";if(0===e.length)return{success:!0};const r="category"===s?"categories":s;return await Promise.all(e.map(t=>c()({path:`/wp/v2/${r}/${t}?force=true`,method:"DELETE"}))),{success:!0}},"rename-uncategorized-category":async()=>({success:!0}),"core-siteicon":async()=>({success:!0}),"yoast-organization-logo":async()=>({success:!0}),"update-term-description":async()=>({success:!0})};var u=s(1971);const g=(0,r.lazy)(()=>s.e(510).then(s.bind(s,7815))),h=(0,r.lazy)(()=>s.e(941).then(s.bind(s,7726))),m=(0,r.lazy)(()=>s.e(529).then(s.bind(s,4506))),y=(0,r.lazy)(()=>s.e(624).then(s.bind(s,7249))),b=(0,r.lazy)(()=>s.e(4).then(s.bind(s,8217))),k=(0,r.lazy)(()=>s.e(152).then(s.bind(s,869))),_=(0,r.lazy)(()=>s.e(454).then(s.bind(s,1599))),f=(0,r.lazy)(()=>s.e(648).then(s.bind(s,3369))),v=(0,r.lazy)(()=>s.e(426).then(s.bind(s,3043))),w=(0,r.lazy)(()=>s.e(717).then(s.bind(s,8646))),T=(0,r.lazy)(()=>s.e(496).then(s.bind(s,4485))),x={"core-blogdescription":g,"set-date-format":h,"select-timezone":m,"core-permalink-structure":y,"core-siteicon":b,"select-locale":k,"disable-comments":_,"disable-comment-pagination":_,"search-engine-visibility":_,"yoast-author-archive":f,"yoast-date-archive":f,"yoast-format-archive":f,"yoast-media-pages":f,"yoast-crawl-settings-emoji-scripts":f,"yoast-crawl-settings-feed-authors":f,"yoast-crawl-settings-feed-global-comments":f,"yoast-organization-logo":b,"aioseo-author-archive":v,"aioseo-date-archive":v,"aioseo-media-pages":v,"aioseo-crawl-settings-feed-authors":v,"aioseo-crawl-settings-feed-comments":v,"rename-uncategorized-category":w,"hello-world":w,"sample-page":w,"update-term-description":w,"remove-terms-without-posts":w,"improve-pdf-handling":(0,r.lazy)(()=>s.e(869).then(s.bind(s,3831))),"sending-email":T,"fewer-tags":w,"seo-plugin":w,"badge-streak":(0,r.lazy)(()=>s.e(937).then(s.bind(s,9886))),"subscribe-form":(0,r.lazy)(()=>s.e(770).then(s.bind(s,2903))),"upgrade-tasks":(0,r.lazy)(()=>s.e(880).then(s.bind(s,841))),"monthly-badges":(0,r.lazy)(()=>s.e(393).then(s.bind(s,8670)))};var I=s(6230),D=s(790);function S({onComplete:t,config:e={}}){const[s,a]=(0,r.useState)(null),[i,n]=(0,r.useState)(null),l=(0,r.useCallback)((t,e)=>{t&&e?(a(t),n(e)):console.warn("PopoverManager: Invalid popover open event - missing taskId or task")},[]),c=(0,r.useCallback)(t=>{t!==s&&t||(a(null),n(null))},[s]);!function(t,e){const s="prpl/popover-manager",a="prpl.popover.open",i="prpl.popover.close",n=(0,r.useRef)(t),l=(0,r.useRef)(e);(0,r.useEffect)(()=>{n.current=t,l.current=e},[t,e]);const c=(0,r.useCallback)((t,e)=>{n.current(t,e)},[]),p=(0,r.useCallback)(t=>{l.current(t)},[]);(0,r.useEffect)(()=>{try{(0,o.addAction)(a,s,c),(0,o.addAction)(i,s,p)}catch(t){console.error("Failed to register popover hooks:",t)}return()=>{try{(0,o.removeAction)(a,s),(0,o.removeAction)(i,s)}catch(t){console.error("Failed to remove popover hooks:",t)}}},[c,p])}(l,c);const p=(0,r.useCallback)(async(e,s)=>{if(t)try{const r=s?.id||e;if(!r)throw new Error("Invalid task ID for submission");await t(r,s),a(null),n(null)}catch(t){console.error("PopoverManager: Error submitting popover form:",t)}else console.warn("PopoverManager: onComplete callback not provided")},[t]),g=(y=i,async t=>{if(!t)return console.warn("useCustomSubmitHandlers: No taskId provided"),{success:!1};const e=function(t){return d[t]||null}(t);return e?e(y||{}):{success:!0}}),h=(0,u.p)(i,s),m=h&&x[h]||null;var y;return i&&!m?(console.warn("PopoverManager: No popover component found for task ID:",h),null):m&&i?(0,D.jsx)(r.Suspense,{fallback:(0,D.jsx)(I.A,{}),children:(0,D.jsx)(m,{task:i,onSubmit:p,onClose:()=>c(s),onCustomSubmit:g,config:e})}):null}var A=s(8343),C=s(8281);const E={list:{listStyle:"none",padding:0,margin:"0 0 var(--prpl-padding) 0"},loading:{display:"block",backgroundColor:"var(--prpl-background-activity)",padding:"calc(var(--prpl-padding) / 2)"},empty:{display:"block",backgroundColor:"var(--prpl-background-activity)",padding:"calc(var(--prpl-padding) / 2)"},toggleButton:{background:"none",border:"none",padding:0,color:"var(--prpl-color-link)",textDecoration:"underline",cursor:"pointer",fontSize:"inherit",fontFamily:"inherit"},hiddenList:{display:"none"}},P=(0,r.forwardRef)(function({tasks:t,celebratingTaskIds:e,skeletonCount:s=0,onComplete:r,onSnooze:a,onDelete:i,onMove:n,onTitleChange:o},l){return(0,D.jsxs)("ul",{id:"prpl-suggested-tasks-list",className:"prpl-suggested-tasks-list",style:E.list,ref:l,children:[t.map((t,s)=>(0,D.jsx)(A.A,{task:t,index:s,isUserTask:"user"===t.prpl_provider?.slug,isCelebrating:e.has(t.id),onComplete:r,onSnooze:a,onDelete:i,onMove:n,onTitleChange:o},t.id)),s>0&&Array(s).fill(0).map((e,s)=>(0,D.jsx)(C.A,{index:t.length+s},`skeleton-${s}`))]})});function O({hasMore:t,canCollapse:e,onLoadMore:s,onCollapse:r}){return t?(0,D.jsx)("p",{className:"prpl-show-all-tasks",children:(0,D.jsx)("button",{type:"button",id:"prpl-load-more-recommendations",className:"prpl-toggle-all-recommendations-button",style:E.toggleButton,onClick:s,children:(0,a.__)("Load more tasks","progress-planner")})}):e?(0,D.jsx)("p",{className:"prpl-show-all-tasks",children:(0,D.jsx)("button",{type:"button",id:"prpl-collapse-recommendations",className:"prpl-toggle-all-recommendations-button",style:E.toggleButton,onClick:r,children:(0,a.__)("Show top 5","progress-planner")})}):null}var M=s(9251),j=s(3572),U=s(8039),R=s(9453),z=s(7401),L=s(9277),N=s(5815);function F({count:t=4}){return(0,D.jsxs)(D.Fragment,{children:[(0,D.jsx)("div",{style:{marginBottom:"1rem"},children:(0,D.jsx)(N.rr,{lines:2})}),(0,D.jsx)(C.P,{count:t})]})}var B=s(8493),J=s(8864);s(714),(0,n.Cu)({id:"suggested-tasks",component:function({config:t={}}){const[e,s]=(0,r.useState)([]),[n,o]=(0,r.useState)(!0),[l,c]=(0,r.useState)(5),[p,d]=(0,r.useState)(new Set),[u,g]=(0,r.useState)(!0),h=(0,r.useRef)(null),m=(0,r.useRef)(new Map),y=(0,r.useRef)(0),b=(0,r.useMemo)(()=>e.slice(0,l),[e,l]),k=(0,r.useMemo)(()=>n||!u?0:Math.max(0,5-b.length),[n,u,b.length]),_=u||e.length>l,f=l>=e.length&&!u,v=l>5&&f&&e.length>5;(0,j.h)();const{celebrate:w}=(0,U.u)(),T=(0,J.fX)(t=>t.onTaskCompleted),x=(0,r.useCallback)((t,e,s)=>{if(m.current.has(e.id))return t;m.current.set(e.id,e);let r=t.length;for(let e=0;e{if(t.prpl_task_actions&&t.prpl_task_actions.length>0)return t;let e=t.prpl_provider?.slug||t.provider_id||t.meta?.provider_id||"";if(!e&&t.slug&&(e=t.slug),!e&&t.prpl_recommendations_provider&&Array.isArray(t.prpl_recommendations_provider)){const s=t.prpl_recommendations_provider[0];if(s&&"object"==typeof s&&s.slug)e=s.slug;else if("number"==typeof s&&t._embedded&&t._embedded["wp:term"]&&t._embedded["wp:term"][0]){const r=t._embedded["wp:term"].flat().find(t=>t&&"prpl_recommendations_provider"===t.taxonomy&&t.id===s);r&&r.slug&&(e=r.slug)}}if(!e)return t;const s=(0,B.CI)(e);if(!s||!s.getTaskActions)return t;try{const e=s.getTaskActions(t);if(e&&e.length>0)return{...t,prpl_task_actions:e}}catch(t){console.error(`Error generating actions for task provider "${e}":`,t)}return t},[]),A=(0,r.useCallback)((t,e)=>{if(m.current.has(t.id))return;void 0===t.prpl_priority&&(t.prpl_priority=e);const r=I(t);s(t=>x(t,r,e)),y.current++},[I,x]),C=(0,r.useCallback)(async t=>{if(!(0,B.wA)())return void g(!1);const e=t-y.current;if(e<=0)return;const s=await(0,B.Sm)(e,A);g(!s.complete)},[A]),N=(0,r.useCallback)(async()=>{const t=(0,B._C)();e.length-l<=0&&u&&await C(y.current+t+1)},[e.length,l,u,C]);(0,r.useEffect)(()=>{let e=!0;return async function(){if(o(!0),!t?.delayCelebration)try{const t=await(0,M.j)({status:"pending",perPage:100,excludeProvider:"user",needsPagination:!1});t.tasks.length>0&&e&&(t.tasks.forEach(t=>{A(t,t.prpl_priority||50)}),t.tasks.forEach(t=>{(0,M.Rt)(t.id).catch(()=>{})}),setTimeout(()=>{if(!e)return;const r=new Set(t.tasks.map(t=>t.id));d(r),w(h.current),setTimeout(()=>{e&&(s(t=>t.filter(t=>!r.has(t.id))),r.forEach(t=>{m.current.delete(t),y.current--}),d(new Set),(0,R.Z)())},2e3)},3e3))}catch{}const r=5+(0,B._C)();let a=!1;const i=await(0,B.Sm)(r,(t,s)=>{e&&(A(t,s),a||(a=!0,o(!1),(0,R.Z)(100)))});e&&(g(!i.complete),a||(o(!1),(0,R.Z)(100)))}(),()=>{e=!1}},[t,w,A]);const W=(0,r.useCallback)(async(t,e)=>{try{d(e=>new Set([...e,t])),await(0,M.Rt)(t),(0,M.e4)(t,"complete");const r=(0,z.$)(e);if(r>0&&T(e,r),r>0&&h.current){const e=h.current.querySelector(`[data-post-id="${t}"]`);w(e)}setTimeout(async()=>{s(e=>e.filter(e=>e.id!==t)),m.current.delete(t),d(e=>{const s=new Set(e);return s.delete(t),s}),await N(),(0,R.Z)()},2e3)}catch{d(e=>{const s=new Set(e);return s.delete(t),s})}},[w,N,T]),H=(0,r.useCallback)(async(t,e)=>{try{await(0,M.cy)(t,e),s(e=>e.filter(e=>e.id!==t)),m.current.delete(t),await N(),(0,R.Z)()}catch{}},[N]),$=(0,r.useCallback)(async t=>{try{await(0,M.vq)(t),(0,M.e4)(t,"delete"),s(e=>e.filter(e=>e.id!==t)),m.current.delete(t),await N(),(0,R.Z)(500)}catch{}},[N]),q=(0,r.useCallback)(async(t,e)=>{try{await(0,M.lC)(t,{title:e})}catch{}},[]),Y=(0,r.useCallback)(async(t,r)=>{const a=e.findIndex(e=>e.id===t);if(-1===a)return;const i="up"===r?a-1:a+1;if(i<0||i>=e.length)return;const n=[...e],[o]=n.splice(a,1);n.splice(i,0,o),s(n),n.forEach((t,e)=>{(0,M.lC)(t.id,{menu_order:e}).catch(()=>{})})},[e]),Z=(0,r.useCallback)(async()=>{const t=l+5;c(t);const e=t+(0,B._C)();y.current{c(5),(0,R.Z)(100)},[]),G=(0,i.decodeEntities)(t?.title||(0,a.sprintf)(/* translators: %s: Ravi's name. */ /* translators: %s: Ravi's name. */
+(0,a.__)("%s's Recommendations","progress-planner"),t?.raviName||"Ravi")),X=(0,i.decodeEntities)(t?.description||(0,a.sprintf)(/* translators: %s: Ravi's name. */ /* translators: %s: Ravi's name. */
+(0,a.__)("Complete a task from %s's Recommendations to improve your site and earn points toward this month's badge!","progress-planner"),t?.raviName||"Ravi"));return n?(0,D.jsxs)(D.Fragment,{children:[(0,D.jsx)(L.A,{title:G}),(0,D.jsx)(F,{count:4})]}):0!==e.length||u?(0,D.jsxs)(D.Fragment,{children:[(0,D.jsx)(L.A,{title:G}),(0,D.jsx)("p",{className:"prpl-suggested-tasks-widget-description",children:X}),(0,D.jsx)(S,{onComplete:W,config:t}),(0,D.jsx)("ul",{style:E.hiddenList}),(0,D.jsx)(P,{ref:h,tasks:b,celebratingTaskIds:p,skeletonCount:k,onComplete:W,onSnooze:H,onDelete:$,onMove:Y,onTitleChange:q}),(0,D.jsx)(O,{hasMore:_,canCollapse:v,onLoadMore:Z,onCollapse:V})]}):(0,D.jsxs)(D.Fragment,{children:[(0,D.jsx)(L.A,{title:G}),(0,D.jsx)("p",{className:"prpl-suggested-tasks-widget-description",children:X}),(0,D.jsx)("ul",{id:"prpl-suggested-tasks-list",className:"prpl-suggested-tasks-list",style:E.list,ref:h}),(0,D.jsxs)("p",{className:"prpl-no-suggested-tasks",style:E.empty,children:[(0,a.__)("You have completed all recommended tasks.","progress-planner"),(0,D.jsx)("br",{}),(0,a.__)("Check back later for new tasks!","progress-planner")]})]})},priority:1,width:2,forceLastColumn:!1,title:(0,a.__)("Ravi's Recommendations","progress-planner")})},6230:(t,e,s)=>{s.d(e,{A:()=>i});var r=s(7723),a=s(790);function i(){return(0,a.jsxs)("div",{className:"prpl-popover-loading",style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",padding:"2rem",minHeight:"200px"},children:[(0,a.jsx)("span",{className:"spinner is-active",style:{float:"none",margin:"0 0 1rem 0"}}),(0,a.jsx)("p",{style:{margin:0,color:"#666"},children:(0,r.__)("Loading…","progress-planner")})]})}},7401:(t,e,s)=>{s.d(e,{$:()=>a});var r=s(8493);function a(t){if(void 0!==t.prpl_points&&null!==t.prpl_points)return parseInt(t.prpl_points,10)||0;const e=t.prpl_provider?.slug;if(e){const s=(0,r.DF)(e);if(s){const a=(0,r.CI)(e);if(a&&"function"==typeof a.getPoints)return a.getPoints(t);if(void 0!==s.points)return s.points}}return 1}},7723:t=>{t.exports=window.wp.i18n},8039:(t,e,s)=>{s.d(e,{u:()=>o});var r=s(6087),a={};!function t(e,s,r,a){var i=!!(e.Worker&&e.Blob&&e.Promise&&e.OffscreenCanvas&&e.OffscreenCanvasRenderingContext2D&&e.HTMLCanvasElement&&e.HTMLCanvasElement.prototype.transferControlToOffscreen&&e.URL&&e.URL.createObjectURL),n="function"==typeof Path2D&&"function"==typeof DOMMatrix,o=function(){if(!e.OffscreenCanvas)return!1;try{var t=new OffscreenCanvas(1,1),s=t.getContext("2d");s.fillRect(0,0,1,1);var r=t.transferToImageBitmap();s.createPattern(r,"no-repeat")}catch(t){return!1}return!0}();function l(){}function c(t){var r=s.exports.Promise,a=void 0!==r?r:e.Promise;return"function"==typeof a?new a(t):(t(l,l),null)}var p,d,u,g,h,m,y,b,k,_,f,v=(p=o,d=new Map,{transform:function(t){if(p)return t;if(d.has(t))return d.get(t);var e=new OffscreenCanvas(t.width,t.height);return e.getContext("2d").drawImage(t,0,0),d.set(t,e),e},clear:function(){d.clear()}}),w=(h=Math.floor(1e3/60),m={},y=0,"function"==typeof requestAnimationFrame&&"function"==typeof cancelAnimationFrame?(u=function(t){var e=Math.random();return m[e]=requestAnimationFrame(function s(r){y===r||y+h-1{const e=t?.closest(".prpl-suggested-tasks-list")||document.querySelector(".prpl-widget-wrapper.prpl-suggested-tasks .prpl-suggested-tasks-list"),s=e?{x:(e.getBoundingClientRect().left+e.offsetWidth/2)/window.innerWidth,y:(e.getBoundingClientRect().top+50)/window.innerHeight}:{x:.5,y:.3},r=window.prplCelebrate||{},a={spread:360,ticks:50,gravity:1,decay:.94,startVelocity:30,shapes:["star"],colors:["FFE400","FFBD00","E89400","FFCA6C","FDFFB8"]};let n=[{particleCount:30,scalar:4,shapes:["image"],shapeOptions:{image:[{src:r.raviIconUrl},{src:r.raviIconUrl},{src:r.raviIconUrl},{src:r.monthIconUrl},{src:r.contentIconUrl},{src:r.maintenanceIconUrl}]}}];void 0!==r.confettiOptions&&Array.isArray(r.confettiOptions)&&r.confettiOptions.length>0&&(n=r.confettiOptions),[0,100,200].forEach(t=>{setTimeout(()=>{n.forEach(t=>{i({...a,...t,origin:s})})},t)}),document.querySelectorAll("#adminmenu #toplevel_page_progress-planner .update-plugins").forEach(t=>t.remove())},[]),triggerGridResize:(0,r.useCallback)(()=>{(0,n.Z)()},[])}}},8281:(t,e,s)=>{s.d(e,{A:()=>i,P:()=>n});var r=s(5815),a=s(790);function i({index:t=0,showActions:e=!0}){const s={margin:0,padding:"0.75rem 0.5rem 0.625rem 0.5rem",display:"grid",gridTemplateColumns:"1.5rem 1fr 3.5rem",gap:"0.25rem 0.5rem",position:"relative",lineHeight:1,backgroundColor:t%2==0?"var(--prpl-background-table)":"transparent"};return(0,a.jsxs)("li",{style:s,children:[(0,a.jsx)("div",{style:{display:"flex",width:"100%",flexDirection:"column",alignItems:"center",justifyContent:"center"},children:(0,a.jsx)(r.iA,{width:"1rem",height:"1rem",style:{borderRadius:"3px"}})}),(0,a.jsx)("div",{style:{display:"flex",alignItems:"center",gap:"0.5rem"},children:(0,a.jsx)(r.iA,{width:60+30*Math.random()+"%",height:"1rem"})}),(0,a.jsx)("div",{style:{display:"flex",gap:"0.5rem",alignItems:"center",justifyContent:"flex-end",gridRowEnd:"span 2"},children:(0,a.jsx)(r.Q8,{size:"1.5rem"})}),e&&(0,a.jsxs)("div",{style:{gridColumn:"2 / span 1",display:"flex",gap:"0.5rem",paddingTop:"0.25rem"},children:[(0,a.jsx)(r.iA,{width:"4rem",height:"1.5rem"}),(0,a.jsx)(r.iA,{width:"4rem",height:"1.5rem"})]})]})}function n({count:t=4}){return(0,a.jsx)("ul",{style:{listStyle:"none",padding:0,margin:0},children:Array.from({length:t}).map((t,e)=>(0,a.jsx)(i,{index:e},e))})}},8343:(t,e,s)=>{s.d(e,{A:()=>q});var r=s(6087),a=s(2619),i=s(8493),n=s(7723),o=s(790);const l={fontSize:"var(--prpl-font-size-small)",color:"var(--prpl-color-link)",lineHeight:1,textDecoration:"none",padding:0,background:"none",border:"none",cursor:"pointer"};function c({as:t="button",style:e,children:s,...a}){const[i,n]=(0,r.useState)(!1),c={...l,textDecoration:i?"underline":"none",...e},p="button"===t?{type:"button"}:{};return(0,o.jsx)(t,{...p,...a,style:c,onMouseEnter:()=>n(!0),onMouseLeave:()=>n(!1),children:s})}function p({taskId:t,taskTitle:e,onClick:s}){return(0,o.jsx)(c,{"data-task-id":t,"data-task-title":e,"data-action":"complete","data-target":"complete",title:(0,n.__)("Mark as complete","progress-planner"),onClick:t=>{t.preventDefault(),s?.()},children:(0,n.__)("Mark as complete","progress-planner")})}var d=s(1059);function u(t){return{margin:0,padding:"0.75rem 0.5rem 0.625rem 0.5rem",display:"grid",gridTemplateColumns:"1.5rem 1fr 3.5rem",gap:"0.25rem 0.5rem",position:"relative",lineHeight:1,backgroundColor:t%2==0?"var(--prpl-background-table)":"transparent"}}const g={display:"flex",width:"100%",gap:0,flexDirection:"column",alignItems:"center",justifyContent:"center"},h={display:"flex",alignItems:"center",gap:"0.5rem",justifyContent:"space-between"};function m(t){return{width:"100%",color:"var(--prpl-color-text)",fontSize:"1rem",margin:0,fontWeight:500,...t?{textDecoration:"line-through"}:{}}}const y={display:"flex",gap:"0.5rem",alignItems:"center",justifyContent:"flex-end",gridRowEnd:"span 2"},b={fontSize:"var(--prpl-font-size-xs)",fontWeight:700,color:"var(--prpl-text-point)",backgroundColor:"var(--prpl-background-point)",width:"1.5rem",height:"1.5rem",borderRadius:"50%",display:"flex",alignItems:"center",justifyContent:"center"},k={padding:"0.1rem",lineHeight:0,margin:0,background:"none",border:"none",cursor:"pointer"},_={...k,padding:0,color:"var(--prpl-color-ui-icon)",boxShadow:"none",marginTop:"1px"},f={display:"flex",justifyContent:"flex-start",flexWrap:"wrap",position:"absolute",left:"calc(-8px - 0.5rem)",top:"50%",transform:"translateY(-50%)",padding:"10px 10px 10px 0"},v={display:"flex",width:"100%",gap:0,flexDirection:"column",alignItems:"center",justifyContent:"center"},w={...k,padding:0,height:"0.75rem",color:"var(--prpl-color-ui-icon)",boxShadow:"none",marginTop:"1px"},T={gridColumn:"2 / span 1",display:"flex"},x={margin:0,flexShrink:0},I={transform:"translate(-20%, calc(100% + 10px))"},D={left:25,right:"auto",transform:"translate(-5px, -10px) rotate(90deg)"},S=[{key:"1-week",label:(0,n.__)("1 week","progress-planner")},{key:"1-month",label:(0,n.__)("1 month","progress-planner")},{key:"3-months",label:(0,n.__)("3 months","progress-planner")},{key:"6-months",label:(0,n.__)("6 months","progress-planner")},{key:"1-year",label:(0,n.__)("1 year","progress-planner")},{key:"forever",label:(0,n.__)("forever","progress-planner")}],A={fieldset:{border:"none",padding:0,margin:0},legend:{display:"block",width:"100%"},legendTitle:{display:"block",fontWeight:500,marginBottom:"0.25rem"},toggleButton:{display:"flex",justifyContent:"space-between",width:"100%",marginTop:"0.5rem",padding:"0.5rem",backgroundColor:"#fff",border:"1px solid #dcdcde",borderRadius:"var(--prpl-border-radius)",lineHeight:1,textAlign:"start",cursor:"pointer"},radioInput:{display:"none"}};function C(t){return{display:t?"block":"none",marginTop:"0.75rem"}}function E(t,e,s){const r={display:"block",padding:"0.5rem",cursor:"pointer",backgroundColor:s?"var(--prpl-color-gauge-remain)":"#fff"};return t>0&&(r.borderTop="1px solid #dcdcde"),0===t&&(r.borderTopLeftRadius="var(--prpl-border-radius)",r.borderTopRightRadius="var(--prpl-border-radius)"),t===e-1&&(r.borderBottomLeftRadius="var(--prpl-border-radius)",r.borderBottomRightRadius="var(--prpl-border-radius)"),r}function P({taskId:t,onSnooze:e}){const[s,a]=(0,r.useState)(!1),[i,l]=(0,r.useState)(null),c=(0,r.useCallback)(()=>{a(!1),l(null)},[]),p=t=>{const s=t.target.value;e?.(s)};return(0,o.jsx)(d.A,{triggerContent:(0,n.__)("Snooze","progress-planner"),tooltipStyle:I,arrowStyle:D,onClose:c,children:(0,o.jsxs)("fieldset",{style:A.fieldset,children:[(0,o.jsxs)("legend",{style:A.legend,children:[(0,o.jsx)("span",{style:A.legendTitle,children:(0,n.__)("Snooze this task?","progress-planner")}),(0,o.jsxs)("button",{type:"button",className:"prpl-toggle-radio-group",style:A.toggleButton,onClick:t=>{t.preventDefault(),t.stopPropagation(),a(!s)},children:[(0,o.jsx)("span",{children:(0,n.__)("How long?","progress-planner")}),(0,o.jsx)("span",{style:(u=s,{transform:u?"rotate(270deg)":"rotate(90deg)",transition:"transform 0.2s ease"}),children:"›"})]})]}),(0,o.jsx)("div",{style:C(s),children:S.map((e,s)=>{const r=`snooze-${t}-${e.key}`;return(0,o.jsxs)("label",{htmlFor:r,style:E(s,S.length,i===e.key),onMouseEnter:()=>l(e.key),onMouseLeave:()=>l(null),children:[(0,o.jsx)("input",{type:"radio",id:r,name:`snooze-duration-${t}`,value:e.key,style:A.radioInput,onChange:p}),e.label]},e.key)})})]})});var u}function O({externalUrl:t,content:e}){return t?(0,o.jsx)(c,{as:"a",href:t,target:"_blank",rel:"noopener noreferrer",children:(0,n.__)("Why is this important?","progress-planner")}):e?(0,o.jsx)(d.A,{triggerContent:(0,n.__)("Info","progress-planner"),tooltipStyle:I,arrowStyle:D,children:(0,o.jsx)("div",{dangerouslySetInnerHTML:{__html:e}})}):null}function M({href:t,label:e,target:s="_self",onClick:r,className:a=""}){return(0,o.jsx)(c,{as:"a",className:a||void 0,href:t||"#",target:s,rel:"_blank"===s?"noopener noreferrer":void 0,onClick:r?t=>{r&&(t.preventDefault(),r(t))}:void 0,children:e})}function j({popoverId:t,label:e,task:s,taskContext:r,eventName:i}){return(0,o.jsx)(c,{onClick:e=>{e.preventDefault();const n=document.getElementById(t);if(n?.showPopover&&n.showPopover(),s&&(0,a.doAction)("prpl.popover.open",t,s),i&&r){const t=new CustomEvent(i,{bubbles:!0,detail:r});e.target.dispatchEvent(t)}},children:e})}function U({postId:t,taskTitle:e,onClick:s}){return(0,o.jsx)(c,{className:"prpl-suggested-task-button trash","data-post-id":t,title:`${(0,n.__)("Delete","progress-planner")}: ${e}`,onClick:t=>{t.preventDefault(),s?.()},children:(0,n.__)("Delete","progress-planner")})}const R={display:"inline-block",width:1,height:"0.75rem",background:"var(--prpl-color-text)",alignSelf:"center"},z={display:"inline-flex",position:"relative",textDecoration:"none"};function L(t,e,s,r,a){const i=e.title?.rendered||e.title||"";switch(t.type){case"complete":return(0,o.jsx)(p,{taskId:t.taskId,taskTitle:t.taskTitle||i,onClick:()=>s(e.id,e)});case"snooze":return(0,o.jsx)(P,{taskId:t.taskId,onSnooze:t=>r(e.id,t)});case"info":return(0,o.jsx)(O,{externalUrl:t.externalUrl,content:t.content});case"link":return t.inlineEdit?(0,o.jsx)(M,{href:"#",label:t.label,onClick:t=>{t.preventDefault();const e=t.target.closest("li.prpl-suggested-task"),s=e?.querySelector(".prpl-task-title span");s?.focus()}}):(0,o.jsx)(M,{href:t.href,label:t.label,target:t.target,className:t.className});case"popover":return(0,o.jsx)(j,{popoverId:t.popoverId,label:t.label,task:e,taskContext:t.taskContext,eventName:t.eventName});case"delete":return(0,o.jsx)(U,{postId:e.id,taskTitle:i,onClick:()=>a(e.id)});default:return null}}function N({task:t,isUserTask:e,isActionsVisible:s=!1,isCelebrating:n=!1,onComplete:l,onSnooze:c,onDelete:p}){const d=(0,r.useRef)(null),u=(0,r.useRef)([]),g=(0,r.useCallback)((t,e)=>s=>{s.preventDefault(),l(t,e)},[l]),h=(0,r.useCallback)(t=>e=>{c(t,e.target.value)},[c]),m=(0,r.useCallback)((t,e)=>s=>{s.preventDefault(),(0,a.doAction)("prpl.popover.open",t,e)},[]),y=(0,r.useCallback)(t=>e=>{e.preventDefault(),p(t)},[p]),b=(0,r.useMemo)(()=>{if(t.prpl_task_actions&&Array.isArray(t.prpl_task_actions)&&t.prpl_task_actions.length>0)return t.prpl_task_actions.map(t=>"string"==typeof t?{type:"html",html:t}:t);let e=t.prpl_provider?.slug||t.provider_id||t.meta?.provider_id||"";if(!e&&t.slug&&(e=t.slug),!e&&t.prpl_recommendations_provider&&Array.isArray(t.prpl_recommendations_provider)){const s=t.prpl_recommendations_provider[0];if(s&&"object"==typeof s&&s.slug)e=s.slug;else if("number"==typeof s&&t._embedded?.["wp:term"]?.[0]){const r=t._embedded["wp:term"].flat().find(t=>"prpl_recommendations_provider"===t?.taxonomy&&t.id===s);r?.slug&&(e=r.slug)}}if(!e)return[];const s=(0,i.CI)(e);if(!s?.getTaskActions)return[];try{return s.getTaskActions(t)||[]}catch(t){return console.error(`Error generating actions for task provider "${e}":`,t),[]}},[t]);(0,r.useEffect)(()=>{if(!d.current)return;const e=d.current;return u.current=[],b.some(t=>"html"===t.type)?(e.querySelectorAll('[data-action="complete"]').forEach(e=>{const s=g(t.id,t);e.addEventListener("click",s),u.current.push({element:e,type:"click",handler:s})}),e.querySelectorAll('.prpl-snooze-duration-radio-group input[type="radio"]').forEach(e=>{const s=h(t.id);e.addEventListener("change",s),u.current.push({element:e,type:"change",handler:s})}),e.querySelectorAll('a[onclick*="showPopover"]').forEach(e=>{const s=e.getAttribute("onclick"),r=s?.match(/getElementById\(['"]([^'"]+)['"]\)/);if(r){const s=r[1].replace("prpl-popover-","");e.removeAttribute("onclick");const a=m(s,t);e.addEventListener("click",a),u.current.push({element:e,type:"click",handler:a})}}),e.querySelectorAll(".prpl-suggested-task-button.trash").forEach(e=>{const s=y(t.id);e.addEventListener("click",s),u.current.push({element:e,type:"click",handler:s})}),()=>{u.current.forEach(({element:t,type:e,handler:s})=>{t.removeEventListener(e,s)}),u.current=[]}):void 0},[t,b,g,h,m,y]);const k=function(t,e){return{display:"flex",justifyContent:"flex-start",flexWrap:"wrap",position:"relative",paddingTop:"2px",gap:"0.4rem",alignItems:"baseline",visibility:t?"visible":"hidden",pointerEvents:e?"none":void 0}}(s,n);if(0===b.length&&!e)return(0,o.jsx)("div",{style:k});const _=b.map((e,s)=>(0,o.jsx)("span",{className:"tooltip-action",style:z,children:"html"===e.type?(0,o.jsx)("span",{dangerouslySetInnerHTML:{__html:e.html}}):L(e,t,l,c,p)},s));e&&_.push((0,o.jsx)("span",{className:"tooltip-action",style:z,children:(0,o.jsx)(U,{postId:t.id,taskTitle:t.title?.rendered||t.title,onClick:()=>p(t.id)})},"user-delete"));const f=[];return _.forEach((t,e)=>{e>0&&f.push((0,o.jsx)("span",{className:"prpl-action-separator",style:R},`sep-${e}`)),f.push(t)}),(0,o.jsx)("div",{style:k,ref:d,children:f})}var F=s(9061);function B({isUserTask:t,taskIsCompleted:e,isCelebrating:s,task:r,onChange:a}){return t?(0,o.jsx)("div",{className:"prpl-suggested-task-checkbox-wrapper",style:g,children:(0,o.jsxs)("label",{style:g,children:[(0,o.jsx)("input",{type:"checkbox",className:"prpl-suggested-task-checkbox",onChange:a,style:{...x,...s?{opacity:.5,borderColor:"#0773bf",backgroundColor:"#effbfe"}:{}},checked:e,disabled:s}),(0,o.jsxs)("span",{className:"screen-reader-text",children:[r.title?.rendered||r.title,":"," ",(0,n.__)("Mark as complete","progress-planner")]})]})}):(0,o.jsx)("div",{className:"prpl-suggested-task-checkbox-wrapper",style:g,children:(0,o.jsx)(F.A,{name:"arrow",style:{width:"0.75rem",color:"var(--prpl-color-ui-icon)"}})})}function J({task:t,isUserTask:e,isCompleted:s,isCelebrating:r,titleRef:a,onKeyDown:i,onInput:l}){const c=t.title?.rendered||t.title,p=function(t){return{textDecoration:"none",backgroundImage:"linear-gradient(#000, #000)",backgroundRepeat:"no-repeat",backgroundPosition:"center left",backgroundSize:t?"100% 1px":"0% 1px",transition:"background-size 500ms ease-in-out"}}(r);return(0,o.jsx)("div",{className:"prpl-suggested-task-title-wrapper",style:h,children:(0,o.jsx)("h3",{className:"prpl-task-title",style:m(s),children:e&&!s?(0,o.jsx)("span",{ref:a,contentEditable:"plaintext-only",role:"textbox",tabIndex:0,"aria-label":(0,n.__)("Edit task title","progress-planner"),"aria-multiline":"false",onKeyDown:i,onInput:l,suppressContentEditableWarning:!0,style:p,dangerouslySetInnerHTML:{__html:c}}):(0,o.jsx)("span",{style:p,dangerouslySetInnerHTML:{__html:c}})})})}var W=s(7401);function H({task:t,isUserTask:e,onDelete:s}){const r=(0,W.$)(t);return(0,o.jsxs)("div",{className:"prpl-suggested-task-points-wrapper",style:y,children:[r>0&&(0,o.jsxs)("span",{className:"prpl-suggested-task-points",style:b,children:["+",r]}),e&&(0,o.jsxs)("button",{type:"button",className:"prpl-suggested-task-button trash",style:_,"data-post-id":t.id,title:(0,n.__)("Delete","progress-planner"),onClick:s,children:[(0,o.jsx)(F.A,{name:"trash"}),(0,o.jsx)("span",{className:"screen-reader-text",children:(0,n.__)("Delete","progress-planner")})]})]})}function $({task:t,taskId:e,onMoveUp:s,onMoveDown:r}){const a=t.title?.rendered||t.title;return(0,o.jsx)("div",{className:"prpl-move-buttons-wrapper",style:f,children:(0,o.jsxs)("span",{className:"prpl-move-buttons",style:v,children:[(0,o.jsxs)("button",{type:"button",className:"prpl-suggested-task-button move-up",style:w,"data-task-id":e,"data-task-title":a,"data-action":"move-up","data-target":"move-up",title:(0,n.__)("Move up","progress-planner"),onClick:s,children:[(0,o.jsx)("span",{className:"dashicons dashicons-arrow-up-alt2"}),(0,o.jsx)("span",{className:"screen-reader-text",children:(0,n.__)("Move up","progress-planner")})]}),(0,o.jsxs)("button",{type:"button",className:"prpl-suggested-task-button move-down",style:w,"data-task-id":e,"data-task-title":a,"data-action":"move-down","data-target":"move-down",title:(0,n.__)("Move down","progress-planner"),onClick:r,children:[(0,o.jsx)("span",{className:"dashicons dashicons-arrow-down-alt2"}),(0,o.jsx)("span",{className:"screen-reader-text",children:(0,n.__)("Move down","progress-planner")})]})]})})}function q({task:t,isUserTask:e,isCelebrating:s,isCompleted:a=!1,index:i=0,showMoveButtons:n=!0,showActions:l=!0,onComplete:c,onSnooze:p,onDelete:d,onMove:g,onTitleChange:h}){const m=(0,r.useRef)(null),y=(0,r.useRef)(null),[b,k]=(0,r.useState)(!1),[_,f]=(0,r.useState)(!1),v=a||"trash"===t.status||"pending"===t.status,w=(0,r.useCallback)(()=>{c(t.id,t)},[t,c]),x=(0,r.useCallback)(t=>{if("Enter"===t.key)return t.preventDefault(),t.stopPropagation(),t.target.blur(),!1},[]),I=(0,r.useCallback)(()=>{clearTimeout(y.current),y.current=setTimeout(()=>{if(m.current){const e=m.current.textContent.replace(/\n/g,"");h(t.id,e)}},300)},[t.id,h]);(0,r.useEffect)(()=>()=>{y.current&&clearTimeout(y.current)},[]);const D=(0,r.useCallback)(()=>{g(t.id,"up")},[t.id,g]),S=(0,r.useCallback)(()=>{g(t.id,"down")},[t.id,g]),A=(0,r.useCallback)(()=>{d(t.id)},[t.id,d]),C=t.slug||t.id,E=t.prpl_provider?.slug||(e?"user":""),P=["prpl-suggested-task",s?"prpl-suggested-task-celebrated":""].filter(Boolean).join(" ");return(0,o.jsxs)("li",{className:P,style:u(i),"data-task-id":C,"data-post-id":t.id,"data-task-action":"pending"===t.status||s?"celebrate":a?"completed":"","data-task-provider-id":E,"data-task-points":(0,W.$)(t),"data-task-order":t.menu_order||0,onMouseEnter:()=>k(!0),onMouseLeave:()=>k(!1),onFocusCapture:()=>f(!0),onBlurCapture:()=>f(!1),children:[(0,o.jsx)(B,{isUserTask:e,taskIsCompleted:v,isCelebrating:s,task:t,onChange:w}),(0,o.jsx)(J,{task:t,isUserTask:e,isCompleted:a,isCelebrating:s,titleRef:m,onKeyDown:x,onInput:I}),(0,o.jsx)(H,{task:t,isUserTask:e,onDelete:A}),e&&n&&!a&&(0,o.jsx)($,{task:t,taskId:C,onMoveUp:D,onMoveDown:S}),l&&(0,o.jsx)("div",{className:"prpl-suggested-task-actions-wrapper",style:T,children:(0,o.jsx)(N,{task:t,isUserTask:e,isActionsVisible:b||_,isCelebrating:s,onComplete:c,onSnooze:p,onDelete:d})})]})}},8493:(t,e,s)=>{s.d(e,{$G:()=>x,CI:()=>v,DF:()=>f,Sm:()=>b,_C:()=>w,nR:()=>h,wA:()=>_});var r=s(2619),a=s(1455),i=s.n(a),n=s(9251);const o=["hello_world_post_id","sample_page_id","inactive_plugins_count","uncategorized_category_id","post_author_count","last_published_post_id","archive_format_count","terms_without_posts","terms_without_description","post_tag_count","published_post_count","unpublished_content","seo_plugin_installed","php_version","wp_debug_status","old_posts_for_review"],l=new Map;let c=new Map,p=[];const d={isPreFetchComplete:!1,isEvaluating:!1,currentIndex:0},u=3,g=5;function h(t){const e=t.providerId;if(!e)return void console.warn("Task class missing providerId, skipping:",t);const s=t.priority||50;(0,r.addFilter)("prpl.tasks.classes",`prpl/task/${e}`,r=>(r.has(e)||r.set(e,{TaskClass:t,priority:s}),r),s),l.set(e,t)}async function m(){try{const t=await i()({path:"/wp/v2/prpl_recommendations?status=publish,trash,future&per_page=100&_embed=true"}),e=new Map;return Array.isArray(t)&&t.forEach(t=>{t.slug&&e.set(t.slug,{...t,_existsInDb:!0,_isActive:"publish"===t.status})}),e}catch(t){return console.error("Error pre-fetching existing tasks:",t),new Map}}function y(){const t=(0,r.applyFilters)("prpl.tasks.classes",new Map);p=Array.from(t.entries()).map(([t,{TaskClass:e,priority:s}])=>({TaskClass:e,priority:s,providerId:t})).sort((t,e)=>t.priority-e.priority)}async function b(t,e){if(!d.isPreFetchComplete){const[t]=await Promise.all([m(),...o.map(t=>(0,n.OJ)(t).catch(()=>null))]);c=t,d.isPreFetchComplete=!0,y()}if(d.isEvaluating)return{complete:!1,tasksAdded:0};d.isEvaluating=!0;let s=0;try{const t=[],r=[];for(;d.currentIndext.priority-e.priority),r.sort((t,e)=>t.priority-e.priority);for(const{task:r,priority:a}of t)e(r,a),s++;for(let t=0;tt.taskDetails);try{const t=await(0,n.J1)(i);t.success&&t.tasks&&t.tasks.forEach((t,r)=>{if(t.success&&t.task){const{priority:i,taskId:n}=a[r];void 0===t.task.prpl_priority&&(t.task.prpl_priority=i),c.set(n,t.task),e(t.task,i),s++}})}catch(t){409!==t?.data?.status&&console.error("Error creating task batch:",t)}}}finally{d.isEvaluating=!1}return{complete:d.currentIndex>=p.length,tasksAdded:s}}async function k(t,e){const s=t.providerId;try{const r=new t,a=t.isMultiTask||!1,i=r.getTasksToInject&&"function"==typeof r.getTasksToInject;if(a||i)return await async function(t,e,s){const r=e.providerId,a=[],i=[];try{if(t.shouldAddTask&&!await t.shouldAddTask())return{};const e=await t.getTasksToInject();if(!Array.isArray(e))return{};for(const n of e){const e=t.getTaskId?.(n)||r,o=c.get(e);if(o)o._isActive&&(void 0===o.prpl_priority&&(o.prpl_priority=s),a.push({task:o,priority:s}));else if(t.getTaskDetails){const a=await t.getTaskDetails(n);a&&(a.task_id=a.task_id||e,a.provider_id=a.provider_id||r,i.push({taskDetails:a,priority:s,taskId:e}))}}return 1===a.length&&0===i.length?{existing:a[0]}:0===a.length&&1===i.length?{toCreate:i[0]}:a.length>0?{existing:a[0]}:i.length>0?{toCreate:i[0]}:{}}catch(t){return console.error(`Error evaluating multi-task provider "${r}":`,t),{}}}(r,t,e);const n=r.getTaskId?.()||s,o=c.get(n);if(o&&!o._isActive)return{};if(o&&o._isActive)return void 0===o.prpl_priority&&(o.prpl_priority=e),{existing:{task:o,priority:e}};if(!r.shouldAddTask)return{};if(!await r.shouldAddTask())return{};if(!r.getTaskDetails)return{};const l=await r.getTaskDetails();return l?(l.task_id=l.task_id||n,l.provider_id=l.provider_id||s,{toCreate:{taskDetails:l,priority:e,taskId:n}}):{}}catch(t){return console.error(`Error evaluating task "${s}":`,t),{}}}function _(){return!d.isPreFetchComplete||d.currentIndex0)try{await(0,n.J1)(t)}catch(t){409!==t?.data?.status&&console.error("Error creating onboarding tasks:",t)}}},8537:t=>{t.exports=window.wp.htmlEntities},8864:(t,e,s)=>{s.d(e,{fX:()=>p});const r=window.React,a=t=>{let e;const s=new Set,r=(t,r)=>{const a="function"==typeof t?t(e):t;if(!Object.is(a,e)){const t=e;e=(null!=r?r:"object"!=typeof a||null===a)?a:Object.assign({},e,a),s.forEach(s=>s(e,t))}},a=()=>e,i={setState:r,getState:a,getInitialState:()=>n,subscribe:t=>(s.add(t),()=>s.delete(t))},n=e=t(r,a,i);return i},i=t=>t,n=t=>{const e=(t=>t?a(t):a)(t),s=t=>function(t,e=i){const s=r.useSyncExternalStore(t.subscribe,r.useCallback(()=>e(t.getState()),[t,e]),r.useCallback(()=>e(t.getInitialState()),[t,e]));return r.useDebugValue(s),s}(e,t);return Object.assign(s,e),s};var o=s(1455),l=s.n(o),c=s(5337);const p=(d=(t,e)=>({sessionPoints:0,totalPoints:0,lastCompletionTime:null,lastCompletedTask:null,activityScore:{current:0,target:100},badgeProgress:{},cacheInvalidatedAt:null,shouldAutoStartWizard:!1,providerTerms:{},termsLoading:!1,termsLoaded:!1,onTaskCompleted:(e,s=0)=>t(t=>({sessionPoints:t.sessionPoints+s,lastCompletionTime:Date.now(),lastCompletedTask:e})),onTaskUncompleted:(e,s=0)=>t(t=>({sessionPoints:Math.max(0,t.sessionPoints-s)})),updateActivityScore:e=>t(t=>({activityScore:{...t.activityScore,...e}})),updateBadgeProgress:(e,s)=>t(t=>({badgeProgress:{...t.badgeProgress,[e]:s}})),invalidateCache:()=>{(0,c.IL)(),t({cacheInvalidatedAt:Date.now()})},setShouldAutoStartWizard:e=>{t({shouldAutoStartWizard:e})},getProviderTermId:t=>{const s=e();return s.providerTerms[t]?.id||null},fetchProviderTerms:async()=>{const s=e();if(s.termsLoaded||s.termsLoading)return s.providerTerms;t({termsLoading:!0});try{const e=await l()({path:"/wp/v2/prpl_recommendations_provider?per_page=100"}),s={};let r=!1;if(e.forEach(t=>{s[t.slug]=t,"user"===t.slug&&(r=!0)}),!r)try{const t=await l()({path:"/wp/v2/prpl_recommendations_provider",method:"POST",data:{slug:"user",name:"user"}});s.user=t}catch(t){if("term_exists"===t.code&&t.data?.term_id)try{const e=await l()({path:`/wp/v2/prpl_recommendations_provider/${t.data.term_id}`});s.user=e}catch(t){console.error("Error fetching existing user term:",t)}else console.error("Error creating user term:",t)}return t({providerTerms:s,termsLoading:!1,termsLoaded:!0}),s}catch(e){return console.error("Error fetching provider terms:",e),t({termsLoading:!1}),{}}}}))?n(d):n;var d},9061:(t,e,s)=>{s.d(e,{A:()=>i});var r=s(790);const a={arrow:{viewBox:"0 0 20 17",paths:[{d:"M19.92 8.12c-.05-.12-.12-.23-.22-.33L12.21.29A.996.996 0 1 0 10.8 1.7l5.79 5.79H1c-.55 0-1 .45-1 1s.45 1 1 1h15.59l-5.79 5.79a.996.996 0 0 0 .71 1.7c.26 0 .51-.1.71-.29l7.5-7.5c.1-.1.17-.21.22-.33.05-.12.07-.24.08-.38 0-.14-.03-.27-.08-.38Z"}]},trash:{viewBox:"0 0 48 48",paths:[{d:"M32.99 47.88H15.01c-3.46 0-6.38-2.7-6.64-6.15L6.04 11.49l-.72.12c-.82.14-1.59-.41-1.73-1.22-.14-.82.41-1.59 1.22-1.73.79-.14 1.57-.26 2.37-.38h.02c2.21-.33 4.46-.6 6.69-.81v-.72c0-3.56 2.74-6.44 6.25-6.55 2.56-.08 5.15-.08 7.71 0 3.5.11 6.25 2.99 6.25 6.55v.72c2.24.2 4.48.47 6.7.81.79.12 1.59.25 2.38.39.82.14 1.36.92 1.22 1.73-.14.82-.92 1.36-1.73 1.22l-.72-.12-2.33 30.24c-.27 3.45-3.18 6.15-6.64 6.15Zm-17.98-3h17.97c1.9 0 3.51-1.48 3.65-3.38l2.34-30.46c-2.15-.3-4.33-.53-6.48-.7h-.03c-5.62-.43-11.32-.43-16.95 0h-.03c-2.15.17-4.33.4-6.48.7l2.34 30.46c.15 1.9 1.75 3.38 3.65 3.38ZM24 7.01c2.37 0 4.74.07 7.11.22v-.49c0-1.93-1.47-3.49-3.34-3.55-2.5-.08-5.03-.08-7.52 0-1.88.06-3.34 1.62-3.34 3.55v.49c2.36-.15 4.73-.22 7.11-.22Zm5.49 32.26h-.06c-.83-.03-1.47-.73-1.44-1.56l.79-20.65c.03-.83.75-1.45 1.56-1.44.83.03 1.47.73 1.44 1.56l-.79 20.65c-.03.81-.7 1.44-1.5 1.44Zm-10.98 0c-.8 0-1.47-.63-1.5-1.44l-.79-20.65c-.03-.83.61-1.52 1.44-1.56.84 0 1.52.61 1.56 1.44l.79 20.65c.03.83-.61 1.52-1.44 1.56h-.06Z"}]},check:{viewBox:"0 0 20 20",paths:[{d:"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",fillRule:"evenodd",clipRule:"evenodd"}]},close:{viewBox:"0 0 20 20",paths:[{d:"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",fillRule:"evenodd",clipRule:"evenodd"}]},chevronDown:{viewBox:"0 0 24 24",stroke:!0,paths:[{d:"m19.5 8.25-7.5 7.5-7.5-7.5",strokeLinecap:"round",strokeLinejoin:"round"}]},info:{viewBox:"0 0 64 64",paths:[{d:"M32 63.73C14.51 63.73.27 49.49.27 32S14.51.27 32 .27 63.73 14.5 63.73 32 49.5 63.73 32 63.73Zm0-58C17.51 5.73 5.73 17.52 5.73 32S17.52 58.27 32 58.27 58.27 46.48 58.27 32 46.49 5.73 32 5.73Zm1.2 41.4c-.42 0-.83-.05-1.24-.15-1.33-.33-2.46-1.17-3.16-2.34-.71-1.18-.91-2.56-.58-3.9l2.13-8.54c-1.25.36-2.62-.21-3.21-1.42-.66-1.35-.1-2.99 1.25-3.65l.13-.06c1.21-.6 2.6-.7 3.91-.27 1.3.44 2.36 1.35 2.97 2.58.55 1.1.69 2.36.39 3.54l-2.13 8.54c1.22-.36 2.58.19 3.19 1.37.69 1.34.16 2.98-1.18 3.67l-.13.07c-.74.37-1.54.56-2.34.56Zm-2.26-15.17Zm1.09-9.03c-1.65 0-3.02-1.34-3.02-2.99s1.34-3.01 2.99-3.01h.03c1.65 0 2.99 1.34 2.99 2.99s-1.34 3.01-2.99 3.01Z"}]},warning:{viewBox:"0 0 24 24",paths:[{d:"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003ZM12 8.25a.75.75 0 0 1 .75.75v3.75a.75.75 0 0 1-1.5 0V9a.75.75 0 0 1 .75-.75Zm0 8.25a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Z",fillRule:"evenodd",clipRule:"evenodd"}]}};function i({name:t,...e}){const s=a[t];if(!s)return null;const i=s.stroke;return(0,r.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:s.viewBox,fill:i?"none":"currentColor",stroke:i?"currentColor":void 0,strokeWidth:i?"1.5":void 0,"aria-hidden":"true",focusable:"false",...e,children:s.paths.map((t,e)=>(0,r.jsx)("path",{...t},e))})}},9251:(t,e,s)=>{s.d(e,{J1:()=>h,OJ:()=>m,Rt:()=>c,UT:()=>l,cy:()=>p,e4:()=>g,j:()=>o,lC:()=>u,vq:()=>d});var r=s(1455),a=s.n(r),i=s(5337);const n={"1-week":7,"2-weeks":14,"1-month":30,"3-months":90,"6-months":180,"1-year":365,forever:3650};async function o({status:t="publish",perPage:e=5,page:s=1,excludeProvider:r,provider:i,excludeIds:n=[],needsPagination:o=!0}={}){const l={status:t,per_page:e,page:s,_embed:!0,"filter[orderby]":"menu_order","filter[order]":"ASC"};r&&(l.exclude_provider=r),i&&(l.provider=i),n.length>0&&(l.exclude=n.join(","));const c=function(t){const e=new URLSearchParams;return Object.entries(t).forEach(([t,s])=>{Array.isArray(s)?s.forEach(s=>e.append(t,s)):null!=s&&""!==s&&e.append(t,s)}),e.toString()}(l);try{if(!o)return{tasks:await a()({path:`/wp/v2/prpl_recommendations?${c}`})||[],totalPages:1,hasMore:!1};const t=await a()({path:`/wp/v2/prpl_recommendations?${c}`,parse:!1}),e=await t.json(),r=parseInt(t.headers.get("X-WP-TotalPages")||"1",10);return{tasks:e||[],totalPages:r,hasMore:s{s.d(e,{A:()=>c});var r=s(7723),a=s(1059),i=s(9061),n=s(790);const o={display:"flex",justifyContent:"flex-start",flexWrap:"wrap",position:"relative"},l={width:"1.25rem",height:"1.25rem",display:"inline-block",verticalAlign:"bottom",color:"#6b7280"};function c({title:t,tooltipContent:e="",className:s=""}){return(0,n.jsxs)("h2",{className:"prpl-widget-title"+(s?` ${s}`:""),children:[t,e&&(0,n.jsx)("div",{style:o,children:(0,n.jsx)(a.A,{triggerContent:(0,n.jsxs)("span",{style:l,children:[(0,n.jsx)(i.A,{name:"info"}),(0,n.jsx)("span",{className:"screen-reader-text",children:(0,r.__)("More info","progress-planner")})]}),children:e})})]})}},9453:(t,e,s)=>{function r(t=0){t>0?setTimeout(()=>{window.dispatchEvent(new CustomEvent("prpl/grid/resize"))},t):window.dispatchEvent(new CustomEvent("prpl/grid/resize"))}s.d(e,{Z:()=>r})}},t=>{t(t.s=6174)}]);
\ No newline at end of file
diff --git a/build/widget-todo-rtl.css b/build/widget-todo-rtl.css
new file mode 100644
index 0000000000..b83e7450bc
--- /dev/null
+++ b/build/widget-todo-rtl.css
@@ -0,0 +1 @@
+.prpl-tooltip-wrapper .prpl-tooltip p{margin-bottom:0}.prpl-tooltip-wrapper .prpl-tooltip p:first-child{margin-top:0}
diff --git a/build/widget-todo.asset.php b/build/widget-todo.asset.php
new file mode 100644
index 0000000000..57a2bbf4f4
--- /dev/null
+++ b/build/widget-todo.asset.php
@@ -0,0 +1 @@
+ array('react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '040aac0e1b34fd95bad6', 'handle' => 'undefined-widget-todo');
diff --git a/build/widget-todo.css b/build/widget-todo.css
new file mode 100644
index 0000000000..b83e7450bc
--- /dev/null
+++ b/build/widget-todo.css
@@ -0,0 +1 @@
+.prpl-tooltip-wrapper .prpl-tooltip p{margin-bottom:0}.prpl-tooltip-wrapper .prpl-tooltip p:first-child{margin-top:0}
diff --git a/build/widget-todo.js b/build/widget-todo.js
new file mode 100644
index 0000000000..357f0dd97d
--- /dev/null
+++ b/build/widget-todo.js
@@ -0,0 +1 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[896],{790:e=>{e.exports=window.ReactJSXRuntime},1059:(e,t,r)=>{r.d(t,{A:()=>h});var n=r(6087),a=r(7723),o=r(790);const s={position:"absolute",top:0,right:0,transform:"translate(-10px, -10px) rotate(90deg)",width:0,height:0,borderStyle:"solid",borderWidth:"7.5px 10px 7.5px 0",borderColor:"transparent var(--prpl-background-activity) transparent transparent"},i={padding:0,lineHeight:1,background:"none",border:"none",cursor:"pointer",fontSize:"var(--prpl-font-size-small)",color:"var(--prpl-color-link)"},l={display:"inline-flex",alignItems:"center",position:"relative"},c={display:"block",position:"absolute",bottom:0,left:"100%",transform:"translate(-100%, calc(100% + 10px))",padding:"0.75rem 1.5rem 0.75rem 0.75rem",width:150,background:"var(--prpl-background-activity)",borderRadius:"var(--prpl-border-radius)",zIndex:2,visibility:"hidden",fontSize:"1rem",fontWeight:400,color:"var(--prpl-color-text)"},d={visibility:"visible",zIndex:10},p={position:"absolute",top:0,right:0,padding:"0.1rem",lineHeight:0,margin:0,background:"none",border:"none",cursor:"pointer"},u={display:"block",position:"fixed",top:0,left:0,width:"100%",height:"100%",zIndex:9,backgroundColor:"rgba(0, 0, 0, 0.5)"};function h({triggerContent:e,children:t,tooltipStyle:r,arrowStyle:h,onClose:g}){const[m,f]=(0,n.useState)(!1),[y,v]=(0,n.useState)(!1),x=(0,n.useRef)(null),b=(0,n.useId)(),k=(0,n.useCallback)(()=>{f(!1),g?.()},[g]);(0,n.useEffect)(()=>{if(!m)return;const e=e=>{"Escape"===e.key&&k()};return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)},[m,k]);const w={...i,textDecoration:y?"underline":"none"};return(0,o.jsxs)("span",{className:"prpl-tooltip-wrapper",style:l,children:[(0,o.jsx)("button",{type:"button",className:"prpl-info-icon","aria-describedby":b,onClick:()=>f(!0),style:w,onMouseEnter:()=>v(!0),onMouseLeave:()=>v(!1),children:e}),m&&(0,o.jsx)("span",{role:"presentation",onClick:k,style:u}),(0,o.jsxs)("span",{ref:x,id:b,className:"prpl-tooltip",role:"tooltip","aria-hidden":!m,style:{...c,...m?d:{},...r},children:[(0,o.jsx)("span",{"data-testid":"tooltip-arrow",style:{...s,...h}}),t,(0,o.jsxs)("button",{type:"button",onClick:k,style:p,children:[(0,o.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,o.jsx)("span",{className:"screen-reader-text",children:(0,a.__)("Close","progress-planner")})]})]})]})}},1362:(e,t,r)=>{r.d(t,{Cu:()=>o,cr:()=>s});var n=r(2619);const a=[];function o(e){const{id:t,component:r,priority:n=10,width:o=1,forceLastColumn:s=!1,title:i=""}=e;if(!t||!r)return void console.warn("Widget registration failed: id and component are required",e);const l=a.findIndex(e=>e.id===t),c={id:t,component:r,priority:n,width:o,forceLastColumn:s,title:i};l>=0?a[l]=c:a.push(c)}function s(){return[...a].sort((e,t)=>e.priority-t.priority)}(0,n.addAction)("prpl.dashboard.registerWidget","progress-planner/widget-registry",o)},1455:e=>{e.exports=window.wp.apiFetch},2619:e=>{e.exports=window.wp.hooks},3572:(e,t,r)=>{r.d(t,{h:()=>a});var n=r(6087);function a(){(0,n.useEffect)(()=>{const e=()=>{document.querySelectorAll(".prpl-widget-wrapper").forEach(e=>{if(!e||e.classList.contains("in-popover"))return;const t=e.querySelector(".widget-inner-container");if(!t)return;const r=document.querySelector(".prpl-widgets-container");if(!r)return;const n=parseInt(window.getComputedStyle(r).getPropertyValue("grid-auto-rows")),a=parseInt(window.getComputedStyle(e).getPropertyValue("padding-top")),o=parseInt(window.getComputedStyle(e).getPropertyValue("padding-bottom")),s=Math.ceil((t.getBoundingClientRect().height+a+o)/n);e.style.gridRowEnd="span "+(s+1)})},t=()=>{setTimeout(e,0)};return window.addEventListener("prpl/grid/resize",e),window.addEventListener("resize",t),window.addEventListener("load",t),t(),setTimeout(t,1e3),()=>{window.removeEventListener("prpl/grid/resize",e),window.removeEventListener("resize",t),window.removeEventListener("load",t)}},[])}},4465:(e,t,r)=>{var n=r(6087),a=r(7723),o=r(1362),s=r(8343),i=r(9251),l=r(3572),c=r(8039),d=r(9453),p=r(7401),u=r(9277),h=r(9061),g=r(790);const m={dialog:{position:"fixed",top:"50%",left:"50%",transform:"translate(-50%, -50%)",zIndex:1e4,background:"white",padding:"20px",borderRadius:"8px",boxShadow:"0 4px 20px rgba(0,0,0,0.15)"},buttons:{display:"flex",gap:"2rem",marginTop:"15px"},overlay:{position:"fixed",top:0,left:0,right:0,bottom:0,background:"rgba(0,0,0,0.3)",zIndex:9999}};function f({isOpen:e,message:t,confirm:r,cancel:n,onConfirm:o,onCancel:s}){return e?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsxs)("div",{className:"prpl-popover",style:m.dialog,children:[(0,g.jsxs)("div",{className:"prpl-note",children:[(0,g.jsx)("span",{className:"prpl-note-icon",children:(0,g.jsx)(h.A,{name:"warning"})}),(0,g.jsx)("span",{className:"prpl-note-text",children:t})]}),(0,g.jsxs)("div",{className:"prpl-buttons-wrapper",style:m.buttons,children:[(0,g.jsx)("button",{onClick:s,children:n}),(0,g.jsx)("button",{onClick:o,children:r})]})]}),(0,g.jsx)("div",{role:"button",tabIndex:0,"aria-label":(0,a.__)("Close dialog","progress-planner"),style:m.overlay,onClick:s,onKeyDown:e=>{"Enter"!==e.key&&" "!==e.key||s()}})]}):null}var y=r(1059),v=r(8281),x=r(5815);function b({count:e=3}){return(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)("div",{style:{marginBottom:"1rem"},children:(0,g.jsx)(x.rr,{lines:2})}),(0,g.jsx)(v.P,{count:e}),(0,g.jsxs)("div",{style:{display:"flex",gap:"0.5rem",marginTop:"var(--prpl-padding)"},children:[(0,g.jsx)(x.iA,{width:"100%",height:"40px",style:{flex:1}}),(0,g.jsx)(x.iA,{width:"40px",height:"40px",style:{borderRadius:"var(--prpl-border-radius)"}})]})]})}var k=r(8864);const w={list:{listStyle:"none",padding:0,margin:0},form:{display:"flex",gap:"0.5rem",marginTop:"var(--prpl-padding)"},input:{flex:1,minWidth:0},addButton:{padding:"0.5rem",background:"var(--prpl-color-button-secondary-background)",border:"1px solid var(--prpl-color-button-secondary-border)",borderRadius:"var(--prpl-border-radius)",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center"},details:{marginTop:"var(--prpl-padding)",borderTop:"1px solid var(--prpl-color-border)",paddingTop:"var(--prpl-padding)"},summary:{cursor:"pointer",fontWeight:500,display:"flex",alignItems:"center",justifyContent:"space-between",padding:"0.5rem 0"},summaryIcon:{marginLeft:"0.5rem",transition:"transform 0.2s",width:"1rem",height:"1rem"},deleteAllWrapper:{marginTop:"0.5rem",marginBottom:"0.5rem",borderBottom:"1px solid var(--prpl-color-border)",paddingBottom:"0.5rem"},deleteAllButton:{display:"flex",alignItems:"center",gap:"0.5rem",padding:"0.5rem",background:"none",border:"none",cursor:"pointer",color:"var(--prpl-color-text)",fontSize:"var(--prpl-font-size-small)"},deleteAllIcon:{display:"inline-block",width:"18px",height:"18px",color:"var(--prpl-color-ui-icon)"},tooltipActions:{display:"inline-flex",justifyContent:"flex-start",flexWrap:"wrap",position:"relative",verticalAlign:"text-top"},icon:{width:"1.25rem",height:"1.25rem",display:"inline-block",verticalAlign:"bottom",color:"#6b7280"},srOnly:{position:"absolute",left:"-9999px"}};(0,o.Cu)({id:"todo",component:function({config:e={}}){const[t,r]=(0,n.useState)([]),[o,m]=(0,n.useState)([]),[v,x]=(0,n.useState)(!0),[_,C]=(0,n.useState)(""),[j,M]=(0,n.useState)(!1),[T,I]=(0,n.useState)(!1),E=(0,n.useRef)(null);(0,l.h)();const{celebrate:S}=(0,c.u)(),A=(0,k.fX)(e=>e.onTaskCompleted),D=(0,k.fX)(e=>e.getProviderTermId("user")),P=(0,k.fX)(e=>e.fetchProviderTerms),N=(0,n.useCallback)(e=>[...e].sort((e,t)=>{const r=1===(0,p.$)(e),n=1===(0,p.$)(t);return r&&!n?-1:!r&&n?1:(e.menu_order||0)-(t.menu_order||0)}),[]);(0,n.useEffect)(()=>{(async()=>{try{const e=await(0,i.j)({status:"publish",provider:"user",perPage:100,needsPagination:!1}),t=await(0,i.j)({status:"trash",provider:"user",perPage:100,needsPagination:!1}),n=N(e.tasks);t.tasks.sort((e,t)=>(e.menu_order||0)-(t.menu_order||0)),r(n),m(t.tasks)}catch(e){console.error("Error loading tasks:",e)}finally{x(!1)}})()},[N]),(0,n.useEffect)(()=>{P()},[P]),(0,n.useEffect)(()=>{v||(0,d.Z)()},[t,o,v]);const L=(0,n.useCallback)(async e=>{if(e.preventDefault(),_.trim()){I(!0);try{const e=t.reduce((e,t)=>Math.max(e,t.menu_order||0),0),n=await(0,i.UT)({title:_,menuOrder:e+1,providerId:D,points:0});r(e=>N([...e,n])),C(""),window.wp?.a11y?.speak&&window.wp.a11y.speak((0,a.__)("Task added successfully","progress-planner"),"polite"),E.current?.focus()}catch(e){console.error("Error creating task:",e)}finally{I(!1)}}},[_,t,N,D]),z=(0,n.useCallback)(async e=>{const n=t.find(t=>t.id===e)||o.find(t=>t.id===e);if(!n)return;const a="trash"===n.status,s=a?"publish":"trash";try{if(await(0,i.lC)(e,{status:s}),a)m(t=>t.filter(t=>t.id!==e)),r(e=>N([...e,{...n,status:"publish"}]));else{r(t=>t.filter(t=>t.id!==e)),m(e=>[...e,{...n,status:"trash"}]);const t=(0,p.$)(n);t>0&&(A(n,t),S())}}catch(e){console.error("Error toggling task:",e)}},[t,o,N,S,A]),R=(0,n.useCallback)(async e=>{try{await(0,i.vq)(e),r(t=>t.filter(t=>t.id!==e)),m(t=>t.filter(t=>t.id!==e))}catch(e){console.error("Error deleting task:",e)}},[]),B=(0,n.useCallback)(async(e,n)=>{const a=t.findIndex(t=>t.id===e);if(-1===a)return;const o="up"===n?a-1:a+1;if(o<0||o>=t.length)return;const s=[...t];[s[a],s[o]]=[s[o],s[a]];const l=s.map((e,t)=>({...e,menu_order:t})),c=N(l);r(c);try{await Promise.all(c.map(e=>(0,i.lC)(e.id,{menu_order:e.menu_order})))}catch(e){console.error("Error saving task order:",e)}},[t,N]),O=(0,n.useCallback)(async(e,t)=>{try{await(0,i.lC)(e,{title:t}),r(r=>r.map(r=>r.id===e?{...r,title:{rendered:t}}:r)),m(r=>r.map(r=>r.id===e?{...r,title:{rendered:t}}:r))}catch(e){console.error("Error updating task title:",e)}},[]),F=(0,n.useCallback)(async()=>{try{await Promise.all(o.map(e=>(0,i.vq)(e.id))),m([]),M(!1),window.wp?.a11y?.speak&&window.wp.a11y.speak((0,a.__)("All completed tasks deleted","progress-planner"),"assertive")}catch(e){console.error("Error deleting completed tasks:",e)}},[o]),U=e?.title||(0,a.__)("My to-do list","progress-planner");if(v)return(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(u.A,{title:U}),(0,g.jsx)(b,{count:3})]});const W=e?.goldenTaskDescription||(0,a.__)("Write down all your tasks you want to get done on your website! You'll earn points for your 'golden task'.","progress-planner"),$=e?.silverTaskDescription||(0,a.__)("Write down all your tasks you want to get done on your website! The top task will become your 'golden task' next week.","progress-planner"),Z=e?.tooltipContent||(0,a.__)("Every Monday, your top task becomes the golden task for the week. Complete it anytime this week to earn points toward your monthly total! Once done, the next task is highlighted to become your golden task next week.","progress-planner");return(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(u.A,{title:U}),(0,g.jsxs)("p",{className:"prpl-widget-description",children:[(0,g.jsx)("span",{className:"prpl-todo-golden-task-description",children:W}),(0,g.jsx)("span",{className:"prpl-todo-silver-task-description",children:$}),(0,g.jsx)("span",{style:w.tooltipActions,children:(0,g.jsx)(y.A,{triggerContent:(0,g.jsxs)("span",{style:w.icon,children:[(0,g.jsx)(h.A,{name:"info"}),(0,g.jsx)("span",{className:"screen-reader-text",children:(0,a.__)("More info","progress-planner")})]}),children:Z})})]}),(0,g.jsx)("div",{id:"todo-aria-live-region","aria-live":"polite",style:w.srOnly}),(0,g.jsxs)("ul",{id:"todo-list",className:"prpl-todo-list prpl-suggested-tasks-list",style:w.list,children:[t.map((e,t)=>(0,g.jsx)(s.A,{task:e,index:t,isUserTask:!0,isCelebrating:!1,isCompleted:!1,showMoveButtons:!0,showActions:!1,onComplete:z,onDelete:R,onMove:B,onTitleChange:O},e.id)),T&&(0,g.jsx)("li",{className:"prpl-loader",role:"status","aria-live":"polite",children:(0,g.jsx)("span",{className:"screen-reader-text",children:(0,a.__)("Loading tasks…","progress-planner")})})]}),(0,g.jsxs)("form",{id:"create-todo-item",style:w.form,onSubmit:L,children:[(0,g.jsx)("input",{ref:E,type:"text",id:"new-todo-content",style:w.input,placeholder:(0,a.__)("Add a new task","progress-planner"),"aria-label":(0,a.__)("Add a new task","progress-planner"),required:!0,value:_,onChange:e=>C(e.target.value)}),(0,g.jsxs)("button",{type:"submit",style:w.addButton,"aria-label":(0,a.__)("Add task","progress-planner"),children:[(0,g.jsx)("span",{className:"dashicons dashicons-plus-alt2","aria-hidden":"true"}),(0,g.jsx)("span",{className:"screen-reader-text",children:(0,a.__)("Add task","progress-planner")})]})]}),o.length>0&&(0,g.jsxs)("details",{id:"todo-list-completed-details",style:w.details,children:[(0,g.jsxs)("summary",{style:w.summary,children:[(0,a.__)("Completed tasks","progress-planner"),(0,g.jsx)("span",{className:"prpl-todo-list-completed-summary-icon",style:w.summaryIcon,children:(0,g.jsx)(h.A,{name:"chevronDown"})})]}),(0,g.jsx)("div",{id:"todo-list-completed-delete-all-wrapper",style:w.deleteAllWrapper,children:(0,g.jsxs)("button",{id:"todo-list-completed-delete-all",style:w.deleteAllButton,onClick:()=>M(!0),children:[(0,g.jsx)("span",{style:w.deleteAllIcon,children:(0,g.jsx)(h.A,{name:"trash"})}),(0,a.__)("Delete all completed tasks","progress-planner")]})}),(0,g.jsx)("ul",{id:"todo-list-completed",className:"prpl-todo-list prpl-suggested-tasks-list",style:w.list,children:o.map((e,t)=>(0,g.jsx)(s.A,{task:e,index:t,isUserTask:!0,isCelebrating:!1,isCompleted:!0,showMoveButtons:!1,showActions:!1,onComplete:z,onDelete:R,onMove:B,onTitleChange:O},e.id))})]}),(0,g.jsx)(f,{isOpen:j,message:(0,a.__)("Are you sure you want to delete all completed tasks? This action cannot be undone.","progress-planner"),cancel:(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)("strong",{children:(0,a.__)("No","progress-planner")}),", ",(0,a.__)("keep this list","progress-planner")]}),confirm:(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)("strong",{children:(0,a.__)("Yes","progress-planner")}),", ",(0,a.__)("delete all completed tasks","progress-planner")]}),onConfirm:F,onCancel:()=>M(!1)})]})},priority:3,width:2,forceLastColumn:!1,title:(0,a.__)("My to-do list","progress-planner")})},5337:(e,t,r)=>{r.d(t,{BJ:()=>l,IL:()=>c,Wz:()=>d});var n=r(1455),a=r.n(n);const o=new Map,s=new Map,i=3e5;async function l(e,t={}){const{skipCache:r=!1,ttl:n=i}=t,l=function(e){if("GET"!==(e.method||"GET").toUpperCase())return null;let t=e.path||e.url||"";if(e.data&&"object"==typeof e.data){const r=new URLSearchParams(e.data).toString();r&&(t+=(t.includes("?")?"&":"?")+r)}return`GET:${t}`}(e);if(!l)return a()(e);if(!r&&o.has(l))return o.get(l);if(!r){const e=s.get(l);if(e&&Date.now()-e.timestamp(s.set(l,{data:e,timestamp:Date.now()}),o.delete(l),e)).catch(e=>{throw o.delete(l),e});return o.set(l,c),c}function c(){s.clear(),o.clear()}function d(e,t){const r=`GET:${e}`;s.set(r,{data:t,timestamp:Date.now()})}},5815:(e,t,r)=>{r.d(t,{Q8:()=>d,iA:()=>c,rr:()=>p});var n=r(6087),a=r(790);const o="\n@keyframes prpl-shimmer {\n\t0% { background-position: 200% 0; }\n\t100% { background-position: -200% 0; }\n}\n";let s=!1;function i(){if(s||"undefined"==typeof document)return;const e=document.createElement("style");e.id="prpl-skeleton-keyframes",e.textContent=o,document.head.appendChild(e),s=!0}const l={background:"linear-gradient(\n\t\t90deg,\n\t\tvar(--prpl-color-gauge-remain, #f0f0f0) 25%,\n\t\tvar(--prpl-color-border, #e0e0e0) 50%,\n\t\tvar(--prpl-color-gauge-remain, #f0f0f0) 75%\n\t)",backgroundSize:"200% 100%",animation:"prpl-shimmer 1.5s ease-in-out infinite",borderRadius:"var(--prpl-border-radius, 8px)"};function c({width:e="100%",height:t="1em",className:r="",style:o={}}){return(0,n.useEffect)(()=>{i()},[]),(0,a.jsx)("div",{className:r||void 0,style:{...l,width:e,height:t,...o}})}function d({size:e="40px",className:t="",style:r={}}){return(0,n.useEffect)(()=>{i()},[]),(0,a.jsx)("div",{className:t||void 0,style:{...l,width:e,height:e,borderRadius:"50%",...r}})}function p({width:e="100%",lines:t=1,className:r="",style:o={},lastShort:s=!0}){return(0,n.useEffect)(()=>{i()},[]),1===t?(0,a.jsx)(c,{width:e,height:"1em",className:r,style:o}):(0,a.jsx)("div",{style:{display:"flex",flexDirection:"column",...o},children:Array.from({length:t}).map((n,o)=>(0,a.jsx)(c,{width:s&&o===t-1?"70%":e,height:"1em",className:r,style:{marginBottom:o{e.exports=window.wp.element},7401:(e,t,r)=>{r.d(t,{$:()=>a});var n=r(8493);function a(e){if(void 0!==e.prpl_points&&null!==e.prpl_points)return parseInt(e.prpl_points,10)||0;const t=e.prpl_provider?.slug;if(t){const r=(0,n.DF)(t);if(r){const a=(0,n.CI)(t);if(a&&"function"==typeof a.getPoints)return a.getPoints(e);if(void 0!==r.points)return r.points}}return 1}},7723:e=>{e.exports=window.wp.i18n},8039:(e,t,r)=>{r.d(t,{u:()=>i});var n=r(6087),a={};!function e(t,r,n,a){var o=!!(t.Worker&&t.Blob&&t.Promise&&t.OffscreenCanvas&&t.OffscreenCanvasRenderingContext2D&&t.HTMLCanvasElement&&t.HTMLCanvasElement.prototype.transferControlToOffscreen&&t.URL&&t.URL.createObjectURL),s="function"==typeof Path2D&&"function"==typeof DOMMatrix,i=function(){if(!t.OffscreenCanvas)return!1;try{var e=new OffscreenCanvas(1,1),r=e.getContext("2d");r.fillRect(0,0,1,1);var n=e.transferToImageBitmap();r.createPattern(n,"no-repeat")}catch(e){return!1}return!0}();function l(){}function c(e){var n=r.exports.Promise,a=void 0!==n?n:t.Promise;return"function"==typeof a?new a(e):(e(l,l),null)}var d,p,u,h,g,m,f,y,v,x,b,k=(d=i,p=new Map,{transform:function(e){if(d)return e;if(p.has(e))return p.get(e);var t=new OffscreenCanvas(e.width,e.height);return t.getContext("2d").drawImage(e,0,0),p.set(e,t),t},clear:function(){p.clear()}}),w=(g=Math.floor(1e3/60),m={},f=0,"function"==typeof requestAnimationFrame&&"function"==typeof cancelAnimationFrame?(u=function(e){var t=Math.random();return m[t]=requestAnimationFrame(function r(n){f===n||f+g-1{const t=e?.closest(".prpl-suggested-tasks-list")||document.querySelector(".prpl-widget-wrapper.prpl-suggested-tasks .prpl-suggested-tasks-list"),r=t?{x:(t.getBoundingClientRect().left+t.offsetWidth/2)/window.innerWidth,y:(t.getBoundingClientRect().top+50)/window.innerHeight}:{x:.5,y:.3},n=window.prplCelebrate||{},a={spread:360,ticks:50,gravity:1,decay:.94,startVelocity:30,shapes:["star"],colors:["FFE400","FFBD00","E89400","FFCA6C","FDFFB8"]};let s=[{particleCount:30,scalar:4,shapes:["image"],shapeOptions:{image:[{src:n.raviIconUrl},{src:n.raviIconUrl},{src:n.raviIconUrl},{src:n.monthIconUrl},{src:n.contentIconUrl},{src:n.maintenanceIconUrl}]}}];void 0!==n.confettiOptions&&Array.isArray(n.confettiOptions)&&n.confettiOptions.length>0&&(s=n.confettiOptions),[0,100,200].forEach(e=>{setTimeout(()=>{s.forEach(e=>{o({...a,...e,origin:r})})},e)}),document.querySelectorAll("#adminmenu #toplevel_page_progress-planner .update-plugins").forEach(e=>e.remove())},[]),triggerGridResize:(0,n.useCallback)(()=>{(0,s.Z)()},[])}}},8281:(e,t,r)=>{r.d(t,{A:()=>o,P:()=>s});var n=r(5815),a=r(790);function o({index:e=0,showActions:t=!0}){const r={margin:0,padding:"0.75rem 0.5rem 0.625rem 0.5rem",display:"grid",gridTemplateColumns:"1.5rem 1fr 3.5rem",gap:"0.25rem 0.5rem",position:"relative",lineHeight:1,backgroundColor:e%2==0?"var(--prpl-background-table)":"transparent"};return(0,a.jsxs)("li",{style:r,children:[(0,a.jsx)("div",{style:{display:"flex",width:"100%",flexDirection:"column",alignItems:"center",justifyContent:"center"},children:(0,a.jsx)(n.iA,{width:"1rem",height:"1rem",style:{borderRadius:"3px"}})}),(0,a.jsx)("div",{style:{display:"flex",alignItems:"center",gap:"0.5rem"},children:(0,a.jsx)(n.iA,{width:60+30*Math.random()+"%",height:"1rem"})}),(0,a.jsx)("div",{style:{display:"flex",gap:"0.5rem",alignItems:"center",justifyContent:"flex-end",gridRowEnd:"span 2"},children:(0,a.jsx)(n.Q8,{size:"1.5rem"})}),t&&(0,a.jsxs)("div",{style:{gridColumn:"2 / span 1",display:"flex",gap:"0.5rem",paddingTop:"0.25rem"},children:[(0,a.jsx)(n.iA,{width:"4rem",height:"1.5rem"}),(0,a.jsx)(n.iA,{width:"4rem",height:"1.5rem"})]})]})}function s({count:e=4}){return(0,a.jsx)("ul",{style:{listStyle:"none",padding:0,margin:0},children:Array.from({length:e}).map((e,t)=>(0,a.jsx)(o,{index:t},t))})}},8343:(e,t,r)=>{r.d(t,{A:()=>H});var n=r(6087),a=r(2619),o=r(8493),s=r(7723),i=r(790);const l={fontSize:"var(--prpl-font-size-small)",color:"var(--prpl-color-link)",lineHeight:1,textDecoration:"none",padding:0,background:"none",border:"none",cursor:"pointer"};function c({as:e="button",style:t,children:r,...a}){const[o,s]=(0,n.useState)(!1),c={...l,textDecoration:o?"underline":"none",...t},d="button"===e?{type:"button"}:{};return(0,i.jsx)(e,{...d,...a,style:c,onMouseEnter:()=>s(!0),onMouseLeave:()=>s(!1),children:r})}function d({taskId:e,taskTitle:t,onClick:r}){return(0,i.jsx)(c,{"data-task-id":e,"data-task-title":t,"data-action":"complete","data-target":"complete",title:(0,s.__)("Mark as complete","progress-planner"),onClick:e=>{e.preventDefault(),r?.()},children:(0,s.__)("Mark as complete","progress-planner")})}var p=r(1059);function u(e){return{margin:0,padding:"0.75rem 0.5rem 0.625rem 0.5rem",display:"grid",gridTemplateColumns:"1.5rem 1fr 3.5rem",gap:"0.25rem 0.5rem",position:"relative",lineHeight:1,backgroundColor:e%2==0?"var(--prpl-background-table)":"transparent"}}const h={display:"flex",width:"100%",gap:0,flexDirection:"column",alignItems:"center",justifyContent:"center"},g={display:"flex",alignItems:"center",gap:"0.5rem",justifyContent:"space-between"};function m(e){return{width:"100%",color:"var(--prpl-color-text)",fontSize:"1rem",margin:0,fontWeight:500,...e?{textDecoration:"line-through"}:{}}}const f={display:"flex",gap:"0.5rem",alignItems:"center",justifyContent:"flex-end",gridRowEnd:"span 2"},y={fontSize:"var(--prpl-font-size-xs)",fontWeight:700,color:"var(--prpl-text-point)",backgroundColor:"var(--prpl-background-point)",width:"1.5rem",height:"1.5rem",borderRadius:"50%",display:"flex",alignItems:"center",justifyContent:"center"},v={padding:"0.1rem",lineHeight:0,margin:0,background:"none",border:"none",cursor:"pointer"},x={...v,padding:0,color:"var(--prpl-color-ui-icon)",boxShadow:"none",marginTop:"1px"},b={display:"flex",justifyContent:"flex-start",flexWrap:"wrap",position:"absolute",left:"calc(-8px - 0.5rem)",top:"50%",transform:"translateY(-50%)",padding:"10px 10px 10px 0"},k={display:"flex",width:"100%",gap:0,flexDirection:"column",alignItems:"center",justifyContent:"center"},w={...v,padding:0,height:"0.75rem",color:"var(--prpl-color-ui-icon)",boxShadow:"none",marginTop:"1px"},_={gridColumn:"2 / span 1",display:"flex"},C={margin:0,flexShrink:0},j={transform:"translate(-20%, calc(100% + 10px))"},M={left:25,right:"auto",transform:"translate(-5px, -10px) rotate(90deg)"},T=[{key:"1-week",label:(0,s.__)("1 week","progress-planner")},{key:"1-month",label:(0,s.__)("1 month","progress-planner")},{key:"3-months",label:(0,s.__)("3 months","progress-planner")},{key:"6-months",label:(0,s.__)("6 months","progress-planner")},{key:"1-year",label:(0,s.__)("1 year","progress-planner")},{key:"forever",label:(0,s.__)("forever","progress-planner")}],I={fieldset:{border:"none",padding:0,margin:0},legend:{display:"block",width:"100%"},legendTitle:{display:"block",fontWeight:500,marginBottom:"0.25rem"},toggleButton:{display:"flex",justifyContent:"space-between",width:"100%",marginTop:"0.5rem",padding:"0.5rem",backgroundColor:"#fff",border:"1px solid #dcdcde",borderRadius:"var(--prpl-border-radius)",lineHeight:1,textAlign:"start",cursor:"pointer"},radioInput:{display:"none"}};function E(e){return{display:e?"block":"none",marginTop:"0.75rem"}}function S(e,t,r){const n={display:"block",padding:"0.5rem",cursor:"pointer",backgroundColor:r?"var(--prpl-color-gauge-remain)":"#fff"};return e>0&&(n.borderTop="1px solid #dcdcde"),0===e&&(n.borderTopLeftRadius="var(--prpl-border-radius)",n.borderTopRightRadius="var(--prpl-border-radius)"),e===t-1&&(n.borderBottomLeftRadius="var(--prpl-border-radius)",n.borderBottomRightRadius="var(--prpl-border-radius)"),n}function A({taskId:e,onSnooze:t}){const[r,a]=(0,n.useState)(!1),[o,l]=(0,n.useState)(null),c=(0,n.useCallback)(()=>{a(!1),l(null)},[]),d=e=>{const r=e.target.value;t?.(r)};return(0,i.jsx)(p.A,{triggerContent:(0,s.__)("Snooze","progress-planner"),tooltipStyle:j,arrowStyle:M,onClose:c,children:(0,i.jsxs)("fieldset",{style:I.fieldset,children:[(0,i.jsxs)("legend",{style:I.legend,children:[(0,i.jsx)("span",{style:I.legendTitle,children:(0,s.__)("Snooze this task?","progress-planner")}),(0,i.jsxs)("button",{type:"button",className:"prpl-toggle-radio-group",style:I.toggleButton,onClick:e=>{e.preventDefault(),e.stopPropagation(),a(!r)},children:[(0,i.jsx)("span",{children:(0,s.__)("How long?","progress-planner")}),(0,i.jsx)("span",{style:(u=r,{transform:u?"rotate(270deg)":"rotate(90deg)",transition:"transform 0.2s ease"}),children:"›"})]})]}),(0,i.jsx)("div",{style:E(r),children:T.map((t,r)=>{const n=`snooze-${e}-${t.key}`;return(0,i.jsxs)("label",{htmlFor:n,style:S(r,T.length,o===t.key),onMouseEnter:()=>l(t.key),onMouseLeave:()=>l(null),children:[(0,i.jsx)("input",{type:"radio",id:n,name:`snooze-duration-${e}`,value:t.key,style:I.radioInput,onChange:d}),t.label]},t.key)})})]})});var u}function D({externalUrl:e,content:t}){return e?(0,i.jsx)(c,{as:"a",href:e,target:"_blank",rel:"noopener noreferrer",children:(0,s.__)("Why is this important?","progress-planner")}):t?(0,i.jsx)(p.A,{triggerContent:(0,s.__)("Info","progress-planner"),tooltipStyle:j,arrowStyle:M,children:(0,i.jsx)("div",{dangerouslySetInnerHTML:{__html:t}})}):null}function P({href:e,label:t,target:r="_self",onClick:n,className:a=""}){return(0,i.jsx)(c,{as:"a",className:a||void 0,href:e||"#",target:r,rel:"_blank"===r?"noopener noreferrer":void 0,onClick:n?e=>{n&&(e.preventDefault(),n(e))}:void 0,children:t})}function N({popoverId:e,label:t,task:r,taskContext:n,eventName:o}){return(0,i.jsx)(c,{onClick:t=>{t.preventDefault();const s=document.getElementById(e);if(s?.showPopover&&s.showPopover(),r&&(0,a.doAction)("prpl.popover.open",e,r),o&&n){const e=new CustomEvent(o,{bubbles:!0,detail:n});t.target.dispatchEvent(e)}},children:t})}function L({postId:e,taskTitle:t,onClick:r}){return(0,i.jsx)(c,{className:"prpl-suggested-task-button trash","data-post-id":e,title:`${(0,s.__)("Delete","progress-planner")}: ${t}`,onClick:e=>{e.preventDefault(),r?.()},children:(0,s.__)("Delete","progress-planner")})}const z={display:"inline-block",width:1,height:"0.75rem",background:"var(--prpl-color-text)",alignSelf:"center"},R={display:"inline-flex",position:"relative",textDecoration:"none"};function B(e,t,r,n,a){const o=t.title?.rendered||t.title||"";switch(e.type){case"complete":return(0,i.jsx)(d,{taskId:e.taskId,taskTitle:e.taskTitle||o,onClick:()=>r(t.id,t)});case"snooze":return(0,i.jsx)(A,{taskId:e.taskId,onSnooze:e=>n(t.id,e)});case"info":return(0,i.jsx)(D,{externalUrl:e.externalUrl,content:e.content});case"link":return e.inlineEdit?(0,i.jsx)(P,{href:"#",label:e.label,onClick:e=>{e.preventDefault();const t=e.target.closest("li.prpl-suggested-task"),r=t?.querySelector(".prpl-task-title span");r?.focus()}}):(0,i.jsx)(P,{href:e.href,label:e.label,target:e.target,className:e.className});case"popover":return(0,i.jsx)(N,{popoverId:e.popoverId,label:e.label,task:t,taskContext:e.taskContext,eventName:e.eventName});case"delete":return(0,i.jsx)(L,{postId:t.id,taskTitle:o,onClick:()=>a(t.id)});default:return null}}function O({task:e,isUserTask:t,isActionsVisible:r=!1,isCelebrating:s=!1,onComplete:l,onSnooze:c,onDelete:d}){const p=(0,n.useRef)(null),u=(0,n.useRef)([]),h=(0,n.useCallback)((e,t)=>r=>{r.preventDefault(),l(e,t)},[l]),g=(0,n.useCallback)(e=>t=>{c(e,t.target.value)},[c]),m=(0,n.useCallback)((e,t)=>r=>{r.preventDefault(),(0,a.doAction)("prpl.popover.open",e,t)},[]),f=(0,n.useCallback)(e=>t=>{t.preventDefault(),d(e)},[d]),y=(0,n.useMemo)(()=>{if(e.prpl_task_actions&&Array.isArray(e.prpl_task_actions)&&e.prpl_task_actions.length>0)return e.prpl_task_actions.map(e=>"string"==typeof e?{type:"html",html:e}:e);let t=e.prpl_provider?.slug||e.provider_id||e.meta?.provider_id||"";if(!t&&e.slug&&(t=e.slug),!t&&e.prpl_recommendations_provider&&Array.isArray(e.prpl_recommendations_provider)){const r=e.prpl_recommendations_provider[0];if(r&&"object"==typeof r&&r.slug)t=r.slug;else if("number"==typeof r&&e._embedded?.["wp:term"]?.[0]){const n=e._embedded["wp:term"].flat().find(e=>"prpl_recommendations_provider"===e?.taxonomy&&e.id===r);n?.slug&&(t=n.slug)}}if(!t)return[];const r=(0,o.CI)(t);if(!r?.getTaskActions)return[];try{return r.getTaskActions(e)||[]}catch(e){return console.error(`Error generating actions for task provider "${t}":`,e),[]}},[e]);(0,n.useEffect)(()=>{if(!p.current)return;const t=p.current;return u.current=[],y.some(e=>"html"===e.type)?(t.querySelectorAll('[data-action="complete"]').forEach(t=>{const r=h(e.id,e);t.addEventListener("click",r),u.current.push({element:t,type:"click",handler:r})}),t.querySelectorAll('.prpl-snooze-duration-radio-group input[type="radio"]').forEach(t=>{const r=g(e.id);t.addEventListener("change",r),u.current.push({element:t,type:"change",handler:r})}),t.querySelectorAll('a[onclick*="showPopover"]').forEach(t=>{const r=t.getAttribute("onclick"),n=r?.match(/getElementById\(['"]([^'"]+)['"]\)/);if(n){const r=n[1].replace("prpl-popover-","");t.removeAttribute("onclick");const a=m(r,e);t.addEventListener("click",a),u.current.push({element:t,type:"click",handler:a})}}),t.querySelectorAll(".prpl-suggested-task-button.trash").forEach(t=>{const r=f(e.id);t.addEventListener("click",r),u.current.push({element:t,type:"click",handler:r})}),()=>{u.current.forEach(({element:e,type:t,handler:r})=>{e.removeEventListener(t,r)}),u.current=[]}):void 0},[e,y,h,g,m,f]);const v=function(e,t){return{display:"flex",justifyContent:"flex-start",flexWrap:"wrap",position:"relative",paddingTop:"2px",gap:"0.4rem",alignItems:"baseline",visibility:e?"visible":"hidden",pointerEvents:t?"none":void 0}}(r,s);if(0===y.length&&!t)return(0,i.jsx)("div",{style:v});const x=y.map((t,r)=>(0,i.jsx)("span",{className:"tooltip-action",style:R,children:"html"===t.type?(0,i.jsx)("span",{dangerouslySetInnerHTML:{__html:t.html}}):B(t,e,l,c,d)},r));t&&x.push((0,i.jsx)("span",{className:"tooltip-action",style:R,children:(0,i.jsx)(L,{postId:e.id,taskTitle:e.title?.rendered||e.title,onClick:()=>d(e.id)})},"user-delete"));const b=[];return x.forEach((e,t)=>{t>0&&b.push((0,i.jsx)("span",{className:"prpl-action-separator",style:z},`sep-${t}`)),b.push(e)}),(0,i.jsx)("div",{style:v,ref:p,children:b})}var F=r(9061);function U({isUserTask:e,taskIsCompleted:t,isCelebrating:r,task:n,onChange:a}){return e?(0,i.jsx)("div",{className:"prpl-suggested-task-checkbox-wrapper",style:h,children:(0,i.jsxs)("label",{style:h,children:[(0,i.jsx)("input",{type:"checkbox",className:"prpl-suggested-task-checkbox",onChange:a,style:{...C,...r?{opacity:.5,borderColor:"#0773bf",backgroundColor:"#effbfe"}:{}},checked:t,disabled:r}),(0,i.jsxs)("span",{className:"screen-reader-text",children:[n.title?.rendered||n.title,":"," ",(0,s.__)("Mark as complete","progress-planner")]})]})}):(0,i.jsx)("div",{className:"prpl-suggested-task-checkbox-wrapper",style:h,children:(0,i.jsx)(F.A,{name:"arrow",style:{width:"0.75rem",color:"var(--prpl-color-ui-icon)"}})})}function W({task:e,isUserTask:t,isCompleted:r,isCelebrating:n,titleRef:a,onKeyDown:o,onInput:l}){const c=e.title?.rendered||e.title,d=function(e){return{textDecoration:"none",backgroundImage:"linear-gradient(#000, #000)",backgroundRepeat:"no-repeat",backgroundPosition:"center left",backgroundSize:e?"100% 1px":"0% 1px",transition:"background-size 500ms ease-in-out"}}(n);return(0,i.jsx)("div",{className:"prpl-suggested-task-title-wrapper",style:g,children:(0,i.jsx)("h3",{className:"prpl-task-title",style:m(r),children:t&&!r?(0,i.jsx)("span",{ref:a,contentEditable:"plaintext-only",role:"textbox",tabIndex:0,"aria-label":(0,s.__)("Edit task title","progress-planner"),"aria-multiline":"false",onKeyDown:o,onInput:l,suppressContentEditableWarning:!0,style:d,dangerouslySetInnerHTML:{__html:c}}):(0,i.jsx)("span",{style:d,dangerouslySetInnerHTML:{__html:c}})})})}var $=r(7401);function Z({task:e,isUserTask:t,onDelete:r}){const n=(0,$.$)(e);return(0,i.jsxs)("div",{className:"prpl-suggested-task-points-wrapper",style:f,children:[n>0&&(0,i.jsxs)("span",{className:"prpl-suggested-task-points",style:y,children:["+",n]}),t&&(0,i.jsxs)("button",{type:"button",className:"prpl-suggested-task-button trash",style:x,"data-post-id":e.id,title:(0,s.__)("Delete","progress-planner"),onClick:r,children:[(0,i.jsx)(F.A,{name:"trash"}),(0,i.jsx)("span",{className:"screen-reader-text",children:(0,s.__)("Delete","progress-planner")})]})]})}function q({task:e,taskId:t,onMoveUp:r,onMoveDown:n}){const a=e.title?.rendered||e.title;return(0,i.jsx)("div",{className:"prpl-move-buttons-wrapper",style:b,children:(0,i.jsxs)("span",{className:"prpl-move-buttons",style:k,children:[(0,i.jsxs)("button",{type:"button",className:"prpl-suggested-task-button move-up",style:w,"data-task-id":t,"data-task-title":a,"data-action":"move-up","data-target":"move-up",title:(0,s.__)("Move up","progress-planner"),onClick:r,children:[(0,i.jsx)("span",{className:"dashicons dashicons-arrow-up-alt2"}),(0,i.jsx)("span",{className:"screen-reader-text",children:(0,s.__)("Move up","progress-planner")})]}),(0,i.jsxs)("button",{type:"button",className:"prpl-suggested-task-button move-down",style:w,"data-task-id":t,"data-task-title":a,"data-action":"move-down","data-target":"move-down",title:(0,s.__)("Move down","progress-planner"),onClick:n,children:[(0,i.jsx)("span",{className:"dashicons dashicons-arrow-down-alt2"}),(0,i.jsx)("span",{className:"screen-reader-text",children:(0,s.__)("Move down","progress-planner")})]})]})})}function H({task:e,isUserTask:t,isCelebrating:r,isCompleted:a=!1,index:o=0,showMoveButtons:s=!0,showActions:l=!0,onComplete:c,onSnooze:d,onDelete:p,onMove:h,onTitleChange:g}){const m=(0,n.useRef)(null),f=(0,n.useRef)(null),[y,v]=(0,n.useState)(!1),[x,b]=(0,n.useState)(!1),k=a||"trash"===e.status||"pending"===e.status,w=(0,n.useCallback)(()=>{c(e.id,e)},[e,c]),C=(0,n.useCallback)(e=>{if("Enter"===e.key)return e.preventDefault(),e.stopPropagation(),e.target.blur(),!1},[]),j=(0,n.useCallback)(()=>{clearTimeout(f.current),f.current=setTimeout(()=>{if(m.current){const t=m.current.textContent.replace(/\n/g,"");g(e.id,t)}},300)},[e.id,g]);(0,n.useEffect)(()=>()=>{f.current&&clearTimeout(f.current)},[]);const M=(0,n.useCallback)(()=>{h(e.id,"up")},[e.id,h]),T=(0,n.useCallback)(()=>{h(e.id,"down")},[e.id,h]),I=(0,n.useCallback)(()=>{p(e.id)},[e.id,p]),E=e.slug||e.id,S=e.prpl_provider?.slug||(t?"user":""),A=["prpl-suggested-task",r?"prpl-suggested-task-celebrated":""].filter(Boolean).join(" ");return(0,i.jsxs)("li",{className:A,style:u(o),"data-task-id":E,"data-post-id":e.id,"data-task-action":"pending"===e.status||r?"celebrate":a?"completed":"","data-task-provider-id":S,"data-task-points":(0,$.$)(e),"data-task-order":e.menu_order||0,onMouseEnter:()=>v(!0),onMouseLeave:()=>v(!1),onFocusCapture:()=>b(!0),onBlurCapture:()=>b(!1),children:[(0,i.jsx)(U,{isUserTask:t,taskIsCompleted:k,isCelebrating:r,task:e,onChange:w}),(0,i.jsx)(W,{task:e,isUserTask:t,isCompleted:a,isCelebrating:r,titleRef:m,onKeyDown:C,onInput:j}),(0,i.jsx)(Z,{task:e,isUserTask:t,onDelete:I}),t&&s&&!a&&(0,i.jsx)(q,{task:e,taskId:E,onMoveUp:M,onMoveDown:T}),l&&(0,i.jsx)("div",{className:"prpl-suggested-task-actions-wrapper",style:_,children:(0,i.jsx)(O,{task:e,isUserTask:t,isActionsVisible:y||x,isCelebrating:r,onComplete:c,onSnooze:d,onDelete:p})})]})}},8493:(e,t,r)=>{r.d(t,{$G:()=>C,CI:()=>k,DF:()=>b,Sm:()=>y,_C:()=>w,nR:()=>g,wA:()=>x});var n=r(2619),a=r(1455),o=r.n(a),s=r(9251);const i=["hello_world_post_id","sample_page_id","inactive_plugins_count","uncategorized_category_id","post_author_count","last_published_post_id","archive_format_count","terms_without_posts","terms_without_description","post_tag_count","published_post_count","unpublished_content","seo_plugin_installed","php_version","wp_debug_status","old_posts_for_review"],l=new Map;let c=new Map,d=[];const p={isPreFetchComplete:!1,isEvaluating:!1,currentIndex:0},u=3,h=5;function g(e){const t=e.providerId;if(!t)return void console.warn("Task class missing providerId, skipping:",e);const r=e.priority||50;(0,n.addFilter)("prpl.tasks.classes",`prpl/task/${t}`,n=>(n.has(t)||n.set(t,{TaskClass:e,priority:r}),n),r),l.set(t,e)}async function m(){try{const e=await o()({path:"/wp/v2/prpl_recommendations?status=publish,trash,future&per_page=100&_embed=true"}),t=new Map;return Array.isArray(e)&&e.forEach(e=>{e.slug&&t.set(e.slug,{...e,_existsInDb:!0,_isActive:"publish"===e.status})}),t}catch(e){return console.error("Error pre-fetching existing tasks:",e),new Map}}function f(){const e=(0,n.applyFilters)("prpl.tasks.classes",new Map);d=Array.from(e.entries()).map(([e,{TaskClass:t,priority:r}])=>({TaskClass:t,priority:r,providerId:e})).sort((e,t)=>e.priority-t.priority)}async function y(e,t){if(!p.isPreFetchComplete){const[e]=await Promise.all([m(),...i.map(e=>(0,s.OJ)(e).catch(()=>null))]);c=e,p.isPreFetchComplete=!0,f()}if(p.isEvaluating)return{complete:!1,tasksAdded:0};p.isEvaluating=!0;let r=0;try{const e=[],n=[];for(;p.currentIndexe.priority-t.priority),n.sort((e,t)=>e.priority-t.priority);for(const{task:n,priority:a}of e)t(n,a),r++;for(let e=0;ee.taskDetails);try{const e=await(0,s.J1)(o);e.success&&e.tasks&&e.tasks.forEach((e,n)=>{if(e.success&&e.task){const{priority:o,taskId:s}=a[n];void 0===e.task.prpl_priority&&(e.task.prpl_priority=o),c.set(s,e.task),t(e.task,o),r++}})}catch(e){409!==e?.data?.status&&console.error("Error creating task batch:",e)}}}finally{p.isEvaluating=!1}return{complete:p.currentIndex>=d.length,tasksAdded:r}}async function v(e,t){const r=e.providerId;try{const n=new e,a=e.isMultiTask||!1,o=n.getTasksToInject&&"function"==typeof n.getTasksToInject;if(a||o)return await async function(e,t,r){const n=t.providerId,a=[],o=[];try{if(e.shouldAddTask&&!await e.shouldAddTask())return{};const t=await e.getTasksToInject();if(!Array.isArray(t))return{};for(const s of t){const t=e.getTaskId?.(s)||n,i=c.get(t);if(i)i._isActive&&(void 0===i.prpl_priority&&(i.prpl_priority=r),a.push({task:i,priority:r}));else if(e.getTaskDetails){const a=await e.getTaskDetails(s);a&&(a.task_id=a.task_id||t,a.provider_id=a.provider_id||n,o.push({taskDetails:a,priority:r,taskId:t}))}}return 1===a.length&&0===o.length?{existing:a[0]}:0===a.length&&1===o.length?{toCreate:o[0]}:a.length>0?{existing:a[0]}:o.length>0?{toCreate:o[0]}:{}}catch(e){return console.error(`Error evaluating multi-task provider "${n}":`,e),{}}}(n,e,t);const s=n.getTaskId?.()||r,i=c.get(s);if(i&&!i._isActive)return{};if(i&&i._isActive)return void 0===i.prpl_priority&&(i.prpl_priority=t),{existing:{task:i,priority:t}};if(!n.shouldAddTask)return{};if(!await n.shouldAddTask())return{};if(!n.getTaskDetails)return{};const l=await n.getTaskDetails();return l?(l.task_id=l.task_id||s,l.provider_id=l.provider_id||r,{toCreate:{taskDetails:l,priority:t,taskId:s}}):{}}catch(e){return console.error(`Error evaluating task "${r}":`,e),{}}}function x(){return!p.isPreFetchComplete||p.currentIndex0)try{await(0,s.J1)(e)}catch(e){409!==e?.data?.status&&console.error("Error creating onboarding tasks:",e)}}},8864:(e,t,r)=>{r.d(t,{fX:()=>d});const n=window.React,a=e=>{let t;const r=new Set,n=(e,n)=>{const a="function"==typeof e?e(t):e;if(!Object.is(a,t)){const e=t;t=(null!=n?n:"object"!=typeof a||null===a)?a:Object.assign({},t,a),r.forEach(r=>r(t,e))}},a=()=>t,o={setState:n,getState:a,getInitialState:()=>s,subscribe:e=>(r.add(e),()=>r.delete(e))},s=t=e(n,a,o);return o},o=e=>e,s=e=>{const t=(e=>e?a(e):a)(e),r=e=>function(e,t=o){const r=n.useSyncExternalStore(e.subscribe,n.useCallback(()=>t(e.getState()),[e,t]),n.useCallback(()=>t(e.getInitialState()),[e,t]));return n.useDebugValue(r),r}(t,e);return Object.assign(r,t),r};var i=r(1455),l=r.n(i),c=r(5337);const d=(p=(e,t)=>({sessionPoints:0,totalPoints:0,lastCompletionTime:null,lastCompletedTask:null,activityScore:{current:0,target:100},badgeProgress:{},cacheInvalidatedAt:null,shouldAutoStartWizard:!1,providerTerms:{},termsLoading:!1,termsLoaded:!1,onTaskCompleted:(t,r=0)=>e(e=>({sessionPoints:e.sessionPoints+r,lastCompletionTime:Date.now(),lastCompletedTask:t})),onTaskUncompleted:(t,r=0)=>e(e=>({sessionPoints:Math.max(0,e.sessionPoints-r)})),updateActivityScore:t=>e(e=>({activityScore:{...e.activityScore,...t}})),updateBadgeProgress:(t,r)=>e(e=>({badgeProgress:{...e.badgeProgress,[t]:r}})),invalidateCache:()=>{(0,c.IL)(),e({cacheInvalidatedAt:Date.now()})},setShouldAutoStartWizard:t=>{e({shouldAutoStartWizard:t})},getProviderTermId:e=>{const r=t();return r.providerTerms[e]?.id||null},fetchProviderTerms:async()=>{const r=t();if(r.termsLoaded||r.termsLoading)return r.providerTerms;e({termsLoading:!0});try{const t=await l()({path:"/wp/v2/prpl_recommendations_provider?per_page=100"}),r={};let n=!1;if(t.forEach(e=>{r[e.slug]=e,"user"===e.slug&&(n=!0)}),!n)try{const e=await l()({path:"/wp/v2/prpl_recommendations_provider",method:"POST",data:{slug:"user",name:"user"}});r.user=e}catch(e){if("term_exists"===e.code&&e.data?.term_id)try{const t=await l()({path:`/wp/v2/prpl_recommendations_provider/${e.data.term_id}`});r.user=t}catch(e){console.error("Error fetching existing user term:",e)}else console.error("Error creating user term:",e)}return e({providerTerms:r,termsLoading:!1,termsLoaded:!0}),r}catch(t){return console.error("Error fetching provider terms:",t),e({termsLoading:!1}),{}}}}))?s(p):s;var p},9061:(e,t,r)=>{r.d(t,{A:()=>o});var n=r(790);const a={arrow:{viewBox:"0 0 20 17",paths:[{d:"M19.92 8.12c-.05-.12-.12-.23-.22-.33L12.21.29A.996.996 0 1 0 10.8 1.7l5.79 5.79H1c-.55 0-1 .45-1 1s.45 1 1 1h15.59l-5.79 5.79a.996.996 0 0 0 .71 1.7c.26 0 .51-.1.71-.29l7.5-7.5c.1-.1.17-.21.22-.33.05-.12.07-.24.08-.38 0-.14-.03-.27-.08-.38Z"}]},trash:{viewBox:"0 0 48 48",paths:[{d:"M32.99 47.88H15.01c-3.46 0-6.38-2.7-6.64-6.15L6.04 11.49l-.72.12c-.82.14-1.59-.41-1.73-1.22-.14-.82.41-1.59 1.22-1.73.79-.14 1.57-.26 2.37-.38h.02c2.21-.33 4.46-.6 6.69-.81v-.72c0-3.56 2.74-6.44 6.25-6.55 2.56-.08 5.15-.08 7.71 0 3.5.11 6.25 2.99 6.25 6.55v.72c2.24.2 4.48.47 6.7.81.79.12 1.59.25 2.38.39.82.14 1.36.92 1.22 1.73-.14.82-.92 1.36-1.73 1.22l-.72-.12-2.33 30.24c-.27 3.45-3.18 6.15-6.64 6.15Zm-17.98-3h17.97c1.9 0 3.51-1.48 3.65-3.38l2.34-30.46c-2.15-.3-4.33-.53-6.48-.7h-.03c-5.62-.43-11.32-.43-16.95 0h-.03c-2.15.17-4.33.4-6.48.7l2.34 30.46c.15 1.9 1.75 3.38 3.65 3.38ZM24 7.01c2.37 0 4.74.07 7.11.22v-.49c0-1.93-1.47-3.49-3.34-3.55-2.5-.08-5.03-.08-7.52 0-1.88.06-3.34 1.62-3.34 3.55v.49c2.36-.15 4.73-.22 7.11-.22Zm5.49 32.26h-.06c-.83-.03-1.47-.73-1.44-1.56l.79-20.65c.03-.83.75-1.45 1.56-1.44.83.03 1.47.73 1.44 1.56l-.79 20.65c-.03.81-.7 1.44-1.5 1.44Zm-10.98 0c-.8 0-1.47-.63-1.5-1.44l-.79-20.65c-.03-.83.61-1.52 1.44-1.56.84 0 1.52.61 1.56 1.44l.79 20.65c.03.83-.61 1.52-1.44 1.56h-.06Z"}]},check:{viewBox:"0 0 20 20",paths:[{d:"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",fillRule:"evenodd",clipRule:"evenodd"}]},close:{viewBox:"0 0 20 20",paths:[{d:"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",fillRule:"evenodd",clipRule:"evenodd"}]},chevronDown:{viewBox:"0 0 24 24",stroke:!0,paths:[{d:"m19.5 8.25-7.5 7.5-7.5-7.5",strokeLinecap:"round",strokeLinejoin:"round"}]},info:{viewBox:"0 0 64 64",paths:[{d:"M32 63.73C14.51 63.73.27 49.49.27 32S14.51.27 32 .27 63.73 14.5 63.73 32 49.5 63.73 32 63.73Zm0-58C17.51 5.73 5.73 17.52 5.73 32S17.52 58.27 32 58.27 58.27 46.48 58.27 32 46.49 5.73 32 5.73Zm1.2 41.4c-.42 0-.83-.05-1.24-.15-1.33-.33-2.46-1.17-3.16-2.34-.71-1.18-.91-2.56-.58-3.9l2.13-8.54c-1.25.36-2.62-.21-3.21-1.42-.66-1.35-.1-2.99 1.25-3.65l.13-.06c1.21-.6 2.6-.7 3.91-.27 1.3.44 2.36 1.35 2.97 2.58.55 1.1.69 2.36.39 3.54l-2.13 8.54c1.22-.36 2.58.19 3.19 1.37.69 1.34.16 2.98-1.18 3.67l-.13.07c-.74.37-1.54.56-2.34.56Zm-2.26-15.17Zm1.09-9.03c-1.65 0-3.02-1.34-3.02-2.99s1.34-3.01 2.99-3.01h.03c1.65 0 2.99 1.34 2.99 2.99s-1.34 3.01-2.99 3.01Z"}]},warning:{viewBox:"0 0 24 24",paths:[{d:"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003ZM12 8.25a.75.75 0 0 1 .75.75v3.75a.75.75 0 0 1-1.5 0V9a.75.75 0 0 1 .75-.75Zm0 8.25a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Z",fillRule:"evenodd",clipRule:"evenodd"}]}};function o({name:e,...t}){const r=a[e];if(!r)return null;const o=r.stroke;return(0,n.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:r.viewBox,fill:o?"none":"currentColor",stroke:o?"currentColor":void 0,strokeWidth:o?"1.5":void 0,"aria-hidden":"true",focusable:"false",...t,children:r.paths.map((e,t)=>(0,n.jsx)("path",{...e},t))})}},9251:(e,t,r)=>{r.d(t,{J1:()=>g,OJ:()=>m,Rt:()=>c,UT:()=>l,cy:()=>d,e4:()=>h,j:()=>i,lC:()=>u,vq:()=>p});var n=r(1455),a=r.n(n),o=r(5337);const s={"1-week":7,"2-weeks":14,"1-month":30,"3-months":90,"6-months":180,"1-year":365,forever:3650};async function i({status:e="publish",perPage:t=5,page:r=1,excludeProvider:n,provider:o,excludeIds:s=[],needsPagination:i=!0}={}){const l={status:e,per_page:t,page:r,_embed:!0,"filter[orderby]":"menu_order","filter[order]":"ASC"};n&&(l.exclude_provider=n),o&&(l.provider=o),s.length>0&&(l.exclude=s.join(","));const c=function(e){const t=new URLSearchParams;return Object.entries(e).forEach(([e,r])=>{Array.isArray(r)?r.forEach(r=>t.append(e,r)):null!=r&&""!==r&&t.append(e,r)}),t.toString()}(l);try{if(!i)return{tasks:await a()({path:`/wp/v2/prpl_recommendations?${c}`})||[],totalPages:1,hasMore:!1};const e=await a()({path:`/wp/v2/prpl_recommendations?${c}`,parse:!1}),t=await e.json(),n=parseInt(e.headers.get("X-WP-TotalPages")||"1",10);return{tasks:t||[],totalPages:n,hasMore:r{r.d(t,{A:()=>c});var n=r(7723),a=r(1059),o=r(9061),s=r(790);const i={display:"flex",justifyContent:"flex-start",flexWrap:"wrap",position:"relative"},l={width:"1.25rem",height:"1.25rem",display:"inline-block",verticalAlign:"bottom",color:"#6b7280"};function c({title:e,tooltipContent:t="",className:r=""}){return(0,s.jsxs)("h2",{className:"prpl-widget-title"+(r?` ${r}`:""),children:[e,t&&(0,s.jsx)("div",{style:i,children:(0,s.jsx)(a.A,{triggerContent:(0,s.jsxs)("span",{style:l,children:[(0,s.jsx)(o.A,{name:"info"}),(0,s.jsx)("span",{className:"screen-reader-text",children:(0,n.__)("More info","progress-planner")})]}),children:t})})]})}},9453:(e,t,r)=>{function n(e=0){e>0?setTimeout(()=>{window.dispatchEvent(new CustomEvent("prpl/grid/resize"))},e):window.dispatchEvent(new CustomEvent("prpl/grid/resize"))}r.d(t,{Z:()=>n})}},e=>{e(e.s=4465)}]);
\ No newline at end of file
diff --git a/build/widget-whats-new-rtl.css b/build/widget-whats-new-rtl.css
new file mode 100644
index 0000000000..b83e7450bc
--- /dev/null
+++ b/build/widget-whats-new-rtl.css
@@ -0,0 +1 @@
+.prpl-tooltip-wrapper .prpl-tooltip p{margin-bottom:0}.prpl-tooltip-wrapper .prpl-tooltip p:first-child{margin-top:0}
diff --git a/build/widget-whats-new.asset.php b/build/widget-whats-new.asset.php
new file mode 100644
index 0000000000..64b3fcf4ea
--- /dev/null
+++ b/build/widget-whats-new.asset.php
@@ -0,0 +1 @@
+ array('react-jsx-runtime', 'wp-api-fetch', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '640b021523a504354f97', 'handle' => 'undefined-widget-whats-new');
diff --git a/build/widget-whats-new.css b/build/widget-whats-new.css
new file mode 100644
index 0000000000..b83e7450bc
--- /dev/null
+++ b/build/widget-whats-new.css
@@ -0,0 +1 @@
+.prpl-tooltip-wrapper .prpl-tooltip p{margin-bottom:0}.prpl-tooltip-wrapper .prpl-tooltip p:first-child{margin-top:0}
diff --git a/build/widget-whats-new.js b/build/widget-whats-new.js
new file mode 100644
index 0000000000..2fcd4db04f
--- /dev/null
+++ b/build/widget-whats-new.js
@@ -0,0 +1 @@
+"use strict";(globalThis.webpackChunkprogress_planner=globalThis.webpackChunkprogress_planner||[]).push([[252],{790:e=>{e.exports=window.ReactJSXRuntime},1059:(e,t,r)=>{r.d(t,{A:()=>u});var n=r(6087),o=r(7723),i=r(790);const s={position:"absolute",top:0,right:0,transform:"translate(-10px, -10px) rotate(90deg)",width:0,height:0,borderStyle:"solid",borderWidth:"7.5px 10px 7.5px 0",borderColor:"transparent var(--prpl-background-activity) transparent transparent"},l={padding:0,lineHeight:1,background:"none",border:"none",cursor:"pointer",fontSize:"var(--prpl-font-size-small)",color:"var(--prpl-color-link)"},a={display:"inline-flex",alignItems:"center",position:"relative"},c={display:"block",position:"absolute",bottom:0,left:"100%",transform:"translate(-100%, calc(100% + 10px))",padding:"0.75rem 1.5rem 0.75rem 0.75rem",width:150,background:"var(--prpl-background-activity)",borderRadius:"var(--prpl-border-radius)",zIndex:2,visibility:"hidden",fontSize:"1rem",fontWeight:400,color:"var(--prpl-color-text)"},d={visibility:"visible",zIndex:10},p={position:"absolute",top:0,right:0,padding:"0.1rem",lineHeight:0,margin:0,background:"none",border:"none",cursor:"pointer"},h={display:"block",position:"fixed",top:0,left:0,width:"100%",height:"100%",zIndex:9,backgroundColor:"rgba(0, 0, 0, 0.5)"};function u({triggerContent:e,children:t,tooltipStyle:r,arrowStyle:u,onClose:g}){const[m,x]=(0,n.useState)(!1),[f,v]=(0,n.useState)(!1),w=(0,n.useRef)(null),y=(0,n.useId)(),b=(0,n.useCallback)(()=>{x(!1),g?.()},[g]);(0,n.useEffect)(()=>{if(!m)return;const e=e=>{"Escape"===e.key&&b()};return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)},[m,b]);const j={...l,textDecoration:f?"underline":"none"};return(0,i.jsxs)("span",{className:"prpl-tooltip-wrapper",style:a,children:[(0,i.jsx)("button",{type:"button",className:"prpl-info-icon","aria-describedby":y,onClick:()=>x(!0),style:j,onMouseEnter:()=>v(!0),onMouseLeave:()=>v(!1),children:e}),m&&(0,i.jsx)("span",{role:"presentation",onClick:b,style:h}),(0,i.jsxs)("span",{ref:w,id:y,className:"prpl-tooltip",role:"tooltip","aria-hidden":!m,style:{...c,...m?d:{},...r},children:[(0,i.jsx)("span",{"data-testid":"tooltip-arrow",style:{...s,...u}}),t,(0,i.jsxs)("button",{type:"button",onClick:b,style:p,children:[(0,i.jsx)("span",{className:"dashicons dashicons-no-alt"}),(0,i.jsx)("span",{className:"screen-reader-text",children:(0,o.__)("Close","progress-planner")})]})]})]})}},1362:(e,t,r)=>{r.d(t,{Cu:()=>i,cr:()=>s});var n=r(2619);const o=[];function i(e){const{id:t,component:r,priority:n=10,width:i=1,forceLastColumn:s=!1,title:l=""}=e;if(!t||!r)return void console.warn("Widget registration failed: id and component are required",e);const a=o.findIndex(e=>e.id===t),c={id:t,component:r,priority:n,width:i,forceLastColumn:s,title:l};a>=0?o[a]=c:o.push(c)}function s(){return[...o].sort((e,t)=>e.priority-t.priority)}(0,n.addAction)("prpl.dashboard.registerWidget","progress-planner/widget-registry",i)},1455:e=>{e.exports=window.wp.apiFetch},2619:e=>{e.exports=window.wp.hooks},4544:(e,t,r)=>{var n=r(6087),o=r(7723),i=r(1362),s=r(8691),l=r(9277),a=r(5815),c=r(790);function d({showImage:e=!0}){return(0,c.jsxs)("li",{children:[e&&(0,c.jsx)(a.iA,{width:"100%",height:"120px",style:{aspectRatio:"3 / 2",marginBottom:"0.75rem",borderRadius:"var(--prpl-border-radius-big)"}}),(0,c.jsx)("div",{style:{marginTop:0,marginBottom:"6px"},children:(0,c.jsx)(a.iA,{width:"85%",height:"var(--prpl-font-size-lg)"})}),(0,c.jsx)("div",{style:{margin:0},children:(0,c.jsx)(a.rr,{lines:2})}),(0,c.jsx)("hr",{})]})}function p({posts:e=2}){return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)("ul",{style:{listStyle:"none",padding:0,margin:0},children:Array.from({length:e}).map((e,t)=>(0,c.jsx)(d,{showImage:0===t},t))}),(0,c.jsx)("div",{style:{display:"flex",justifyContent:"flex-end"},children:(0,c.jsx)(a.iA,{width:"6rem",height:"1rem"})})]})}function h({link:e,url:t}){const[r,o]=(0,n.useState)(!1),i={width:"100%",minHeight:"120px",aspectRatio:"3 / 2",backgroundSize:"cover",marginBottom:"0.75rem",borderRadius:"var(--prpl-border-radius-big)",border:"1px solid var(--prpl-color-border)",backgroundColor:"var(--prpl-color-gauge-remain)",transition:"transform 0.2s, box-shadow 0.2s",backgroundImage:`url(${t})`},s=r?{transform:"scale(1.01)",boxShadow:"4px 4px 8px 0 rgba(0, 0, 0, 0.2)"}:{};return(0,c.jsx)("a",{href:e,target:"_blank",rel:"noopener noreferrer",children:(0,c.jsx)("div",{className:"prpl-blog-post-image",style:{...i,...s},onMouseEnter:()=>o(!0),onMouseLeave:()=>o(!1)})})}function u({link:e,color:t,hoverColor:r,textDecoration:o="none",hoverTextDecoration:i="underline",children:s}){const[l,a]=(0,n.useState)(!1),d={color:l?r:t,textDecoration:l?i:o};return(0,c.jsx)("a",{href:e,target:"_blank",rel:"noopener noreferrer",style:d,onMouseEnter:()=>a(!0),onMouseLeave:()=>a(!1),children:s})}(0,i.Cu)({id:"whats-new",component:function({config:e={}}){const{isLoading:t,data:r}=(0,s.KS)("/progress-planner/v1/widgets/whats-new"),i=e?.title||(0,o.__)("What's new on the Progress Planner blog","progress-planner");if(t)return(0,c.jsxs)(n.Fragment,{children:[(0,c.jsx)(l.A,{title:i}),(0,c.jsx)("hr",{}),(0,c.jsx)(p,{posts:2})]});const a=r?.posts||[],d=r?.blogUrl||"";if(0===a.length)return null;const g={marginTop:0,fontSize:"var(--prpl-font-size-lg)",lineHeight:1.25,fontWeight:600,marginBottom:"6px"},m={margin:0};return(0,c.jsxs)(n.Fragment,{children:[(0,c.jsx)(l.A,{title:i}),(0,c.jsx)("hr",{}),(0,c.jsx)("ul",{style:{listStyle:"none",padding:0,margin:0},children:a.map((e,t)=>(0,c.jsxs)("li",{children:[e.imageUrl&&(0,c.jsx)(h,{link:e.link,url:e.imageUrl}),(0,c.jsx)("h3",{style:g,children:(0,c.jsx)(u,{link:e.link,color:"var(--prpl-color-headings)",hoverColor:"var(--prpl-color-link)",children:e.title})}),(0,c.jsx)("p",{style:m,children:e.excerpt}),(0,c.jsx)("hr",{})]},t))}),(0,c.jsx)("div",{className:"prpl-widget-footer",style:{display:"flex",justifyContent:"flex-end"},children:(0,c.jsx)(u,{link:d,color:"var(--prpl-color-link)",hoverColor:"var(--prpl-color-link-hover)",textDecoration:"underline",hoverTextDecoration:"none",children:(0,o.__)("Read all posts","progress-planner")})})]})},priority:10,width:1,forceLastColumn:!1,title:(0,o.__)("What's new on the Progress Planner blog","progress-planner")})},5337:(e,t,r)=>{r.d(t,{BJ:()=>a,IL:()=>c,Wz:()=>d});var n=r(1455),o=r.n(n);const i=new Map,s=new Map,l=3e5;async function a(e,t={}){const{skipCache:r=!1,ttl:n=l}=t,a=function(e){if("GET"!==(e.method||"GET").toUpperCase())return null;let t=e.path||e.url||"";if(e.data&&"object"==typeof e.data){const r=new URLSearchParams(e.data).toString();r&&(t+=(t.includes("?")?"&":"?")+r)}return`GET:${t}`}(e);if(!a)return o()(e);if(!r&&i.has(a))return i.get(a);if(!r){const e=s.get(a);if(e&&Date.now()-e.timestamp(s.set(a,{data:e,timestamp:Date.now()}),i.delete(a),e)).catch(e=>{throw i.delete(a),e});return i.set(a,c),c}function c(){s.clear(),i.clear()}function d(e,t){const r=`GET:${e}`;s.set(r,{data:t,timestamp:Date.now()})}},5815:(e,t,r)=>{r.d(t,{Q8:()=>d,iA:()=>c,rr:()=>p});var n=r(6087),o=r(790);const i="\n@keyframes prpl-shimmer {\n\t0% { background-position: 200% 0; }\n\t100% { background-position: -200% 0; }\n}\n";let s=!1;function l(){if(s||"undefined"==typeof document)return;const e=document.createElement("style");e.id="prpl-skeleton-keyframes",e.textContent=i,document.head.appendChild(e),s=!0}const a={background:"linear-gradient(\n\t\t90deg,\n\t\tvar(--prpl-color-gauge-remain, #f0f0f0) 25%,\n\t\tvar(--prpl-color-border, #e0e0e0) 50%,\n\t\tvar(--prpl-color-gauge-remain, #f0f0f0) 75%\n\t)",backgroundSize:"200% 100%",animation:"prpl-shimmer 1.5s ease-in-out infinite",borderRadius:"var(--prpl-border-radius, 8px)"};function c({width:e="100%",height:t="1em",className:r="",style:i={}}){return(0,n.useEffect)(()=>{l()},[]),(0,o.jsx)("div",{className:r||void 0,style:{...a,width:e,height:t,...i}})}function d({size:e="40px",className:t="",style:r={}}){return(0,n.useEffect)(()=>{l()},[]),(0,o.jsx)("div",{className:t||void 0,style:{...a,width:e,height:e,borderRadius:"50%",...r}})}function p({width:e="100%",lines:t=1,className:r="",style:i={},lastShort:s=!0}){return(0,n.useEffect)(()=>{l()},[]),1===t?(0,o.jsx)(c,{width:e,height:"1em",className:r,style:i}):(0,o.jsx)("div",{style:{display:"flex",flexDirection:"column",...i},children:Array.from({length:t}).map((n,i)=>(0,o.jsx)(c,{width:s&&i===t-1?"70%":e,height:"1em",className:r,style:{marginBottom:i{e.exports=window.wp.element},7723:e=>{e.exports=window.wp.i18n},8691:(e,t,r)=>{r.d(t,{KS:()=>s});var n=r(6087),o=r(5337);const i=3e5;function s(e,t=[],r="Failed to load data",s={}){const{cache:l=!0,cacheTtl:a=i,skipCache:c=!1}=s,[d,p]=(0,n.useState)(!0),[h,u]=(0,n.useState)(null),[g,m]=(0,n.useState)(null),x=(0,n.useCallback)(async(t=!1)=>{if(e){p(!0),u(null);try{const r=await(0,o.BJ)({path:e},{skipCache:t||c||!l,ttl:a});m(r)}catch(e){const t=e.message||("string"==typeof r?r:r.message||"Failed to load data");u(t)}finally{p(!1)}}else p(!1)},[e,l,a,c,r]);return(0,n.useEffect)(()=>{x()},[e,...t]),{isLoading:d,error:h,data:g,refetch:(0,n.useCallback)((e=!0)=>{x(e)},[x])}}},9061:(e,t,r)=>{r.d(t,{A:()=>i});var n=r(790);const o={arrow:{viewBox:"0 0 20 17",paths:[{d:"M19.92 8.12c-.05-.12-.12-.23-.22-.33L12.21.29A.996.996 0 1 0 10.8 1.7l5.79 5.79H1c-.55 0-1 .45-1 1s.45 1 1 1h15.59l-5.79 5.79a.996.996 0 0 0 .71 1.7c.26 0 .51-.1.71-.29l7.5-7.5c.1-.1.17-.21.22-.33.05-.12.07-.24.08-.38 0-.14-.03-.27-.08-.38Z"}]},trash:{viewBox:"0 0 48 48",paths:[{d:"M32.99 47.88H15.01c-3.46 0-6.38-2.7-6.64-6.15L6.04 11.49l-.72.12c-.82.14-1.59-.41-1.73-1.22-.14-.82.41-1.59 1.22-1.73.79-.14 1.57-.26 2.37-.38h.02c2.21-.33 4.46-.6 6.69-.81v-.72c0-3.56 2.74-6.44 6.25-6.55 2.56-.08 5.15-.08 7.71 0 3.5.11 6.25 2.99 6.25 6.55v.72c2.24.2 4.48.47 6.7.81.79.12 1.59.25 2.38.39.82.14 1.36.92 1.22 1.73-.14.82-.92 1.36-1.73 1.22l-.72-.12-2.33 30.24c-.27 3.45-3.18 6.15-6.64 6.15Zm-17.98-3h17.97c1.9 0 3.51-1.48 3.65-3.38l2.34-30.46c-2.15-.3-4.33-.53-6.48-.7h-.03c-5.62-.43-11.32-.43-16.95 0h-.03c-2.15.17-4.33.4-6.48.7l2.34 30.46c.15 1.9 1.75 3.38 3.65 3.38ZM24 7.01c2.37 0 4.74.07 7.11.22v-.49c0-1.93-1.47-3.49-3.34-3.55-2.5-.08-5.03-.08-7.52 0-1.88.06-3.34 1.62-3.34 3.55v.49c2.36-.15 4.73-.22 7.11-.22Zm5.49 32.26h-.06c-.83-.03-1.47-.73-1.44-1.56l.79-20.65c.03-.83.75-1.45 1.56-1.44.83.03 1.47.73 1.44 1.56l-.79 20.65c-.03.81-.7 1.44-1.5 1.44Zm-10.98 0c-.8 0-1.47-.63-1.5-1.44l-.79-20.65c-.03-.83.61-1.52 1.44-1.56.84 0 1.52.61 1.56 1.44l.79 20.65c.03.83-.61 1.52-1.44 1.56h-.06Z"}]},check:{viewBox:"0 0 20 20",paths:[{d:"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",fillRule:"evenodd",clipRule:"evenodd"}]},close:{viewBox:"0 0 20 20",paths:[{d:"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",fillRule:"evenodd",clipRule:"evenodd"}]},chevronDown:{viewBox:"0 0 24 24",stroke:!0,paths:[{d:"m19.5 8.25-7.5 7.5-7.5-7.5",strokeLinecap:"round",strokeLinejoin:"round"}]},info:{viewBox:"0 0 64 64",paths:[{d:"M32 63.73C14.51 63.73.27 49.49.27 32S14.51.27 32 .27 63.73 14.5 63.73 32 49.5 63.73 32 63.73Zm0-58C17.51 5.73 5.73 17.52 5.73 32S17.52 58.27 32 58.27 58.27 46.48 58.27 32 46.49 5.73 32 5.73Zm1.2 41.4c-.42 0-.83-.05-1.24-.15-1.33-.33-2.46-1.17-3.16-2.34-.71-1.18-.91-2.56-.58-3.9l2.13-8.54c-1.25.36-2.62-.21-3.21-1.42-.66-1.35-.1-2.99 1.25-3.65l.13-.06c1.21-.6 2.6-.7 3.91-.27 1.3.44 2.36 1.35 2.97 2.58.55 1.1.69 2.36.39 3.54l-2.13 8.54c1.22-.36 2.58.19 3.19 1.37.69 1.34.16 2.98-1.18 3.67l-.13.07c-.74.37-1.54.56-2.34.56Zm-2.26-15.17Zm1.09-9.03c-1.65 0-3.02-1.34-3.02-2.99s1.34-3.01 2.99-3.01h.03c1.65 0 2.99 1.34 2.99 2.99s-1.34 3.01-2.99 3.01Z"}]},warning:{viewBox:"0 0 24 24",paths:[{d:"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003ZM12 8.25a.75.75 0 0 1 .75.75v3.75a.75.75 0 0 1-1.5 0V9a.75.75 0 0 1 .75-.75Zm0 8.25a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Z",fillRule:"evenodd",clipRule:"evenodd"}]}};function i({name:e,...t}){const r=o[e];if(!r)return null;const i=r.stroke;return(0,n.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:r.viewBox,fill:i?"none":"currentColor",stroke:i?"currentColor":void 0,strokeWidth:i?"1.5":void 0,"aria-hidden":"true",focusable:"false",...t,children:r.paths.map((e,t)=>(0,n.jsx)("path",{...e},t))})}},9277:(e,t,r)=>{r.d(t,{A:()=>c});var n=r(7723),o=r(1059),i=r(9061),s=r(790);const l={display:"flex",justifyContent:"flex-start",flexWrap:"wrap",position:"relative"},a={width:"1.25rem",height:"1.25rem",display:"inline-block",verticalAlign:"bottom",color:"#6b7280"};function c({title:e,tooltipContent:t="",className:r=""}){return(0,s.jsxs)("h2",{className:"prpl-widget-title"+(r?` ${r}`:""),children:[e,t&&(0,s.jsx)("div",{style:l,children:(0,s.jsx)(o.A,{triggerContent:(0,s.jsxs)("span",{style:a,children:[(0,s.jsx)(i.A,{name:"info"}),(0,s.jsx)("span",{className:"screen-reader-text",children:(0,n.__)("More info","progress-planner")})]}),children:t})})]})}}},e=>{e(e.s=4544)}]);
\ No newline at end of file
diff --git a/classes/admin/class-dashboard-widget-score.php b/classes/admin/class-dashboard-widget-score.php
deleted file mode 100644
index 56aae5ec82..0000000000
--- a/classes/admin/class-dashboard-widget-score.php
+++ /dev/null
@@ -1,115 +0,0 @@
-get_admin__page()->enqueue_styles();
- \progress_planner()->get_admin__enqueue()->enqueue_script( 'web-components/prpl-gauge' );
-
- $suggested_tasks_widget = \progress_planner()->get_admin__page()->get_widget( 'suggested-tasks' );
- if ( $suggested_tasks_widget ) {
- $suggested_tasks_widget->enqueue_styles();
- $suggested_tasks_widget->enqueue_scripts();
- }
-
- \progress_planner()->get_admin__enqueue()->enqueue_style( "progress-planner/dashboard-widgets/{$this->id}" );
-
- \progress_planner()->get_admin__enqueue()->enqueue_script( 'external-link-accessibility-helper' );
-
- // Majoriry of the tasks are now interactive, we need a global object to handle the AJAX requests.
- \progress_planner()->get_admin__enqueue()->enqueue_script(
- 'recommendations/interactive-task',
- [
- 'name' => 'progressPlanner',
- 'data' => [
- 'ajaxUrl' => \admin_url( 'admin-ajax.php' ),
- 'nonce' => \wp_create_nonce( 'progress_planner' ),
- ],
- ]
- );
-
- \progress_planner()->the_view( "dashboard-widgets/{$this->id}.php" );
- }
-
- /**
- * Get the badge.
- *
- * @param string $category The category of the badge.
- *
- * @return array
- */
- public function get_badge_details( $category = 'content' ) {
- static $cached = [
- 'content' => false,
- 'maintenance' => false,
- ];
-
- if ( $cached[ $category ] ) {
- return $cached[ $category ];
- }
-
- // Get the badge to display.
- foreach ( \progress_planner()->get_badges()->get_badges( $category ) as $badge ) {
- $progress = $badge->get_progress();
- if ( 100 > $progress['progress'] ) {
- break;
- }
- }
-
- if ( ! isset( $badge ) || ! isset( $progress ) ) {
- return [];
- }
-
- $result = [
- 'progress' => $progress,
- 'badge' => $badge,
- 'color' => 'var(--prpl-graph-color-1)',
- 'background' => $badge->get_background(),
- ];
-
- if ( $result['progress']['progress'] > 50 ) {
- $result['color'] = 'var(--prpl-color-monthly)';
- }
- if ( $result['progress']['progress'] > 75 ) {
- $result['color'] = 'var(--prpl-graph-color-3)';
- }
-
- $cached[ $category ] = $result;
-
- return $result;
- }
-}
diff --git a/classes/admin/class-dashboard-widget-todo.php b/classes/admin/class-dashboard-widget-todo.php
deleted file mode 100644
index 7f8c08c76c..0000000000
--- a/classes/admin/class-dashboard-widget-todo.php
+++ /dev/null
@@ -1,52 +0,0 @@
-get_admin__page()->enqueue_styles();
-
- $todo_widget = \progress_planner()->get_admin__page()->get_widget( 'todo' );
- if ( $todo_widget ) {
- $todo_widget->enqueue_styles();
- $todo_widget->enqueue_scripts();
- }
-
- \progress_planner()->the_view( "dashboard-widgets/{$this->id}.php" );
-
- \progress_planner()->the_view( 'js-templates/suggested-task.html' );
- }
-}
-// phpcs:enable Generic.Commenting.Todo
diff --git a/classes/admin/class-dashboard-widget.php b/classes/admin/class-dashboard-widget.php
deleted file mode 100644
index 276d9785fb..0000000000
--- a/classes/admin/class-dashboard-widget.php
+++ /dev/null
@@ -1,55 +0,0 @@
-id}",
- $this->get_title(),
- [ $this, 'render_widget' ]
- );
- }
-
- /**
- * Get the title of the widget.
- *
- * @return string
- */
- abstract protected function get_title();
-
- /**
- * Render the dashboard widget.
- *
- * @return void
- */
- abstract public function render_widget();
-}
diff --git a/classes/admin/class-editor.php b/classes/admin/class-editor.php
index 262f13bccb..cebf5d017c 100644
--- a/classes/admin/class-editor.php
+++ b/classes/admin/class-editor.php
@@ -27,6 +27,9 @@ public function __construct() {
public function enqueue_editor_script() {
$page_types = \progress_planner()->get_page_types()->get_page_types();
+ // Initialize default page type.
+ $prpl_preselected_page_type = 0;
+
// Check if the page-type is set in the URL (user is coming from the Settings page).
if ( isset( $_GET['prpl_page_type'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$prpl_pt = \sanitize_text_field( \wp_unslash( $_GET['prpl_page_type'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
@@ -37,21 +40,52 @@ public function enqueue_editor_script() {
break;
}
}
- } else {
- // Get the default page-type.
+ }
+
+ // If no page type was set from URL, get the default.
+ if ( ! $prpl_preselected_page_type ) {
$prpl_preselected_page_type = \progress_planner()->get_page_types()->get_default_page_type( (string) \get_post_type(), (int) \get_the_ID() );
}
- \progress_planner()->get_admin__enqueue()->enqueue_script(
- 'editor',
+ // Enqueue the l10n script to make prplL10nStrings available.
+ \progress_planner()->get_admin__enqueue()->enqueue_script( 'progress-planner/l10n' );
+
+ // Enqueue the built editor script.
+ $editor_asset_file = \constant( 'PROGRESS_PLANNER_DIR' ) . '/build/editor.asset.php';
+ $editor_asset = \file_exists( $editor_asset_file )
+ ? require $editor_asset_file // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable
+ : [
+ 'dependencies' => [],
+ 'version' => \progress_planner()->get_version(),
+ ];
+
+ // Ensure dependencies is an array.
+ if ( ! \is_array( $editor_asset['dependencies'] ) ) {
+ $editor_asset['dependencies'] = [];
+ }
+
+ // Add l10n as a dependency if not already present.
+ if ( ! \in_array( 'progress-planner/l10n', $editor_asset['dependencies'], true ) ) {
+ $editor_asset['dependencies'][] = 'progress-planner/l10n';
+ }
+
+ \wp_enqueue_script(
+ 'progress-planner/editor',
+ \constant( 'PROGRESS_PLANNER_URL' ) . '/build/editor.js',
+ $editor_asset['dependencies'],
+ $editor_asset['version'],
+ true
+ );
+
+ // Localize the script.
+ \wp_localize_script(
+ 'progress-planner/editor',
+ 'progressPlannerEditor',
[
- 'name' => 'progressPlannerEditor',
- 'data' => [
- 'lessons' => \progress_planner()->get_lessons()->get_items(),
- 'pageTypes' => $page_types,
- 'defaultPageType' => $prpl_preselected_page_type,
- 'adminMenuIconSvg' => \progress_planner()->get_ui__branding()->get_admin_menu_icon( true ),
- ],
+ 'lessons' => \progress_planner()->get_lessons()->get_items(),
+ 'pageTypes' => $page_types,
+ 'defaultPageType' => $prpl_preselected_page_type,
+ 'adminMenuIconSvg' => \progress_planner()->get_ui__branding()->get_admin_menu_icon( true ),
]
);
diff --git a/classes/admin/class-enqueue.php b/classes/admin/class-enqueue.php
index 8959089943..6272c122b0 100644
--- a/classes/admin/class-enqueue.php
+++ b/classes/admin/class-enqueue.php
@@ -7,8 +7,6 @@
namespace Progress_Planner\Admin;
-use Progress_Planner\Badges\Monthly;
-
/**
* Enqueue class.
*/
@@ -27,11 +25,7 @@ class Enqueue {
* @var array
*/
const VENDOR_SCRIPTS = [
- 'vendor/tsparticles.confetti.bundle.min' => [
- 'handle' => 'particles-confetti',
- 'version' => '2.11.0',
- ],
- 'vendor/driver.js.iife' => [
+ 'vendor/driver.js.iife' => [
'handle' => 'driver',
'version' => '1.3.1',
],
@@ -53,7 +47,6 @@ class Enqueue {
* @return void
*/
public function init() {
- \add_action( 'admin_head', [ $this, 'maybe_empty_session_storage' ], 1 );
}
/**
@@ -195,121 +188,6 @@ public function localize_script( $handle, $localize_data = [] ) {
'data' => $this->get_localized_strings(),
];
break;
-
- case 'progress-planner/web-components/prpl-badge':
- $localize_data = [
- 'name' => 'progressPlannerBadge',
- 'data' => [
- 'remoteServerRootUrl' => \progress_planner()->get_remote_server_root_url(),
- 'placeholderImageUrl' => \progress_planner()->get_placeholder_svg(),
- ],
- ];
- break;
-
- case 'progress-planner/suggested-task':
- // Celebrate only on the Progress Planner Dashboard page.
- $delay_celebration = true;
- if ( \progress_planner()->is_on_progress_planner_dashboard_page() ) {
- // should_show_upgrade_popover() also checks if we're on the Progress Planner Dashboard page - but let's be explicit since that method might change in the future.
- $delay_celebration = \progress_planner()->get_plugin_upgrade_tasks()->should_show_upgrade_popover();
- }
-
- // Get the providers available for the user.
- $include_providers = [];
- $providers_available_for_user = \progress_planner()->get_suggested_tasks()->get_tasks_manager()->get_task_providers_available_for_user();
- foreach ( $providers_available_for_user as $provider ) {
- // Skip user provider.
- if ( 'user' === $provider->get_provider_id() ) {
- continue;
- }
- $include_providers[] = $provider->get_provider_id();
- }
-
- // Check if user wants to see all recommendations.
- $show_all_recommendations = isset( $_GET['prpl_show_all_recommendations'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
- $tasks_per_page = $show_all_recommendations ? -1 : \Progress_Planner\Admin\Widgets\Suggested_Tasks::PER_PAGE_DEFAULT;
-
- // Get tasks from task providers (limited to 5 by default, or unlimited if showing all).
- $tasks = \progress_planner()->get_suggested_tasks()->get_tasks_in_rest_format(
- [
- 'post_status' => 'publish',
- 'posts_per_page' => $tasks_per_page,
- 'include_provider' => $include_providers, // User provider is already excluded.
- ]
- );
- // Get pending celebration tasks.
- $pending_celebration_tasks = \progress_planner()->get_suggested_tasks()->get_tasks_in_rest_format(
- [
- 'post_status' => 'pending',
- 'posts_per_page' => 100,
- 'include_provider' => $include_providers, // User provider is already excluded.
- ]
- );
-
- // Get user tasks.
- $user_tasks = \progress_planner()->get_suggested_tasks()->get_tasks_in_rest_format(
- [
- 'post_status' => [ 'publish', 'trash' ],
- 'include_provider' => [ 'user' ],
- ]
- );
-
- $localize_data = [
- 'name' => 'prplSuggestedTask',
- 'data' => [
- 'nonce' => \wp_create_nonce( 'progress_planner' ),
- 'assets' => [
- 'infoIcon' => \constant( 'PROGRESS_PLANNER_URL' ) . '/assets/images/icon_info.svg',
- 'snoozeIcon' => \constant( 'PROGRESS_PLANNER_URL' ) . '/assets/images/icon_snooze.svg',
- ],
- 'tasks' => [
- 'pendingTasks' => $tasks,
- 'pendingCelebrationTasks' => $pending_celebration_tasks,
- 'userTasks' => $user_tasks,
- ],
- 'delayCelebration' => $delay_celebration,
- 'tasksPerPage' => $tasks_per_page,
- 'perPageDefault' => \Progress_Planner\Admin\Widgets\Suggested_Tasks::PER_PAGE_DEFAULT,
- ],
- ];
- break;
-
- case 'progress-planner/celebrate':
- // Check if current date is between Feb 12-16 to use hearts confetti.
- $confetti_options = [];
- // February 12 will be (string) '0212', and when converted to int it will be 212.
- // February 16 will be (string) '0216', and when converted to int it will be 216.
- // The integer conversion makes it easier and faster to compare the dates.
- $date_md = (int) \gmdate( 'md' );
-
- if ( 212 <= $date_md && $date_md <= 216 ) {
- $confetti_options = [
- [
- 'particleCount' => 50,
- 'scalar' => 2.2,
- 'shapes' => [ 'heart' ],
- 'colors' => [ 'FFC0CB', 'FF69B4', 'FF1493', 'C71585' ],
- ],
- [
- 'particleCount' => 20,
- 'scalar' => 3.2,
- 'shapes' => [ 'heart' ],
- 'colors' => [ 'FFC0CB', 'FF69B4', 'FF1493', 'C71585' ],
- ],
- ];
- }
- $localize_data = [
- 'name' => 'prplCelebrate',
- 'data' => [
- 'raviIconUrl' => \constant( 'PROGRESS_PLANNER_URL' ) . '/assets/images/icon_progress_planner.svg',
- 'confettiOptions' => $confetti_options,
- ],
- ];
-
- foreach ( $this->get_badge_urls() as $context => $url ) {
- $localize_data['data'][ $context . 'IconUrl' ] = $url;
- }
- break;
}
if ( ! $localize_data['name'] ) {
@@ -324,28 +202,42 @@ public function localize_script( $handle, $localize_data = [] ) {
*
* @return string[] The badge URLs.
*/
- private function get_badge_urls() {
- // Get the monthly badge URL.
- $monthly_badge = \progress_planner()->get_badges()->get_badge( Monthly::get_badge_id_from_date( new \DateTime() ) );
+ public function get_badge_urls() {
+ $badge_urls = [];
- if ( $monthly_badge ) {
- $badge_urls['month'] = \progress_planner()->get_remote_server_root_url() . '/wp-json/progress-planner-saas/v1/badge-svg/?badge_id=' . $monthly_badge->get_id() . '&branding_id=' . (int) \progress_planner()->get_ui__branding()->get_branding_id();
+ // Get the monthly badge URL.
+ $now = new \DateTime();
+ $badge_id = 'monthly-' . $now->format( 'Y' ) . '-m' . $now->format( 'n' );
+ $badge_urls['month'] = \progress_planner()->get_remote_server_root_url() . '/wp-json/progress-planner-saas/v1/badge-svg/?badge_id=' . $badge_id . '&branding_id=' . (int) \progress_planner()->get_ui__branding()->get_branding_id();
+
+ // Get the content and maintenance badge URLs from saved stats.
+ $settings = \progress_planner()->get_settings()->get( 'badges', [] );
+
+ // Content badges.
+ $content_badge_ids = [ 'content-curator', 'revision-ranger', 'purposeful-publisher' ];
+ foreach ( $content_badge_ids as $badge_id ) {
+ if ( isset( $settings[ $badge_id ] ) && (int) ( $settings[ $badge_id ]['progress'] ?? 0 ) >= 100 ) {
+ $badge_urls['content'] = \progress_planner()->get_remote_server_root_url() . '/wp-json/progress-planner-saas/v1/badge-svg/?badge_id=' . $badge_id . '&branding_id=' . (int) \progress_planner()->get_ui__branding()->get_branding_id();
+ break;
+ }
+ }
+ if ( ! isset( $badge_urls['content'] ) ) {
+ // Fallback to the first badge in the set if no badge is completed.
+ $badge_urls['content'] = \progress_planner()->get_remote_server_root_url() . '/wp-json/progress-planner-saas/v1/badge-svg/?badge_id=content-curator&branding_id=' . (int) \progress_planner()->get_ui__branding()->get_branding_id();
}
- // Get the content and maintenance badge URLs.
- foreach ( [ 'content', 'maintenance' ] as $context ) {
- $set_badges = \progress_planner()->get_badges()->get_badges( $context );
- foreach ( $set_badges as $badge ) {
- $progress = $badge->get_progress();
- if ( $progress['progress'] > 100 ) {
- $badge_urls[ $context ] = \progress_planner()->get_remote_server_root_url() . '/wp-json/progress-planner-saas/v1/badge-svg/?badge_id=' . $badge->get_id() . '&branding_id=' . (int) \progress_planner()->get_ui__branding()->get_branding_id();
- }
- }
- if ( ! isset( $badge_urls[ $context ] ) ) {
- // Fallback to the first badge in the set if no badge is completed.
- $badge_urls[ $context ] = \progress_planner()->get_remote_server_root_url() . '/wp-json/progress-planner-saas/v1/badge-svg/?badge_id=' . $set_badges[0]->get_id() . '&branding_id=' . (int) \progress_planner()->get_ui__branding()->get_branding_id();
+ // Maintenance badges.
+ $maintenance_badge_ids = [ 'progress-padawan', 'maintenance-maniac', 'super-site-specialist' ];
+ foreach ( $maintenance_badge_ids as $badge_id ) {
+ if ( isset( $settings[ $badge_id ] ) && (int) ( $settings[ $badge_id ]['progress'] ?? 0 ) >= 100 ) {
+ $badge_urls['maintenance'] = \progress_planner()->get_remote_server_root_url() . '/wp-json/progress-planner-saas/v1/badge-svg/?badge_id=' . $badge_id . '&branding_id=' . (int) \progress_planner()->get_ui__branding()->get_branding_id();
+ break;
}
}
+ if ( ! isset( $badge_urls['maintenance'] ) ) {
+ // Fallback to the first badge in the set if no badge is completed.
+ $badge_urls['maintenance'] = \progress_planner()->get_remote_server_root_url() . '/wp-json/progress-planner-saas/v1/badge-svg/?badge_id=progress-padawan&branding_id=' . (int) \progress_planner()->get_ui__branding()->get_branding_id();
+ }
return $badge_urls;
}
@@ -415,40 +307,4 @@ public function get_localized_strings() {
'fixThisIssue' => \esc_html__( 'Fix this issue for %d points', 'progress-planner' ),
];
}
-
- /**
- * Maybe empty the session storage for the prpl_recommendations post type.
- * We need to do it early, before the WP API script reads the cached data from the browser.
- *
- * @return void
- */
- public function maybe_empty_session_storage() {
- $screen = \get_current_screen();
-
- if ( ! $screen ) {
- return;
- }
-
- // Inject the script only on the Progress Planner Dashboard and the WordPress dashboard pages.
- if ( 'toplevel_page_progress-planner' !== $screen->id && 'dashboard' !== $screen->id ) {
- return;
- }
- ?>
-
-
- */
- public function get_widgets() {
- $widgets = [
- \progress_planner()->get_admin__widgets__suggested_tasks(),
- \progress_planner()->get_admin__widgets__todo(),
- \progress_planner()->get_admin__widgets__monthly_badges(),
- \progress_planner()->get_admin__widgets__badge_streak_content(),
- \progress_planner()->get_admin__widgets__badge_streak_maintenance(),
- \progress_planner()->get_admin__widgets__challenge(),
- \progress_planner()->get_admin__widgets__activity_scores(),
- \progress_planner()->get_admin__widgets__content_activity(),
- \progress_planner()->get_admin__widgets__whats_new(),
- ];
-
- /**
- * Filter the widgets.
- *
- * @param array<\Progress_Planner\Admin\Widgets\Widget> $widgets The widgets.
- *
- * @return array<\Progress_Planner\Admin\Widgets\Widget>
- */
- return \apply_filters( 'progress_planner_admin_widgets', $widgets ); // @phpstan-ignore-line parameter.phpDocType
}
- /**
- * Get a widget object.
- *
- * @param string $id The widget ID.
- *
- * @return \Progress_Planner\Admin\Widgets\Widget|void
- */
- public function get_widget( $id ) {
- $widgets = $this->get_widgets();
- foreach ( $widgets as $widget ) {
- if ( $widget->get_id() === $id ) {
- return $widget;
- }
- }
- }
/**
* Add the admin page.
@@ -157,7 +162,12 @@ public function render_page() {
* @return void
*/
public function enqueue_assets( $hook ) {
- $this->maybe_enqueue_focus_el_script( $hook );
+ // Menu badge positioning styles - needed on all admin pages.
+ \wp_add_inline_style(
+ 'wp-admin',
+ '#toplevel_page_progress-planner{position:relative}#toplevel_page_progress-planner .update-plugins{position:absolute;left:18px;bottom:0;min-width:15px;height:15px;line-height:1.5}#toplevel_page_progress-planner .wp-submenu .update-plugins{display:none}'
+ );
+
if ( 'toplevel_page_progress-planner' !== $hook ) {
return;
}
@@ -188,19 +198,12 @@ public function enqueue_scripts() {
],
];
+ // Always enqueue dashboard - React handles both welcome and dashboard states.
+ $this->enqueue_dashboard_script();
+
if ( true === \progress_planner()->is_privacy_policy_accepted() ) {
- \progress_planner()->get_admin__enqueue()->enqueue_script( 'web-components/prpl-gauge' );
- \progress_planner()->get_admin__enqueue()->enqueue_script( 'web-components/prpl-badge-progress-bar' );
- \progress_planner()->get_admin__enqueue()->enqueue_script( 'web-components/prpl-chart-bar' );
- \progress_planner()->get_admin__enqueue()->enqueue_script( 'web-components/prpl-chart-line' );
- \progress_planner()->get_admin__enqueue()->enqueue_script( 'web-components/prpl-big-counter' );
- \progress_planner()->get_admin__enqueue()->enqueue_script( 'web-components/prpl-tooltip' );
- \progress_planner()->get_admin__enqueue()->enqueue_script( 'header-filters', $default_localization_data );
\progress_planner()->get_admin__enqueue()->enqueue_script( 'settings', $default_localization_data );
- \progress_planner()->get_admin__enqueue()->enqueue_script( 'grid-masonry' );
\progress_planner()->get_admin__enqueue()->enqueue_script( 'upgrade-tasks' );
- } else {
- \progress_planner()->get_admin__enqueue()->enqueue_script( 'onboard', $default_localization_data );
}
\progress_planner()->get_admin__enqueue()->enqueue_script( 'external-link-accessibility-helper' );
@@ -208,68 +211,244 @@ public function enqueue_scripts() {
}
/**
- * Enqueue the focus element script.
- *
- * @param string $hook The current admin page.
+ * Enqueue the unified dashboard React script and widget entry points.
*
* @return void
*/
- public function maybe_enqueue_focus_el_script( $hook ) {
- // Get all registered task providers from the task manager.
- $tasks_providers = \progress_planner()->get_suggested_tasks()->get_tasks_manager()->get_task_providers();
- $tasks_details = [];
- $total_points = 0;
- $completed_points = 0;
-
- // Filter providers to only those relevant to the current admin page.
- foreach ( $tasks_providers as $provider ) {
- $link_setting = $provider->get_link_setting();
-
- // Skip tasks that aren't configured for this admin page.
- if ( ! isset( $link_setting['hook'] ) ||
- $hook !== $link_setting['hook']
- ) {
+ private function enqueue_dashboard_script() {
+ $asset_file = \PROGRESS_PLANNER_DIR . '/build/dashboard.asset.php';
+ if ( ! \file_exists( $asset_file ) ) {
+ return;
+ }
+ $asset = include $asset_file;
+
+ // Enqueue main dashboard script.
+ \wp_enqueue_script(
+ 'progress-planner/dashboard',
+ \constant( 'PROGRESS_PLANNER_URL' ) . '/build/dashboard.js',
+ $asset['dependencies'],
+ $asset['version'],
+ true
+ );
+
+ // Enqueue dashboard styles (includes FormInputs component styles).
+ \wp_enqueue_style(
+ 'progress-planner/dashboard',
+ \constant( 'PROGRESS_PLANNER_URL' ) . '/build/dashboard.css',
+ [],
+ $asset['version']
+ );
+
+ // Preload REST API data to eliminate initial API request waterfalls.
+ // Must be called after script is enqueued but before it runs.
+ $this->preload_rest_data();
+
+ // Enqueue webpack runtime (shared across all entry points).
+ // This ensures modules like Zustand store are instantiated only once.
+ $runtime_asset_file = \PROGRESS_PLANNER_DIR . '/build/runtime.asset.php';
+ if ( \file_exists( $runtime_asset_file ) ) {
+ $runtime_asset = include $runtime_asset_file;
+ \wp_enqueue_script(
+ 'progress-planner/runtime',
+ \constant( 'PROGRESS_PLANNER_URL' ) . '/build/runtime.js',
+ $runtime_asset['dependencies'],
+ $runtime_asset['version'],
+ true
+ );
+ }
+
+ // Enqueue individual widget scripts.
+ $widget_scripts = [
+ 'widget-suggested-tasks',
+ 'widget-todo',
+ 'widget-monthly-badges',
+ 'widget-streak-badges',
+ 'widget-content-badges',
+ 'widget-activity-scores',
+ 'widget-content-activity',
+ 'widget-whats-new',
+ ];
+
+ foreach ( $widget_scripts as $script_handle ) {
+ $widget_asset_file = \PROGRESS_PLANNER_DIR . '/build/' . $script_handle . '.asset.php';
+ if ( ! \file_exists( $widget_asset_file ) ) {
continue;
}
+ $widget_asset = include $widget_asset_file;
+
+ // Widget scripts depend on dashboard and runtime to ensure shared modules.
+ $widget_dependencies = \array_merge(
+ $widget_asset['dependencies'],
+ [ 'progress-planner/dashboard', 'progress-planner/runtime' ]
+ );
+
+ \wp_enqueue_script(
+ 'progress-planner/' . $script_handle,
+ \constant( 'PROGRESS_PLANNER_URL' ) . '/build/' . $script_handle . '.js',
+ $widget_dependencies,
+ $widget_asset['version'],
+ true
+ );
+
+ // Enqueue the corresponding CSS file if it exists.
+ $widget_css_file = \PROGRESS_PLANNER_DIR . '/build/' . $script_handle . '.css';
+ if ( \file_exists( $widget_css_file ) ) {
+ \wp_enqueue_style(
+ 'progress-planner/' . $script_handle,
+ \constant( 'PROGRESS_PLANNER_URL' ) . '/build/' . $script_handle . '.css',
+ [ 'progress-planner/dashboard' ],
+ $widget_asset['version']
+ );
+ }
+ }
- // Build task details for JavaScript.
- $details = [
- 'link_setting' => $link_setting, // Contains selector, hook, and highlight config.
- 'task_id' => $provider->get_task_id(),
- 'points' => $provider->get_points(),
- 'is_complete' => $provider->is_task_completed(),
- ];
+ // Get header configuration.
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
+ $current_range = isset( $_GET['range'] )
+ ? \sanitize_text_field( \wp_unslash( $_GET['range'] ) )
+ : '-6 months';
+ $current_frequency = isset( $_GET['frequency'] )
+ ? \sanitize_text_field( \wp_unslash( $_GET['frequency'] ) )
+ : 'monthly';
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
+
+ // Get logo HTML using output buffering.
+ \ob_start();
+ \progress_planner()->get_ui__branding()->the_logo();
+ $logo_html = \ob_get_clean();
+
+ // Get tour icon SVG.
+ $tour_icon_svg = \progress_planner()->get_asset( 'images/icon_tour.svg' );
+
+ // Get register/subscribe icon SVG.
+ $register_icon_svg = \progress_planner()->get_asset( 'images/register_icon.svg' );
+
+ // Get progress icon SVG for welcome page.
+ $progress_icon_svg = \progress_planner()->get_asset( 'images/icon_progress_planner.svg' );
+
+ // Get current user data for welcome/onboarding form.
+ $current_user = \wp_get_current_user();
+
+ // Localize dashboard config.
+ $dashboard_config = [
+ 'privacyPolicyAccepted' => \progress_planner()->is_privacy_policy_accepted(),
+ // Header configuration.
+ 'licenseKey' => \progress_planner()->get_license_key() ? \progress_planner()->get_license_key() : 'no-license',
+ // Welcome/onboarding configuration.
+ 'onboardNonceURL' => \progress_planner()->get_utils__onboard()->get_remote_url( 'get-nonce' ),
+ 'onboardAPIUrl' => \progress_planner()->get_utils__onboard()->get_remote_url( 'onboard' ),
+ 'ajaxUrl' => \admin_url( 'admin-ajax.php' ),
+ 'nonce' => \wp_create_nonce( 'progress_planner' ),
+ 'userFirstName' => $current_user->user_firstname,
+ 'userEmail' => $current_user->user_email,
+ 'siteUrl' => \site_url(),
+ 'timezoneOffset' => (float) \get_option( 'gmt_offset', 0 ),
+ 'baseUrl' => \constant( 'PROGRESS_PLANNER_URL' ),
+ 'branding' => [
+ 'logoHtml' => $logo_html,
+ 'tourIconHtml' => $tour_icon_svg ? $tour_icon_svg : '',
+ 'registerIconHtml' => $register_icon_svg ? $register_icon_svg : '',
+ 'progressIconHtml' => $progress_icon_svg ? $progress_icon_svg : '',
+ 'homeUrl' => \progress_planner()->get_ui__branding()->get_url( 'https://prpl.fyi/home' ),
+ 'privacyPolicyUrl' => \progress_planner()->get_ui__branding()->get_url( 'https://progressplanner.com/privacy-policy/#h-plugin-privacy-policy' ),
+ ],
+ 'currentRange' => $current_range,
+ 'currentFrequency' => $current_frequency,
+ 'rangeOptions' => [
+ [
+ 'value' => '-3 months',
+ 'label' => \__( 'Activity over the past 3 months', 'progress-planner' ),
+ ],
+ [
+ 'value' => '-6 months',
+ 'label' => \__( 'Activity over the past 6 months', 'progress-planner' ),
+ ],
+ [
+ 'value' => '-12 months',
+ 'label' => \__( 'Activity over the past 12 months', 'progress-planner' ),
+ ],
+ [
+ 'value' => '-18 months',
+ 'label' => \__( 'Activity over the past 18 months', 'progress-planner' ),
+ ],
+ [
+ 'value' => '-24 months',
+ 'label' => \__( 'Activity over the past 24 months', 'progress-planner' ),
+ ],
+ ],
+ 'frequencyOptions' => [
+ [
+ 'value' => 'weekly',
+ 'label' => \__( 'Weekly', 'progress-planner' ),
+ ],
+ [
+ 'value' => 'monthly',
+ 'label' => \__( 'Monthly', 'progress-planner' ),
+ ],
+ ],
+ ];
- $tasks_details[] = $details;
- $total_points += $details['points'];
- if ( $details['is_complete'] ) {
- $completed_points += $details['points'];
- }
+ // Apply filter to allow Onboard_Wizard to add wizard config.
+ $dashboard_config = \apply_filters( 'progress_planner_dashboard_config', $dashboard_config );
+
+ \wp_localize_script(
+ 'progress-planner/dashboard',
+ 'prplDashboardConfig',
+ $dashboard_config
+ );
+
+ // Localize celebration data for confetti.
+ $confetti_options = [];
+ // Check if current date is between Feb 12-16 to use hearts confetti.
+ // February 12 will be (string) '0212', and when converted to int it will be 212.
+ // February 16 will be (string) '0216', and when converted to int it will be 216.
+ // The integer conversion makes it easier and faster to compare the dates.
+ $date_md = (int) \gmdate( 'md' );
+
+ if ( 212 <= $date_md && $date_md <= 216 ) {
+ $confetti_options = [
+ [
+ 'particleCount' => 50,
+ 'scalar' => 2.2,
+ 'shapes' => [ 'heart' ],
+ 'colors' => [ 'FFC0CB', 'FF69B4', 'FF1493', 'C71585' ],
+ ],
+ [
+ 'particleCount' => 20,
+ 'scalar' => 3.2,
+ 'shapes' => [ 'heart' ],
+ 'colors' => [ 'FFC0CB', 'FF69B4', 'FF1493', 'C71585' ],
+ ],
+ ];
}
- // No tasks for this page - don't enqueue the script.
- if ( empty( $tasks_details ) ) {
- return;
+ $celebration_data = [
+ 'raviIconUrl' => \constant( 'PROGRESS_PLANNER_URL' ) . '/assets/images/icon_progress_planner.svg',
+ 'confettiOptions' => $confetti_options,
+ ];
+
+ // Get badge URLs from enqueue class.
+ $enqueue = \progress_planner()->get_admin__enqueue();
+ $badge_urls = $enqueue->get_badge_urls();
+ foreach ( $badge_urls as $context => $url ) {
+ $celebration_data[ $context . 'IconUrl' ] = $url;
}
- // Enqueue the focus element script with task data.
- \progress_planner()->get_admin__enqueue()->enqueue_script(
- 'focus-element',
+ \wp_localize_script(
+ 'progress-planner/dashboard',
+ 'prplCelebrate',
+ $celebration_data
+ );
+
+ // Localize badge configuration for React Badge component.
+ \wp_localize_script(
+ 'progress-planner/dashboard',
+ 'progressPlannerBadge',
[
- 'name' => 'progressPlannerFocusElement',
- 'data' => [
- 'tasks' => $tasks_details,
- 'totalPoints' => $total_points,
- 'completedPoints' => $completed_points,
- 'base_url' => \constant( 'PROGRESS_PLANNER_URL' ),
- 'l10n' => [
- /* translators: %d: The number of points. */
- 'fixThisIssue' => \esc_html__( 'Fix this issue to get %d point(s) in Progress Planner', 'progress-planner' ),
- ],
- ],
+ 'remoteServerRootUrl' => \progress_planner()->get_remote_server_root_url(),
+ 'placeholderImageUrl' => \progress_planner()->get_placeholder_svg(),
]
);
- \progress_planner()->get_admin__enqueue()->enqueue_style( 'progress-planner/focus-element' );
}
/**
@@ -289,12 +468,17 @@ public function enqueue_styles() {
\wp_add_inline_style( 'progress-planner/admin', \progress_planner()->get_ui__branding()->get_custom_css() );
static::$branding_inline_styles_added = true;
}
- \progress_planner()->get_admin__enqueue()->enqueue_style( 'progress-planner/web-components/prpl-tooltip' );
- \progress_planner()->get_admin__enqueue()->enqueue_style( 'progress-planner/web-components/prpl-install-plugin' );
if ( 'toplevel_page_progress-planner' === $current_screen->id ) {
- // Enqueue ugprading (onboarding) tasks styles, these are needed both when privacy policy is accepted and when it is not.
+ // Enqueue upgrading (onboarding) tasks styles, these are needed both when privacy policy is accepted and when it is not.
\progress_planner()->get_admin__enqueue()->enqueue_style( 'progress-planner/upgrade-tasks' );
+ // Enqueue onboarding wizard CSS.
+ \wp_enqueue_style(
+ 'progress-planner-onboarding',
+ \constant( 'PROGRESS_PLANNER_URL' ) . '/assets/css/onboarding/onboarding.css',
+ [],
+ \progress_planner()->get_plugin_version()
+ );
}
}
@@ -323,47 +507,95 @@ public function remove_admin_notices() {
}
/**
- * Clear the cache.
+ * Get REST API paths to preload for dashboard.
*
- * @param \Progress_Planner\Activities\Activity $activity The activity.
+ * Combines static paths from PRELOAD_PATHS constant with dynamic paths
+ * that depend on URL parameters.
+ *
+ * @return string[] Array of REST API paths to preload.
+ */
+ private function get_preload_paths(): array {
+ // Get current range/frequency from URL params or defaults.
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
+ $current_range = isset( $_GET['range'] )
+ ? \sanitize_text_field( \wp_unslash( $_GET['range'] ) )
+ : '-6 months';
+ $current_frequency = isset( $_GET['frequency'] )
+ ? \sanitize_text_field( \wp_unslash( $_GET['frequency'] ) )
+ : 'monthly';
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
+
+ // Merge static paths with dynamic activity-scores path.
+ $preload_paths = self::PRELOAD_PATHS;
+ $preload_paths[] = '/progress-planner/v1/widgets/activity-scores?range=' . \rawurlencode( $current_range ) . '&frequency=' . \rawurlencode( $current_frequency );
+ return $preload_paths;
+ }
+
+ /**
+ * Preload REST API data and inject into page.
+ *
+ * Fetches critical REST API data server-side and injects it as inline JSON.
+ * JavaScript middleware then intercepts apiFetch calls and returns this
+ * preloaded data instantly, bypassing network requests.
*
* @return void
*/
- public function clear_activity_scores_cache( $activity ) {
- if ( 'content' !== $activity->category ) {
- return;
+ private function preload_rest_data(): void {
+ $paths = $this->get_preload_paths();
+ $preload_data = [];
+
+ foreach ( $paths as $path ) {
+ // Parse the path to separate route from query params.
+ $parsed = \wp_parse_url( $path );
+ $route_path = \is_array( $parsed ) && isset( $parsed['path'] ) ? $parsed['path'] : $path;
+
+ // Create REST request.
+ $request = new \WP_REST_Request( 'GET', $route_path );
+
+ // Set query params if present.
+ if ( ! empty( $parsed['query'] ) ) {
+ \parse_str( $parsed['query'], $query_params );
+ foreach ( $query_params as $key => $value ) {
+ $request->set_param( $key, $value );
+ }
+ }
+
+ // Execute the request internally.
+ $response = \rest_do_request( $request );
+
+ // Only store successful responses.
+ if ( ! $response->is_error() ) {
+ // Use the full path (with query params) as the key for JS to match.
+ $preload_data[ $path ] = [
+ 'body' => $response->get_data(),
+ 'headers' => $response->get_headers(),
+ ];
+ }
}
- // Clear the cache for the activity scores widget.
- \progress_planner()->get_settings()->set( \progress_planner()->get_admin__widgets__activity_scores()->get_cache_key(), [] );
+ // Inject preloaded data as inline script BEFORE the dashboard script runs.
+ if ( ! empty( $preload_data ) ) {
+ \wp_add_inline_script(
+ 'progress-planner/dashboard',
+ 'window.prplPreloadedData = ' . \wp_json_encode( $preload_data ) . ';',
+ 'before'
+ );
+ }
}
/**
- * Add a custom admin footer.
+ * Clear the cache.
+ *
+ * @param \Progress_Planner\Activities\Activity $activity The activity.
*
* @return void
*/
- public function admin_footer() {
- ?>
-
- get_settings()->set( 'activities_weekly_post_record', [] );
}
}
diff --git a/classes/admin/class-tour.php b/classes/admin/class-tour.php
index bf7b6bb419..5f2f8984ad 100644
--- a/classes/admin/class-tour.php
+++ b/classes/admin/class-tour.php
@@ -36,7 +36,7 @@ public function get_steps() {
],
],
[
- 'element' => '.prpl-widget-wrapper.prpl-activity-scores prpl-gauge',
+ 'element' => '.prpl-widget-wrapper.prpl-activity-scores .prpl-gauge',
'popover' => [
'title' => \esc_html__( 'Website activity score', 'progress-planner' ),
'description' => \esc_html__( "This is the website activity score. It shows how active you've been on your website.", 'progress-planner' ),
@@ -63,25 +63,7 @@ public function get_steps() {
],
],
[
- 'element' => '#prpl-popover-monthly-badges-trigger',
- 'popover' => [
- 'title' => \esc_html__( 'Monthly badges', 'progress-planner' ),
- 'description' => \esc_html__( 'With this button you can open the monthly badges.', 'progress-planner' ),
- 'side' => 'top',
- 'align' => 'center',
- ],
- ],
- [
- 'element' => '#prpl-popover-monthly-badges',
- 'popover' => [
- 'title' => \esc_html__( 'Your badges', 'progress-planner' ),
- 'description' => \esc_html__( 'As you progress and are more active on your website, you can earn badges. These badges are displayed here!', 'progress-planner' ),
- 'side' => 'top',
- 'align' => 'center',
- ],
- ],
- [
- 'element' => '.prpl-widget-wrapper.prpl-badge-streak .prpl-info-icon',
+ 'element' => '.prpl-widget-wrapper.prpl-badge-streak-maintenance .prpl-info-icon',
'popover' => [
'title' => \esc_html__( 'Your badge progress', 'progress-planner' ),
'description' => \esc_html__( 'Clicking the info icon will show you more information about your badge progress. You can also learn about streak freezes here.', 'progress-planner' ),
diff --git a/classes/admin/widgets/class-badge-streak-content.php b/classes/admin/widgets/class-badge-streak-content.php
deleted file mode 100644
index eca6d5244a..0000000000
--- a/classes/admin/widgets/class-badge-streak-content.php
+++ /dev/null
@@ -1,28 +0,0 @@
-get_admin__enqueue()->enqueue_style( 'progress-planner/page-widgets/badge-streak' );
- }
-
- /**
- * Get the badge.
- *
- * @param string $context The context of the badges (content|maintenance|monthly).
- *
- * @return \Progress_Planner\Badges\Badge|false
- */
- public function get_details( $context ) {
- static $result = [];
- if ( isset( $result[ $context ] ) && ! empty( $result[ $context ] ) ) {
- return $result[ $context ];
- }
-
- $badges = \progress_planner()->get_badges()->get_badges( $context );
-
- // Get the badge to display.
- foreach ( $badges as $badge ) {
- $progress = $badge->get_progress();
- if ( 100 >= $progress['progress'] ) {
- $result[ $context ] = $badge;
- break;
- }
- }
-
- return isset( $result[ $context ] ) ? $result[ $context ] : false;
- }
-}
diff --git a/classes/admin/widgets/class-challenge.php b/classes/admin/widgets/class-challenge.php
deleted file mode 100644
index 79fc75e87f..0000000000
--- a/classes/admin/widgets/class-challenge.php
+++ /dev/null
@@ -1,99 +0,0 @@
-get_cache_key();
- $feed_data = \progress_planner()->get_utils__cache()->get( $cache_key );
-
- // Transient not set.
- if ( false === $feed_data ) {
- $feed_data = [
- 'feed' => [],
- 'expires' => 0,
- ];
- }
-
- // Transient expired, fetch new feed.
- if ( $feed_data['expires'] < \time() ) {
- // Get the feed using the REST API.
- $response = \wp_remote_get( $this->get_remote_api_url() );
-
- if ( 200 !== \wp_remote_retrieve_response_code( $response ) ) {
- // If we cant fetch the feed, we will try again later.
- $feed_data['expires'] = \time() + 5 * MINUTE_IN_SECONDS;
- } else {
- $feed = \json_decode( \wp_remote_retrieve_body( $response ), true );
-
- $feed_data['feed'] = $feed;
- $feed_data['expires'] = \time() + 1 * DAY_IN_SECONDS;
- if ( empty( $feed ) ) {
- $feed_data['expires'] = \time() + 1 * HOUR_IN_SECONDS;
- }
- }
-
- // Transient uses 'expires' key to determine if it's expired.
- \progress_planner()->get_utils__cache()->set( $cache_key, $feed_data, 0 );
- }
-
- return $feed_data['feed'];
- }
-
- /**
- * Render the widget.
- *
- * @return void
- */
- public function render() {
- if ( empty( $this->get_challenge() ) ) {
- return;
- }
- parent::render();
- }
-
- /**
- * Get the cache key.
- *
- * @return string
- */
- public function get_cache_key() {
- return \md5( $this->get_remote_api_url() );
- }
-
- /**
- * Get the remote-API URL.
- *
- * @return string
- */
- public function get_remote_api_url() {
- return \add_query_arg(
- [
- 'license_key' => \progress_planner()->get_license_key(),
- 'site' => \get_site_url(),
- ],
- \progress_planner()->get_remote_server_root_url() . '/wp-json/progress-planner-saas/v1/challenges'
- );
- }
-}
diff --git a/classes/admin/widgets/class-content-activity.php b/classes/admin/widgets/class-content-activity.php
deleted file mode 100644
index 0c6198b830..0000000000
--- a/classes/admin/widgets/class-content-activity.php
+++ /dev/null
@@ -1,87 +0,0 @@
-get_chart_args( $type, $color ),
- [
- // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
- 'count_callback' => fn( $activities, $date = null ) => \count( $activities ),
- 'return_data' => [ 'label', 'score' ],
- ]
- );
- }
-
- /**
- * Get the chart args.
- *
- * @param string $type The type of activity.
- * @param string $color The color of the chart.
- *
- * @return array The chart args.
- */
- public function get_chart_args( $type = 'publish', $color = '#534786' ) {
- return [
- 'type' => 'line',
- 'items_callback' => fn( $start_date, $end_date ) => \progress_planner()->get_activities__query()->query_activities(
- [
- 'category' => 'content',
- 'start_date' => $start_date,
- 'end_date' => $end_date,
- 'type' => $type,
- ]
- ),
- 'dates_params' => [
- 'start_date' => \DateTime::createFromFormat( 'Y-m-d', \gmdate( 'Y-m-01' ) )->modify( $this->get_range() ),
- 'end_date' => new \DateTime(),
- 'frequency' => $this->get_frequency(),
- 'format' => 'M',
- ],
- 'filter_results' => [ $this, 'filter_activities' ],
- 'color' => fn() => $color,
- ];
- }
-
- /**
- * Callback to filter the activities.
- *
- * @param \Progress_Planner\Activities\Content[] $activities The activities array.
- *
- * @return \Progress_Planner\Activities\Content[]
- */
- public function filter_activities( $activities ) {
- return \array_filter(
- $activities,
- fn( $activity ) => 'delete' === $activity->type
- || ( \is_object( $activity->get_post() )
- && \in_array( $activity->get_post()->post_type, \progress_planner()->get_activities__content_helpers()->get_post_types_names(), true )
- )
- );
- }
-}
diff --git a/classes/admin/widgets/class-monthly-badges.php b/classes/admin/widgets/class-monthly-badges.php
deleted file mode 100644
index b50c2050f1..0000000000
--- a/classes/admin/widgets/class-monthly-badges.php
+++ /dev/null
@@ -1,92 +0,0 @@
- The scores.
- */
- public function get_score() {
- $activities = \progress_planner()->get_activities__query()->query_activities(
- [
- 'category' => 'suggested_task',
- 'start_date' => \DateTime::createFromFormat( 'Y-m-d', \gmdate( 'Y-m-01' ) ),
- 'end_date' => \DateTime::createFromFormat( 'Y-m-d', \gmdate( 'Y-m-t' ) ),
- ]
- );
-
- $score = 0;
- foreach ( $activities as $activity ) {
- $score += $activity->get_points( $activity->date );
- }
-
- return [
- 'score' => (int) $score,
- 'target' => (int) Monthly::TARGET_POINTS,
- 'target_score' => (int) \min( Monthly::TARGET_POINTS, \max( 0, \floor( $score ) ) ),
- ];
- }
-
- /**
- * Get previous month badge.
- *
- * @return \Progress_Planner\Badges\Monthly[]
- */
- public function get_previous_incomplete_months_badges() {
- $previous_incomplete_month_badges = [];
-
- $minus_one_month = ( new DateTime() )->modify( 'first day of previous month' );
- $minus_one_month_badge = Monthly::get_instance_from_id( Monthly::get_badge_id_from_date( $minus_one_month ) );
- if ( $minus_one_month_badge && $minus_one_month_badge->progress_callback()['progress'] < 100 ) {
- $previous_incomplete_month_badges[] = $minus_one_month_badge;
- }
-
- $minus_two_months = ( new DateTime() )->modify( 'first day of previous month' )->modify( 'first day of previous month' );
- $minus_two_months_badge = Monthly::get_instance_from_id( Monthly::get_badge_id_from_date( $minus_two_months ) );
- if ( $minus_two_months_badge && $minus_two_months_badge->progress_callback()['progress'] < 100 ) {
- $previous_incomplete_month_badges[] = $minus_two_months_badge;
- }
-
- return $previous_incomplete_month_badges;
- }
-
- /**
- * Get the stylesheet dependencies.
- *
- * @return array
- */
- public function get_stylesheet_dependencies() {
- // Register styles for the web-component.
- \wp_register_style(
- 'progress-planner-suggested-task',
- \constant( 'PROGRESS_PLANNER_URL' ) . '/assets/css/suggested-task.css',
- [],
- \progress_planner()->get_file_version( \constant( 'PROGRESS_PLANNER_DIR' ) . '/assets/css/suggested-task.css' )
- );
-
- return [
- 'progress-planner-suggested-task',
- ];
- }
-}
diff --git a/classes/admin/widgets/class-suggested-tasks.php b/classes/admin/widgets/class-suggested-tasks.php
deleted file mode 100644
index 435e5f0616..0000000000
--- a/classes/admin/widgets/class-suggested-tasks.php
+++ /dev/null
@@ -1,54 +0,0 @@
-get_file_version( \constant( 'PROGRESS_PLANNER_DIR' ) . '/assets/css/suggested-task.css' )
- );
-
- return [
- 'progress-planner-suggested-task',
- ];
- }
-}
diff --git a/classes/admin/widgets/class-todo.php b/classes/admin/widgets/class-todo.php
deleted file mode 100644
index 171abb3d0a..0000000000
--- a/classes/admin/widgets/class-todo.php
+++ /dev/null
@@ -1,123 +0,0 @@
-' . \esc_html__( 'Write down all the website maintenance tasks you want to get done!', 'progress-planner' ) . '';
- $this->the_todo_list();
- }
-
- /**
- * The TODO list.
- *
- * @return void
- */
- public function the_todo_list() {
- ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- the_asset( 'images/icon_exclamation_triangle_solid.svg' ); ?>
-
-
-
-
-
-
-
-
-
-
-
- get_file_version( \constant( 'PROGRESS_PLANNER_DIR' ) . '/assets/css/suggested-task.css' )
- );
-
- return [
- 'progress-planner-suggested-task',
- ];
- }
-}
-// phpcs:enable Generic.Commenting.Todo
diff --git a/classes/admin/widgets/class-widget.php b/classes/admin/widgets/class-widget.php
deleted file mode 100644
index 53b4c81a33..0000000000
--- a/classes/admin/widgets/class-widget.php
+++ /dev/null
@@ -1,123 +0,0 @@
-id;
- }
-
- /**
- * Get the widget range.
- *
- * @return string
- */
- public function get_range() {
- return $this->get_sanitized_get( 'range', '-6 months' );
- }
-
- /**
- * Get the widget frequency.
- *
- * @return string
- */
- public function get_frequency() {
- return $this->get_sanitized_get( 'frequency', 'monthly' );
- }
-
- /**
- * Render the widget.
- *
- * @return void
- */
- public function render() {
- $this->enqueue_styles();
- $this->enqueue_scripts();
- ?>
-
- get_admin__enqueue()->enqueue_style( "progress-planner/page-widgets/{$this->id}" );
- }
-
- /**
- * Enqueue scripts.
- *
- * @return void
- */
- public function enqueue_scripts() {
- \progress_planner()->get_admin__enqueue()->enqueue_script( 'widgets/' . $this->id );
- }
-
- /**
- * Get the stylesheet dependencies.
- *
- * @return array
- */
- public function get_stylesheet_dependencies() {
- return [];
- }
-}
diff --git a/classes/badges/class-badge-content.php b/classes/badges/class-badge-content.php
deleted file mode 100644
index d03a3db07d..0000000000
--- a/classes/badges/class-badge-content.php
+++ /dev/null
@@ -1,21 +0,0 @@
- Goal::class,
- 'id' => 'weekly_activity',
- 'title' => \esc_html__( 'Weekly activity', 'progress-planner' ),
- 'description' => \esc_html__( 'Streak: The number of weeks this goal has been accomplished consistently.', 'progress-planner' ),
- 'status' => 'active',
- 'priority' => 'low',
- 'evaluate' => fn( $goal_object ) => \count(
- \progress_planner()->get_activities__query()->query_activities(
- [
- 'start_date' => $goal_object->get_details()['start_date'],
- 'end_date' => $goal_object->get_details()['end_date'],
- ]
- )
- ),
- ],
- [
- 'frequency' => 'weekly',
- 'start_date' => \progress_planner()->get_activation_date(),
- 'end_date' => new \DateTime(), // Today.
- 'allowed_break' => 1, // Allow break in the streak for 1 week.
- ]
- );
- }
-
- /**
- * Get the saved progress.
- *
- * @return array
- */
- protected function get_saved() {
- $value = parent::get_saved();
-
- if ( isset( $value['progress'] ) && 100 === $value['progress'] ) {
- return $value;
- }
-
- if ( isset( $value['date'] ) ) {
- $last_date = new \DateTime( $value['date'] );
- $diff = $last_date->diff( new \DateTime() );
- if ( $diff->days <= 2 ) {
- return $value;
- }
- }
-
- return [];
- }
-}
diff --git a/classes/badges/class-badge.php b/classes/badges/class-badge.php
deleted file mode 100644
index dedb3c0f11..0000000000
--- a/classes/badges/class-badge.php
+++ /dev/null
@@ -1,115 +0,0 @@
-id;
- }
-
- /**
- * Get the badge name.
- *
- * @return string
- */
- abstract public function get_name();
-
- /**
- * Get the badge description.
- *
- * @return string
- */
- abstract public function get_description();
-
- /**
- * Progress callback.
- *
- * @param array $args The arguments for the progress callback.
- *
- * @return array
- */
- abstract public function progress_callback( $args = [] );
-
- /**
- * Get the saved progress.
- *
- * @return array
- */
- protected function get_saved() {
- return \progress_planner()->get_settings()->get( [ 'badges', $this->id ], [] );
- }
-
- /**
- * Get the badge progress.
- *
- * @return array
- */
- public function get_progress() {
- return $this->progress_callback();
- }
-
- /**
- * Save the progress.
- *
- * @param array $progress The progress to save.
- *
- * @return void
- */
- protected function save_progress( $progress ) {
- $progress['date'] = ( new \DateTime() )->format( 'Y-m-d H:i:s' );
- \progress_planner()->get_settings()->set( [ 'badges', $this->id ], $progress );
- }
-
- /**
- * Clear the saved progress.
- *
- * @return void
- */
- public function clear_progress() {
- \progress_planner()->get_settings()->set( [ 'badges', $this->id ], [] );
- }
-
- /**
- * Get the background color for the badge.
- *
- * @return string
- */
- public function get_background() {
- return $this->background;
- }
-}
diff --git a/classes/badges/class-monthly.php b/classes/badges/class-monthly.php
deleted file mode 100644
index 449fe35aa9..0000000000
--- a/classes/badges/class-monthly.php
+++ /dev/null
@@ -1,328 +0,0 @@
-id = $id;
- }
-
- /**
- * Get an array of instances (one for each month).
- *
- * @return array
- */
- public static function init_badges() {
- if ( ! empty( self::$instances ) ) {
- return self::$instances;
- }
-
- $activation_date = \progress_planner()->get_activation_date();
- if ( $activation_date < new \DateTime( 'first day of November 2024' ) ) { // When badges were introduced.
- $start_date = $activation_date->modify( 'first day of November 2024' );
- } else {
- $start_date = $activation_date->modify( 'first day of this month' );
- }
-
- // Year when plugin was released.
- $end_date = ( 2024 === (int) $start_date->format( 'Y' ) && 2024 === (int) \gmdate( 'Y' ) )
- ? new \DateTime( 'last day of December next year' )
- : new \DateTime( 'last day of December this year' );
-
- $dates = \iterator_to_array( new \DatePeriod( $start_date, new \DateInterval( 'P1M' ), $end_date ), false );
-
- // To make sure keys are defined only once and consistent.
- $self_months = \array_keys( self::get_months() );
-
- foreach ( $dates as $date ) {
- $year = (int) $date->format( 'Y' );
- $month = (int) $date->format( 'n' );
- $id = 'monthly-' . $year . '-' . $self_months[ $month - 1 ];
-
- if ( ! isset( self::$instances[ $year ] ) ) {
- self::$instances[ $year ] = [];
- }
-
- self::$instances[ $year ][] = new self( $id );
- }
-
- return self::$instances;
- }
-
- /**
- * Get an array of instances (one for each month).
- *
- * @return array
- */
- public static function get_instances() {
- if ( empty( self::$instances ) ) {
- self::$instances = self::init_badges();
- }
- return self::$instances;
- }
-
- /**
- * Get an array of instances (one for each month).
- *
- * @param int $year The year.
- *
- * @return array
- */
- public static function get_instances_for_year( $year ) {
- if ( empty( self::$instances ) ) {
- self::$instances = self::init_badges();
- }
- return isset( self::$instances[ $year ] ) ? self::$instances[ $year ] : [];
- }
-
- /**
- * Get the badge ID from a date.
- *
- * @param \DateTime $date The date.
- *
- * @return string
- */
- public static function get_badge_id_from_date( $date ) {
- return 'monthly-' . $date->format( 'Y' ) . '-m' . $date->format( 'n' );
- }
-
- /**
- * Get the badge object from a badge ID.
- *
- * @param string $badge_id The badge ID.
- *
- * @return \Progress_Planner\Badges\Monthly|null
- */
- public static function get_instance_from_id( $badge_id ) {
- $year = (int) \explode( '-', \str_replace( 'monthly-', '', $badge_id ) )[0];
- $month = (int) \str_replace( 'm', '', \explode( '-', \str_replace( 'monthly-', '', $badge_id ) )[1] );
-
- $instances = self::get_instances();
-
- if ( isset( $instances[ $year ] ) ) {
- foreach ( $instances[ $year ] as $instance ) {
- if ( (int) $instance->get_month() === $month ) {
- return $instance;
- }
- }
- }
-
- return null;
- }
-
- /**
- * Get an array of months.
- *
- * @return array
- */
- public static function get_months() {
- /*
- * Indexed months, The array keys are prefixed with an "m"
- * so that they are strings and not integers.
- */
- $months = [
- 'm1' => 'Jack January',
- 'm2' => 'Felix February',
- 'm3' => 'Mary March',
- 'm4' => 'Avery April',
- 'm5' => 'Matteo May',
- 'm6' => 'Jasmine June',
- 'm7' => 'Joey July',
- 'm8' => 'Abed August',
- 'm9' => 'Sam September',
- 'm10' => 'Oksana October',
- 'm11' => 'Noah November',
- 'm12' => 'Daisy December',
- ];
- return $months;
- }
-
- /**
- * The badge name.
- *
- * @return string
- */
- public function get_name() {
- return $this->id
- ? self::get_months()[ 'm' . $this->get_month() ]
- : '';
- }
-
- /**
- * Get the badge description.
- *
- * @return string
- */
- public function get_description() {
- return '';
- }
-
- /**
- * Get the year for the month.
- *
- * @return string
- */
- public function get_year() {
- return \explode( '-', \str_replace( 'monthly-', '', $this->id ) )[0];
- }
-
- /**
- * Get the month for the badge.
- *
- * @return string
- */
- public function get_month() {
- return \str_replace( 'm', '', \explode( '-', \str_replace( 'monthly-', '', $this->id ) )[1] );
- }
-
- /**
- * Progress callback.
- *
- * @param array $args The arguments for the progress callback.
- *
- * @return array
- */
- public function progress_callback( $args = [] ) {
- $saved_progress = $this->get_saved();
-
- // If we have a saved value, return it.
- if ( isset( $saved_progress['progress'] )
- && isset( $saved_progress['remaining'] )
- && isset( $saved_progress['points'] )
- && 100 === $saved_progress['progress']
- ) {
- return $saved_progress;
- }
-
- $month = self::get_months()[ 'm' . $this->get_month() ];
- $year = $this->get_year();
- $month_num = (int) $this->get_month();
-
- $start_date = \DateTime::createFromFormat( 'Y-m-d', "{$year}-{$month_num}-01" );
- $end_date = \DateTime::createFromFormat( 'Y-m-d', "{$year}-{$month_num}-" . \gmdate( 't', \strtotime( $month ) ) );
-
- // Get the activities for the month.
- $activities = \progress_planner()->get_activities__query()->query_activities(
- [
- 'category' => 'suggested_task',
- 'start_date' => $start_date,
- 'end_date' => $end_date,
- ],
- );
-
- $points = 0;
- foreach ( $activities as $activity ) {
- $points += $activity->get_points( $activity->date );
- }
-
- $return_progress = [
- 'progress' => (int) \max( 0, \min( 100, \floor( 100 * $points / self::TARGET_POINTS ) ) ),
- 'remaining' => (int) \max( 0, \min( self::TARGET_POINTS - $points, 10 ) ),
- 'points' => $points,
- ];
-
- $this->save_progress( $return_progress );
-
- if ( $points >= self::TARGET_POINTS || ( isset( $args['no_next_badge_points'] ) && $args['no_next_badge_points'] ) ) {
- return $return_progress;
- }
-
- $points += $this->get_next_badges_excess_points();
- return [
- 'progress' => (int) \max( 0, \min( 100, \floor( 100 * $points / self::TARGET_POINTS ) ) ),
- 'remaining' => (int) \max( 0, \min( self::TARGET_POINTS - $points, 10 ) ),
- 'points' => $points,
- ];
- }
-
- /**
- * Get the next badge-ID.
- *
- * @return string
- */
- public function get_next_badge_id() {
- $year = $this->get_year();
- $month = $this->get_month();
- $month = $month < 10 ? "0$month" : $month;
- $datetime = \DateTime::createFromFormat( 'Y-m-d', "{$year}-{$month}-10" );
- if ( ! $datetime ) {
- return '';
- }
- return self::get_badge_id_from_date( $datetime->modify( 'first day of next month' ) );
- }
-
- /**
- * Get the next badge that has an excess of points, going forward up to 2 months.
- *
- * @return int
- */
- public function get_next_badges_excess_points() {
- $next_1_badge_points = 0;
- $next_2_badge_points = 0;
- $badge_1_excess_points = 0;
- $badge_2_excess_points = 0;
-
- // Get the next badge object.
- $next_1_badge = self::get_instance_from_id( $this->get_next_badge_id() );
- if ( $next_1_badge ) {
- $next_1_badge_points = $next_1_badge->progress_callback( [ 'no_next_badge_points' => true ] )['points'];
-
- $next_2_badge = self::get_instance_from_id( $next_1_badge->get_next_badge_id() );
- if ( $next_2_badge ) {
- $next_2_badge_points = $next_2_badge->progress_callback( [ 'no_next_badge_points' => true ] )['points'];
- }
- }
-
- // If the $next_1_badge has more than 10 points, calculate the excess points.
- if ( $next_1_badge_points > self::TARGET_POINTS ) {
- $badge_1_excess_points = \max( 0, $next_1_badge_points - self::TARGET_POINTS );
- }
-
- // If the $next_2_badge has more than 10 points, calculate the excess points.
- if ( $next_2_badge_points > self::TARGET_POINTS ) {
- $badge_2_excess_points = \max( 0, $next_2_badge_points - self::TARGET_POINTS );
-
- // Does the $next_1_badge need more points to reach 10?
- if ( $next_1_badge_points < self::TARGET_POINTS ) {
- $badge_2_excess_points = \max( 0, ( $next_1_badge_points + $badge_2_excess_points ) - self::TARGET_POINTS );
- }
- }
-
- return (int) $badge_1_excess_points + (int) $badge_2_excess_points;
- }
-}
diff --git a/classes/badges/content/class-content-curator.php b/classes/badges/content/class-content-curator.php
deleted file mode 100644
index bb4e9a3653..0000000000
--- a/classes/badges/content/class-content-curator.php
+++ /dev/null
@@ -1,112 +0,0 @@
-get_saved();
-
- // If we have a saved value, return it.
- if ( isset( $saved_progress['progress'] ) && isset( $saved_progress['remaining'] ) ) {
- return $saved_progress;
- }
-
- // Get the total number of posts.
- $total_posts_count = 0;
- foreach ( \progress_planner()->get_activities__content_helpers()->get_post_types_names() as $post_type ) {
- $total_posts_count += \wp_count_posts( $post_type )->publish;
- }
-
- $remaining = 20 - \min( 20, $total_posts_count );
-
- // If there are 20 existing posts, save the badge as complete and return.
- if ( 0 === $remaining ) {
- $this->save_progress(
- [
- 'progress' => 100,
- 'remaining' => 0,
- ]
- );
-
- return [
- 'progress' => 100,
- 'remaining' => 0,
- ];
- }
-
- // Get the new posts count.
- $new_count = \count(
- \progress_planner()->get_activities__query()->query_activities(
- [
- 'category' => 'content',
- 'type' => 'publish',
- 'start_date' => \progress_planner()->get_activation_date(),
- ]
- )
- );
-
- $remaining_new = 10 - \min( 10, $new_count );
-
- $final_percent = \max(
- \min( 100, \floor( $total_posts_count / 2 ) ),
- \min( 100, \floor( $new_count * 10 ) )
- );
- $final_remaining = \min( $remaining, $remaining_new );
-
- $this->save_progress(
- [
- 'progress' => $final_percent,
- 'remaining' => $final_remaining,
- ]
- );
-
- return [
- 'progress' => $final_percent,
- 'remaining' => $final_remaining,
- ];
- }
-}
diff --git a/classes/badges/content/class-purposeful-publisher.php b/classes/badges/content/class-purposeful-publisher.php
deleted file mode 100644
index bcaf594278..0000000000
--- a/classes/badges/content/class-purposeful-publisher.php
+++ /dev/null
@@ -1,84 +0,0 @@
-get_saved();
-
- // If we have a saved value, return it.
- if ( isset( $saved_progress['progress'] ) && isset( $saved_progress['remaining'] ) ) {
- return $saved_progress;
- }
-
- // Get the number of new posts published.
- $new_count = \count(
- \progress_planner()->get_activities__query()->query_activities(
- [
- 'category' => 'content',
- 'type' => 'publish',
- 'start_date' => \progress_planner()->get_activation_date(),
- ],
- )
- );
-
- $percent = \min( 100, \floor( 100 * $new_count / 50 ) );
- $remaining = 50 - \min( 50, $new_count );
-
- $this->save_progress(
- [
- 'progress' => $percent,
- 'remaining' => $remaining,
- ]
- );
-
- return [
- 'progress' => $percent,
- 'remaining' => $remaining,
- ];
- }
-}
diff --git a/classes/badges/content/class-revision-ranger.php b/classes/badges/content/class-revision-ranger.php
deleted file mode 100644
index f5463b8b8a..0000000000
--- a/classes/badges/content/class-revision-ranger.php
+++ /dev/null
@@ -1,84 +0,0 @@
-get_saved();
-
- // If we have a saved value, return it.
- if ( isset( $saved_progress['progress'] ) && isset( $saved_progress['remaining'] ) ) {
- return $saved_progress;
- }
-
- // Get the number of new posts published.
- $new_count = \count(
- \progress_planner()->get_activities__query()->query_activities(
- [
- 'category' => 'content',
- 'type' => 'publish',
- 'start_date' => \progress_planner()->get_activation_date(),
- ],
- )
- );
-
- $percent = \min( 100, \floor( 100 * $new_count / 30 ) );
- $remaining = 30 - \min( 30, $new_count );
-
- $this->save_progress(
- [
- 'progress' => $percent,
- 'remaining' => $remaining,
- ]
- );
-
- return [
- 'progress' => $percent,
- 'remaining' => $remaining,
- ];
- }
-}
diff --git a/classes/badges/maintenance/class-maintenance-maniac.php b/classes/badges/maintenance/class-maintenance-maniac.php
deleted file mode 100644
index fbcabe55f2..0000000000
--- a/classes/badges/maintenance/class-maintenance-maniac.php
+++ /dev/null
@@ -1,74 +0,0 @@
-get_saved();
-
- // If we have a saved value, return it.
- if ( isset( $saved_progress['progress'] ) && isset( $saved_progress['remaining'] ) ) {
- return $saved_progress;
- }
-
- $max_streak = $this->get_goal()->get_streak()['max_streak'];
- $percent = \min( 100, \floor( 100 * $max_streak / 26 ) );
- $remaining = 26 - \min( 26, $max_streak );
-
- $this->save_progress(
- [
- 'progress' => $percent,
- 'remaining' => $remaining,
- ]
- );
-
- return [
- 'progress' => $percent,
- 'remaining' => $remaining,
- ];
- }
-}
diff --git a/classes/badges/maintenance/class-progress-padawan.php b/classes/badges/maintenance/class-progress-padawan.php
deleted file mode 100644
index f42b2ff398..0000000000
--- a/classes/badges/maintenance/class-progress-padawan.php
+++ /dev/null
@@ -1,74 +0,0 @@
-get_saved();
-
- // If we have a saved value, return it.
- if ( isset( $saved_progress['progress'] ) && isset( $saved_progress['remaining'] ) ) {
- return $saved_progress;
- }
-
- $max_streak = $this->get_goal()->get_streak()['max_streak'];
- $percent = \min( 100, \floor( 100 * $max_streak / 6 ) );
- $remaining = 6 - \min( 6, $max_streak );
-
- $this->save_progress(
- [
- 'progress' => $percent,
- 'remaining' => $remaining,
- ]
- );
-
- return [
- 'progress' => $percent,
- 'remaining' => $remaining,
- ];
- }
-}
diff --git a/classes/badges/maintenance/class-super-site-specialist.php b/classes/badges/maintenance/class-super-site-specialist.php
deleted file mode 100644
index 1af22f3d89..0000000000
--- a/classes/badges/maintenance/class-super-site-specialist.php
+++ /dev/null
@@ -1,74 +0,0 @@
-get_saved();
-
- // If we have a saved value, return it.
- if ( isset( $saved_progress['progress'] ) && isset( $saved_progress['remaining'] ) ) {
- return $saved_progress;
- }
-
- $max_streak = $this->get_goal()->get_streak()['max_streak'];
- $percent = \min( 100, \floor( 100 * $max_streak / 52 ) );
- $remaining = 52 - \min( 52, $max_streak );
-
- $this->save_progress(
- [
- 'progress' => $percent,
- 'remaining' => $remaining,
- ]
- );
-
- return [
- 'progress' => $percent,
- 'remaining' => $remaining,
- ];
- }
-}
diff --git a/classes/class-badges.php b/classes/class-badges.php
index 904c94f0b2..3ca1a3b9fb 100644
--- a/classes/class-badges.php
+++ b/classes/class-badges.php
@@ -2,110 +2,31 @@
/**
* Handle user badges.
*
+ * Simplified class that only handles WordPress hooks for progress clearing.
+ * Badge logic and calculations are now handled in React.
+ *
* @package Progress_Planner
*/
namespace Progress_Planner;
-use Progress_Planner\Badges\Monthly;
-
/**
* Badges class.
*/
class Badges {
- /**
- * Content badges.
- *
- * @var \Progress_Planner\Badges\Badge[]
- */
- private $content = [];
-
- /**
- * Maintenance badges.
- *
- * @var \Progress_Planner\Badges\Badge[]
- */
- private $maintenance = [];
-
- /**
- * Monthly badges.
- *
- * @var \Progress_Planner\Badges\Badge[]
- */
- private $monthly = [];
-
- /**
- * Monthly badges flat.
- *
- * @var \Progress_Planner\Badges\Badge[]
- */
- private $monthly_flat = [];
-
- /**
- * Latest completed badge.
- *
- * @var \Progress_Planner\Badges\Badge|null
- */
- private $latest_completed_badge;
-
/**
* Constructor.
*/
public function __construct() {
- $this->content = [
- \progress_planner()->get_badges__content__content_curator(),
- \progress_planner()->get_badges__content__revision_ranger(),
- \progress_planner()->get_badges__content__purposeful_publisher(),
- ];
-
- $this->maintenance = [
- \progress_planner()->get_badges__maintenance__progress_padawan(),
- \progress_planner()->get_badges__maintenance__maintenance_maniac(),
- \progress_planner()->get_badges__maintenance__super_site_specialist(),
- ];
-
- // Init monthly badges.
- $this->monthly = Monthly::get_instances();
- foreach ( $this->monthly as $monthly_year_badges ) {
- $this->monthly_flat = \array_merge( $this->monthly_flat, $monthly_year_badges );
- }
-
\add_action( 'progress_planner_suggested_task_completed', [ $this, 'clear_monthly_progress' ] );
\add_action( 'progress_planner_activity_content_publish_saved', [ $this, 'clear_content_progress' ] );
}
/**
- * Get the badges for a context.
- *
- * @param string $context The badges context (content|maintenance|monthly).
- *
- * @return \Progress_Planner\Badges\Badge[]
- */
- public function get_badges( $context ) {
- return isset( $this->$context ) ? $this->$context : [];
- }
-
- /**
- * Get a single badge.
+ * Clear the progress of monthly badges when a task is completed.
*
- * @param string $badge_id The badge ID.
- *
- * @return \Progress_Planner\Badges\Badge|null
- */
- public function get_badge( $badge_id ) {
- foreach ( [ 'content', 'maintenance', 'monthly_flat' ] as $context ) {
- foreach ( $this->$context as $badge ) {
- if ( $badge->get_id() === $badge_id ) {
- return $badge;
- }
- }
- }
- return null;
- }
-
- /**
- * Clear the progress of all monthly badges.
+ * This clears saved progress so React can recalculate from activities.
*
* @param string $activity_id The activity ID.
*
@@ -124,100 +45,91 @@ public function clear_monthly_progress( $activity_id ) {
return;
}
- // Clear monthly saved progress.
- $badge_id = Monthly::get_badge_id_from_date( $activities[0]->date );
- $monthly_badge = $this->get_badge( $badge_id );
+ // Generate monthly badge ID from activity date.
+ $activity_date = $activities[0]->date;
+ $year = $activity_date->format( 'Y' );
+ $month = $activity_date->format( 'n' );
+ $badge_id = "monthly-{$year}-m{$month}";
- if ( $monthly_badge ) {
- // Clear the progress.
- $monthly_badge->clear_progress();
+ // Clear saved progress for this monthly badge.
+ $settings = \progress_planner()->get_settings();
+ $badges = $settings->get( 'badges', [] );
- // Save the progress.
- $monthly_badge->get_progress();
+ // Only clear if badge is not complete (preserve completion date).
+ if ( isset( $badges[ $badge_id ] ) && 100 > (int) ( $badges[ $badge_id ]['progress'] ?? 0 ) ) {
+ unset( $badges[ $badge_id ] );
+ $settings->set( 'badges', $badges );
}
}
/**
- * Clear the progress of all badges.
+ * Clear the progress of content badges when content is published.
+ *
+ * This clears saved progress so React can recalculate from activities.
*
* @return void
*/
public function clear_content_progress() {
- // Clear content saved progress.
- foreach ( $this->content as $badge ) {
- // If the badge is already complete, skip it.
- if ( 100 <= $badge->progress_callback()['progress'] ) {
- continue;
+ $settings = \progress_planner()->get_settings();
+ $badges = $settings->get( 'badges', [] );
+
+ $content_badge_ids = [
+ 'content-curator',
+ 'revision-ranger',
+ 'purposeful-publisher',
+ ];
+
+ $updated = false;
+ foreach ( $content_badge_ids as $badge_id ) {
+ // Only clear if badge is not complete (preserve completion date).
+ if ( isset( $badges[ $badge_id ] ) && 100 > (int) ( $badges[ $badge_id ]['progress'] ?? 0 ) ) {
+ unset( $badges[ $badge_id ] );
+ $updated = true;
}
+ }
- // Delete the badge value so it can be re-calculated.
- $badge->clear_progress();
+ if ( $updated ) {
+ $settings->set( 'badges', $badges );
}
}
/**
* Get the latest completed badge across all badge types.
*
- * Badge selection algorithm:
- * 1. Iterates through all badge contexts (content, maintenance, monthly_flat)
- * 2. For each badge, checks if it's 100% complete
- * 3. Compares completion dates stored in settings to find the most recent
- * 4. Returns the badge with the most recent completion date
- *
- * The completion date is stored in settings when a badge reaches 100% progress:
- * - Format: 'Y-m-d H:i:s' (e.g., '2025-10-31 14:30:00')
- * - Compared as Unix timestamps for accurate chronological ordering
- * - Later completion dates take precedence (>= comparison ensures newer badges win)
- *
- * This is used to:
- * - Trigger celebrations for newly completed badges
- * - Track user progress momentum
+ * Reads from saved badge stats to find the most recently completed badge.
*
- * @return \Progress_Planner\Badges\Badge|null The most recently completed badge, or null if none completed.
+ * @return array|null Badge data with id and date, or null if none completed.
*/
public function get_latest_completed_badge() {
- if ( $this->latest_completed_badge ) {
- return $this->latest_completed_badge;
- }
-
- // Get the settings for badges (stores completion dates).
$settings = \progress_planner()->get_settings()->get( 'badges', [] );
- $latest_date = null;
-
- // Loop through all badge contexts to find the most recently completed badge.
- foreach ( [ 'content', 'maintenance', 'monthly_flat' ] as $context ) {
- foreach ( $this->$context as $badge ) {
- // Skip badges that don't have a completion date recorded.
- if ( ! isset( $settings[ $badge->get_id() ]['date'] ) ) {
- continue;
- }
-
- $badge_progress = $badge->get_progress();
-
- // Skip badges that aren't 100% complete.
- if ( 100 > (int) $badge_progress['progress'] ) {
- continue;
- }
-
- // Initialize with the first completed badge found.
- if ( null === $latest_date ) {
- $this->latest_completed_badge = $badge;
- if ( isset( $settings[ $badge->get_id() ]['date'] ) ) {
- $latest_date = $settings[ $badge->get_id() ]['date'];
- }
- continue;
- }
-
- // Compare completion dates as Unix timestamps to find the most recent.
- // Using >= ensures that if multiple badges complete simultaneously, the last one processed wins.
- if ( \DateTime::createFromFormat( 'Y-m-d H:i:s', $settings[ $badge->get_id() ]['date'] )->format( 'U' ) >= \DateTime::createFromFormat( 'Y-m-d H:i:s', $latest_date )->format( 'U' ) ) {
- $latest_date = $settings[ $badge->get_id() ]['date'];
- $this->latest_completed_badge = $badge;
- }
+ $latest_date = null;
+ $latest_badge = null;
+
+ foreach ( $settings as $badge_id => $badge_data ) {
+ // Skip if not complete or no completion date.
+ if ( ! isset( $badge_data['progress'] ) || 100 > (int) $badge_data['progress'] ) {
+ continue;
+ }
+ if ( ! isset( $badge_data['date'] ) ) {
+ continue;
+ }
+
+ // Compare completion dates.
+ $badge_date = \DateTime::createFromFormat( 'Y-m-d H:i:s', $badge_data['date'] );
+ if ( ! $badge_date ) {
+ continue;
+ }
+
+ if ( null === $latest_date || $badge_date->format( 'U' ) >= $latest_date->format( 'U' ) ) {
+ $latest_date = $badge_date;
+ $latest_badge = [
+ 'id' => $badge_id,
+ 'date' => $badge_data['date'],
+ ];
}
}
- return $this->latest_completed_badge;
+ return $latest_badge;
}
}
diff --git a/classes/class-base.php b/classes/class-base.php
index 7978a9367d..fbeca1c606 100644
--- a/classes/class-base.php
+++ b/classes/class-base.php
@@ -18,13 +18,30 @@
* @method \Progress_Planner\Page_Types get_page_types()
* @method \Progress_Planner\Rest\Stats get_rest__stats()
* @method \Progress_Planner\Rest\Tasks get_rest__tasks()
+ * @method \Progress_Planner\Rest\Widgets\Content_Activity get_rest__widgets__content_activity()
+ * @method \Progress_Planner\Rest\Widgets\Activity_Scores get_rest__widgets__activity_scores()
+ * @method \Progress_Planner\Rest\Activities get_rest__activities()
+ * @method \Progress_Planner\Rest\Badge_Stats get_rest__badge_stats()
+ * @method \Progress_Planner\Rest\Widgets\Whats_New get_rest__widgets__whats_new()
+ * @method \Progress_Planner\Rest\Plugin_Installer get_rest__plugin_installer()
+ * @method \Progress_Planner\Rest\Popover_Actions get_rest__popover_actions()
+ * @method \Progress_Planner\Rest\Email_Test get_rest__email_test()
+ * @method \Progress_Planner\Rest\Email_Sending_Config get_rest__email_sending_config()
+ * @method \Progress_Planner\Rest\Upgrade_Tasks_Config get_rest__upgrade_tasks_config()
+ * @method \Progress_Planner\Rest\Subscribe get_rest__subscribe()
+ * @method \Progress_Planner\Rest\Timezone_Options get_rest__timezone_options()
+ * @method \Progress_Planner\Rest\Locale_Options get_rest__locale_options()
+ * @method \Progress_Planner\Rest\Data_Collectors get_rest__data_collectors()
+ * @method \Progress_Planner\Rest\Task_Evaluation get_rest__task_evaluation()
+ * @method \Progress_Planner\Rest\Page_Settings get_rest__page_settings()
+ * @method \Progress_Planner\Rest\Updates get_rest__updates()
+ * @method \Progress_Planner\Rest\Wizard_Config get_rest__wizard_config()
* @method \Progress_Planner\Todo get_todo()
* @method \Progress_Planner\Utils\Onboard get_utils__onboard()
+ * @method \Progress_Planner\Onboard_Wizard get_onboard_wizard()
* @method \Progress_Planner\Utils\Playground get_utils__playground()
* @method \Progress_Planner\Admin\Page get_admin__page()
* @method \Progress_Planner\Admin\Tour get_admin__tour()
- * @method \Progress_Planner\Admin\Dashboard_Widget_Score get_admin__dashboard_widget_score()
- * @method \Progress_Planner\Admin\Dashboard_Widget_Todo get_admin__dashboard_widget_todo()
* @method \Progress_Planner\Admin\Editor get_admin__editor()
* @method \Progress_Planner\Actions\Content get_actions__content()
* @method \Progress_Planner\Actions\Content_Scan get_actions__content_scan()
@@ -41,19 +58,9 @@
* @method \Progress_Planner\Suggested_Tasks_DB get_suggested_tasks_db()
* @method \Progress_Planner\Utils\Deprecations get_utils__deprecations()
* @method \Progress_Planner\UI\Branding get_ui__branding()
- * @method \Progress_Planner\Plugin_Installer get_plugin_installer()
- * @method \Progress_Planner\Admin\Widgets\Badge_Streak_Content get_admin__widgets__badge_streak_content()
- * @method \Progress_Planner\Admin\Widgets\Badge_Streak_Maintenance get_admin__widgets__badge_streak_maintenance()
* @method \Progress_Planner\Admin\Enqueue get_admin__enqueue()
- * @method \Progress_Planner\Admin\Widgets\Whats_New get_admin__widgets__whats_new()
- * @method \Progress_Planner\Admin\Widgets\ToDo get_admin__widgets__todo()
- * @method \Progress_Planner\Admin\Widgets\Monthly_Badges get_admin__widgets__monthly_badges()
- * @method \Progress_Planner\UI\Popover get_ui__popover()
- * @method \Progress_Planner\Admin\Widgets\Content_Activity get_admin__widgets__content_activity()
* @method \Progress_Planner\UI\Chart get_ui__chart()
* @method \Progress_Planner\Activities\Content_Helpers|null get_activities__content_helpers()
- * @method \Progress_Planner\Admin\Widgets\Challenge get_admin__widgets__challenge()
- * @method \Progress_Planner\Admin\Widgets\Activity_Scores get_admin__widgets__activity_scores()
* @method \Progress_Planner\Utils\Date get_utils__date()
* @method \Progress_Planner\Onboard_Wizard get_onboard_wizard()
*/
@@ -111,12 +118,6 @@ public function init() {
if ( \is_admin() && \current_user_can( 'edit_others_posts' ) ) {
$this->get_admin__page();
$this->get_admin__tour();
-
- // Dont add the widget if the privacy policy is not accepted.
- if ( true === $this->is_privacy_policy_accepted() ) {
- $this->get_admin__dashboard_widget_score();
- $this->get_admin__dashboard_widget_todo();
- }
}
$this->get_suggested_tasks();
@@ -130,9 +131,28 @@ public function init() {
// REST API.
$this->get_rest__stats();
$this->get_rest__tasks();
+ $this->get_rest__widgets__content_activity();
+ $this->get_rest__widgets__activity_scores();
+ $this->get_rest__widgets__whats_new();
+ $this->get_rest__plugin_installer();
+ $this->get_rest__activities();
+ $this->get_rest__badge_stats();
+ $this->get_rest__popover_actions();
+ $this->get_rest__email_test();
+ $this->get_rest__email_sending_config();
+ $this->get_rest__upgrade_tasks_config();
+ $this->get_rest__subscribe();
+ $this->get_rest__timezone_options();
+ $this->get_rest__locale_options();
+ $this->get_rest__data_collectors();
+ $this->get_rest__task_evaluation();
+ $this->get_rest__page_settings();
+ $this->get_rest__updates();
+ $this->get_rest__wizard_config();
// Onboarding.
$this->get_utils__onboard();
+ $this->get_onboard_wizard();
// To-do.
$this->get_todo();
@@ -166,9 +186,6 @@ public function init() {
// Plugin upgrade.
$this->get_plugin_migrations();
- // Plugin installer.
- $this->get_plugin_installer();
-
/**
* Redirect on login.
*/
@@ -181,9 +198,6 @@ public function init() {
// Init the enqueue class.
$this->get_admin__enqueue()->init();
-
- // TODO: Decide when this needs to be initialized.
- $this->get_onboard_wizard();
}
/**
@@ -203,7 +217,7 @@ public function init() {
* get_admin__page() → Progress_Planner\Admin\Page
* get_activities__query() → Progress_Planner\Activities\Query
* get_suggested_tasks_db() → Progress_Planner\Suggested_Tasks_Db
- * get_admin__widgets__todo() → Progress_Planner\Admin\Widgets\Todo
+ * get_rest__widgets__activity_scores() → Progress_Planner\Rest\Widgets\Activity_Scores
* ```
*
* Transformation process:
diff --git a/classes/class-onboard-wizard.php b/classes/class-onboard-wizard.php
index f484b487e5..bcd987b827 100644
--- a/classes/class-onboard-wizard.php
+++ b/classes/class-onboard-wizard.php
@@ -81,26 +81,8 @@ public function maybe_register_popover_hooks() {
*/
$show_onboarding = \apply_filters( 'progress_planner_show_onboarding', $show_onboarding );
- if ( ! $show_onboarding ) {
- return;
- }
-
- // Add popover on front end.
- \add_action( 'wp_footer', [ $this, 'add_popover' ] );
- \add_action( 'wp_footer', [ $this, 'add_popover_step_templates' ] );
- \add_action( 'wp_enqueue_scripts', [ $this, 'add_popover_scripts' ] );
-
- // Add popover on admin.
- \add_action( 'admin_footer', [ $this, 'add_popover' ] );
- \add_action( 'admin_footer', [ $this, 'add_popover_step_templates' ] );
- \add_action( 'admin_enqueue_scripts', [ $this, 'add_popover_scripts' ] );
-
- // Trigger the onboarding wizard on the front end.
- \add_action( 'wp_footer', [ $this, 'trigger_onboarding' ] );
- \add_action( 'admin_footer', [ $this, 'trigger_onboarding' ] );
-
- // Define steps and their order.
- \add_action( 'init', [ $this, 'define_steps_and_order' ], 101 );
+ // Wizard config is now provided via REST API endpoint (/progress-planner/v1/onboarding-wizard/config)
+ // React components fetch the config directly from the API.
// Allow only images for the front-end upload.
\add_filter( 'rest_pre_insert_attachment', [ $this, 'rest_pre_insert_attachment' ], 10, 2 );
@@ -127,24 +109,19 @@ public function define_steps_and_order() {
$tasks = [];
- foreach ( $onboarding_tasks as $task_id ) {
- $task = \progress_planner()->get_suggested_tasks_db()->get_tasks_by( [ 'task_id' => $task_id ] );
- $task_provider = \progress_planner()->get_suggested_tasks()->get_tasks_manager()->get_task_provider( $task_id );
-
- // If there is no task, create it.
- if ( ! $task && $task_provider ) {
- $task_data = $task_provider->get_task_details();
-
- // Task will not be inserted if it already exists.
- \progress_planner()->get_suggested_tasks_db()->add( $task_data );
+ // Action labels for onboarding tasks.
+ $action_labels = [
+ 'core-blogdescription' => \esc_html__( 'Verify tagline', 'progress-planner' ),
+ 'select-timezone' => \esc_html__( 'Set the timezone', 'progress-planner' ),
+ 'select-locale' => \esc_html__( 'Set the locale', 'progress-planner' ),
+ 'core-siteicon' => \esc_html__( 'Set site icon', 'progress-planner' ),
+ ];
- // Now get the task.
- $task = \progress_planner()->get_suggested_tasks_db()->get_tasks_by( [ 'task_id' => $task_id ] );
- }
+ foreach ( $onboarding_tasks as $task_id ) {
+ $task = \progress_planner()->get_suggested_tasks_db()->get_tasks_by( [ 'task_id' => $task_id ] );
- // Safety check: Skip if task could not be created or retrieved.
+ // Tasks are created by React. Skip if task doesn't exist yet.
if ( empty( $task ) ) {
- \error_log( 'Onboarding: Could not retrieve or create task: ' . $task_id ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
continue;
}
@@ -154,10 +131,10 @@ public function define_steps_and_order() {
'url' => $task[0]->url ?? '',
'provider_id' => $task[0]->get_provider_id(),
'points' => $task[0]->points ?? 0,
- 'action_label' => $task_provider ? $task_provider->get_task_action_label() : \esc_html__( 'Do it', 'progress-planner' ),
+ 'action_label' => $action_labels[ $task_id ],
];
- // Add task specific data.
+ // Add task specific data for React form components.
if ( 'core-blogdescription' === $task_id ) {
$task_formatted['site_description'] = \get_bloginfo( 'description' );
}
@@ -167,60 +144,81 @@ public function define_steps_and_order() {
$this->steps = [
[
- 'script_file_name' => 'WelcomeStep',
- 'template_file_name' => 'welcome',
- 'template_id' => 'onboarding-step-welcome',
+ 'script_file_name' => 'WelcomeStep',
+ 'template_id' => 'onboarding-step-welcome',
/* translators: %s: Progress Planner name. */
- 'title' => sprintf( esc_html__( 'Welcome to %s', 'progress-planner' ), \esc_html( \progress_planner()->get_ui__branding()->get_admin_menu_name() ) ),
+ 'title' => \sprintf( \esc_html__( 'Welcome to %s', 'progress-planner' ), \esc_html( \progress_planner()->get_ui__branding()->get_admin_menu_name() ) ),
],
[
- 'script_file_name' => 'WhatsWhatStep',
- 'template_file_name' => 'whats-what',
- 'template_id' => 'onboarding-step-whats-what',
- 'title' => esc_html__( 'What\'s what?', 'progress-planner' ),
+ 'script_file_name' => 'WhatsWhatStep',
+ 'template_id' => 'onboarding-step-whats-what',
+ 'title' => \esc_html__( 'What\'s what?', 'progress-planner' ),
],
];
// Add first task step if there are tasks or if the first task is already completed.
if ( ! empty( $tasks ) || $was_first_task_completed ) {
$this->steps[] = [
- 'script_file_name' => 'FirstTaskStep',
- 'template_file_name' => 'first-task',
- 'template_data' => ! $was_first_task_completed ? [ 'task' => \array_shift( $tasks ) ] : [],
- 'template_id' => 'onboarding-step-first-task',
- 'title' => esc_html__( 'Complete your first task!', 'progress-planner' ),
+ 'script_file_name' => 'FirstTaskStep',
+ 'template_data' => ! $was_first_task_completed ? [ 'task' => \array_shift( $tasks ) ] : [],
+ 'template_id' => 'onboarding-step-first-task',
+ 'title' => \esc_html__( 'Complete your first task!', 'progress-planner' ),
];
}
+ // Get badge data for BadgesStep.
+ // Generate badge data for current month's badge.
+ $now = new \DateTime();
+ $year = $now->format( 'Y' );
+ $month = $now->format( 'n' );
+ $badge_id = "monthly-{$year}-m{$month}";
+ $badge_name = $now->format( 'F' ); // Full month name.
+ $branding_id = (int) \progress_planner()->get_ui__branding()->get_branding_id();
+ $max_points = 10; // Target points for monthly badges.
+ $current_value = 0;
+
+ // Get current badge progress from saved stats.
+ $badges = \progress_planner()->get_settings()->get( 'badges', [] );
+ if ( isset( $badges[ $badge_id ]['points'] ) ) {
+ $current_value = (float) $badges[ $badge_id ]['points'];
+ }
+
+ $badge_data = [
+ 'badgeId' => $badge_id,
+ 'badgeName' => $badge_name,
+ 'brandingId' => $branding_id,
+ 'maxPoints' => $max_points,
+ 'currentValue' => $current_value,
+ ];
+
$this->steps[] = [
- 'script_file_name' => 'BadgesStep',
- 'template_file_name' => 'badges',
- 'template_id' => 'onboarding-step-badges',
- 'title' => esc_html__( 'Our badges are waiting for you', 'progress-planner' ),
+ 'script_file_name' => 'BadgesStep',
+ 'template_id' => 'onboarding-step-badges',
+ 'template_data' => $badge_data,
+ 'title' => \esc_html__( 'Our badges are waiting for you', 'progress-planner' ),
];
$this->steps[] = [
- 'script_file_name' => 'EmailFrequencyStep',
- 'template_file_name' => 'email-frequency',
- 'template_id' => 'onboarding-step-email-frequency',
- 'title' => esc_html__( 'Email Frequency', 'progress-planner' ),
+ 'script_file_name' => 'EmailFrequencyStep',
+ 'template_id' => 'onboarding-step-email-frequency',
+ 'title' => \esc_html__( 'Email Frequency', 'progress-planner' ),
];
$this->steps[] = [
- 'script_file_name' => 'SettingsStep',
- 'template_file_name' => 'settings',
- 'template_id' => 'onboarding-step-settings',
- 'title' => esc_html__( 'Settings', 'progress-planner' ),
+ 'script_file_name' => 'SettingsStep',
+ 'template_id' => 'onboarding-step-settings',
+ 'title' => \esc_html__( 'Settings', 'progress-planner' ),
];
// Add more-tasks step if there are remaining tasks.
if ( ! empty( $tasks ) ) {
+ // Convert tasks object to array for React.
+ $tasks_array = \array_values( $tasks );
$this->steps[] = [
- 'script_file_name' => 'MoreTasksStep',
- 'template_file_name' => 'more-tasks',
- 'template_data' => [ 'tasks' => $tasks ],
- 'template_id' => 'onboarding-step-more-tasks',
- 'title' => esc_html__( 'Finish onboarding!', 'progress-planner' ),
+ 'script_file_name' => 'MoreTasksStep',
+ 'template_data' => [ 'tasks' => $tasks_array ],
+ 'template_id' => 'onboarding-step-more-tasks',
+ 'title' => \esc_html__( 'Finish onboarding!', 'progress-planner' ),
];
}
}
@@ -242,7 +240,7 @@ public function rest_pre_insert_attachment( $attachment, $request ) {
if ( empty( $files['file'] ) ) {
return new \WP_Error(
'rest_no_file',
- __( 'No file uploaded.', 'progress-planner' ),
+ \__( 'No file uploaded.', 'progress-planner' ),
[ 'status' => 400 ]
);
}
@@ -250,10 +248,10 @@ public function rest_pre_insert_attachment( $attachment, $request ) {
$file = $files['file'];
// Check MIME type.
- if ( strpos( $file['type'], 'image/' ) !== 0 ) {
+ if ( \strpos( $file['type'], 'image/' ) !== 0 ) {
return new \WP_Error(
'rest_invalid_file_type',
- __( 'Only images are allowed for this upload.', 'progress-planner' ),
+ \__( 'Only images are allowed for this upload.', 'progress-planner' ),
[ 'status' => 400 ]
);
}
@@ -262,68 +260,18 @@ public function rest_pre_insert_attachment( $attachment, $request ) {
return $attachment;
}
+
/**
- * Add popover scripts.
+ * Get wizard steps.
*
- * @return void
+ * @return array
*/
- public function add_popover_scripts() {
- // Enqueue variables-color.css.
- \wp_enqueue_style( 'prpl-variables-color', \constant( 'PROGRESS_PLANNER_URL' ) . '/assets/css/variables-color.css', [], \progress_planner()->get_plugin_version() );
-
- \wp_add_inline_style( 'prpl-variables-color', \progress_planner()->get_ui__branding()->get_custom_css() );
-
- // Enqueue onboarding.css.
- progress_planner()->get_admin__enqueue()->enqueue_style( 'onboarding/onboarding' );
-
- // Enqueue PrplOnboardTask (used by MoreTasksStep).
- \progress_planner()->get_admin__enqueue()->enqueue_script( 'onboarding/OnboardTask' );
-
- // Enqueue base step class.
- \progress_planner()->get_admin__enqueue()->enqueue_script( 'onboarding/steps/OnboardingStep' );
-
- // Enqueue step components.
- foreach ( $this->steps as $step ) {
- \progress_planner()->get_admin__enqueue()->enqueue_script( 'onboarding/steps/' . $step['script_file_name'] );
+ public function get_steps() {
+ // Ensure steps are defined.
+ if ( empty( $this->steps ) ) {
+ $this->define_steps_and_order();
}
-
- \progress_planner()->get_admin__enqueue()->enqueue_script( 'web-components/prpl-gauge' );
-
- // Get saved progress from user meta.
- $saved_progress = $this->get_saved_progress();
-
- // Enqueue main onboarding.js (depends on all step components).
- \progress_planner()->get_admin__enqueue()->enqueue_script(
- 'onboarding/onboarding',
- [
- 'name' => 'ProgressPlannerOnboardData',
- 'data' => [
- 'adminAjaxUrl' => \esc_url_raw( admin_url( 'admin-ajax.php' ) ),
- 'nonceProgressPlanner' => \esc_js( \wp_create_nonce( 'progress_planner' ) ),
- 'nonceWPAPI' => \esc_js( \wp_create_nonce( 'wp_rest' ) ),
- 'popoverId' => 'prpl-popover-onboarding',
- 'onboardAPIUrl' => \progress_planner()->get_utils__onboard()->get_remote_url( 'onboard' ),
- 'onboardNonceURL' => \progress_planner()->get_utils__onboard()->get_remote_url( 'get-nonce' ),
- 'site' => \esc_attr( \set_url_scheme( \site_url() ) ),
- 'timezone_offset' => (float) ( \wp_timezone()->getOffset( new \DateTime( 'midnight' ) ) / 3600 ),
- 'savedProgress' => $saved_progress,
- 'lastStepRedirectUrl' => \esc_url_raw( admin_url( 'admin.php?page=progress-planner' ) ),
- 'fullscreenMode' => true, // Enable fullscreen takeover mode.
- 'hasLicense' => false !== \progress_planner()->get_license_key(),
- 'l10n' => [
- 'next' => \esc_html__( 'Next', 'progress-planner' ),
- 'startOnboarding' => \esc_html__( 'Start onboarding', 'progress-planner' ),
- /* translators: %s: Progress Planner name. */
- 'privacyPolicyError' => sprintf( \esc_html__( 'You need to agree with the privacy policy to use the %s plugin.', 'progress-planner' ), \esc_html( \progress_planner()->get_ui__branding()->get_admin_menu_name() ) ),
- /* translators: %s: arrow icon */
- 'dashboard' => sprintf( \esc_html__( 'Take me to the dashboard %s', 'progress-planner' ), '' ),
- 'backToRecommendations' => \esc_html__( 'Back to recommendations', 'progress-planner' ),
- ],
- 'errorIcon' => \progress_planner()->get_asset( 'images/icon_exclamation_circle.svg' ),
- 'steps' => array_column( $this->steps, 'script_file_name' ),
- ],
- ]
- );
+ return $this->steps;
}
/**
@@ -331,7 +279,7 @@ public function add_popover_scripts() {
*
* @return array|null
*/
- protected function get_saved_progress() {
+ public function get_saved_progress() {
if ( ! \get_current_user_id() ) {
return null;
}
@@ -377,8 +325,6 @@ public function ajax_save_onboarding_progress() {
}
$progress = \sanitize_text_field( \wp_unslash( $_POST['state'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified in verify_ajax_security().
- \error_log( print_r( $progress, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r, WordPress.PHP.DevelopmentFunctions.error_log_error_log
-
// Save as user meta?
\update_option( self::PROGRESS_OPTION_NAME, $progress );
@@ -417,24 +363,13 @@ public function ajax_complete_task() {
\wp_send_json_error( [ 'message' => \esc_html__( 'Task not found.', 'progress-planner' ) ] );
}
- // To get the provider and complete the task, we need to use the provider.
- $provider = \progress_planner()->get_suggested_tasks()->get_tasks_manager()->get_task_provider( $task->get_provider_id() );
- if ( ! $provider ) {
- \wp_send_json_error( [ 'message' => \esc_html__( 'Provider not found.', 'progress-planner' ) ] );
- }
-
- // Complete the task.
- $task_completed = $provider->complete_task( $form_values, $task_id );
-
- // It will skip the celebration and set the task's post status to trash.
+ // Mark the task as completed (skips celebration and sets post status to trash).
$task_post_marked_as_completed = \progress_planner()->get_suggested_tasks()->mark_task_as_completed( $task_id, null, true );
- if ( ! $task_completed || ! $task_post_marked_as_completed ) {
- \error_log( 'Task not completed: ' . $task_id ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
+ if ( ! $task_post_marked_as_completed ) {
\wp_send_json_error( [ 'message' => \esc_html__( 'Task not completed.', 'progress-planner' ) ] );
}
- \error_log( 'Task completed: ' . $task_id ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
\wp_send_json_success( [ 'message' => \esc_html__( 'Task completed.', 'progress-planner' ) ] );
}
@@ -471,134 +406,20 @@ public function ajax_save_all_onboarding_settings() {
}
}
- // Handle post types.
- $include_post_types = isset( $_POST['prpl-post-types-include'] ) // phpcs:ignore WordPress.Security.NonceVerification.Missing
- ? \array_map( 'sanitize_text_field', \wp_unslash( $_POST['prpl-post-types-include'] ) ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
- : [];
+ // Handle post types (sent as comma-separated string via FormData).
+ $include_post_types = [];
+ if ( ! empty( $_POST['prpl-post-types-include'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ $raw_post_types = \sanitize_text_field( \wp_unslash( $_POST['prpl-post-types-include'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ $include_post_types = \explode( ',', $raw_post_types );
+ }
$page_settings->save_post_types( $include_post_types );
// Handle login destination.
- $redirect_on_login = isset( $_POST['prpl-redirect-on-login'] ) ? (bool) \sanitize_text_field( \wp_unslash( $_POST['prpl-redirect-on-login'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ $redirect_on_login = isset( $_POST['prpl-redirect-on-login'] ) // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ ? (bool) \sanitize_text_field( \wp_unslash( $_POST['prpl-redirect-on-login'] ) ) // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ : false;
$page_settings->save_settings( $redirect_on_login );
\wp_send_json_success( [ 'message' => \esc_html__( 'All settings saved successfully.', 'progress-planner' ) ] );
}
-
- /**
- * Trigger the onboarding wizard on the front end.
- *
- * @return void
- */
- public function trigger_onboarding() {
-
- // If the request is an AJAX request, do not trigger the onboarding wizard.
- if ( \wp_doing_ajax() ) {
- return;
- }
-
- // Dont trigger it if user is not logged in and is not a admin.
- if ( ! \is_user_logged_in() || ! \current_user_can( 'manage_options' ) ) {
- return;
- }
-
- $get_saved_progress = $this->get_saved_progress();
-
- // If there is no saved progress, trigger the onboarding wizard.
- if ( ! $get_saved_progress ) {
- ?>
-
-
-
-
-
-
-
-
- steps[0]['title'] ); ?>
-
-
- steps as $step ) :
- ?>
- -
-
- [] ] ); ?>
-
-
-
-
-
- get_ui__branding()->the_logo(); ?>
-
-
-
-
-
-
-
-
-
- steps as $step ) {
- \progress_planner()->the_view( 'onboarding/' . $step['template_file_name'] . '.php', isset( $step['template_data'] ) ? $step['template_data'] : [] );
- }
-
- // Add quit confirmation template.
- \progress_planner()->the_view( 'onboarding/quit-confirmation.php' );
- ?>
-
- id ) {
return;
}
- $this->the_popover();
- $this->the_inline_script();
- $this->the_inline_style();
- }
- /**
- * The popover.
- *
- * @return void
- */
- protected function the_popover() {
$reasons = [
[
'id' => 'unexpected-behavior',
@@ -107,210 +97,34 @@ protected function the_popover() {
'feedback_type' => false,
];
- ?>
-
-
-
-
-
- $reasons,
+ 'remoteServerUrl' => \progress_planner()->get_remote_server_root_url(),
+ 'deactivateUrl' => \wp_nonce_url( 'plugins.php?action=deactivate&plugin=' . \rawurlencode( \plugin_basename( \constant( 'PROGRESS_PLANNER_FILE' ) ) ), 'deactivate-plugin_' . \plugin_basename( \constant( 'PROGRESS_PLANNER_FILE' ) ) ),
+ 'pluginSlug' => self::PLUGIN_SLUG,
+ 'siteUrl' => \esc_attr( \get_site_url() ),
+ ]
+ );
+
+ // Render mount container.
+ echo '';
}
}
diff --git a/classes/class-plugin-installer.php b/classes/class-plugin-installer.php
deleted file mode 100644
index 613623e7f5..0000000000
--- a/classes/class-plugin-installer.php
+++ /dev/null
@@ -1,298 +0,0 @@
-check_capabilities();
- if ( ! $can_install ) {
- \wp_die( \esc_html( $can_install ) );
- }
-
- // Check the nonce.
- \check_ajax_referer( 'progress_planner', 'nonce' );
-
- // Get the plugin slug from the request.
- $slug = isset( $_POST['plugin_slug'] )
- ? \sanitize_text_field( \wp_unslash( $_POST['plugin_slug'] ) )
- : '';
-
- // If the plugin slug is empty, return an error.
- if ( empty( $slug ) ) {
- \wp_send_json_error(
- [
- 'code' => 'empty_plugin_slug',
- 'message' => \esc_attr__( 'An Error Occured', 'progress-planner' ),
- ]
- );
- }
-
- // If the plugin is already installed, return a success message.
- if ( $this->is_plugin_installed( $slug ) ) {
- \wp_send_json_success(
- [
- 'code' => 'plugin_already_installed',
- 'message' => \esc_html__( 'Plugin already installed', 'progress-planner' ),
- ]
- );
- }
-
- // Install the plugin.
- $installed = $this->install_plugin( $slug );
-
- // If the plugin is installed, return a success message.
- if ( $installed && ! \is_wp_error( $installed ) ) {
- \wp_send_json_success(
- [
- 'code' => 'plugin_installed',
- 'message' => \esc_html__( 'Plugin installed', 'progress-planner' ),
- ]
- );
- }
-
- // If the plugin is not installed, return an error message.
- \wp_send_json_error(
- [
- 'code' => 'install_failed',
- 'message' => \esc_html__( 'An Error Occured', 'progress-planner' ),
- ]
- );
- }
-
- /**
- * Tries to activate the plugin
- *
- * @return void
- */
- public function activate() {
- // Check if the user has the necessary capabilities.
- $can_activate = $this->check_capabilities();
- if ( ! $can_activate ) {
- \wp_die( \esc_html( $can_activate ) );
- }
-
- // Check the nonce.
- \check_ajax_referer( 'progress_planner', 'nonce' );
-
- // Get the plugin slug from the request.
- $plugin_slug = isset( $_POST['plugin_slug'] )
- ? \sanitize_text_field( \wp_unslash( $_POST['plugin_slug'] ) )
- : '';
-
- // If the plugin slug is empty, return an error.
- if ( empty( $plugin_slug ) ) {
- \wp_send_json_error(
- [
- 'code' => 'empty_plugin_slug',
- 'message' => \esc_attr__( 'An Error Occured', 'progress-planner' ),
- ]
- );
- }
-
- // Get the plugin path.
- $plugin_path = '';
- foreach ( \array_keys( \get_plugins() ) as $plugin ) {
- if ( \explode( '/', $plugin )[0] === $plugin_slug ) {
- $plugin_path = $plugin;
- break;
- }
- }
-
- // If the plugin path is empty, return an error.
- if ( empty( $plugin_path ) ) {
- \wp_send_json_error(
- [
- 'code' => 'plugin_not_found',
- 'message' => \esc_attr__( 'An Error Occured', 'progress-planner' ),
- ]
- );
- }
-
- // Activate the plugin.
- $activated = \activate_plugin( $plugin_path );
-
- // If the plugin is not activated, return an error message.
- if ( \is_wp_error( $activated ) ) {
- \wp_send_json_error(
- [
- 'code' => 'activate_failed',
- 'message' => \esc_attr__( 'An Error Occured', 'progress-planner' ),
- ]
- );
- }
-
- // If the plugin is activated, return a success message.
- \wp_send_json_success(
- [
- 'code' => 'plugin_activated',
- 'message' => \esc_html__( 'Plugin activated', 'progress-planner' ),
- ]
- );
- }
-
- /**
- * Install a plugin.
- *
- * @param string $plugin The plugin to install.
- *
- * @return bool|\WP_Error
- */
- private function install_plugin( $plugin ) {
- // Include the necessary files.
- require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; // @phpstan-ignore-line
- require_once ABSPATH . 'wp-admin/includes/plugin-install.php'; // @phpstan-ignore-line
- require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php'; // @phpstan-ignore-line
- require_once ABSPATH . 'wp-admin/includes/class-plugin-installer-skin.php'; // @phpstan-ignore-line
-
- // Get the plugin information.
- $api = \plugins_api(
- 'plugin_information',
- [
- 'slug' => $plugin,
- 'fields' => [
- 'sections' => false,
- ],
- ]
- );
-
- // If the plugin information is not found, return an error.
- if ( \is_wp_error( $api ) ) {
- \wp_die( $api ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- }
-
- $api = (object) $api;
- // If the plugin download link is not found, return an error.
- if ( ! isset( $api->download_link ) ) {
- return new \WP_Error( 'no_download_link', \__( 'No download link found', 'progress-planner' ) );
- }
-
- // If the plugin name is not found, return an error.
- if ( ! isset( $api->name ) ) {
- return new \WP_Error( 'no_name', \__( 'No name found', 'progress-planner' ) );
- }
-
- // If the plugin version is not found, return an error.
- if ( ! isset( $api->version ) ) {
- return new \WP_Error( 'no_version', \__( 'No version found', 'progress-planner' ) );
- }
-
- // Create a new plugin upgrader.
- $upgrader = new \Plugin_Upgrader(
- new \Plugin_Installer_Skin(
- [
- 'type' => 'web',
- /* translators: %s: Plugin name and version. */
- 'title' => \sprintf( \__( 'Installing Plugin: %s', 'progress-planner' ), $api->name . ' ' . $api->version ),
- 'url' => 'update.php?action=install-plugin&plugin=' . \rawurlencode( $plugin ),
- 'nonce' => 'install-plugin_' . $plugin,
- 'plugin' => $plugin,
- 'api' => $api,
- ]
- )
- );
-
- // Install the plugin.
- return $upgrader->install( $api->download_link );
- }
-
- /**
- * Check if the user is allowed to install the plugin.
- *
- * @return string|true Error message, or true if the user is allowed to install the plugin.
- */
- public function check_capabilities() {
- return \current_user_can( 'install_plugins' )
- ? true
- : \esc_html__( 'Sorry, you are not allowed to install plugins on this site.', 'progress-planner' );
- }
-
- /**
- * Checks if plugin is intalled
- *
- * @param string $plugin_slug The slug of the plugin we want to install.
- *
- * @return bool
- */
- public function is_plugin_installed( $plugin_slug ) {
- return ! empty( $this->get_plugin_path( $plugin_slug ) );
- }
-
- /**
- * Checks if plugin is activated
- *
- * @param string $plugin_slug The slug of the plugin we want to install.
- *
- * @return bool
- */
- public function is_plugin_activated( $plugin_slug ) {
- // Get the plugin path.
- $plugin_path = $this->get_plugin_path( $plugin_slug );
-
- // If the plugin path is empty, return false.
- if ( empty( $plugin_path ) ) {
- return false;
- }
-
- // If the is_plugin_active function does not exist, include the necessary file.
- if ( ! \function_exists( 'is_plugin_active' ) ) {
- require_once ABSPATH . 'wp-admin/includes/plugin.php'; // @phpstan-ignore-line
- }
-
- // Return if the plugin is activated.
- return \is_plugin_active( $plugin_path );
- }
-
- /**
- * Get the path of the plugin
- *
- * @param string $plugin_slug The slug of the plugin we want to install.
- *
- * @return string
- */
- private function get_plugin_path( $plugin_slug ) {
- // If the plugin slug is empty, return an empty string.
- if ( empty( $plugin_slug ) ) {
- return '';
- }
-
- // If the get_plugins function does not exist, include the necessary file.
- if ( ! \function_exists( 'get_plugins' ) ) {
- require_once ABSPATH . 'wp-admin/includes/plugin.php'; // @phpstan-ignore-line
- }
-
- // Return the plugin path.
- foreach ( \array_keys( \get_plugins() ) as $plugin ) {
- if ( \explode( '/', $plugin )[0] === $plugin_slug ) {
- return $plugin;
- }
- }
-
- // If the plugin path is not found, return an empty string.
- return '';
- }
-}
diff --git a/classes/class-plugin-upgrade-tasks.php b/classes/class-plugin-upgrade-tasks.php
index a111e79065..2322de6cae 100644
--- a/classes/class-plugin-upgrade-tasks.php
+++ b/classes/class-plugin-upgrade-tasks.php
@@ -23,7 +23,7 @@ public function __construct() {
\add_action( 'progress_planner_plugin_updated', [ $this, 'plugin_updated' ], 10 );
// Check if the plugin was upgraded or new plugin was activated.
- \add_action( 'init', [ $this, 'handle_activation_or_upgrade' ], 100 ); // We need to run this after the Local_Tasks_Manager::init() is called.
+ \add_action( 'init', [ $this, 'handle_activation_or_upgrade' ], 100 );
// Add the action to add the upgrade tasks popover.
\add_action( 'progress_planner_admin_page_after_widgets', [ $this, 'add_upgrade_tasks_popover' ] );
@@ -139,31 +139,12 @@ public function maybe_add_onboarding_tasks() {
/**
* Get the newly added task providers.
*
- * @return array
+ * @deprecated Task providers are now handled by React. This method returns empty array.
+ *
+ * @return array Always returns empty array.
*/
public function get_newly_added_task_providers() {
- static $newly_added_task_providers;
-
- if ( ! $this->should_show_upgrade_popover() ) {
- return [];
- }
-
- if ( null === $newly_added_task_providers ) {
- $task_provider_ids = $this->get_upgrade_popover_task_provider_ids();
-
- $task_providers = [];
-
- foreach ( $task_provider_ids as $task_provider_id ) {
- $task_provider = \progress_planner()->get_suggested_tasks()->get_tasks_manager()->get_task_provider( $task_provider_id ); // @phpstan-ignore-line method.nonObject
- if ( $task_provider ) { // @phpstan-ignore-line
- $task_providers[] = $task_provider;
- }
- }
-
- $newly_added_task_providers = $task_providers;
- }
-
- return $newly_added_task_providers;
+ return [];
}
/**
@@ -200,7 +181,39 @@ public function delete_upgrade_popover_task_providers() {
*/
public function add_upgrade_tasks_popover() {
if ( $this->should_show_upgrade_popover() ) {
- \progress_planner()->get_ui__popover()->the_popover( 'upgrade-tasks' )->render();
+ // Popover is now handled by React via PopoverManager.
+ // Data is fetched via REST API when popover opens.
+ // Trigger popover via WordPress hook after a short delay to ensure React is loaded.
+ \add_action( 'admin_footer', [ $this, 'trigger_upgrade_tasks_popover' ], 999 );
}
}
+
+ /**
+ * Trigger upgrade tasks popover via WordPress hook.
+ *
+ * @return void
+ */
+ public function trigger_upgrade_tasks_popover() {
+ // Delete upgrade popover task providers when popover is shown.
+ // This matches the original PHP template behavior.
+ $this->delete_upgrade_popover_task_providers();
+
+ // Create a task object for the popover.
+ $task = [
+ 'id' => 'upgrade-tasks',
+ 'slug' => 'upgrade-tasks',
+ 'title' => \__( "We've added new recommendations to the Progress Planner plugin", 'progress-planner' ),
+ ];
+
+ // Trigger popover via WordPress hook.
+ ?>
+
+ 'future',
];
- /**
- * An object containing tasks.
- *
- * @var \Progress_Planner\Suggested_Tasks\Tasks_Manager
- */
- private Tasks_Manager $tasks_manager;
-
/**
* Constructor.
*/
public function __construct() {
- $this->tasks_manager = new Tasks_Manager();
-
if ( \is_admin() ) {
- \add_action( 'admin_init', [ $this, 'init' ], 20 ); // Wait for the post types to be initialized and transients to be set.
-
// Check GET parameter and maybe set task as pending.
\add_action( 'init', [ $this, 'maybe_complete_task' ] );
}
@@ -70,28 +57,6 @@ public function __construct() {
\add_filter( 'wp_trash_post_days', [ $this, 'change_trashed_posts_lifetime' ], 10, 2 );
}
- /**
- * Run the tasks.
- *
- * @return void
- */
- public function init(): void {
- // Check for completed tasks.
- $completed_tasks = $this->tasks_manager->evaluate_tasks();
-
- foreach ( $completed_tasks as $task ) {
- if ( ! $task->post_name && $task->ID ) {
- continue;
- }
-
- // Change the task status to pending.
- $task->celebrate();
-
- // Insert an activity.
- $this->insert_activity( \progress_planner()->get_suggested_tasks()->get_task_id_from_slug( $task->post_name ) );
- }
- }
-
/**
* Insert an activity.
*
@@ -159,15 +124,6 @@ public function on_automatic_updates_complete(): void {
$this->insert_activity( \progress_planner()->get_suggested_tasks()->get_task_id_from_slug( $pending_tasks[0]->post_name ) );
}
- /**
- * Get the tasks manager.
- *
- * @return \Progress_Planner\Suggested_Tasks\Tasks_Manager
- */
- public function get_tasks_manager(): Tasks_Manager {
- return $this->tasks_manager;
- }
-
/**
* Check if a task was completed. Task is considered completed if it was trashed or pending.
*
@@ -330,15 +286,8 @@ public function suggested_task_action() {
\wp_send_json_error( [ 'message' => \esc_html__( 'Task not found.', 'progress-planner' ) ] );
}
- $provider = \progress_planner()->get_suggested_tasks()->get_tasks_manager()->get_task_provider( $task->get_provider_id() );
-
- if ( ! $provider ) {
- \wp_send_json_error( [ 'message' => \esc_html__( 'Provider not found.', 'progress-planner' ) ] );
- }
-
- if ( ! $provider->capability_required() ) {
- \wp_send_json_error( [ 'message' => \esc_html__( 'You do not have permission to complete this task.', 'progress-planner' ) ] );
- }
+ // Capability is checked client-side before task was shown,
+ // and user must be logged in with edit_others_posts to reach this endpoint.
$updated = false;
@@ -467,7 +416,7 @@ public function register_taxonomy() {
public function rest_api_tax_query( $args, $request ) {
$tax_query = [];
- // Exclude terms.
+ // Exclude providers.
if ( isset( $request['exclude_provider'] ) ) {
$tax_query[] = [
'taxonomy' => 'prpl_recommendations_provider',
@@ -477,26 +426,19 @@ public function rest_api_tax_query( $args, $request ) {
];
}
- $include_providers = [];
- $providers_available_for_user = \progress_planner()->get_suggested_tasks()->get_tasks_manager()->get_task_providers_available_for_user();
- foreach ( $providers_available_for_user as $provider ) {
- $include_providers[] = $provider->get_provider_id();
- }
-
- // Include terms (matches any term in list).
+ // Include specific providers if requested.
if ( isset( $request['provider'] ) ) {
- $request_providers = \explode( ',', $request['provider'] );
- $include_providers = \array_intersect( $include_providers, $request_providers );
+ $tax_query[] = [
+ 'taxonomy' => 'prpl_recommendations_provider',
+ 'field' => 'slug',
+ 'terms' => \explode( ',', $request['provider'] ),
+ 'operator' => 'IN',
+ ];
}
- $tax_query[] = [
- 'taxonomy' => 'prpl_recommendations_provider',
- 'field' => 'slug',
- 'terms' => $include_providers,
- 'operator' => 'IN',
- ];
-
- $args['tax_query'] = $tax_query; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
+ if ( ! empty( $tax_query ) ) {
+ $args['tax_query'] = $tax_query; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
+ }
// Handle sorting parameters.
if ( isset( $request['filter']['orderby'] ) ) {
@@ -526,41 +468,13 @@ public function rest_prepare_recommendation( $response, $post ) {
if ( ! isset( $response->data['meta'] ) ) {
$response->data['meta'] = [];
}
- $provider = false;
- if ( $provider_term && ! \is_wp_error( $provider_term ) ) {
- $provider = \progress_planner()->get_suggested_tasks()->get_tasks_manager()->get_task_provider( $provider_term[0]->slug );
- }
- $response->data['slug'] = \progress_planner()->get_suggested_tasks()->get_task_id_from_slug( $response->data['slug'] );
-
- if ( $provider ) {
+ if ( $provider_term && ! \is_wp_error( $provider_term ) ) {
+ // Set prpl_provider from the term so React can identify the provider and generate actions client-side.
$response->data['prpl_provider'] = $provider_term[0];
- // Link should be added during run time, since it is not added for users without required capability.
- $response->data['meta']['prpl_url'] = $response->data['meta']['prpl_url'] && $provider->capability_required()
- ? \esc_url( (string) $response->data['meta']['prpl_url'] )
- : '';
-
- $response->data['prpl_popover_id'] = $provider->get_popover_id();
- $response->data['prpl_points'] = $provider->get_points();
-
- /*
- * Check if task was completed before - for example, comments were disabled and then re-enabled, and remove points if so.
- * Those are tasks which are completed by toggling an option, so non repetitive & not user tasks.
- */
- if ( ! \has_term( 'user', 'prpl_recommendations_provider', $post->ID ) && ! $provider->is_repetitive() && $provider->task_has_activity( $response->data['slug'] ) ) {
- $response->data['prpl_points'] = 0;
- }
-
- // Assign point only to golden user task.
- if ( 'user' === $provider->get_provider_id() ) {
- $response->data['prpl_points'] = ( ! empty( $post->post_excerpt ) && \str_contains( $post->post_excerpt, 'GOLDEN' ) ) ? 1 : 0;
- }
-
- // This has to be the last item to be added because actions use data from previous items.
- $response->data['prpl_task_actions'] = $provider->get_task_actions( $response->data );
}
- // Category taxonomy removed - no longer adding prpl_category to response.
+ $response->data['slug'] = \progress_planner()->get_suggested_tasks()->get_task_id_from_slug( $response->data['slug'] );
return $response;
}
diff --git a/classes/goals/class-goal-recurring.php b/classes/goals/class-goal-recurring.php
index 6a5cb3e822..6ca6bebb47 100644
--- a/classes/goals/class-goal-recurring.php
+++ b/classes/goals/class-goal-recurring.php
@@ -182,8 +182,9 @@ public function get_streak() {
$occurences = $this->get_occurences();
// Initialize streak counters.
- $streak_nr = 0; // Current ongoing streak.
- $max_streak = 0; // Best streak ever achieved.
+ $streak_nr = 0; // Current ongoing streak.
+ $max_streak = 0; // Best streak ever achieved.
+ $remaining_breaks = $this->allowed_break; // Local copy to avoid mutating instance property.
foreach ( $occurences as $occurence ) {
// Check if this occurrence's goal was met.
@@ -197,10 +198,10 @@ public function get_streak() {
}
// Goal was not met: Check if we can use an allowed break.
- if ( $this->allowed_break > 0 ) {
+ if ( $remaining_breaks > 0 ) {
// Use one allowed break to keep the streak alive.
// This prevents the streak from resetting for this missed goal.
- --$this->allowed_break;
+ --$remaining_breaks;
continue;
}
diff --git a/classes/rest/class-activities.php b/classes/rest/class-activities.php
new file mode 100644
index 0000000000..1980e05e14
--- /dev/null
+++ b/classes/rest/class-activities.php
@@ -0,0 +1,113 @@
+ 'GET',
+ 'callback' => [ $this, 'get_activities' ],
+ 'permission_callback' => [ $this, 'check_permissions' ],
+ ],
+ ]
+ );
+ }
+
+ /**
+ * Check if the current user has permission to access this endpoint.
+ *
+ * @return bool
+ */
+ public function check_permissions() {
+ return \current_user_can( 'edit_posts' );
+ }
+
+ /**
+ * Get activities data.
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ *
+ * @return \WP_REST_Response
+ */
+ public function get_activities( $request ) {
+ $query = \progress_planner()->get_activities__query();
+
+ // Get all activities (we'll filter in React).
+ $activities = $query->query_activities( [] );
+
+ // Convert activities to array format.
+ $activities_data = [];
+ foreach ( $activities as $activity ) {
+ $activity_data = [
+ 'id' => $activity->id,
+ 'date' => $activity->date ? $activity->date->format( 'Y-m-d H:i:s' ) : null,
+ 'category' => $activity->category,
+ 'type' => $activity->type,
+ 'data_id' => $activity->data_id,
+ 'user_id' => $activity->user_id,
+ ];
+
+ // For suggested_task activities, get points.
+ if ( $activity->category === 'suggested_task' ) {
+ $activity_date = $activity->date ? $activity->date : new \DateTime();
+ $activity_data['points'] = $activity->get_points( $activity_date );
+ }
+
+ $activities_data[] = $activity_data;
+ }
+
+ // Get total posts count for content badges.
+ $total_posts_count = 0;
+ $post_types = \progress_planner()
+ ->get_activities__content_helpers()
+ ->get_post_types_names();
+ foreach ( $post_types as $post_type ) {
+ $counts = \wp_count_posts( $post_type );
+ if ( isset( $counts->publish ) ) {
+ $total_posts_count += (int) $counts->publish;
+ }
+ }
+
+ // Get activation date.
+ $activation_date = \progress_planner()->get_activation_date();
+
+ // Get config (branding, URLs).
+ $branding_id = (int) \progress_planner()->get_ui__branding()->get_branding_id();
+ $remote_server_url = \progress_planner()->get_remote_server_root_url();
+ $placeholder_url = \progress_planner()->get_placeholder_svg( 200, 200 );
+
+ // Build response data.
+ $response_data = [
+ 'activities' => $activities_data,
+ 'totalPostsCount' => $total_posts_count,
+ 'activationDate' => $activation_date->format( 'Y-m-d' ),
+ 'config' => [
+ 'brandingId' => $branding_id,
+ 'remoteServerUrl' => $remote_server_url,
+ 'placeholderUrl' => $placeholder_url,
+ ],
+ ];
+
+ return new \WP_REST_Response( $response_data );
+ }
+}
diff --git a/classes/rest/class-badge-stats.php b/classes/rest/class-badge-stats.php
new file mode 100644
index 0000000000..09b5ca938f
--- /dev/null
+++ b/classes/rest/class-badge-stats.php
@@ -0,0 +1,150 @@
+ 'GET',
+ 'callback' => [ $this, 'get_badge_stats' ],
+ 'permission_callback' => [ $this, 'check_permissions' ],
+ ],
+ [
+ 'methods' => 'POST',
+ 'callback' => [ $this, 'save_badge_stats' ],
+ 'permission_callback' => [ $this, 'check_permissions' ],
+ 'args' => [
+ 'badges' => [
+ 'required' => true,
+ 'type' => 'object',
+ 'validate_callback' => [ $this, 'validate_badge_stats' ],
+ ],
+ ],
+ ],
+ ]
+ );
+ }
+
+ /**
+ * Check if the current user has permission to access this endpoint.
+ *
+ * @return bool
+ */
+ public function check_permissions() {
+ return \current_user_can( 'edit_posts' );
+ }
+
+ /**
+ * Validate badge stats data.
+ *
+ * @param mixed $badges Badge stats data.
+ *
+ * @return bool
+ */
+ public function validate_badge_stats( $badges ) {
+ if ( ! \is_array( $badges ) ) {
+ return false;
+ }
+
+ foreach ( $badges as $badge_id => $badge_data ) {
+ if ( ! \is_string( $badge_id ) ) {
+ return false;
+ }
+ if ( ! \is_array( $badge_data ) ) {
+ return false;
+ }
+ // Validate required fields.
+ if ( ! isset( $badge_data['progress'] ) || ! \is_numeric( $badge_data['progress'] ) ) {
+ return false;
+ }
+ if ( ! isset( $badge_data['remaining'] ) || ! \is_numeric( $badge_data['remaining'] ) ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Get badge stats.
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ *
+ * @return \WP_REST_Response
+ */
+ public function get_badge_stats( $request ) {
+ $settings = \progress_planner()->get_settings();
+ $badges = $settings->get( 'badges', [] );
+
+ return new \WP_REST_Response( [ 'badges' => $badges ] );
+ }
+
+ /**
+ * Save badge stats.
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ *
+ * @return \WP_REST_Response
+ */
+ public function save_badge_stats( $request ) {
+ $badges_data = $request->get_param( 'badges' );
+
+ if ( ! \is_array( $badges_data ) ) {
+ return new \WP_Error(
+ 'invalid_data',
+ \__( 'Invalid badge data.', 'progress-planner' ),
+ [ 'status' => 400 ]
+ );
+ }
+
+ $settings = \progress_planner()->get_settings();
+ $existing = $settings->get( 'badges', [] );
+
+ // Merge with existing data, preserving completion dates for completed badges.
+ foreach ( $badges_data as $badge_id => $badge_data ) {
+ // If badge is being marked as complete (100%), set completion date.
+ if (
+ isset( $badge_data['progress'] ) &&
+ 100 === (int) $badge_data['progress'] &&
+ ( ! isset( $existing[ $badge_id ]['progress'] ) ||
+ 100 !== (int) $existing[ $badge_id ]['progress'] )
+ ) {
+ $badge_data['date'] = ( new \DateTime() )->format( 'Y-m-d H:i:s' );
+ } elseif ( isset( $existing[ $badge_id ]['date'] ) ) {
+ // Preserve existing completion date.
+ $badge_data['date'] = $existing[ $badge_id ]['date'];
+ }
+
+ $existing[ $badge_id ] = $badge_data;
+ }
+
+ $settings->set( 'badges', $existing );
+
+ return new \WP_REST_Response(
+ [
+ 'success' => true,
+ 'badges' => $existing,
+ ]
+ );
+ }
+}
diff --git a/classes/rest/class-data-collectors.php b/classes/rest/class-data-collectors.php
new file mode 100644
index 0000000000..41f1e67b22
--- /dev/null
+++ b/classes/rest/class-data-collectors.php
@@ -0,0 +1,149 @@
+[a-zA-Z0-9_-]+)',
+ [
+ [
+ 'methods' => 'GET',
+ 'callback' => [ $this, 'get_collector_data' ],
+ 'permission_callback' => [ $this, 'permission_callback' ],
+ 'args' => [
+ 'collector_id' => [
+ 'required' => true,
+ 'type' => 'string',
+ 'sanitize_callback' => 'sanitize_key',
+ ],
+ ],
+ ],
+ ]
+ );
+ }
+
+ /**
+ * Permission callback for data collector endpoint.
+ *
+ * @return bool
+ */
+ public function permission_callback() {
+ return \current_user_can( 'edit_others_posts' );
+ }
+
+ /**
+ * Get data collector data.
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ * @return \WP_REST_Response|\WP_Error The REST response object or error.
+ */
+ public function get_collector_data( $request ) {
+ $collector_id = $request->get_param( 'collector_id' );
+
+ if ( ! \is_string( $collector_id ) ) {
+ return new \WP_Error(
+ 'rest_invalid_collector_id',
+ \esc_html__( 'Invalid collector ID.', 'progress-planner' ),
+ [ 'status' => 400 ]
+ );
+ }
+
+ // Map collector IDs to data collector classes.
+ $collector_map = $this->get_collector_map();
+
+ if ( ! isset( $collector_map[ $collector_id ] ) ) {
+ return new \WP_Error(
+ 'rest_collector_not_found',
+ \esc_html__( 'Data collector not found.', 'progress-planner' ),
+ [ 'status' => 404 ]
+ );
+ }
+
+ $collector_class = $collector_map[ $collector_id ];
+ // @phpstan-ignore-next-line -- Array key access is validated above.
+
+ if ( ! \class_exists( $collector_class ) ) {
+ return new \WP_Error(
+ 'rest_collector_class_not_found',
+ \esc_html__( 'Data collector class not found.', 'progress-planner' ),
+ [ 'status' => 500 ]
+ );
+ }
+
+ // Instantiate and collect data.
+ $collector = new $collector_class();
+ // @phpstan-ignore-next-line -- Dynamic class instantiation.
+ $data = $collector->collect();
+
+ return new \WP_REST_Response(
+ [
+ 'collector_id' => $collector_id,
+ 'data' => $data,
+ ],
+ 200
+ );
+ }
+
+ /**
+ * Get the map of collector IDs to class names.
+ *
+ * Maps collector IDs (kebab-case) to data collector class names.
+ * Collector IDs should match the DATA_KEY constant values (converted to kebab-case).
+ *
+ * @return array Array of collector_id => class_name mappings.
+ */
+ protected function get_collector_map() {
+ $map = [
+ 'hello_world_post_id' => \Progress_Planner\Suggested_Tasks\Data_Collector\Hello_World::class,
+ 'sample_page_id' => \Progress_Planner\Suggested_Tasks\Data_Collector\Sample_Page::class,
+ 'inactive_plugins_count' => \Progress_Planner\Suggested_Tasks\Data_Collector\Inactive_Plugins::class,
+ 'uncategorized_category_id' => \Progress_Planner\Suggested_Tasks\Data_Collector\Uncategorized_Category::class,
+ 'post_author_count' => \Progress_Planner\Suggested_Tasks\Data_Collector\Post_Author::class,
+ 'last_published_post_id' => \Progress_Planner\Suggested_Tasks\Data_Collector\Last_Published_Post::class,
+ 'archive_format_count' => \Progress_Planner\Suggested_Tasks\Data_Collector\Archive_Format::class,
+ 'terms_without_posts' => \Progress_Planner\Suggested_Tasks\Data_Collector\Terms_Without_Posts::class,
+ 'terms_without_description' => \Progress_Planner\Suggested_Tasks\Data_Collector\Terms_Without_Description::class,
+ 'post_tag_count' => \Progress_Planner\Suggested_Tasks\Data_Collector\Post_Tag_Count::class,
+ 'published_post_count' => \Progress_Planner\Suggested_Tasks\Data_Collector\Published_Post_Count::class,
+ 'unpublished_content' => \Progress_Planner\Suggested_Tasks\Data_Collector\Unpublished_Content::class,
+ 'seo_plugin_installed' => \Progress_Planner\Suggested_Tasks\Data_Collector\SEO_Plugin::class,
+ 'php_version' => \Progress_Planner\Suggested_Tasks\Data_Collector\PHP_Version::class,
+ 'wp_debug_status' => \Progress_Planner\Suggested_Tasks\Data_Collector\WP_Debug::class,
+ 'old_posts_for_review' => \Progress_Planner\Suggested_Tasks\Data_Collector\Old_Posts_For_Review::class,
+ 'permalink_has_date' => \Progress_Planner\Suggested_Tasks\Data_Collector\Permalink_Has_Date::class,
+ 'yoast_options' => \Progress_Planner\Suggested_Tasks\Data_Collector\Yoast_Options::class,
+ 'yoast_premium_status' => \Progress_Planner\Suggested_Tasks\Data_Collector\Yoast_Premium_Status::class,
+ 'yoast_orphaned_content' => \Progress_Planner\Suggested_Tasks\Data_Collector\Yoast_Orphaned_Content::class,
+ 'aioseo_options' => \Progress_Planner\Suggested_Tasks\Data_Collector\AIOSEO_Options::class,
+ ];
+
+ /**
+ * Filter the data collector map.
+ *
+ * Allows third-party plugins to register custom data collectors.
+ *
+ * @param array $map Array of collector_id => class_name mappings.
+ * @return array Modified map.
+ */
+ return \apply_filters( 'progress_planner_data_collector_map', $map );
+ }
+}
diff --git a/classes/rest/class-email-sending-config.php b/classes/rest/class-email-sending-config.php
new file mode 100644
index 0000000000..75389833aa
--- /dev/null
+++ b/classes/rest/class-email-sending-config.php
@@ -0,0 +1,120 @@
+ 'GET',
+ 'callback' => [ $this, 'get_config' ],
+ 'permission_callback' => [ $this, 'check_permissions' ],
+ ],
+ ]
+ );
+ }
+
+ /**
+ * Check if the current user has permission to access this endpoint.
+ *
+ * @return bool
+ */
+ public function check_permissions() {
+ return \current_user_can( 'manage_options' );
+ }
+
+ /**
+ * Get email sending configuration.
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ *
+ * @return \WP_REST_Response
+ */
+ public function get_config( $request ) {
+ // Get current user for default email.
+ $current_user = \wp_get_current_user();
+ $default_email = $current_user->user_email ?? '';
+
+ // Get troubleshooting guide URL.
+ $troubleshooting_guide_url = \esc_url(
+ \progress_planner()->get_ui__branding()->get_url( 'https://prpl.fyi/troubleshoot-smtp' )
+ );
+
+ // Check if there's an email override (SMTP plugin).
+ $has_email_override = $this->is_there_sending_email_override();
+
+ // Get email subject.
+ $email_subject = \esc_html__( 'Your Progress Planner test message!', 'progress-planner' );
+
+ return new \WP_REST_Response(
+ [
+ 'email_subject' => $email_subject,
+ 'troubleshooting_guide_url' => $troubleshooting_guide_url,
+ 'has_email_override' => $has_email_override,
+ 'default_email' => $default_email,
+ ],
+ 200
+ );
+ }
+
+ /**
+ * Check if there's an email sending override (SMTP plugin).
+ *
+ * @return bool
+ */
+ private function is_there_sending_email_override() {
+ return $this->is_wp_mail_filtered() || $this->is_wp_mail_overridden();
+ }
+
+ /**
+ * Check if wp_mail is filtered (phpmailer_init or pre_wp_mail hooks have callbacks).
+ *
+ * @return bool
+ */
+ private function is_wp_mail_filtered() {
+ global $wp_filter;
+
+ foreach ( [ 'phpmailer_init', 'pre_wp_mail' ] as $filter ) {
+ if ( isset( $wp_filter[ $filter ] ) && $wp_filter[ $filter ] instanceof \WP_Hook && ! empty( $wp_filter[ $filter ]->callbacks ) ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Check if wp_mail function has been overridden by a plugin.
+ *
+ * @return bool
+ */
+ private function is_wp_mail_overridden() {
+ // Just in case, since it will trigger PHP fatal error if the function doesn't exist.
+ if ( ! \function_exists( 'wp_mail' ) ) {
+ return false;
+ }
+
+ $file_path = ( new \ReflectionFunction( 'wp_mail' ) )->getFileName();
+
+ return $file_path && $file_path !== ABSPATH . 'wp-includes/pluggable.php';
+ }
+}
diff --git a/classes/rest/class-email-test.php b/classes/rest/class-email-test.php
new file mode 100644
index 0000000000..128bfb2a05
--- /dev/null
+++ b/classes/rest/class-email-test.php
@@ -0,0 +1,125 @@
+ 'POST',
+ 'callback' => [ $this, 'test_email' ],
+ 'permission_callback' => [ $this, 'check_permissions' ],
+ 'args' => [
+ 'email_address' => [
+ 'required' => true,
+ 'type' => 'string',
+ 'sanitize_callback' => 'sanitize_email',
+ 'validate_callback' => function ( $param ) {
+ return \is_email( $param );
+ },
+ ],
+ 'task_id' => [
+ 'required' => false,
+ 'type' => 'string',
+ 'default' => '',
+ ],
+ ],
+ ],
+ ]
+ );
+ }
+
+ /**
+ * Check if the current user has permission to access this endpoint.
+ *
+ * @return bool
+ */
+ public function check_permissions() {
+ return \current_user_can( 'manage_options' );
+ }
+
+ /**
+ * Test email sending.
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ *
+ * @return \WP_REST_Response|\WP_Error
+ */
+ public function test_email( $request ) {
+ $email_address = $request->get_param( 'email_address' );
+ $task_id = $request->get_param( 'task_id' );
+
+ if ( ! \is_email( $email_address ) ) {
+ return new \WP_Error(
+ 'invalid_email',
+ \esc_html__( 'Invalid email address.', 'progress-planner' ),
+ [ 'status' => 400 ]
+ );
+ }
+
+ // Get task ID from request or use default.
+ $task_id = ! empty( $task_id ) ? $task_id : 'sending-email';
+
+ // Generate a secure token for the completion link to prevent CSRF.
+ $user_id = \get_current_user_id();
+ $token = \progress_planner()->get_suggested_tasks()->generate_task_completion_token( $task_id, $user_id );
+
+ $email_subject = \esc_html__( 'Your Progress Planner test message!', 'progress-planner' );
+ $email_content = \sprintf(
+ // translators: %1$s the admin URL, %2$s the assistant name.
+ \__( 'You just used Progress Planner to verify if sending email works on your website.
The good news; it does! Click here to mark %2$s\'s Recommendation as completed.', 'progress-planner' ),
+ \admin_url( 'admin.php?page=progress-planner&prpl_complete_task=' . $task_id . '&token=' . $token ),
+ \esc_html( \progress_planner()->get_ui__branding()->get_ravi_name() )
+ );
+
+ $headers = [ 'Content-Type: text/html; charset=UTF-8' ];
+
+ // Track email errors.
+ $email_error = null;
+ \add_action(
+ 'wp_mail_failed',
+ function ( $error ) use ( &$email_error ) {
+ $email_error = $error->get_error_message() ? $error->get_error_message() : \esc_html__( 'Unknown error', 'progress-planner' );
+ }
+ );
+
+ $result = \wp_mail( $email_address, $email_subject, $email_content, $headers );
+
+ if ( $result ) {
+ return new \WP_REST_Response(
+ [
+ 'success' => true,
+ 'message' => \esc_html__( 'Email sent successfully.', 'progress-planner' ),
+ ],
+ 200
+ );
+ }
+
+ // If email failed, return the error.
+ $error_message = $email_error ? $email_error : \esc_html__( 'Unknown error', 'progress-planner' );
+ return new \WP_Error(
+ 'email_failed',
+ $error_message,
+ [ 'status' => 500 ]
+ );
+ }
+}
diff --git a/classes/rest/class-locale-options.php b/classes/rest/class-locale-options.php
new file mode 100644
index 0000000000..c5d455904e
--- /dev/null
+++ b/classes/rest/class-locale-options.php
@@ -0,0 +1,112 @@
+ 'GET',
+ 'callback' => [ $this, 'get_locale_options' ],
+ 'permission_callback' => [ $this, 'check_permissions' ],
+ ],
+ ]
+ );
+ }
+
+ /**
+ * Check if the current user has permission to access this endpoint.
+ *
+ * @return bool
+ */
+ public function check_permissions() {
+ return \current_user_can( 'manage_options' );
+ }
+
+ /**
+ * Get locale options.
+ *
+ * @return \WP_REST_Response
+ */
+ public function get_locale_options() {
+ $options = $this->build_locale_options();
+
+ return new \WP_REST_Response( $options, 200 );
+ }
+
+ /**
+ * Build locale options array.
+ *
+ * Uses WordPress's get_available_languages() and wp_get_available_translations()
+ * to build the list of available locales.
+ *
+ * @return array Array of locale option objects with 'value' and 'label' properties.
+ */
+ private function build_locale_options() {
+ if ( ! \function_exists( 'request_filesystem_credentials' ) ) {
+ // @phpstan-ignore-next-line requireOnce.fileNotFound
+ require_once ABSPATH . 'wp-admin/includes/file.php';
+ }
+
+ if ( ! \function_exists( 'wp_get_available_translations' ) ) {
+ // @phpstan-ignore-next-line requireOnce.fileNotFound
+ require_once ABSPATH . 'wp-admin/includes/translation-install.php';
+ }
+
+ $languages = \get_available_languages();
+ $translations = \wp_get_available_translations();
+
+ $options = [
+ [
+ 'value' => '',
+ 'label' => 'English (United States)',
+ ],
+ ];
+
+ foreach ( $languages as $locale ) {
+ $label = isset( $translations[ $locale ] )
+ ? $translations[ $locale ]['native_name']
+ : $locale;
+
+ $options[] = [
+ 'value' => $locale,
+ 'label' => $label,
+ ];
+ }
+
+ // Include installable languages if user can install them.
+ if ( \current_user_can( 'install_languages' ) && \wp_can_install_language_pack() ) {
+ foreach ( $translations as $translation ) {
+ if ( \in_array( $translation['language'], $languages, true ) ) {
+ continue;
+ }
+
+ $options[] = [
+ 'value' => $translation['language'],
+ 'label' => $translation['native_name'],
+ ];
+ }
+ }
+
+ return $options;
+ }
+}
diff --git a/classes/rest/class-page-settings.php b/classes/rest/class-page-settings.php
new file mode 100644
index 0000000000..81b350ad5f
--- /dev/null
+++ b/classes/rest/class-page-settings.php
@@ -0,0 +1,54 @@
+ 'GET',
+ 'callback' => [ $this, 'get_page_settings' ],
+ 'permission_callback' => [ $this, 'permission_callback' ],
+ ]
+ );
+ }
+
+ /**
+ * Get page settings data.
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ * @return \WP_REST_Response The REST response object.
+ */
+ public function get_page_settings( $request ) {
+ $settings = \progress_planner()->get_admin__page_settings()->get_settings();
+
+ return new \WP_REST_Response( $settings, 200 );
+ }
+
+ /**
+ * Permission callback for page settings endpoint.
+ *
+ * @return bool
+ */
+ public function permission_callback() {
+ return \current_user_can( 'manage_options' );
+ }
+}
diff --git a/classes/rest/class-plugin-installer.php b/classes/rest/class-plugin-installer.php
new file mode 100644
index 0000000000..036721d03c
--- /dev/null
+++ b/classes/rest/class-plugin-installer.php
@@ -0,0 +1,275 @@
+ 'POST',
+ 'callback' => [ $this, 'install_plugin' ],
+ 'permission_callback' => [ $this, 'check_permissions' ],
+ 'args' => [
+ 'plugin_slug' => [
+ 'required' => true,
+ 'type' => 'string',
+ 'sanitize_callback' => 'sanitize_text_field',
+ 'validate_callback' => function ( $param ) {
+ return ! empty( $param );
+ },
+ ],
+ ],
+ ],
+ ]
+ );
+
+ \register_rest_route(
+ 'progress-planner/v1',
+ '/plugins/activate',
+ [
+ [
+ 'methods' => 'POST',
+ 'callback' => [ $this, 'activate_plugin' ],
+ 'permission_callback' => [ $this, 'check_permissions' ],
+ 'args' => [
+ 'plugin_slug' => [
+ 'required' => true,
+ 'type' => 'string',
+ 'sanitize_callback' => 'sanitize_text_field',
+ 'validate_callback' => function ( $param ) {
+ return ! empty( $param );
+ },
+ ],
+ ],
+ ],
+ ]
+ );
+ }
+
+ /**
+ * Check if the current user has permission to access this endpoint.
+ *
+ * @return bool
+ */
+ public function check_permissions() {
+ return \current_user_can( 'install_plugins' );
+ }
+
+ /**
+ * Install a plugin.
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ *
+ * @return \WP_REST_Response|\WP_Error
+ */
+ public function install_plugin( $request ) {
+ $slug = $request->get_param( 'plugin_slug' );
+
+ // If the plugin slug is empty, return an error.
+ if ( empty( $slug ) ) {
+ return new \WP_Error(
+ 'empty_plugin_slug',
+ \esc_html__( 'An Error Occured', 'progress-planner' ),
+ [ 'status' => 400 ]
+ );
+ }
+
+ // If the plugin is already installed, return a success message.
+ if ( $this->is_plugin_installed( $slug ) ) {
+ return new \WP_REST_Response(
+ [
+ 'code' => 'plugin_already_installed',
+ 'message' => \esc_html__( 'Plugin already installed', 'progress-planner' ),
+ ],
+ 200
+ );
+ }
+
+ // Install the plugin.
+ $installed = $this->do_install_plugin( $slug );
+
+ // If the plugin is installed, return a success message.
+ if ( $installed && ! \is_wp_error( $installed ) ) {
+ return new \WP_REST_Response(
+ [
+ 'code' => 'plugin_installed',
+ 'message' => \esc_html__( 'Plugin installed', 'progress-planner' ),
+ ],
+ 200
+ );
+ }
+
+ // If the plugin installation returned a WP_Error, use that error.
+ if ( \is_wp_error( $installed ) ) {
+ return new \WP_Error(
+ $installed->get_error_code(),
+ $installed->get_error_message(),
+ [ 'status' => 500 ]
+ );
+ }
+
+ // If the plugin is not installed, return an error message.
+ return new \WP_Error(
+ 'install_failed',
+ \esc_html__( 'An Error Occured', 'progress-planner' ),
+ [ 'status' => 500 ]
+ );
+ }
+
+ /**
+ * Activate a plugin.
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ *
+ * @return \WP_REST_Response|\WP_Error
+ */
+ public function activate_plugin( $request ) {
+ $plugin_slug = $request->get_param( 'plugin_slug' );
+
+ // If the plugin slug is empty, return an error.
+ if ( empty( $plugin_slug ) ) {
+ return new \WP_Error(
+ 'empty_plugin_slug',
+ \esc_html__( 'An Error Occured', 'progress-planner' ),
+ [ 'status' => 400 ]
+ );
+ }
+
+ // Get the plugin path.
+ $plugin_path = $this->get_plugin_path( $plugin_slug );
+
+ // If the plugin path is empty, return an error.
+ if ( empty( $plugin_path ) ) {
+ return new \WP_Error(
+ 'plugin_not_found',
+ \esc_html__( 'An Error Occured', 'progress-planner' ),
+ [ 'status' => 404 ]
+ );
+ }
+
+ // Activate the plugin.
+ $activated = \activate_plugin( $plugin_path );
+
+ // If the plugin is not activated, return an error message.
+ if ( \is_wp_error( $activated ) ) {
+ return new \WP_Error(
+ 'activate_failed',
+ \esc_html__( 'An Error Occured', 'progress-planner' ),
+ [ 'status' => 500 ]
+ );
+ }
+
+ // If the plugin is activated, return a success message.
+ return new \WP_REST_Response(
+ [
+ 'code' => 'plugin_activated',
+ 'message' => \esc_html__( 'Plugin activated', 'progress-planner' ),
+ ],
+ 200
+ );
+ }
+
+ /**
+ * Install a plugin.
+ *
+ * @param string $plugin The plugin to install.
+ *
+ * @return bool|\WP_Error
+ */
+ private function do_install_plugin( $plugin ) {
+ // Include the necessary files.
+ require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; // @phpstan-ignore-line
+ require_once ABSPATH . 'wp-admin/includes/plugin-install.php'; // @phpstan-ignore-line
+ require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php'; // @phpstan-ignore-line
+ require_once ABSPATH . 'wp-admin/includes/class-plugin-installer-skin.php'; // @phpstan-ignore-line
+
+ // Get the plugin information.
+ $api = \plugins_api(
+ 'plugin_information',
+ [
+ 'slug' => $plugin,
+ 'fields' => [
+ 'sections' => false,
+ ],
+ ]
+ );
+
+ // If the plugin information is not found, return an error.
+ if ( \is_wp_error( $api ) ) {
+ return $api;
+ }
+
+ $api = (object) $api;
+ // If the plugin download link is not found, return an error.
+ if ( ! isset( $api->download_link ) ) {
+ return new \WP_Error( 'no_download_link', \__( 'No download link found', 'progress-planner' ) );
+ }
+
+ // If the plugin name is not found, return an error.
+ if ( ! isset( $api->name ) ) {
+ return new \WP_Error( 'no_name', \__( 'No name found', 'progress-planner' ) );
+ }
+
+ // If the plugin version is not found, return an error.
+ if ( ! isset( $api->version ) ) {
+ return new \WP_Error( 'no_version', \__( 'No version found', 'progress-planner' ) );
+ }
+
+ // Create a new plugin upgrader.
+ $upgrader = new \Plugin_Upgrader(
+ new \Plugin_Installer_Skin(
+ [
+ 'type' => 'web',
+ /* translators: %s: Plugin name and version. */
+ 'title' => \sprintf( \__( 'Installing Plugin: %s', 'progress-planner' ), $api->name . ' ' . $api->version ),
+ 'url' => 'update.php?action=install-plugin&plugin=' . \rawurlencode( $plugin ),
+ 'nonce' => 'install-plugin_' . $plugin,
+ 'plugin' => $plugin,
+ 'api' => $api,
+ ]
+ )
+ );
+
+ // Install the plugin.
+ return $upgrader->install( $api->download_link );
+ }
+
+ /**
+ * Checks if plugin is installed.
+ *
+ * @param string $plugin_slug The slug of the plugin we want to check.
+ *
+ * @return bool
+ */
+ private function is_plugin_installed( $plugin_slug ) {
+ return \Progress_Planner\Utils\Plugin_Utils::is_plugin_installed( $plugin_slug );
+ }
+
+ /**
+ * Get the path of the plugin.
+ *
+ * @param string $plugin_slug The slug of the plugin we want to get the path for.
+ *
+ * @return string
+ */
+ private function get_plugin_path( $plugin_slug ) {
+ return \Progress_Planner\Utils\Plugin_Utils::get_plugin_path( $plugin_slug );
+ }
+}
diff --git a/classes/rest/class-popover-actions.php b/classes/rest/class-popover-actions.php
new file mode 100644
index 0000000000..fbdb645f63
--- /dev/null
+++ b/classes/rest/class-popover-actions.php
@@ -0,0 +1,189 @@
+ 'POST',
+ 'callback' => [ $this, 'submit_action' ],
+ 'permission_callback' => [ $this, 'check_permissions' ],
+ 'args' => [
+ 'setting' => [
+ 'required' => true,
+ 'type' => 'string',
+ 'sanitize_callback' => 'sanitize_text_field',
+ 'validate_callback' => function ( $param ) {
+ return ! empty( $param );
+ },
+ ],
+ 'value' => [
+ 'required' => true,
+ 'type' => 'string',
+ 'sanitize_callback' => 'sanitize_text_field',
+ // Allow empty strings as some settings may be empty.
+ 'validate_callback' => function ( $param ) {
+ return null !== $param;
+ },
+ ],
+ 'setting_path' => [
+ 'required' => false,
+ 'type' => 'string',
+ 'sanitize_callback' => 'sanitize_text_field',
+ 'default' => '',
+ 'description' => 'JSON string representing the path to nested setting (e.g., \'["key1","key2"]\')',
+ ],
+ ],
+ ],
+ ]
+ );
+ }
+
+ /**
+ * Check if the current user has permission to access this endpoint.
+ *
+ * @return bool
+ */
+ public function check_permissions() {
+ return \current_user_can( 'manage_options' );
+ }
+
+ /**
+ * Handle popover form submission.
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ *
+ * @return \WP_REST_Response|\WP_Error
+ */
+ public function submit_action( $request ) {
+ $setting = $request->get_param( 'setting' );
+ $value = $request->get_param( 'value' );
+ $setting_path = $request->get_param( 'setting_path' );
+
+ // Get allowed options from Tasks_Interactive class.
+ // We need to instantiate a temporary instance to access the protected method.
+ // Since it's abstract, we'll use a reflection-based approach or create a helper.
+ $allowed_options = $this->get_allowed_interactive_options();
+
+ if ( ! \in_array( $setting, $allowed_options, true ) ) {
+ return new \WP_Error(
+ 'invalid_setting',
+ \esc_html__( 'Invalid setting. This option cannot be updated through interactive tasks.', 'progress-planner' ),
+ [ 'status' => 400 ]
+ );
+ }
+
+ // Handle nested setting paths.
+ if ( ! empty( $setting_path ) ) {
+ $setting_path_array = \json_decode( $setting_path, true );
+ // Check if JSON decode was successful and result is a non-empty array.
+ if ( \json_last_error() !== \JSON_ERROR_NONE || ! \is_array( $setting_path_array ) || empty( $setting_path_array ) ) {
+ return new \WP_Error(
+ 'invalid_setting_path',
+ \esc_html__( 'Invalid setting path format. Expected a JSON array.', 'progress-planner' ),
+ [ 'status' => 400 ]
+ );
+ }
+ $setting_value = \get_option( $setting, [] );
+ // Ensure setting_value is an array for nested path updates.
+ if ( ! \is_array( $setting_value ) ) {
+ $setting_value = [];
+ }
+ \_wp_array_set( $setting_value, $setting_path_array, $value );
+ $updated = \update_option( $setting, $setting_value );
+ if ( ! $updated ) {
+ return new \WP_Error(
+ 'update_failed',
+ \esc_html__( 'Failed to update setting.', 'progress-planner' ),
+ [ 'status' => 500 ]
+ );
+ }
+ return new \WP_REST_Response(
+ [
+ 'success' => true,
+ 'message' => \esc_html__( 'Setting updated.', 'progress-planner' ),
+ ],
+ 200
+ );
+ }
+
+ // Handle simple setting update.
+ $updated = \update_option( $setting, $value );
+ if ( ! $updated ) {
+ return new \WP_Error(
+ 'update_failed',
+ \esc_html__( 'Failed to update setting.', 'progress-planner' ),
+ [ 'status' => 500 ]
+ );
+ }
+
+ return new \WP_REST_Response(
+ [
+ 'success' => true,
+ 'message' => \esc_html__( 'Setting updated.', 'progress-planner' ),
+ ],
+ 200
+ );
+ }
+
+ /**
+ * Get the list of allowed options that can be updated via interactive tasks.
+ *
+ * This mirrors the method from Tasks_Interactive class.
+ *
+ * @return array List of allowed option names.
+ */
+ private function get_allowed_interactive_options() {
+ $allowed_options = [
+ // Core WordPress settings that are safe to update via interactive tasks.
+ 'blogdescription', // Site tagline.
+ 'blog_public', // Search engine visibility (allow indexing).
+ 'default_comment_status', // Comment settings.
+ 'default_ping_status', // Pingback settings.
+ 'timezone_string', // Site timezone.
+ 'WPLANG', // Site language/locale (deprecated since WP 4.0, but still used by class-select-locale.php).
+ 'date_format', // Date format.
+ 'time_format', // Time format.
+ 'default_pingback_flag', // Pingback flag.
+ 'comment_registration', // Comment registration.
+ 'close_comments_for_old_posts', // Close comments for old posts.
+ 'thread_comments', // Threaded comments.
+ 'comments_per_page', // Comments per page.
+ 'comment_order', // Comment order.
+ 'page_comments', // Paginate comments.
+ ];
+
+ /**
+ * Filter the list of allowed options for interactive tasks.
+ *
+ * WARNING: Be very careful when extending this list. Adding sensitive
+ * options like 'admin_email', 'users_can_register', or plugin-specific
+ * options that control access or permissions could create security vulnerabilities.
+ *
+ * @param array $allowed_options List of allowed option names.
+ *
+ * @return array Modified list of allowed option names.
+ */
+ return \apply_filters( 'progress_planner_interactive_task_allowed_options', $allowed_options );
+ }
+}
diff --git a/classes/rest/class-stats.php b/classes/rest/class-stats.php
index 5ff4217bb9..d93c074804 100644
--- a/classes/rest/class-stats.php
+++ b/classes/rest/class-stats.php
@@ -12,8 +12,6 @@
namespace Progress_Planner\Rest;
-use Progress_Planner\Admin\Widgets\Activity_Scores;
-
/**
* Rest_API_Stats class.
*/
diff --git a/classes/rest/class-subscribe.php b/classes/rest/class-subscribe.php
new file mode 100644
index 0000000000..d8897b9427
--- /dev/null
+++ b/classes/rest/class-subscribe.php
@@ -0,0 +1,142 @@
+ 'POST',
+ 'callback' => [ $this, 'subscribe' ],
+ 'permission_callback' => [ $this, 'check_permissions' ],
+ 'args' => [
+ 'name' => [
+ 'required' => true,
+ 'type' => 'string',
+ 'sanitize_callback' => 'sanitize_text_field',
+ 'validate_callback' => function ( $param ) {
+ return ! empty( $param );
+ },
+ ],
+ 'email' => [
+ 'required' => true,
+ 'type' => 'string',
+ 'sanitize_callback' => 'sanitize_email',
+ 'validate_callback' => function ( $param ) {
+ return \is_email( $param );
+ },
+ ],
+ 'site' => [
+ 'required' => true,
+ 'type' => 'string',
+ 'sanitize_callback' => 'esc_url_raw',
+ 'validate_callback' => function ( $param ) {
+ return ! empty( $param );
+ },
+ ],
+ 'timezone_offset' => [
+ 'required' => false,
+ 'type' => 'number',
+ 'default' => 0,
+ ],
+ 'with_email' => [
+ 'required' => false,
+ 'type' => 'string',
+ 'default' => 'yes',
+ ],
+ ],
+ ],
+ ]
+ );
+ }
+
+ /**
+ * Check if the current user has permission to access this endpoint.
+ *
+ * @return bool
+ */
+ public function check_permissions() {
+ return \current_user_can( 'manage_options' );
+ }
+
+ /**
+ * Handle subscription.
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ *
+ * @return \WP_REST_Response|\WP_Error
+ */
+ public function subscribe( $request ) {
+ $name = $request->get_param( 'name' );
+ $email = $request->get_param( 'email' );
+ $site = $request->get_param( 'site' );
+ $timezone_offset = $request->get_param( 'timezone_offset' );
+ $with_email = $request->get_param( 'with_email' );
+
+ // Build data object for onboarding API.
+ $data = [
+ 'name' => $name,
+ 'email' => $email,
+ 'site' => $site,
+ 'timezone_offset' => $timezone_offset,
+ 'with-email' => $with_email,
+ ];
+
+ // Get nonce from external API.
+ $onboard_utils = \progress_planner()->get_utils__onboard();
+ $nonce = $onboard_utils->get_remote_nonce();
+
+ if ( empty( $nonce ) ) {
+ return new \WP_Error(
+ 'nonce_failed',
+ \esc_html__( 'Failed to get nonce from remote server.', 'progress-planner' ),
+ [ 'status' => 500 ]
+ );
+ }
+
+ // Add nonce to data.
+ $data['nonce'] = $nonce;
+
+ // Make request to external API using the Onboard utility.
+ $license_key = $onboard_utils->make_remote_onboarding_request( $data );
+
+ if ( empty( $license_key ) ) {
+ return new \WP_Error(
+ 'api_request_failed',
+ \esc_html__( 'Failed to submit subscription.', 'progress-planner' ),
+ [ 'status' => 500 ]
+ );
+ }
+
+ // Save the license key to the database.
+ \update_option( 'progress_planner_license_key', $license_key, false );
+
+ return new \WP_REST_Response(
+ [
+ 'success' => true,
+ 'message' => \esc_html__( 'Subscription successful.', 'progress-planner' ),
+ 'license_key' => $license_key,
+ ],
+ 200
+ );
+ }
+}
diff --git a/classes/rest/class-task-evaluation.php b/classes/rest/class-task-evaluation.php
new file mode 100644
index 0000000000..76b7274d24
--- /dev/null
+++ b/classes/rest/class-task-evaluation.php
@@ -0,0 +1,636 @@
+ 'POST',
+ 'callback' => [ $this, 'create_task' ],
+ 'permission_callback' => [ $this, 'permission_callback' ],
+ 'args' => [
+ 'task_details' => [
+ 'required' => true,
+ 'type' => 'object',
+ 'validate_callback' => [ $this, 'validate_task_details' ],
+ 'sanitize_callback' => [ $this, 'sanitize_task_details' ],
+ ],
+ ],
+ ],
+ ]
+ );
+
+ // Batch task creation endpoint.
+ \register_rest_route(
+ 'progress-planner/v1',
+ '/tasks/evaluate-batch',
+ [
+ [
+ 'methods' => 'POST',
+ 'callback' => [ $this, 'create_tasks_batch' ],
+ 'permission_callback' => [ $this, 'permission_callback' ],
+ 'args' => [
+ 'tasks' => [
+ 'required' => true,
+ 'type' => 'array',
+ ],
+ ],
+ ],
+ ]
+ );
+ }
+
+ /**
+ * Permission callback for task evaluation endpoint.
+ *
+ * @return bool
+ */
+ public function permission_callback() {
+ return \current_user_can( 'edit_others_posts' );
+ }
+
+ /**
+ * Validate task details.
+ *
+ * @param mixed $value The task details array.
+ * @param \WP_REST_Request $request The request object.
+ * @param string $param The parameter name.
+ * @return bool
+ */
+ public function validate_task_details( $value, $request, $param ) {
+ if ( ! \is_array( $value ) ) {
+ return false;
+ }
+
+ // Required fields.
+ $required = [ 'task_id', 'provider_id', 'post_title' ];
+ foreach ( $required as $field ) {
+ if ( ! isset( $value[ $field ] ) || empty( $value[ $field ] ) ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Sanitize task details.
+ *
+ * @param array $value The task details array.
+ * @param \WP_REST_Request $request The request object.
+ * @param string $param The parameter name.
+ * @return array
+ */
+ public function sanitize_task_details( $value, $request, $param ) {
+ $sanitized = [];
+
+ // Sanitize string fields.
+ $string_fields = [
+ 'task_id',
+ 'provider_id',
+ 'post_title',
+ 'description',
+ 'url',
+ 'url_target',
+ 'external_link_url',
+ ];
+ foreach ( $string_fields as $field ) {
+ if ( isset( $value[ $field ] ) ) {
+ $sanitized[ $field ] = \sanitize_text_field( $value[ $field ] );
+ }
+ }
+
+ // Sanitize integer fields.
+ $int_fields = [ 'parent', 'priority', 'points', 'order' ];
+ foreach ( $int_fields as $field ) {
+ if ( isset( $value[ $field ] ) ) {
+ $sanitized[ $field ] = (int) $value[ $field ];
+ }
+ }
+
+ // Sanitize boolean fields.
+ $bool_fields = [ 'dismissable' ];
+ foreach ( $bool_fields as $field ) {
+ if ( isset( $value[ $field ] ) ) {
+ $sanitized[ $field ] = (bool) $value[ $field ];
+ }
+ }
+
+ // Preserve array fields (like link_setting).
+ $array_fields = [ 'link_setting' ];
+ foreach ( $array_fields as $field ) {
+ if ( isset( $value[ $field ] ) && \is_array( $value[ $field ] ) ) {
+ $sanitized[ $field ] = $value[ $field ];
+ }
+ }
+
+ return $sanitized;
+ }
+
+ /**
+ * Create a task post.
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ * @return \WP_REST_Response|\WP_Error The REST response object or error.
+ */
+ public function create_task( $request ) {
+ $task_details = $request->get_param( 'task_details' );
+ $result = $this->create_single_task( $task_details );
+
+ if ( \is_wp_error( $result ) ) {
+ return $result;
+ }
+
+ $status_code = isset( $result['post_id'] ) && $result['message'] === \esc_html__( 'Task created successfully.', 'progress-planner' ) ? 201 : 200;
+ return new \WP_REST_Response( $result, $status_code );
+ }
+
+ /**
+ * Create multiple tasks in a batch with optimized database operations.
+ *
+ * Optimizations over sequential processing:
+ * - Single lock for entire batch (vs per-task locks)
+ * - Bulk existence check with one query (vs per-task queries)
+ * - Pre-fetch all provider terms at once (vs per-task term lookups)
+ * - Direct response building (no internal REST calls)
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ * @return \WP_REST_Response The REST response object.
+ */
+ public function create_tasks_batch( $request ) {
+ $tasks = $request->get_param( 'tasks' );
+ if ( empty( $tasks ) ) {
+ return new \WP_REST_Response(
+ [
+ 'success' => true,
+ 'tasks' => [],
+ ],
+ 200
+ );
+ }
+
+ // Sanitize all tasks first.
+ $sanitized_tasks = [];
+ foreach ( $tasks as $task_details ) {
+ $sanitized_tasks[] = $this->sanitize_task_details( $task_details, $request, 'tasks' );
+ }
+
+ // Acquire a single lock for the entire batch.
+ $lock_key = 'prpl_batch_lock_' . \md5( \wp_json_encode( \array_column( $sanitized_tasks, 'task_id' ) ) );
+ $lock_value = \time();
+
+ if ( ! \add_option( $lock_key, $lock_value, '', false ) ) {
+ $current = \get_option( $lock_key );
+ if ( ! $current || $current >= \time() - 30 ) {
+ // Lock is held by another active process.
+ return new \WP_REST_Response(
+ [
+ 'success' => false,
+ 'message' => \esc_html__( 'Batch creation in progress by another process.', 'progress-planner' ),
+ ],
+ 409
+ );
+ }
+ // Stale lock, take it over.
+ \update_option( $lock_key, $lock_value );
+ }
+
+ try {
+ $results = $this->process_batch_tasks( $sanitized_tasks );
+ } finally {
+ \delete_option( $lock_key );
+ }
+
+ return new \WP_REST_Response(
+ [
+ 'success' => true,
+ 'tasks' => $results,
+ ],
+ 201
+ );
+ }
+
+ /**
+ * Process batch tasks with optimized database operations.
+ *
+ * @param array $sanitized_tasks Array of sanitized task details.
+ * @return array Array of results for each task.
+ */
+ private function process_batch_tasks( $sanitized_tasks ) {
+ $results = [];
+
+ // Step 1: Bulk check for existing tasks (single query).
+ $task_ids = \array_column( $sanitized_tasks, 'task_id' );
+ $existing_map = $this->bulk_check_existing_tasks( $task_ids );
+
+ // Step 2: Pre-fetch/create all needed provider terms.
+ $provider_ids = \array_unique( \array_column( $sanitized_tasks, 'provider_id' ) );
+ $term_map = $this->ensure_provider_terms( $provider_ids );
+
+ // Step 3: Process each task - create only those that don't exist.
+ foreach ( $sanitized_tasks as $task_details ) {
+ $task_id = (string) $task_details['task_id'];
+
+ // Check if task exists from our bulk query.
+ if ( isset( $existing_map[ $task_id ] ) ) {
+ $existing = $existing_map[ $task_id ];
+ $results[] = [
+ 'success' => true,
+ 'post_id' => $existing->ID,
+ 'task' => $this->build_task_response_from_post( $existing ),
+ 'message' => \esc_html__( 'Task already exists.', 'progress-planner' ),
+ ];
+ continue;
+ }
+
+ // Prepare task data.
+ $task_data = [
+ 'task_id' => $task_details['task_id'],
+ 'provider_id' => $task_details['provider_id'],
+ 'post_title' => $task_details['post_title'],
+ 'description' => $task_details['description'] ?? '',
+ 'priority' => $task_details['priority'] ?? 50,
+ 'points' => $task_details['points'] ?? 1,
+ 'parent' => $task_details['parent'] ?? 0,
+ 'order' => $task_details['order'] ?? ( $task_details['priority'] ?? 50 ),
+ 'url' => $task_details['url'] ?? '',
+ 'url_target' => $task_details['url_target'] ?? '_self',
+ 'external_link_url' => $task_details['external_link_url'] ?? '',
+ 'dismissable' => $task_details['dismissable'] ?? false,
+ 'post_status' => 'publish',
+ ];
+
+ if ( isset( $task_details['link_setting'] ) && \is_array( $task_details['link_setting'] ) ) {
+ $task_data['link_setting'] = $task_details['link_setting'];
+ }
+
+ // Create the task post directly (bypass Suggested_Tasks_DB::add() to avoid per-task locking).
+ $post_id = $this->create_task_post( $task_data, $term_map );
+
+ if ( ! $post_id ) {
+ $results[] = [
+ 'success' => false,
+ 'message' => \esc_html__( 'Failed to create task.', 'progress-planner' ),
+ ];
+ continue;
+ }
+
+ $results[] = [
+ 'success' => true,
+ 'post_id' => $post_id,
+ 'task' => $this->build_task_response( $post_id, $task_data ),
+ 'message' => \esc_html__( 'Task created successfully.', 'progress-planner' ),
+ ];
+ }
+
+ return $results;
+ }
+
+ /**
+ * Bulk check for existing tasks with a single database query.
+ *
+ * @param string[] $task_ids Array of task IDs to check.
+ * @return array Map of task_id => WP_Post for existing tasks.
+ */
+ private function bulk_check_existing_tasks( array $task_ids ) {
+ if ( empty( $task_ids ) ) {
+ return [];
+ }
+
+ // Convert task IDs to post slugs.
+ $slugs = [];
+ $trashed_slugs = [];
+ foreach ( $task_ids as $task_id ) {
+ $slug = \progress_planner()->get_suggested_tasks()->get_task_id_from_slug( $task_id );
+ $slugs[] = $slug;
+ $trashed_slugs[] = $slug . '__trashed';
+ }
+
+ // Single query for all tasks (including trashed).
+ $all_slugs = \array_merge( $slugs, $trashed_slugs );
+ $posts = \get_posts(
+ [
+ 'post_type' => 'prpl_recommendations',
+ 'post_status' => [ 'publish', 'trash', 'draft', 'future', 'pending' ],
+ 'post_name__in' => $all_slugs,
+ 'posts_per_page' => \count( $all_slugs ),
+ 'no_found_rows' => true,
+ ]
+ );
+
+ // Build map of task_id => post.
+ $map = [];
+ foreach ( $posts as $post ) {
+ // Find the original task_id this post belongs to.
+ $slug = $post->post_name;
+ // Remove __trashed suffix if present.
+ $clean_slug = \preg_replace( '/__trashed$/', '', $slug );
+
+ // Find matching task_id.
+ foreach ( $task_ids as $task_id ) {
+ $expected_slug = \progress_planner()->get_suggested_tasks()->get_task_id_from_slug( $task_id );
+ if ( $clean_slug === $expected_slug ) {
+ $map[ $task_id ] = $post;
+ break;
+ }
+ }
+ }
+
+ return $map;
+ }
+
+ /**
+ * Ensure all provider terms exist, creating any that don't.
+ *
+ * @param string[] $provider_ids Array of provider IDs.
+ * @return array Map of provider_id => term_id.
+ */
+ private function ensure_provider_terms( array $provider_ids ) {
+ if ( empty( $provider_ids ) ) {
+ return [];
+ }
+
+ $taxonomy = 'prpl_recommendations_provider';
+ $term_map = [];
+
+ // Get all existing terms in one query.
+ $existing_terms = \get_terms(
+ [
+ 'taxonomy' => $taxonomy,
+ 'name' => $provider_ids,
+ 'hide_empty' => false,
+ ]
+ );
+
+ if ( ! \is_wp_error( $existing_terms ) ) {
+ foreach ( $existing_terms as $term ) {
+ $term_map[ $term->name ] = $term->term_id;
+ }
+ }
+
+ // Create any missing terms.
+ foreach ( $provider_ids as $provider_id ) {
+ if ( ! isset( $term_map[ $provider_id ] ) ) {
+ $result = \wp_insert_term( $provider_id, $taxonomy );
+ if ( ! \is_wp_error( $result ) ) {
+ $term_map[ $provider_id ] = $result['term_id'];
+ }
+ }
+ }
+
+ return $term_map;
+ }
+
+ /**
+ * Create a task post directly (optimized for batch processing).
+ *
+ * @param array $task_data The task data.
+ * @param array $term_map Map of provider_id => term_id.
+ * @return int|false The post ID or false on failure.
+ */
+ private function create_task_post( array $task_data, array $term_map ) {
+ $args = [
+ 'post_type' => 'prpl_recommendations',
+ 'post_title' => $task_data['post_title'],
+ 'post_content' => $task_data['description'] ?? '',
+ 'post_status' => 'publish',
+ 'menu_order' => $task_data['order'] ?? 0,
+ 'post_name' => \progress_planner()->get_suggested_tasks()->get_task_id_from_slug( (string) $task_data['task_id'] ),
+ ];
+
+ $post_id = \wp_insert_post( $args );
+ if ( ! $post_id ) {
+ return false;
+ }
+
+ // Set provider term using pre-fetched term_id.
+ $provider_id = (string) $task_data['provider_id'];
+ if ( isset( $term_map[ $provider_id ] ) ) {
+ \wp_set_post_terms( $post_id, [ $term_map[ $provider_id ] ], 'prpl_recommendations_provider' );
+ }
+
+ // Set meta fields.
+ $meta_fields = [
+ 'task_id',
+ 'priority',
+ 'points',
+ 'url',
+ 'url_target',
+ 'external_link_url',
+ 'dismissable',
+ 'link_setting',
+ ];
+
+ foreach ( $meta_fields as $field ) {
+ if ( isset( $task_data[ $field ] ) ) {
+ \update_post_meta( $post_id, "prpl_$field", $task_data[ $field ] );
+ }
+ }
+
+ return $post_id;
+ }
+
+ /**
+ * Build task response from an existing post object.
+ *
+ * @param \WP_Post $post The post object.
+ * @return array The task response data.
+ */
+ private function build_task_response_from_post( $post ) {
+ // Fetch all meta values.
+ $priority = \get_post_meta( $post->ID, 'prpl_priority', true );
+ $points = \get_post_meta( $post->ID, 'prpl_points', true );
+ $url = \get_post_meta( $post->ID, 'prpl_url', true );
+ $url_target = \get_post_meta( $post->ID, 'prpl_url_target', true );
+ $external_link = \get_post_meta( $post->ID, 'prpl_external_link_url', true );
+ $link_setting = \get_post_meta( $post->ID, 'prpl_link_setting', true );
+
+ return [
+ 'id' => $post->ID,
+ 'date' => $post->post_date,
+ 'date_gmt' => $post->post_date_gmt,
+ 'modified' => $post->post_modified,
+ 'modified_gmt' => $post->post_modified_gmt,
+ 'slug' => $post->post_name,
+ 'status' => $post->post_status,
+ 'type' => $post->post_type,
+ 'link' => \get_permalink( $post->ID ),
+ 'title' => [
+ 'rendered' => $post->post_title,
+ ],
+ 'content' => [
+ 'rendered' => $post->post_content,
+ ],
+ 'menu_order' => $post->menu_order,
+ 'prpl_priority' => $priority ? $priority : 50,
+ 'prpl_points' => $points ? $points : 1,
+ 'prpl_url' => $url ? $url : '',
+ 'prpl_url_target' => $url_target ? $url_target : '_self',
+ 'prpl_external_link' => $external_link ? $external_link : '',
+ 'prpl_dismissable' => (bool) \get_post_meta( $post->ID, 'prpl_dismissable', true ),
+ 'prpl_link_setting' => $link_setting ? $link_setting : null,
+ 'prpl_provider' => $this->get_post_provider( $post->ID ),
+ ];
+ }
+
+ /**
+ * Get the provider ID for a post.
+ *
+ * @param int $post_id The post ID.
+ * @return string|null The provider ID or null.
+ */
+ private function get_post_provider( $post_id ) {
+ $terms = \wp_get_post_terms( $post_id, 'prpl_recommendations_provider' );
+ if ( ! empty( $terms ) && ! \is_wp_error( $terms ) ) {
+ return $terms[0]->name;
+ }
+ return null;
+ }
+
+ /**
+ * Create a single task (internal helper).
+ *
+ * @param array $task_details The task details.
+ * @return array|\WP_Error Result array with task data or WP_Error.
+ */
+ private function create_single_task( $task_details ) {
+ // Check if task already exists.
+ $existing_task = \progress_planner()->get_suggested_tasks_db()->get_post( $task_details['task_id'] );
+ if ( $existing_task ) {
+ // Task already exists, return full task data.
+ $task_data = $this->get_full_task_data( $existing_task->ID );
+ return [
+ 'success' => true,
+ 'post_id' => $existing_task->ID,
+ 'task' => $task_data,
+ 'message' => \esc_html__( 'Task already exists.', 'progress-planner' ),
+ ];
+ }
+
+ // Prepare data for task creation.
+ $task_data = [
+ 'task_id' => $task_details['task_id'],
+ 'provider_id' => $task_details['provider_id'],
+ 'post_title' => $task_details['post_title'],
+ 'description' => $task_details['description'] ?? '',
+ 'priority' => $task_details['priority'] ?? 50,
+ 'points' => $task_details['points'] ?? 1,
+ 'parent' => $task_details['parent'] ?? 0,
+ 'order' => $task_details['order'] ?? ( $task_details['priority'] ?? 50 ),
+ 'url' => $task_details['url'] ?? '',
+ 'url_target' => $task_details['url_target'] ?? '_self',
+ 'external_link_url' => $task_details['external_link_url'] ?? '',
+ 'dismissable' => $task_details['dismissable'] ?? false,
+ 'post_status' => 'publish',
+ ];
+
+ // Add link_setting if provided.
+ if ( isset( $task_details['link_setting'] ) && \is_array( $task_details['link_setting'] ) ) {
+ $task_data['link_setting'] = $task_details['link_setting'];
+ }
+
+ // Create the task post.
+ $post_id = \progress_planner()->get_suggested_tasks_db()->add( $task_data );
+
+ if ( ! $post_id ) {
+ return new \WP_Error(
+ 'rest_task_creation_failed',
+ \esc_html__( 'Failed to create task.', 'progress-planner' ),
+ [ 'status' => 500 ]
+ );
+ }
+
+ // Build response directly from task data (avoids expensive internal REST call).
+ $full_task_data = $this->build_task_response( $post_id, $task_data );
+
+ return [
+ 'success' => true,
+ 'post_id' => $post_id,
+ 'task' => $full_task_data,
+ 'message' => \esc_html__( 'Task created successfully.', 'progress-planner' ),
+ ];
+ }
+
+ /**
+ * Get full task data via REST API internal request.
+ * Used for existing tasks where we don't have the original data.
+ *
+ * @param int $post_id The post ID.
+ * @return array|null The task data or null on error.
+ */
+ private function get_full_task_data( $post_id ) {
+ $request = new \WP_REST_Request( 'GET', '/wp/v2/prpl_recommendations/' . $post_id );
+ $request->set_param( '_embed', true );
+ $response = \rest_do_request( $request );
+
+ if ( $response->is_error() ) {
+ return null;
+ }
+
+ return $response->get_data();
+ }
+
+ /**
+ * Build task response directly from task data (avoids internal REST call).
+ *
+ * @param int $post_id The post ID.
+ * @param array $task_data The task data used to create the post.
+ * @return array The task response data.
+ */
+ private function build_task_response( $post_id, $task_data ) {
+ $post = \get_post( $post_id );
+ if ( ! $post ) {
+ return null;
+ }
+
+ // Build response matching REST API format.
+ return [
+ 'id' => $post_id,
+ 'date' => $post->post_date,
+ 'date_gmt' => $post->post_date_gmt,
+ 'modified' => $post->post_modified,
+ 'modified_gmt' => $post->post_modified_gmt,
+ 'slug' => $post->post_name,
+ 'status' => $post->post_status,
+ 'type' => $post->post_type,
+ 'link' => \get_permalink( $post_id ),
+ 'title' => [
+ 'rendered' => $task_data['post_title'],
+ ],
+ 'content' => [
+ 'rendered' => $task_data['description'] ?? '',
+ ],
+ 'menu_order' => $post->menu_order,
+ 'prpl_priority' => $task_data['priority'] ?? 50,
+ 'prpl_points' => $task_data['points'] ?? 1,
+ 'prpl_url' => $task_data['url'] ?? '',
+ 'prpl_url_target' => $task_data['url_target'] ?? '_self',
+ 'prpl_external_link' => $task_data['external_link_url'] ?? '',
+ 'prpl_dismissable' => $task_data['dismissable'] ?? false,
+ 'prpl_link_setting' => $task_data['link_setting'] ?? null,
+ 'prpl_provider' => $task_data['provider_id'],
+ ];
+ }
+}
diff --git a/classes/rest/class-timezone-options.php b/classes/rest/class-timezone-options.php
new file mode 100644
index 0000000000..15e6b9fc44
--- /dev/null
+++ b/classes/rest/class-timezone-options.php
@@ -0,0 +1,123 @@
+ 'GET',
+ 'callback' => [ $this, 'get_timezone_options' ],
+ 'permission_callback' => [ $this, 'check_permissions' ],
+ ],
+ ]
+ );
+ }
+
+ /**
+ * Check if the current user has permission to access this endpoint.
+ *
+ * @return bool
+ */
+ public function check_permissions() {
+ return \current_user_can( 'manage_options' );
+ }
+
+ /**
+ * Get timezone options.
+ *
+ * @return \WP_REST_Response
+ */
+ public function get_timezone_options() {
+ $options = $this->build_timezone_options();
+
+ return new \WP_REST_Response( $options, 200 );
+ }
+
+ /**
+ * Build timezone options array.
+ *
+ * Uses WordPress's wp_timezone_choice() function and extracts options from the HTML.
+ * This ensures we stay in sync with WordPress core behavior.
+ *
+ * @return array Array of timezone option objects with 'value' and 'label' properties.
+ */
+ private function build_timezone_options() {
+ // Get HTML output from WordPress core function.
+ $html = \wp_timezone_choice( '', \get_user_locale() );
+
+ // Parse HTML to extract option elements.
+ $options = $this->parse_timezone_html( $html );
+
+ return $options;
+ }
+
+ /**
+ * Parse HTML from wp_timezone_choice() to extract timezone options.
+ *
+ * Uses WP_HTML_Tag_Processor to find option tags and extract both value attributes
+ * and text content using next_token() and get_modifiable_text().
+ *
+ * @param string $html The HTML output from wp_timezone_choice().
+ * @return array Array of timezone option objects with 'value' and 'label' properties.
+ */
+ private function parse_timezone_html( $html ) {
+ $options = [];
+
+ // Use WP_HTML_Tag_Processor to find option tags and extract data.
+ $processor = new \WP_HTML_Tag_Processor( $html );
+ while ( $processor->next_tag( 'option' ) ) {
+ $value = $processor->get_attribute( 'value' );
+
+ // Extract text content by moving through tokens after the opening tag.
+ // Collect all text nodes until we hit the closing tag.
+ $label = '';
+ while ( $processor->next_token() ) {
+ $token_name = $processor->get_token_name();
+
+ // If we hit the closing option tag, we're done collecting text.
+ if ( 'OPTION' === $token_name && $processor->is_tag_closer() ) {
+ break;
+ }
+
+ // Collect text from text nodes (decoded automatically by get_modifiable_text).
+ if ( '#text' === $token_name ) {
+ $label .= $processor->get_modifiable_text();
+ }
+ }
+
+ $label = \trim( $label );
+
+ // Skip empty options (like the "Select a city" placeholder).
+ if ( ( null === $value || '' === $value ) && '' === $label ) {
+ continue;
+ }
+
+ $options[] = [
+ 'value' => $value ?? '',
+ 'label' => $label,
+ ];
+ }
+
+ return $options;
+ }
+}
diff --git a/classes/rest/class-updates.php b/classes/rest/class-updates.php
new file mode 100644
index 0000000000..a9ecba2318
--- /dev/null
+++ b/classes/rest/class-updates.php
@@ -0,0 +1,137 @@
+ 'GET',
+ 'callback' => [ $this, 'get_updates' ],
+ 'permission_callback' => [ $this, 'permission_callback' ],
+ ]
+ );
+ }
+
+ /**
+ * Get update data.
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ * @return \WP_REST_Response|\WP_Error The REST response object or error.
+ */
+ public function get_updates( $request ) {
+ // Ensure update functions are loaded.
+ if ( ! \function_exists( 'get_core_updates' ) ) {
+ // @phpstan-ignore-next-line requireOnce.fileNotFound
+ require_once ABSPATH . 'wp-admin/includes/update.php';
+ }
+
+ // Get update data.
+ $update_data = \wp_get_update_data();
+
+ // Format response.
+ $response = [
+ 'core' => [],
+ 'plugins' => [],
+ 'themes' => [],
+ 'counts' => [
+ 'total' => $update_data['counts']['total'] ?? 0,
+ 'core' => $update_data['counts']['core'] ?? 0,
+ 'plugins' => $update_data['counts']['plugins'] ?? 0,
+ 'themes' => $update_data['counts']['themes'] ?? 0,
+ 'translations' => $update_data['counts']['translations'] ?? 0,
+ ],
+ ];
+
+ // Get core updates.
+ $core_updates = \get_core_updates();
+ if ( \is_array( $core_updates ) && ! empty( $core_updates ) ) {
+ $response['core'] = \array_map(
+ function ( $update ) {
+ return [
+ 'version' => $update->version ?? '',
+ 'current' => $update->current ?? '',
+ 'download' => $update->download ?? '',
+ 'locale' => $update->locale ?? '',
+ 'packages' => $update->packages ?? [],
+ 'response' => $update->response ?? '',
+ 'php_version' => $update->php_version ?? '',
+ ];
+ },
+ \array_filter( $core_updates, 'is_object' )
+ );
+ }
+
+ // Get plugin updates.
+ $plugin_updates = \get_plugin_updates();
+ if ( $plugin_updates ) {
+ $response['plugins'] = \array_map(
+ function ( $file, $data ) {
+ $update = isset( $data->update ) && \is_object( $data->update ) ? $data->update : null;
+ return [
+ 'file' => $file,
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
+ 'name' => $data->Name ?? '',
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
+ 'version' => $data->Version ?? '',
+ 'new_version' => $update->new_version ?? '',
+ 'url' => $update->url ?? '',
+ 'package' => $update->package ?? '',
+ ];
+ },
+ \array_keys( $plugin_updates ),
+ $plugin_updates
+ );
+ }
+
+ // Get theme updates.
+ $theme_updates = \get_theme_updates();
+ if ( $theme_updates ) {
+ $response['themes'] = \array_map(
+ function ( $stylesheet, $data ) {
+ return [
+ 'stylesheet' => $stylesheet,
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
+ 'name' => $data->Name ?? '',
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
+ 'version' => $data->Version ?? '',
+ 'new_version' => $data->update['new_version'] ?? '',
+ 'url' => $data->update['url'] ?? '',
+ 'package' => $data->update['package'] ?? '',
+ ];
+ },
+ \array_keys( $theme_updates ),
+ $theme_updates
+ );
+ }
+
+ return new \WP_REST_Response( $response, 200 );
+ }
+
+ /**
+ * Permission callback for updates endpoint.
+ *
+ * @return bool
+ */
+ public function permission_callback() {
+ return \current_user_can( 'update_core' );
+ }
+}
diff --git a/classes/rest/class-upgrade-tasks-config.php b/classes/rest/class-upgrade-tasks-config.php
new file mode 100644
index 0000000000..2120e4b117
--- /dev/null
+++ b/classes/rest/class-upgrade-tasks-config.php
@@ -0,0 +1,102 @@
+ 'GET',
+ 'callback' => [ $this, 'get_config' ],
+ 'permission_callback' => [ $this, 'check_permissions' ],
+ ],
+ ]
+ );
+ }
+
+ /**
+ * Check if the current user has permission to access this endpoint.
+ *
+ * @return bool
+ */
+ public function check_permissions() {
+ return \current_user_can( 'manage_options' );
+ }
+
+ /**
+ * Get upgrade tasks configuration.
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ *
+ * @return \WP_REST_Response
+ */
+ public function get_config( $request ) {
+ $plugin_upgrade_tasks = \progress_planner()->get_plugin_upgrade_tasks();
+ $task_providers = $plugin_upgrade_tasks->get_newly_added_task_providers();
+
+ // Build task providers data for React.
+ $task_providers_data = [];
+ foreach ( $task_providers as $task_provider ) {
+ $task_data = [
+ 'task_id' => $task_provider->get_task_id(),
+ 'provider_id' => $task_provider->get_provider_id(),
+ ];
+
+ // Get task details.
+ $task = \progress_planner()->get_suggested_tasks_db()->get_post( $task_data['task_id'] );
+
+ // If task doesn't exist, add it.
+ if ( ! $task ) {
+ $task_post_id = \progress_planner()->get_suggested_tasks_db()->add( $task_provider->get_task_details( $task_data ) );
+ if ( $task_post_id ) {
+ $task = \progress_planner()->get_suggested_tasks_db()->get_post( $task_post_id );
+ }
+ }
+
+ if ( $task ) {
+ $task_completed = $task_provider->evaluate_task( $task_data['task_id'] );
+
+ $task_providers_data[] = [
+ 'task_id' => $task_data['task_id'],
+ 'title' => $task->post_title,
+ 'points' => $task->points ?? 0,
+ 'completed' => $task_completed,
+ ];
+ }
+ }
+
+ // Generate monthly badge ID.
+ $now = new \DateTime();
+ $badge_id = 'monthly-' . $now->format( 'Y' ) . '-m' . $now->format( 'n' );
+
+ return new \WP_REST_Response(
+ [
+ 'taskProviders' => $task_providers_data,
+ 'brandingId' => (int) \progress_planner()->get_ui__branding()->get_branding_id(),
+ 'remoteServerUrl' => \progress_planner()->get_remote_server_root_url(),
+ 'placeholderSvg' => \progress_planner()->get_placeholder_svg(),
+ 'badgeId' => $badge_id,
+ ],
+ 200
+ );
+ }
+}
diff --git a/classes/rest/class-wizard-config.php b/classes/rest/class-wizard-config.php
new file mode 100644
index 0000000000..11d3d71be8
--- /dev/null
+++ b/classes/rest/class-wizard-config.php
@@ -0,0 +1,180 @@
+ 'GET',
+ 'callback' => [ $this, 'get_wizard_config' ],
+ 'permission_callback' => [ $this, 'check_permissions' ],
+ ],
+ ]
+ );
+ }
+
+ /**
+ * Check if the current user has permission to access this endpoint.
+ *
+ * @return bool
+ */
+ public function check_permissions() {
+ return \current_user_can( 'manage_options' );
+ }
+
+ /**
+ * Get wizard configuration.
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ * @return \WP_REST_Response|\WP_Error
+ */
+ public function get_wizard_config( $request ) {
+ $wizard = \progress_planner()->get_onboard_wizard();
+
+ // Get saved progress from user meta.
+ $saved_progress = $wizard->get_saved_progress();
+
+ // Force re-calculation of steps.
+ // Tasks may have been created by React just before this request,
+ // so we need fresh data instead of cached steps from the init hook.
+ $wizard->define_steps_and_order();
+
+ // Get steps using public method.
+ $steps = $wizard->get_steps();
+
+ // Format steps for React.
+ $steps_formatted = [];
+ foreach ( $steps as $index => $step ) {
+ $steps_formatted[] = [
+ 'id' => $step['template_id'],
+ 'title' => \html_entity_decode( $step['title'], ENT_QUOTES, 'UTF-8' ),
+ 'data' => isset( $step['template_data'] ) ? $step['template_data'] : [],
+ ];
+ }
+
+ // Get pages for settings step.
+ $pages = \get_pages(
+ [
+ 'sort_column' => 'post_title',
+ 'sort_order' => 'ASC',
+ ]
+ );
+ $pages_formatted = [];
+ foreach ( $pages as $page ) {
+ $pages_formatted[] = [
+ 'id' => $page->ID,
+ 'title' => $page->post_title,
+ ];
+ }
+
+ // Page type descriptions for SettingsStep.
+ // Use __() instead of esc_html__() to avoid HTML entity encoding in JSON.
+ $page_types = [
+ 'homepage' => [
+ 'id' => 'homepage',
+ 'title' => \__( 'Home page', 'progress-planner' ),
+ 'description' => \__( 'Help us understand your site a little better so we can give you more useful recommendations. Let\'s start with the home page.', 'progress-planner' ),
+ 'note' => \__( 'A Home page is important. We\'ll remind you to make one at a later time.', 'progress-planner' ),
+ ],
+ 'about' => [
+ 'id' => 'about',
+ 'title' => \__( 'About page', 'progress-planner' ),
+ 'description' => \__( 'Next up, pick the page you use as your about page.', 'progress-planner' ),
+ 'note' => \__( 'An About page is important. We\'ll remind you to make one at a later time.', 'progress-planner' ),
+ ],
+ 'contact' => [
+ 'id' => 'contact',
+ 'title' => \__( 'Contact page', 'progress-planner' ),
+ 'description' => \__( 'Now choose the page you use as your contact page.', 'progress-planner' ),
+ 'note' => \__( 'A Contact page is important. We\'ll remind you to make one at a later time.', 'progress-planner' ),
+ ],
+ 'faq' => [
+ 'id' => 'faq',
+ 'title' => \__( 'FAQ page', 'progress-planner' ),
+ 'description' => \__( 'Next, pick the page you use as your FAQ page.', 'progress-planner' ),
+ 'note' => \__( 'An FAQ page is important. We\'ll remind you to make one at a later time.', 'progress-planner' ),
+ ],
+ ];
+
+ // Get post types for settings step.
+ $post_types = \progress_planner()->get_settings()->get_public_post_types();
+ $post_types_formatted = [];
+ foreach ( $post_types as $post_type ) {
+ $post_type_obj = \get_post_type_object( $post_type );
+ if ( $post_type_obj ) {
+ $post_types_formatted[] = [
+ 'id' => $post_type,
+ 'title' => $post_type_obj->labels->name,
+ ];
+ }
+ }
+
+ // Check skip_onboarding flag.
+ $is_branded = 0 !== (int) \progress_planner()->get_ui__branding()->get_branding_id();
+ $skip_onboarding = \progress_planner()->is_privacy_policy_accepted()
+ && ! \get_option( 'prpl_onboard_progress', false )
+ && ! $is_branded;
+ $skip_onboarding = \apply_filters( 'progress_planner_skip_onboarding', $skip_onboarding );
+
+ // Capture logo HTML.
+ \ob_start();
+ \progress_planner()->get_ui__branding()->the_logo();
+ $logo_html = \ob_get_clean();
+
+ // Get current user data for email frequency step.
+ $current_user = \wp_get_current_user();
+
+ $config = [
+ 'enabled' => ! $skip_onboarding,
+ 'steps' => $steps_formatted,
+ 'savedProgress' => $saved_progress,
+ 'ajaxUrl' => \admin_url( 'admin-ajax.php' ),
+ 'nonce' => \wp_create_nonce( 'progress_planner' ),
+ 'nonceWPAPI' => \wp_create_nonce( 'wp_rest' ),
+ 'userFirstName' => $current_user->first_name ? $current_user->first_name : $current_user->display_name,
+ 'userEmail' => $current_user->user_email,
+ 'onboardAPIUrl' => \progress_planner()->get_utils__onboard()->get_remote_url( 'onboard' ),
+ 'onboardNonceURL' => \progress_planner()->get_utils__onboard()->get_remote_url( 'get-nonce' ),
+ 'site' => \esc_attr( \set_url_scheme( \site_url() ) ),
+ 'timezoneOffset' => (float) ( \wp_timezone()->getOffset( new \DateTime( 'midnight' ) ) / 3600 ),
+ 'lastStepRedirectUrl' => \esc_url_raw( \admin_url( 'admin.php?page=progress-planner' ) ),
+ 'hasLicense' => false !== \progress_planner()->get_license_key(),
+ 'pages' => $pages_formatted,
+ 'postTypes' => $post_types_formatted,
+ 'pageTypes' => $page_types,
+ 'logoHtml' => $logo_html,
+ 'baseUrl' => \constant( 'PROGRESS_PLANNER_URL' ),
+ 'privacyPolicyUrl' => \progress_planner()->get_ui__branding()->get_url( 'https://progressplanner.com/privacy-policy/#h-plugin-privacy-policy' ),
+ 'l10n' => [
+ 'next' => \esc_html__( 'Next', 'progress-planner' ),
+ 'startOnboarding' => \esc_html__( 'Start onboarding', 'progress-planner' ),
+ /* translators: %s: Progress Planner name. */
+ 'privacyPolicyError' => \sprintf( \esc_html__( 'You need to agree with the privacy policy to use the %s plugin.', 'progress-planner' ), \esc_html( \progress_planner()->get_ui__branding()->get_admin_menu_name() ) ),
+ 'dashboard' => \esc_html__( 'Take me to the dashboard', 'progress-planner' ),
+ 'backToRecommendations' => \esc_html__( 'Back to recommendations', 'progress-planner' ),
+ ],
+ ];
+
+ return new \WP_REST_Response( $config, 200 );
+ }
+}
diff --git a/classes/admin/widgets/class-activity-scores.php b/classes/rest/widgets/class-activity-scores.php
similarity index 57%
rename from classes/admin/widgets/class-activity-scores.php
rename to classes/rest/widgets/class-activity-scores.php
index 8adcde6448..bc1ced8ad6 100644
--- a/classes/admin/widgets/class-activity-scores.php
+++ b/classes/rest/widgets/class-activity-scores.php
@@ -1,66 +1,123 @@
'GET',
+ 'callback' => [ $this, 'get_activity_scores' ],
+ 'permission_callback' => [ $this, 'check_permissions' ],
+ 'args' => [
+ 'range' => [
+ 'type' => 'string',
+ 'default' => '-6 months',
+ 'sanitize_callback' => 'sanitize_text_field',
+ ],
+ 'frequency' => [
+ 'type' => 'string',
+ 'default' => 'monthly',
+ 'sanitize_callback' => 'sanitize_text_field',
+ ],
+ ],
+ ],
+ ]
+ );
+ }
/**
- * The color callback.
+ * Check if the current user has permission to access this endpoint.
*
- * @param int $number The number to calculate the color for.
- * @param \DateTime $date The date.
+ * @return bool
+ */
+ public function check_permissions() {
+ return \current_user_can( 'edit_posts' );
+ }
+
+ /**
+ * Get activity scores data.
+ *
+ * @param \WP_REST_Request $request The REST request object.
*
- * @return string The color.
+ * @return \WP_REST_Response
*/
- public function get_color( $number, $date ) {
- // If monthly and the latest month, return gray (in progress).
- if (
- 'monthly' === $this->get_frequency() &&
- \gmdate( 'Y-m-01' ) === $date->format( 'Y-m-01' )
- ) {
- return 'var(--prpl-color-border)';
- }
+ public function get_activity_scores( $request ) {
+ $range = $request->get_param( 'range' ) ?? '-6 months';
+ $frequency = $request->get_param( 'frequency' ) ?? 'monthly';
- // If weekly and the current week, return gray (in progress).
- if (
- 'weekly' === $this->get_frequency() &&
- \gmdate( 'Y-W' ) === $date->format( 'Y-W' )
- ) {
- return 'var(--prpl-color-border)';
- }
+ $score = $this->get_score();
+ $record = $this->personal_record_callback();
+ $checklist = $this->get_checklist_results();
- if ( $number > 90 ) {
- return 'var(--prpl-graph-color-3)';
- }
- if ( $number > 30 ) {
- return 'var(--prpl-color-monthly)';
- }
- return 'var(--prpl-graph-color-1)';
+ // Get chart data.
+ $chart = \progress_planner()->get_ui__chart();
+ $start_date = \DateTime::createFromFormat( 'Y-m-d', \gmdate( 'Y-m-01' ) )->modify( $range );
+ $end_date = new \DateTime();
+
+ $chart_data = $chart->get_chart_data(
+ [
+ 'type' => 'bar',
+ 'items_callback' => fn( $start_date, $end_date ) => \progress_planner()->get_activities__query()->query_activities(
+ [
+ 'start_date' => $start_date,
+ 'end_date' => $end_date,
+ ]
+ ),
+ 'dates_params' => [
+ 'start_date' => $start_date,
+ 'end_date' => $end_date,
+ 'frequency' => $frequency,
+ 'format' => 'M',
+ ],
+ 'count_callback' => fn( $activities, $date ) => \array_sum( \array_map( fn( $activity ) => $activity->get_points( $date ), $activities ) ) * 100 / Plugin_Base::SCORE_TARGET,
+ 'normalized' => true,
+ 'max' => 100,
+ 'return_data' => [ 'label', 'score' ], // Don't return color - that's presentation logic.
+ ]
+ );
+
+ // Build response data.
+ $response_data = [
+ 'score' => $score,
+ 'chartData' => $chart_data,
+ 'personalRecord' => [
+ 'maxStreak' => (int) $record['max_streak'],
+ 'currentStreak' => (int) $record['current_streak'],
+ ],
+ 'checklist' => $checklist,
+ ];
+
+ return new \WP_REST_Response( $response_data );
}
/**
@@ -68,7 +125,7 @@ public function get_color( $number, $date ) {
*
* @return int The score.
*/
- public function get_score() {
+ private function get_score() {
$activities = \progress_planner()->get_activities__query()->query_activities(
// Use 31 days to take into account the activities score decay from previous activities.
[ 'start_date' => new \DateTime( '-31 days' ) ]
@@ -94,7 +151,7 @@ public function get_score() {
*
* @return array The checklist results.
*/
- public function get_checklist_results() {
+ private function get_checklist_results() {
$items = $this->get_checklist();
$results = [];
foreach ( $items as $item ) {
@@ -109,7 +166,7 @@ public function get_checklist_results() {
*
* @return array The checklist items.
*/
- public function get_checklist() {
+ private function get_checklist() {
return [
[
'label' => \esc_html__( 'published content', 'progress-planner' ),
@@ -144,29 +201,12 @@ public function get_checklist() {
];
}
- /**
- * Get the gauge color.
- *
- * @param int $score The score.
- *
- * @return string The color.
- */
- public function get_gauge_color( $score ) {
- if ( $score >= 75 ) {
- return 'var(--prpl-graph-color-3)';
- }
- if ( $score >= 50 ) {
- return 'var(--prpl-color-monthly)';
- }
- return 'var(--prpl-graph-color-1)';
- }
-
/**
* Get the personal record goal.
*
* @return array
*/
- public function personal_record_callback() {
+ private function personal_record_callback() {
$goal = Goal_Recurring::get_instance(
'weekly_post_record',
[
@@ -178,7 +218,7 @@ public function personal_record_callback() {
'priority' => 'low',
'evaluate' => function ( $goal_object ) {
// Get the cached activities.
- $cached_activities = \progress_planner()->get_settings()->get( $this->cache_key, [] );
+ $cached_activities = \progress_planner()->get_settings()->get( self::CACHE_KEY, [] );
// Get the weekly cache key.
$weekly_cache_key = $goal_object->get_details()['start_date']->format( 'Y-m-d' ) . '_' . $goal_object->get_details()['end_date']->format( 'Y-m-d' );
@@ -200,7 +240,7 @@ public function personal_record_callback() {
// Cache the activities.
$cached_activities[ $weekly_cache_key ] = (bool) \count( $activities );
- \progress_planner()->get_settings()->set( $this->cache_key, $cached_activities );
+ \progress_planner()->get_settings()->set( self::CACHE_KEY, $cached_activities );
// Return the cached value.
return $cached_activities[ $weekly_cache_key ];
@@ -216,13 +256,4 @@ public function personal_record_callback() {
return $goal->get_streak();
}
-
- /**
- * Get the cache key.
- *
- * @return string The cache key.
- */
- public function get_cache_key() {
- return $this->cache_key;
- }
}
diff --git a/classes/rest/widgets/class-content-activity.php b/classes/rest/widgets/class-content-activity.php
new file mode 100644
index 0000000000..e84b3b7ad1
--- /dev/null
+++ b/classes/rest/widgets/class-content-activity.php
@@ -0,0 +1,238 @@
+ 'GET',
+ 'callback' => [ $this, 'get_content_activity' ],
+ 'permission_callback' => [ $this, 'check_permissions' ],
+ 'args' => [
+ 'range' => [
+ 'type' => 'string',
+ 'default' => '-6 months',
+ 'sanitize_callback' => 'sanitize_text_field',
+ ],
+ 'frequency' => [
+ 'type' => 'string',
+ 'default' => 'monthly',
+ 'sanitize_callback' => 'sanitize_text_field',
+ ],
+ ],
+ ],
+ ]
+ );
+ }
+
+ /**
+ * Check if the current user has permission to access this endpoint.
+ *
+ * @return bool
+ */
+ public function check_permissions() {
+ return \current_user_can( 'edit_posts' );
+ }
+
+ /**
+ * Get content activity data.
+ *
+ * @param \WP_REST_Request $request The REST request object.
+ *
+ * @return \WP_REST_Response
+ */
+ public function get_content_activity( $request ) {
+ $range = $request->get_param( 'range' ) ?? '-6 months';
+ $frequency = $request->get_param( 'frequency' ) ?? 'monthly';
+
+ // Activity types configuration.
+ $activity_types = [
+ 'publish' => [
+ 'label' => \__( 'published', 'progress-planner' ),
+ 'color' => 'var(--prpl-color-monthly)',
+ ],
+ 'update' => [
+ 'label' => \__( 'updated', 'progress-planner' ),
+ 'color' => 'var(--prpl-graph-color-3)',
+ ],
+ 'delete' => [
+ 'label' => \__( 'deleted', 'progress-planner' ),
+ 'color' => 'var(--prpl-color-headings)',
+ ],
+ ];
+
+ $tracked_post_types = \progress_planner()->get_activities__content_helpers()->get_post_types_names();
+
+ // Prepare chart data and options.
+ $chart_data = [];
+ $chart_options = [
+ 'dataArgs' => [],
+ 'chartId' => 'prpl-chart-content-activity',
+ 'axisColor' => 'var(--prpl-color-border)',
+ 'rulersColor' => 'var(--prpl-color-border)',
+ 'filtersLabel' => '