Around the turn of the century people stopped going crazy with macros, globals and exposing struct definitions in header files, at least this is where I draw the line between old and new school
Hiding the struct like:
typedef struct foo_t foo_t;
/* ... */
foo_t *foo_new();
kinda forces heap allocs. There are times when you want to allocate on the stack, and not use alloca.Most of the time, I still keep struct definitions in header files, but API wise I always write functions or macros for anything that touches them and discourage direct access to struct members. Depending on the use case of course. Abstract types have their uses too.