Vous devez mettre la vérification de l'utilisateur dans la jointure, pas dans la condition where, comme ceci :
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
La raison en est que les JOINS utilisent la "jointure gauche" (qui est implicitement une jointure externe". Ce type de jointure signifie que si la condition fonctionne, renvoie toutes les données de colonne de cette table pour cette ligne.. si l'ensemble condition ne fonctionne pas, elle renverra toutes les données des tables mentionnées précédemment, mais pour la table mentionnée dans la ligne, elle renverra NULLS pour toutes ces colonnes.
Je m'excuse pour cette description, car il est difficile de mettre des mots sur le fonctionnement exact d'une jointure externe (ou gauche) complexe sans devenir verbeux.