register(); } protected function get_tag():string { $parts = explode('\\', get_called_class()); return sanitize_key(preg_replace('/([a-z])([A-Z])/', '$1-$2', array_pop($parts))); } protected function register():void { add_shortcode($this->get_tag(), [$this, 'callback']); } public function get_default_attributes():array { return []; } public function get_attributes(array $atts = []):array { return shortcode_atts($this->get_default_attributes(), $atts, $this->get_tag()); } public function callback(array $atts, ?string $content = null) { ob_start(); $this->render($this->get_attributes($atts), (!is_null($content) ? $content : '')); return ob_get_clean(); } public abstract function render(array $atts, string $content):void; }