Since Area Triggers are hard-coded into the client (f**k off, Blizztards), instead of hunting for unused area triggers for custom teleports, I decided to create an area-based NPC that looks and functions like a portal using SmartAI scripts.
First, the SQL code for the creature itself. Once it's in the SQL database, you can (of course) change the model.
INSERT INTO `creature_template` (`entry`, `modelid1`, `modelid2`, `modelid3`, `modelid4`, `name`, `faction_A`, `faction_H`, `speed_walk`, `speed_run`, `unit_class`, `unit_flags`, `AIName`) VALUES (5551218, 26496, 26496, 26496, 26496, 'Portal to Stormwind', 1, 1, 0.000001, 0.000001, 1, 6, 'SmartAI');
SELECT `entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `modelid1`, `modelid2`, `modelid3`, `modelid4`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction_A`, `faction_H`, `npcflag`, `speed_walk`, `speed_run`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `dmg_multiplier`, `baseattacktime`, `rangeattacktime`, `unit_class`, `unit_flags`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `spell5`, `spell6`, `spell7`, `spell8`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `Health_mod`, `Mana_mod`, `Armor_mod`, `RacialLeader`, `questItem1`, `questItem2`, `questItem3`, `questItem4`, `questItem5`, `questItem6`, `movementId`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`, `WDBVerified` FROM `creature_template` WHERE `entry`=5551218;
The second SQL code was the pain to figure out. It had to auto-trigger when the NPC came within a certain distance, not move and always work.
INSERT INTO `smart_scripts` (`entryorguid`, `event_type`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `target_param1`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES (5551218, 10, 1, 2, 2, 2, 62, 8, -8474.02, 1345.12, 5.3701, 4.73895, 'Portal NPC to Stormwind Harbor');
SELECT `entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment` FROM `smart_scripts` WHERE `entryorguid`=5551218 AND `source_type`=0 AND `id`=0 AND `link`=0;
The only things that would need to be changed for each new "portal" are the entry ID (which has to ALWAYS be the same as the character entry), the distance the character has to be from the "portal"/NPC (which is, in meters, 2, 2, 2), the coordinates including orientation (-8474.02, 1345.12, 5.3701, 4.73895 will put you on Stormwind Harbor on one of the docks facing Stormwind) and, if you'd like, the comments.
Once the "portal" NPC is placed, you can change the Unit Flags in character_template to 33554432 (which makes it untargetable), .reload character_template and .respawn (or restart the server if you want to play it safe). This should work for any recent TrinityCore release (possibly MaNGOS but I haven't used them since about 2009).
Enjoy! ^_^