Initial Setup
Element Studio needs somewhere to put your elements. Out of the box the only choices it
offers are Oxygen's own plugin folders, and anything saved there is destroyed by the next
plugin update. So the first thing to do — before you build a single element — is create a
small plugin of your own and register it as a saving location.
It is about twenty lines of PHP and you only ever do it once.
1. Create the plugin
Make a folder in wp-content/plugins/ — my-oxygen-elements/ in this example — with a
single plugin.php inside it:
/**
* Plugin Name: My Oxygen Elements
* Description: Custom elements built with Element Studio.
* Author: Your Name
* License: GPLv2
* Version: 0.0.1
*/
namespace MyOxygenElements;
use function BreakdanceUtilgetDirectoryPathRelativeToPluginFolder;
add_action('breakdance_loaded', function () {
BreakdanceElementStudioregisterSaveLocation(
getDirectoryPathRelativeToPluginFolder(__DIR__) . '/elements',
'MyOxygenElements',
'element',
'My Elements',
false
);
BreakdanceElementStudioregisterSaveLocation(
getDirectoryPathRelativeToPluginFolder(__DIR__) . '/macros',
'MyOxygenElements',
'macro',
'My Macros',
false
);
BreakdanceElementStudioregisterSaveLocation(
getDirectoryPathRelativeToPluginFolder(__DIR__) . '/presets',
'MyOxygenElements',
'preset',
'My Presets',
false
);
}, 9);
Create the three empty folders next to it — elements/, macros/, presets/ — then
activate the plugin from Plugins in wp-admin.
2. Reload the builder

Close and reopen the builder, then open Element Studio and click New element. My
Elements is now one of the saving locations, and everything you build there is yours.
What each argument does
registerSaveLocation($directoryPath, $namespace, $type, $label, $onlyForAdvancedUsers);
$directoryPath — the folder, relative to wp-content/plugins/. Not an absolute
path, which is why the example uses getDirectoryPathRelativeToPluginFolder(__DIR__)
rather than __DIR__ alone.
$namespace — the PHP namespace your generated element classes are written into. It
has to be unique on the site: it becomes the first half of every element slug your plugin
produces (MyOxygenElementsTestimonialCard), and two plugins claiming the same namespace
will collide. Use something derived from your own or your agency's name — never
EssentialElements or OxygenElements, which are Oxygen's.
$type — 'element', 'macro' or 'preset'. One call per type; a folder registered
as 'element' will not accept macros.
$label — what appears in the "Select a saving location" list when you create
something. Make it recognisable, because that list is the only thing standing between your
work and a first-party folder.
$onlyForAdvancedUsers — pass false. Oxygen's own locations pass true, which is
how they mark themselves as places ordinary users shouldn't be saving into.
Why the priority matters
The 9 at the end of the add_action call is not decoration. Oxygen loads element class
files on breakdance_loaded at the default priority of 10, by scanning every registered
saving location. Register your location any later than that and the scan has already run:
your folder is skipped, and your elements simply don't exist until the next page load.
Anything below 10 works. Oxygen's own element library registers at priority 5.
Use breakdance_loaded, not oxygen_loaded, for this one. The two are the same hook
under two names, but the oxygen_-prefixed copy fires only after every breakdance_loaded
callback has run — which is after the priority-10 element scan. A saving location
registered on oxygen_loaded is always too late, whatever priority you give it.
Keep it in git
Element Studio writes real files, and its Delete button removes them with no undo. The
sane workflow is a git repository at the root of your plugin folder:
cd wp-content/plugins/my-oxygen-elements
git init
git add .
git commit -m "Element plugin scaffold"
Commit after each element you finish. Beyond the safety net, this is also how you move
elements between sites — the plugin folder is the deliverable. Clone it into another
Oxygen install's wp-content/plugins/, activate it, and every element comes with it.
Where your files end up
Creating an element called "Testimonial Card" in this plugin produces:
wp-content/plugins/my-oxygen-elements/elements/Testimonial_Card/
├── element.php
├── html.twig
├── css.twig
└── default.css
Oxygen finds elements by globbing <saving location>/*/*.php, so every element needs its
own subfolder — which is what the studio creates. Files named ssr.php are skipped by that
scan on purpose; they're loaded at render time instead, which is what makes
server-side rendering work.