Is 3 minutes to join a 50 million table too much?
First, add these indexes:

ALTER TABLE cat_01
ADD INDEX `ShopBuyDates` (`shop_id`,`buy_date`)

ALTER TABLE orders
ADD INDEX `OrderSales` (`order_id`,`sales`)


Then try this query, and report the results. Make sure to run it at least twice, and discard the first result's performance, to flush out the effects of populating the cache.

SELECT 
'cat_01' as category,
m.shop_id,
o.name,
count(m.shop_id) as total,
tr2.traffic,
IF(mm.bought IS NULL,0,mm.bought) as bought 
FROM cat_01 m 
JOIN shops o 
ON m.shop_id = o.id 
JOIN (
    select 
    mmm.shop_id,
    max(mmm.buy_date) as bought 
    FROM cat_01 mmm 
    GROUP BY mmm.shop_id
) mm
ON o.id = mm.shop_id 
LEFT JOIN (
    SELECT mmmmm.shop_id, sum(bs.sales) AS traffic 
    FROM cat_01 mmmmm
    JOIN orders bs
    ON mmmmm.order = bs.order_id 
    group by mmmmm.shop_id
) tr2
ON tr2.shop_id = mm.shop_id 
WHERE (m.buy_date IS NULL)
OR (m.buy_date = 0)
OR (m.buy_date &lt; 1)
GROUP BY m.shop_id


After we see the improvement from this (a new EXPLAIN would be good too, from this query), we can iterate to see what else is slowing down your query.