It is maybe just a simple rework of the conditional statements needed,
WHERE projects.exp = '0000-00-00'
AND projects.status = 'active'
AND ((projects.posted < DATE_SUB(CURDATE(), INTERVAL 31 DAY)) OR (projects.updated < DATE_SUB(CURDATE(), INTERVAL 31 DAY)))
AND ((task_A.status != 'active'
AND ((task_A.posted < DATE_SUB(CURDATE(), INTERVAL 31 DAY)) OR (task_A.updated < DATE_SUB(CURDATE(), INTERVAL 31 DAY))))
OR
(task_B.status != 'active'
AND ((task_B.posted < DATE_SUB(CURDATE(), INTERVAL 31 DAY)) OR (task_B.updated < DATE_SUB(CURDATE(), INTERVAL 31 DAY)))))
And in shorthand notation,
L0: projects.exp = '0000-00-00'
L1: projects.status = 'active'
L2: projects.posted < DATE_SUB(CURDATE(), INTERVAL 31 DAY)
L3: projects.updated < DATE_SUB(CURDATE(), INTERVAL 31 DAY)
L4: task_A.status != 'active'
L5: task_A.posted < DATE_SUB(CURDATE(), INTERVAL 31 DAY)
L6: task_A.updated < DATE_SUB(CURDATE(), INTERVAL 31 DAY)
L7: task_B.status != 'active'
L8: task_B.posted < DATE_SUB(CURDATE(), INTERVAL 31 DAY)
L9: task_B.updated < DATE_SUB(CURDATE(), INTERVAL 31 DAY)
old:
WHERE L0 AND L1 AND (L2 OR L3) AND L4 AND (L5 OR L6) AND L7 AND (L8 OR L9)
new
WHERE L0 AND L1 AND (L2 OR L3) AND ((L4 AND (L5 OR L6)) OR (L7 AND (L8 OR L9)))