-
Notifications
You must be signed in to change notification settings - Fork 389
[personal-wp] Backup reminder UI #3162
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
de5b08e to
1baf5fd
Compare
73357f6 to
6db275d
Compare
1baf5fd to
9676f6f
Compare
6db275d to
4cff483
Compare
6192b58 to
30ade19
Compare
ccebb0e to
1555eba
Compare
30ade19 to
6ee19d9
Compare
1555eba to
4da5ad5
Compare
6ee19d9 to
c9b2a78
Compare
817712c to
7158776
Compare
packages/playground/personal-wp/src/components/backup-reminder/index.tsx
Outdated
Show resolved
Hide resolved
packages/playground/personal-wp/src/components/backup-reminder/index.tsx
Show resolved
Hide resolved
| const response = await playground.run({ | ||
| code: `<?php | ||
| require_once '/wordpress/wp-load.php'; | ||
| echo html_entity_decode(get_option('blogname', 'WordPress'), ENT_QUOTES, 'UTF-8'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use WordPress HTML API for this? Or decode is in JavaScript? html_entity_decode doesn't do its job well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about using json_encode() in PHP and JSON.parse() in JS? That would fully avoid any HTML entities.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or actually, right now:
get_option()→Alex's WordPresshtml_entity_decode()→Alex's WordPresssanitizeForFilename()→Alex-s-WordPress(apostrophe becomes-)
I just verified that WordPress stores the blogname via
case 'blogdescription':
case 'blogname':
// ...
$value = esc_html( $value );
break;Which itself uses _wp_specialchars which itself uses htmlspecialchars for which html_entity_decode should be appropriate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left some notes, the blocking ones are filename sanitization, HTML decoding of the title, and the import question. The rest I think is ready for merging.
7158776 to
b72b187
Compare
Adds a dropdown to the backup reminder UI that lets users schedule automatic backup downloads on a daily, every-2-days, or weekly basis. When enabled, the toolbar backup indicator is hidden and backups trigger automatically after WordPress boots.
Remove redundant daysUsedSinceLastBackup tracking. The backup indicator now derives days since last backup directly from backupHistory timestamps, which is simpler and more reliable.
| const [showHistory, setShowHistory] = useState(false); | ||
| const importInputRef = useRef<HTMLInputElement>(null); | ||
|
|
||
| // TODO: Support local directory sites. With a directory handle, we could |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice comment
| } from '../../lib/hooks/use-backup-constants'; | ||
| import { isSameDay } from '../../lib/utils/date'; | ||
|
|
||
| function getDaysSinceBackup(lastBackupTimestamp: number | undefined): number { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have some datetime formatting utils we could reuse here. Not a blocker.
|
|
||
| const message = hasBackup | ||
| ? 'Are you sure you want to start over? This will delete all your data and reset WordPress to a fresh install.' | ||
| : 'Are you sure you want to start over? You have never made a backup – all your data will be permanently lost.'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice
| return; | ||
| } | ||
|
|
||
| // Reset trigger flag when switching to a different site |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, you can switch to a different site here? how? or is this just "defense in depth" in case someone finds a button we forgot to hide?
| code: `<?php | ||
| require_once '/wordpress/wp-load.php'; | ||
| $name = get_option('blogname', 'WordPress'); | ||
| echo html_entity_decode($name, ENT_QUOTES, 'UTF-8'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm I can't see my previous comment, I'm pretty sure I've left it here 🤔 html_entity_decode is pretty bad, we'd be better off decoding in JS. I wouldn't say it's a blocker because of how the siteName is used, but changing it might save us some & literals.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot echo $name and decode the entity in JS in a secure way.
| @@ -0,0 +1,31 @@ | |||
| export function getRelativeDate(inputDate: Date): string { | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we could extract this to a shared package and import in both website and personal-wp. Not blocking.
adamziel
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM aside of the html encoding issue. I've asked copilot to adjust it. We can merge regardless.


Based on #3157.
Motivation for the change, related issues
Personal Playgrounds store data in the browser's Origin Private File System (OPFS), which can be cleared unexpectedly by the browser. Users need a gentle reminder to back up their work periodically to avoid data loss.
This PR adds a backup status indicator that tracks usage days since the last backup and prompts users to download backups based on urgency.
Screenshots
(No button when the backup is up to date)
Auto-Backup
Implementation details
New files:
backup-status-indicator.tsx- Component showing days since last backup with color-coded urgency (green ≤1 day, yellow 2-4 days, red 5+ days)backup-status-indicator.module.css- Styles for the indicator buttonuse-backup.ts- Hook that handles backup creation usingzipWpContentandfile-saverModified files:
slice-sites.ts- Added metadata fields:backupHistory- Array of recent backups (filename + timestamp)lastAccessDate- Timestamp for tracking usage daysdaysUsedSinceLastBackup- Counter reset on backuppersistent-browser-chrome/index.tsx- Added BackupStatusIndicator to toolbarBehavior:
Testing Instructions (or ideally a Blueprint)
{site-name}-backup-{date}-{time}.zipdaysUsedSinceLastBackupto 5 - indicator should appear in red