Du skal sætte brugercheck i join, ikke i where conditionlike så:
SELECT c.course_id,l.topic,l.id,l.vid_duration,p.*
FROM courses c
LEFT JOIN lessons l ON l.course_id=c.course_id
LEFT JOIN progress p ON l.id = p.lesson_id and p.user_id = :userid
WHERE c.slug = :course
Grunden til at gøre dette er, at JOINS bruger "venstre join" (som implicit er en ydre joinforbindelse". Denne type join betyder, at hvis betingelsen virker, returnerer du alle kolonnedata for den tabel for den række.. hvis hele betingelse ikke virker, vil den returnere alle data for tabeller nævnt tidligere, men for tabellen nævnt i rækken, vil den returnere NULLS for alle disse kolonner.
Jeg undskylder for den beskrivelse, da det er svært at sætte ord på præcis, hvordan en kompleks ydre (eller venstre) sammenføjning fungerer uden at blive ordrig.