For general transparency handling, you could use some form of order-independent transparency.
Typically, though, you sort by Z-distance along the camera view vector before rendering (you can get a "good enough for most uses" approximate with dot(camera.view, object.worldpos - camera.worldpos)
). A high-powered rendering pipeline will sort all of its objects by constructing an integer key (Wolfire has a nice article on this I can't for the life of me find right now, sorry) and then radix sorting on that. The key would be something like [alpha flag, depth, material index, mesh index]
all packed into a 32-bit or 64-bit integer. The depth should be reversed for opaque objects. The idea is to make it so that after sorting, objects are in the order to be drawn (opaque in a closest-first order, transparent in a farthest-first order, objects with identical materials or meshes grouped together).
The advantage of sorting everything is three-fold. First, it allows transparency to function without advanced order-independent techniques (most of which have their own significant downsides) by ensuring that transparent objects are always drawn after opaque objects and drawn in the correct order.
Second, it allows objects with similar or identical states to be batched together easily. E.g. if two scene nodes need the same shader it's more efficient to draw them together than to draw one, switch to another object/shader, and then switch back to the first shader to draw another object.
Third, it's can be highly beneficial on some hardware to draw opaque objects in a closest-first order. The reason being that hierarchical-Z and early-Z techniques commonly implemented in hardware will ensure that fragment shaders are not run for hidden geometry and hence will drastically cut down compute overhead and overdraw. Some hardware implicitly sorts fragments itself or has more GPU power available than the CPU has capability to sort objects, so as always, profile and test on target hardware.
For foliage specifically, as Nathan Reed commented, you can avoid all the extra work by just not doing real transparency. When you have enough similar objects like a ton of foliage textures you really can't tell the difference between "proper" blended transparency and just alpha-tested transparency. Same goes for things like hair and fur. Some transparent particle effects can also use different blending techniques and get away without being sorted especially.
It's not uncommon to have multiple passes to your renderer, say one that does the object sorting/batching for "normal" objects and then an entirely separate pass for quickly rendering large amounts of foliage or the like (where the sorting might be too expensive due to the sheer number of objects). Likewise you can avoid needing to get too fancy with the sorted key generation by simply putting all opaque and all transparent objects into separate render queues where the opaque queue is always sorted and rendered first.