diff --git a/eth-embed-anchor-fm.php b/eth-embed-anchor-fm.php
index bb370d507efeffd83971d6bc716855fc762b5ee2..89de486694b5dcff420244f8fceb5b279f0bb01d 100644
--- a/eth-embed-anchor-fm.php
+++ b/eth-embed-anchor-fm.php
@@ -27,3 +27,23 @@
  */
 
 namespace ETH_Embed_Anchor_FM;
+
+/**
+ * Perform setup actions after plugin loads.
+ *
+ * @return void
+ */
+function action_plugins_loaded() {
+	load_plugin_textdomain(
+		'eth-embed-anchor-fm',
+		false,
+		dirname( plugin_basename( __FILE__ ) ) . '/languages/'
+	);
+}
+add_action( 'plugins_loaded', __NAMESPACE__ . '\action_plugins_loaded' );
+
+/**
+ * Load plugin classes.
+ */
+require_once __DIR__ . '/inc/class-plugin.php';
+Plugin::get_instance();
diff --git a/inc/class-plugin.php b/inc/class-plugin.php
new file mode 100644
index 0000000000000000000000000000000000000000..461c552c7f8a047b79919edcd6f32488b4d48ef9
--- /dev/null
+++ b/inc/class-plugin.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Plugin functionality.
+ *
+ * @package ETH_Embed_Anchor_FM
+ */
+
+namespace ETH_Embed_Anchor_FM;
+
+/**
+ * Class Plugin.
+ */
+class Plugin {
+	/**
+	 * Singleton.
+	 *
+	 * @var Plugin
+	 */
+	private static $_instance = null;
+
+	/**
+	 * Implement singleton.
+	 *
+	 * @return Plugin
+	 */
+	public static function get_instance(): Plugin {
+		if ( ! is_a( self::$_instance, __CLASS__ ) ) {
+			self::$_instance = new self();
+			self::$_instance->setup();
+		}
+
+		return self::$_instance;
+	}
+
+	/**
+	 * Silence is golden!
+	 */
+	private function __construct() {}
+
+	/**
+	 * Register hooks.
+	 *
+	 * @return void
+	 */
+	private function setup(): void {
+		// TODO: add oEmbed handler.
+		// TODO: add shortcode.
+	}
+}