I find it hard to get good performance from large queries with CTEs. Often, it's much easier (and uglier) to just split them to multiple steps, create intermediate tables for each step and add necessary indexes.
Temporary tables are then of course even better, since usually you don't want to have these left around. But temporary tables are also unlogged.