Placing navigation items into an array
Return Early

If you extract the PHP code to a function, you can return early, and thus save a level of nesting:

&lt;ul id="nav"&gt;
&lt;?php printNavigation(); ?&gt;
&lt;/ul&gt;

&lt;?php
function printNavigation() {
    if(!($grabNav = $db-&gt;prepare("SELECT caption,url,visibility,id,class,parent_id FROM navigation ORDER BY parent_id ASC, order_id ASC"))) {
        return;
    }
    [...]
    ?&gt;
}


Remove Duplication and further simplifications

Currently, your visibility check and your one long echo line are duplicates. You can extract these to functions:

function isVisible($visibilityLevel, $cUser) {
    switch($visibilityLevel, $cUser)
    {
        case 0: return false;
        case 1: return true;
        case 2: return LOGGED_IN &amp;&amp; isset($cUser);
        case 3: return !LOGGED_IN || !isset($cUser);
        default: throw new Exception('invalid visibility level.');
    }
}


And then use it as 

    foreach($grabNav as $nav)
    {
        if(!isVisible($nav['visibility'], $cUser) || $nav['parent_id'] != -1) { continue; }
        [...]


Note also that I removed the useless default from the beginning of the switch, added it again at the end, and threw an exception for invalid values.

I also simplified cases 2 and 3 (if (cond) true else false can be phrased as cond), and I combined the two continue conditions.