7

Title sounds counter-intuitive but bear with me. :)

I have options page, made with Settings API. When user enters invalid data I want to display error notice with add_settings_error() call.

But! To determine that data is invalid I need to make an remote API call. That call relies on saved data. So I can't do this in sanitization callback (which is recommended place to throw such notices) because my data is not saved yet.

Instead I had tried to hooking my check into admin_notices. It works fine most of the time except one (and most important) case - when settings are saved they are always followed by native Settings saved. notice and my custom notices are completely ignored for some reason.

So how do I throw that error notice even if WP thinks everything is fine?

Edit

More focused question - why exactly Settings saved. trumps any other notices?

PS I could try to make API call optionally take data as argument instead of reading it from saved option, but so far I think it will make arguments overly bulky.

2 Answers 2

4

Ok, I think I have an idea what is going on.

  1. The list of notices to display is retrieved by get_settings_errors() ( source ).

  2. This function reads notices from global $wp_settings_errors unless there is settings_errors transient set, which trumps global var.

  3. When settings are saved there is check for no setting errors and if so Settings saved. notice is generated. After that (in either case) errors are saved into settings_errors transient (I assume to preserve them on redirect) ( source ) .

Basically no matter what notices you generate in your code - they will be ignored when transient is set and it is always going to be set after saving settings.

As for me it would make sense to concatenate transient with global variable rather than making it exclusive or choice.

And I guess to display custom notices when transient is set I will need to mess with that transient, which is probably not worth the trouble.

5
  • Wow...i overlooked the exclusive treatment of the transient ones...yes, totally, you'd expect them to be combined, which is why i missed what you spotted. ;-) Anyways, messing with the transients should be fairly save and simple, you just read the transient store with get_settings_errors(), at that point the transient store is cleared, then you restore them with add_settings_error() one by one and add your new one. Now the transient store is cleared and you have all of them in the page-local store, so the next run of settings_errors() will catch them. What do you think?
    – wyrfel
    Commented Feb 21, 2011 at 19:27
  • Ahh that was a bit confused...i guess in your case you'll need to filter the saved message form the results of your get_settings_errors() call, or keep it in there if everything's fine on your second check.
    – wyrfel
    Commented Feb 21, 2011 at 19:32
  • @wyrfel in the end I decided that changing mechanics of Settings API and those notices is neither purpose or scope of plugin, so implemented my API check in sanitization callback (turned out easy to adjust to optionally passed API key rather than saved).
    – Rarst
    Commented Feb 23, 2011 at 12:31
  • sounds sensible, but less fun. ;-)
    – wyrfel
    Commented Feb 23, 2011 at 14:08
  • @wyrfel I'll save that kind of fun for when I code for myself :)
    – Rarst
    Commented Feb 23, 2011 at 20:05
0

One thing you could do, i guess:

  • in your validation callback, read the current settings (you may do so anyways?) and store them in a variable
  • check all other values first
  • if they aren't valid, return errors, don't check the critical value
  • if they are, store them in the db (within your validation function)
  • do your remote API call
  • validate the tricky value
  • if valid, return the whole bunch and all good
  • if not, store the old settings you got at the beginning back to the db, do your error output via add_settings_error() Of course that somewhat defeats/abuses the Settings API, but it could be a way.

Edit: The Settings Saved message doesn't trump your other notices, it rather only shows up because your other notices have already been wiped (for some reason) from the internal settings_error store. Why that's the case i don't know, but the Settings Saved message simply gets added to the error store if and only if it's empty. What could contribute to your dilemma is that whenever the settings error store gets read (via get_settings_errors()) it also gets wiped.

4
  • Thought about doing it this way. Working approach, but also very bulky (and I agree that it seems to defeat Settings API here). I added a somewhat rephrased question - I am currently more interested not in how to make it work, but why doesn't it work my way (with separate admin notices)?
    – Rarst
    Commented Feb 21, 2011 at 18:25
  • Can you post the add_settings_error() related lines of code and those doing the hooking, please?
    – wyrfel
    Commented Feb 21, 2011 at 19:07
  • I think I figured it out (see answer I just posted), but could use second opinion on it :)
    – Rarst
    Commented Feb 21, 2011 at 19:14
  • @Rarst Did you notice the second opinion?
    – wyrfel
    Commented Feb 22, 2011 at 12:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.