It's obvious :-)
Here are different phases of the parser involved.
The first important phase is here the special character phase, a caret escapes the next characters, important for ^|&<> characters.
The line will be reduced from
echo|set /P=!foo! ^^^^^| !bar!
to
echo|set /P=!foo! ^^| !bar!
As one caret escapes the next, and the last caret escapes the pipe.
The next important phase here is the delayed expansion phase, this phase only occours when at least one ! is in the line.
In this phase carets escapes also the next character, but here it's only necessary for the caret itself and the !, and in this phase the delayed variables are expanded.
From
echo|set /P=!foo! ^^| !bar!
to
echo|set /P=Hello world ^| Why why
As you use a pipe here, both sides of the pipe will be transfered to a new cmd.exe process and there the commands will be parsed again.
cmd.exe /c "echo" and cmd /c "set /P=Hello world ^| Why why
Only set /P=Hello world ^| Why why is relavant now.
Again in the special character phase the one caret escapes the pipe character to
set /P=Hello world | Why why
The delayed expansion phase will not occour, first as delayed expansion is disabled in the new cmd.exe (by default) and second as there aren't any ! in the line.
That's all!
Btw.
Spawning two processes here is not necessary, a redirection is simpler and faster
<nul set /P=!foo! ^^^| !bar!
Without delayed expansion, you only need one caret
<nul set /P=FOO ^| BAR
Or look at the difference of
setlocal EnableDelayedExpansion
echo "carets ^^^"
echo "carets ^^^" !