Правильно, только в json_decode второй параметр tr

Правильно, только в json_decode второй параметр true надо добавить, чтобы получить в результате не объект, а массив, с ним проще работать. И вы совсем перепутали все переменные, не красиво.

$extended_json = $row['extended'];

$extended = json_decode($extended_json, true);

print $extended['age']; // 31

Еще скажу, что объект modUserProfile при попытке получить поле extended ведет себя несколько иначе и возвращает не json-строку, а сразу массив. За это отвечает описание поля в его мап-файле. Если вы выполните

$extended = $modx->getObject('modUser', $id)->Profile->get('extended');

, то получите сразу массив.