Playwright versus WordPress's "admin email confirmation" screen — how automation can clear the 6-month gate
If you drive the WordPress admin via Playwright for long enough, one day a screen you've never seen before will appear after login , and everything downstream stops working. Is admin@example.com still the correct admin email address? [ Yes, the email is correct ] [ Change the address ] That's WordPress's admin email confirmation screen . Roughly every six months, after the admin user logs in, this confirmation screen gets injected — standard behavior since WP 4.9. A human just clicks once. An automation script can't see it without explicit handling. Why automation gets stuck A straightforward Playwright login looks like: page . fill ( ' #user_login ' , user ) page . fill ( ' #user_pass ' , pwd ) page . click ( ' input[type= " submit " ] ' ) page . wait_for_load_state ( ' domcontentloaded ' ) # Assumes we're on the dashboard page . goto ( ' /wp-admin/plugins.php ' ) But on a "confirmation day," the URL right after wait_for_load_state is something like /wp-admin/profile.php?...action=confirm_admin_email... — the confirmation screen. You thought you were navigating to the plugins page, but the DOM you expected isn't there. Subsequent selectors fail, and everything downstream cascades into failure. A specific selector identifies the screen WordPress's confirmation screen has a uniquely-named submit button: <input type= "submit" name= "correct-admin-email" value= "Yes, the email is correct" /> If input[name="correct-admin-email"] exists on the page, you're on the confirmation screen. The same selector serves as both the detection signal and the click target , so handling is only a few lines: admin_email_confirm = page . locator ( ' input[type= " submit " ][name= " correct-admin-email " ] ' ) if admin_email_confirm . count () > 0 : logger . info ( " Confirmation screen detected — clicking ' email is correct '" ) admin_email_confirm . first . click () page . wait_for_load_state ( ' domcontentloaded ' , timeout = 30000 ) Insert this after the post-login wait_for_load_state