diff --git a/README.md b/README.md
index a4f6c256..dc826039 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,25 @@ Desenvolva um Plugin em WordPress que implemente a funcionalidade de favoritar p
* PHP >= 5.6
* Orientado a objetos
-## Dúvidas
-
-Em caso de dúvidas, crie uma issue.
+## Como Usar o Plugin
+
+### 1. Instalação
+- Faça upload do plugin para `/wp-content/plugins/`
+- Ative o plugin no painel administrativo
+
+### 2. Adicionar Botão de Favorito
+No arquivo `single.php` do seu tema, adicione:
+```php
+
+```
+
+### 3. Exibir Lista de Favoritos
+Use o shortcode em qualquer página:
+```
+[wp_favorites_list]
+```
+
+### 4. API REST
+- **Favoritar**: `POST /wp-json/wp-favorites/v1/favorite`
+- **Desfavoritar**: `POST /wp-json/wp-favorites/v1/unfavorite`
+- **Listar**: `GET /wp-json/wp-favorites/v1/favorites`
diff --git a/wp-favorites-plugin/assets/css/wp-favorites.css b/wp-favorites-plugin/assets/css/wp-favorites.css
new file mode 100644
index 00000000..4e00fb50
--- /dev/null
+++ b/wp-favorites-plugin/assets/css/wp-favorites.css
@@ -0,0 +1,117 @@
+/**
+ * WP Favorites Plugin Styles
+ */
+
+.wp-favorites-button {
+ display: inline-flex;
+ align-items: center;
+ gap: 5px;
+ background: #0073aa;
+ color: white;
+ border: none;
+ padding: 8px 16px;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ font-size: 14px;
+ text-decoration: none;
+ line-height: 1.4;
+}
+
+.wp-favorites-button:hover {
+ background: #005a87;
+ color: white;
+ text-decoration: none;
+}
+
+.wp-favorites-button.favorited {
+ background: #d63638;
+}
+
+.wp-favorites-button.favorited:hover {
+ background: #b32d2e;
+}
+
+.wp-favorites-button:disabled {
+ opacity: 0.6;
+ cursor: not-allowed;
+}
+
+.wp-favorites-icon {
+ font-size: 16px;
+ line-height: 1;
+}
+
+.wp-favorites-count {
+ background: rgba(255, 255, 255, 0.2);
+ padding: 2px 6px;
+ border-radius: 10px;
+ font-size: 12px;
+ margin-left: 5px;
+}
+
+.wp-favorites-message {
+ position: fixed;
+ top: 20px;
+ right: 20px;
+ padding: 12px 20px;
+ border-radius: 4px;
+ color: white;
+ z-index: 9999;
+ font-size: 14px;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+ animation: wp-favorites-slide-in 0.3s ease;
+}
+
+.wp-favorites-message.success {
+ background: #46b450;
+}
+
+.wp-favorites-message.error {
+ background: #dc3232;
+}
+
+@keyframes wp-favorites-slide-in {
+ from {
+ transform: translateX(100%);
+ opacity: 0;
+ }
+ to {
+ transform: translateX(0);
+ opacity: 1;
+ }
+}
+
+/* Loading state */
+.wp-favorites-button.loading {
+ opacity: 0.7;
+ pointer-events: none;
+}
+
+.wp-favorites-button.loading .wp-favorites-icon {
+ animation: wp-favorites-spin 1s linear infinite;
+}
+
+@keyframes wp-favorites-spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+/* Responsive */
+@media (max-width: 768px) {
+ .wp-favorites-button {
+ padding: 6px 12px;
+ font-size: 13px;
+ }
+
+ .wp-favorites-message {
+ top: 10px;
+ right: 10px;
+ left: 10px;
+ font-size: 13px;
+ }
+}
\ No newline at end of file
diff --git a/wp-favorites-plugin/assets/js/wp-favorites.js b/wp-favorites-plugin/assets/js/wp-favorites.js
new file mode 100644
index 00000000..0f6ebbdb
--- /dev/null
+++ b/wp-favorites-plugin/assets/js/wp-favorites.js
@@ -0,0 +1,194 @@
+/**
+ * WP Favorites Plugin JavaScript
+ */
+
+(function($) {
+ 'use strict';
+
+ // WP Favorites Plugin namespace
+ window.WPFavorites = window.WPFavorites || {};
+
+ // Configuration
+ WPFavorites.config = {
+ restUrl: wpFavorites.restUrl || '/wp-json/wp-favorites/v1',
+ nonce: wpFavorites.nonce || '',
+ messages: {
+ favorited: 'Post added to favorites!',
+ unfavorited: 'Post removed from favorites!',
+ error: 'An error occurred. Please try again.',
+ loginRequired: 'Please log in to favorite posts.'
+ }
+ };
+
+ // Main class
+ WPFavorites.FavoritesButton = function(element, options) {
+ this.element = $(element);
+ this.options = $.extend({}, WPFavorites.config, options);
+ this.postId = this.element.data('post-id');
+ this.isFavorited = false;
+ this.isLoading = false;
+
+ this.init();
+ };
+
+ WPFavorites.FavoritesButton.prototype = {
+ init: function() {
+ this.bindEvents();
+ this.checkFavoriteStatus();
+ },
+
+ bindEvents: function() {
+ var self = this;
+ this.element.on('click', function(e) {
+ e.preventDefault();
+ self.toggleFavorite();
+ });
+ },
+
+ checkFavoriteStatus: function() {
+ var self = this;
+ $.ajax({
+ url: self.options.restUrl + '/favorites',
+ method: 'GET',
+ beforeSend: function(xhr) {
+ xhr.setRequestHeader('X-WP-Nonce', self.options.nonce);
+ },
+ success: function(response) {
+ if (response.success && response.favorites.includes(parseInt(self.postId))) {
+ self.setFavorited(true);
+ }
+ },
+ error: function() {
+ // Silent fail for status check
+ }
+ });
+ },
+
+ toggleFavorite: function() {
+ if (this.isLoading) return;
+
+ if (this.isFavorited) {
+ this.unfavorite();
+ } else {
+ this.favorite();
+ }
+ },
+
+ favorite: function() {
+ var self = this;
+ this.setLoading(true);
+
+ $.ajax({
+ url: self.options.restUrl + '/favorite',
+ method: 'POST',
+ data: JSON.stringify({
+ post_id: self.postId
+ }),
+ contentType: 'application/json',
+ beforeSend: function(xhr) {
+ xhr.setRequestHeader('X-WP-Nonce', self.options.nonce);
+ },
+ success: function(response) {
+ if (response.success) {
+ self.setFavorited(true);
+ self.showMessage(self.options.messages.favorited, 'success');
+ } else {
+ self.showMessage(response.message || self.options.messages.error, 'error');
+ }
+ },
+ error: function(xhr) {
+ var message = self.options.messages.error;
+ if (xhr.status === 401) {
+ message = self.options.messages.loginRequired;
+ }
+ self.showMessage(message, 'error');
+ },
+ complete: function() {
+ self.setLoading(false);
+ }
+ });
+ },
+
+ unfavorite: function() {
+ var self = this;
+ this.setLoading(true);
+
+ $.ajax({
+ url: self.options.restUrl + '/unfavorite',
+ method: 'POST',
+ data: JSON.stringify({
+ post_id: self.postId
+ }),
+ contentType: 'application/json',
+ beforeSend: function(xhr) {
+ xhr.setRequestHeader('X-WP-Nonce', self.options.nonce);
+ },
+ success: function(response) {
+ if (response.success) {
+ self.setFavorited(false);
+ self.showMessage(self.options.messages.unfavorited, 'success');
+ } else {
+ self.showMessage(response.message || self.options.messages.error, 'error');
+ }
+ },
+ error: function() {
+ self.showMessage(self.options.messages.error, 'error');
+ },
+ complete: function() {
+ self.setLoading(false);
+ }
+ });
+ },
+
+ setFavorited: function(favorited) {
+ this.isFavorited = favorited;
+ this.element.toggleClass('favorited', favorited);
+
+ var icon = this.element.find('.wp-favorites-icon');
+ var text = this.element.find('.wp-favorites-text');
+
+ if (favorited) {
+ icon.text('♥');
+ text.text('Favorited');
+ } else {
+ icon.text('♡');
+ text.text('Favorite');
+ }
+ },
+
+ setLoading: function(loading) {
+ this.isLoading = loading;
+ this.element.toggleClass('loading', loading);
+ this.element.prop('disabled', loading);
+ },
+
+ showMessage: function(message, type) {
+ var messageElement = $('
')
+ .addClass('wp-favorites-message ' + type)
+ .text(message);
+
+ $('body').append(messageElement);
+
+ setTimeout(function() {
+ messageElement.fadeOut(300, function() {
+ $(this).remove();
+ });
+ }, 3000);
+ }
+ };
+
+ // jQuery plugin
+ $.fn.wpFavorites = function(options) {
+ return this.each(function() {
+ if (!$(this).data('wp-favorites')) {
+ $(this).data('wp-favorites', new WPFavorites.FavoritesButton(this, options));
+ }
+ });
+ };
+
+ // Auto-initialize on document ready
+ $(document).ready(function() {
+ $('.wp-favorites-button').wpFavorites();
+ });
+
+})(jQuery);
\ No newline at end of file
diff --git a/wp-favorites-plugin/config.php b/wp-favorites-plugin/config.php
new file mode 100644
index 00000000..e448a098
--- /dev/null
+++ b/wp-favorites-plugin/config.php
@@ -0,0 +1,62 @@
+ '1.0.0',
+ 'name' => 'WP Favorites Plugin',
+ 'description' => 'A WordPress plugin that allows logged-in users to favorite and unfavorite posts using WP REST API',
+ 'author' => 'WordPress Back-end Challenge',
+ 'license' => 'GPL v2 or later',
+ 'text_domain' => 'wp-favorites-plugin',
+ 'domain_path' => '/languages',
+
+ // Database
+ 'table_name' => 'user_favorites',
+
+ // REST API
+ 'rest_namespace' => 'wp-favorites/v1',
+ 'rest_routes' => array(
+ 'favorite' => '/favorite',
+ 'unfavorite' => '/unfavorite',
+ 'favorites' => '/favorites'
+ ),
+
+ // Assets
+ 'assets' => array(
+ 'css' => array(
+ 'wp-favorites-style' => 'assets/css/wp-favorites.css'
+ ),
+ 'js' => array(
+ 'wp-favorites-script' => 'assets/js/wp-favorites.js'
+ )
+ ),
+
+ // Shortcodes
+ 'shortcodes' => array(
+ 'wp_favorites_button' => 'Favorite Button',
+ 'wp_favorites_list' => 'Favorites List'
+ ),
+
+ // Hooks
+ 'hooks' => array(
+ 'wp_favorites_post_favorited' => 'Fired when a post is favorited',
+ 'wp_favorites_post_unfavorited' => 'Fired when a post is unfavorited'
+ ),
+
+ // Requirements
+ 'requirements' => array(
+ 'php' => '5.6',
+ 'wordpress' => '4.7',
+ 'plugins' => array()
+ )
+);
\ No newline at end of file
diff --git a/wp-favorites-plugin/includes/class-wp-favorites-assets.php b/wp-favorites-plugin/includes/class-wp-favorites-assets.php
new file mode 100644
index 00000000..d35f2744
--- /dev/null
+++ b/wp-favorites-plugin/includes/class-wp-favorites-assets.php
@@ -0,0 +1,106 @@
+ rest_url('wp-favorites/v1'),
+ 'nonce' => wp_create_nonce('wp_rest'),
+ 'ajaxUrl' => admin_url('admin-ajax.php'),
+ 'isLoggedIn' => is_user_logged_in(),
+ 'strings' => array(
+ 'favorited' => __('Post added to favorites!', 'wp-favorites-plugin'),
+ 'unfavorited' => __('Post removed from favorites!', 'wp-favorites-plugin'),
+ 'error' => __('An error occurred. Please try again.', 'wp-favorites-plugin'),
+ 'loginRequired' => __('Please log in to favorite posts.', 'wp-favorites-plugin')
+ )
+ ));
+ }
+
+ /**
+ * Enqueue admin scripts and styles
+ */
+ public static function enqueue_admin_scripts($hook) {
+ // Only enqueue on plugin settings page
+ if (strpos($hook, 'wp-favorites') === false) {
+ return;
+ }
+
+ wp_enqueue_style(
+ 'wp-favorites-admin-style',
+ WP_FAVORITES_PLUGIN_URL . 'assets/css/wp-favorites-admin.css',
+ array(),
+ WP_FAVORITES_PLUGIN_VERSION
+ );
+
+ wp_enqueue_script(
+ 'wp-favorites-admin-script',
+ WP_FAVORITES_PLUGIN_URL . 'assets/js/wp-favorites-admin.js',
+ array('jquery'),
+ WP_FAVORITES_PLUGIN_VERSION,
+ true
+ );
+ }
+
+ /**
+ * Get asset URL
+ *
+ * @param string $path Asset path
+ * @return string
+ */
+ public static function get_asset_url($path) {
+ return WP_FAVORITES_PLUGIN_URL . 'assets/' . ltrim($path, '/');
+ }
+
+ /**
+ * Get asset path
+ *
+ * @param string $path Asset path
+ * @return string
+ */
+ public static function get_asset_path($path) {
+ return WP_FAVORITES_PLUGIN_PATH . 'assets/' . ltrim($path, '/');
+ }
+}
\ No newline at end of file
diff --git a/wp-favorites-plugin/includes/class-wp-favorites-helpers.php b/wp-favorites-plugin/includes/class-wp-favorites-helpers.php
new file mode 100644
index 00000000..30d4beac
--- /dev/null
+++ b/wp-favorites-plugin/includes/class-wp-favorites-helpers.php
@@ -0,0 +1,124 @@
+prefix . 'user_favorites';
+ $user_id = get_current_user_id();
+
+ $result = $wpdb->get_var($wpdb->prepare(
+ "SELECT COUNT(*) FROM $table_name WHERE user_id = %d AND post_id = %d",
+ $user_id,
+ $post_id
+ ));
+
+ return $result > 0;
+ }
+
+ /**
+ * Get user's favorite posts
+ *
+ * @param int $user_id User ID (optional, defaults to current user)
+ * @return array
+ */
+ public static function get_user_favorites($user_id = null) {
+ if (!$user_id) {
+ $user_id = get_current_user_id();
+ }
+
+ if (!$user_id) {
+ return array();
+ }
+
+ global $wpdb;
+ $table_name = $wpdb->prefix . 'user_favorites';
+
+ $favorites = $wpdb->get_col($wpdb->prepare(
+ "SELECT post_id FROM $table_name WHERE user_id = %d ORDER BY created_at DESC",
+ $user_id
+ ));
+
+ return $favorites;
+ }
+
+ /**
+ * Get favorite count for a post
+ *
+ * @param int $post_id Post ID
+ * @return int
+ */
+ public static function get_favorite_count($post_id) {
+ global $wpdb;
+ $table_name = $wpdb->prefix . 'user_favorites';
+
+ $count = $wpdb->get_var($wpdb->prepare(
+ "SELECT COUNT(*) FROM $table_name WHERE post_id = %d",
+ $post_id
+ ));
+
+ return (int) $count;
+ }
+
+ /**
+ * Sanitize post ID
+ *
+ * @param mixed $post_id
+ * @return int|false
+ */
+ public static function sanitize_post_id($post_id) {
+ $post_id = absint($post_id);
+ return $post_id > 0 ? $post_id : false;
+ }
+
+ /**
+ * Validate post exists
+ *
+ * @param int $post_id Post ID
+ * @return bool
+ */
+ public static function post_exists($post_id) {
+ return get_post($post_id) !== null;
+ }
+
+ /**
+ * Get REST API base URL
+ *
+ * @return string
+ */
+ public static function get_rest_base_url() {
+ return rest_url('wp-favorites/v1');
+ }
+
+ /**
+ * Get nonce for AJAX requests
+ *
+ * @return string
+ */
+ public static function get_nonce() {
+ return wp_create_nonce('wp_rest');
+ }
+}
\ No newline at end of file
diff --git a/wp-favorites-plugin/includes/class-wp-favorites-plugin.php b/wp-favorites-plugin/includes/class-wp-favorites-plugin.php
new file mode 100644
index 00000000..a7a58ec9
--- /dev/null
+++ b/wp-favorites-plugin/includes/class-wp-favorites-plugin.php
@@ -0,0 +1,298 @@
+init_hooks();
+ }
+
+ /**
+ * Initialize hooks
+ */
+ private function init_hooks() {
+ add_action('init', array($this, 'init'));
+ register_activation_hook(WP_FAVORITES_PLUGIN_FILE, array($this, 'activate'));
+ register_deactivation_hook(WP_FAVORITES_PLUGIN_FILE, array($this, 'deactivate'));
+ }
+
+ /**
+ * Initialize plugin
+ */
+ public function init() {
+ $this->create_table();
+ $this->register_rest_routes();
+ $this->init_assets();
+ $this->init_templates();
+ }
+
+ /**
+ * Plugin activation
+ */
+ public function activate() {
+ $this->create_table();
+ }
+
+ /**
+ * Plugin deactivation
+ */
+ public function deactivate() {
+ // Cleanup if needed
+ }
+
+ /**
+ * Create custom table
+ */
+ private function create_table() {
+ global $wpdb;
+
+ $table_name = $wpdb->prefix . 'user_favorites';
+ $charset_collate = $wpdb->get_charset_collate();
+
+ $sql = "CREATE TABLE $table_name (
+ id mediumint(9) NOT NULL AUTO_INCREMENT,
+ user_id bigint(20) NOT NULL,
+ post_id bigint(20) NOT NULL,
+ created_at datetime DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY (id),
+ UNIQUE KEY user_post (user_id, post_id)
+ ) $charset_collate;";
+
+ require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
+ dbDelta($sql);
+
+ // Verify table was created
+ $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") == $table_name;
+ if (!$table_exists) {
+ error_log('WP Favorites Plugin: Failed to create table ' . $table_name);
+ }
+ }
+
+ /**
+ * Check if table exists and create if not
+ */
+ private function ensure_table_exists() {
+ global $wpdb;
+ $table_name = $wpdb->prefix . 'user_favorites';
+
+ $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") == $table_name;
+ if (!$table_exists) {
+ $this->create_table();
+ }
+ }
+
+ /**
+ * Register REST API routes
+ */
+ private function register_rest_routes() {
+ add_action('rest_api_init', function () {
+ register_rest_route('wp-favorites/v1', '/favorite', array(
+ 'methods' => 'POST',
+ 'callback' => array($this, 'favorite_post'),
+ 'permission_callback' => array($this, 'check_user_logged_in'),
+ ));
+
+ register_rest_route('wp-favorites/v1', '/unfavorite', array(
+ 'methods' => 'POST',
+ 'callback' => array($this, 'unfavorite_post'),
+ 'permission_callback' => array($this, 'check_user_logged_in'),
+ ));
+
+ register_rest_route('wp-favorites/v1', '/favorites', array(
+ 'methods' => 'GET',
+ 'callback' => array($this, 'get_user_favorites'),
+ 'permission_callback' => array($this, 'check_user_logged_in'),
+ ));
+ });
+ }
+
+ /**
+ * Check if user is logged in
+ */
+ public function check_user_logged_in() {
+ return is_user_logged_in();
+ }
+
+ /**
+ * Favorite a post
+ */
+ public function favorite_post($request) {
+ $user_id = get_current_user_id();
+ $post_id = $request->get_param('post_id');
+
+ if (!$post_id || !get_post($post_id)) {
+ return new WP_Error('invalid_post', 'Invalid post ID', array('status' => 400));
+ }
+
+ global $wpdb;
+ $table_name = $wpdb->prefix . 'user_favorites';
+
+ // Ensure table exists
+ $this->ensure_table_exists();
+
+ // Check if already favorited
+ $existing = $wpdb->get_var($wpdb->prepare(
+ "SELECT id FROM $table_name WHERE user_id = %d AND post_id = %d",
+ $user_id,
+ $post_id
+ ));
+
+ if ($existing) {
+ return array(
+ 'success' => true,
+ 'message' => 'Post already favorited',
+ 'post_id' => $post_id
+ );
+ }
+
+ $result = $wpdb->insert(
+ $table_name,
+ array(
+ 'user_id' => $user_id,
+ 'post_id' => $post_id,
+ ),
+ array('%d', '%d')
+ );
+
+ if ($result === false) {
+ return new WP_Error('database_error', 'Failed to favorite post', array('status' => 500));
+ }
+
+ do_action('wp_favorites_post_favorited', $user_id, $post_id);
+
+ return array(
+ 'success' => true,
+ 'message' => 'Post favorited successfully',
+ 'post_id' => $post_id
+ );
+ }
+
+ /**
+ * Unfavorite a post
+ */
+ public function unfavorite_post($request) {
+ $user_id = get_current_user_id();
+ $post_id = $request->get_param('post_id');
+
+ if (!$post_id) {
+ return new WP_Error('invalid_post', 'Invalid post ID', array('status' => 400));
+ }
+
+ global $wpdb;
+ $table_name = $wpdb->prefix . 'user_favorites';
+
+ // Ensure table exists
+ $this->ensure_table_exists();
+
+ // Check if already favorited
+ $existing = $wpdb->get_var($wpdb->prepare(
+ "SELECT id FROM $table_name WHERE user_id = %d AND post_id = %d",
+ $user_id,
+ $post_id
+ ));
+
+ if (!$existing) {
+ return array(
+ 'success' => true,
+ 'message' => 'Post not favorited',
+ 'post_id' => $post_id
+ );
+ }
+
+ $result = $wpdb->delete(
+ $table_name,
+ array(
+ 'user_id' => $user_id,
+ 'post_id' => $post_id,
+ ),
+ array('%d', '%d')
+ );
+
+ if ($result === false) {
+ return new WP_Error('database_error', 'Failed to unfavorite post', array('status' => 500));
+ }
+
+ do_action('wp_favorites_post_unfavorited', $user_id, $post_id);
+
+ return array(
+ 'success' => true,
+ 'message' => 'Post unfavorited successfully',
+ 'post_id' => $post_id
+ );
+ }
+
+ /**
+ * Get user favorites
+ */
+ public function get_user_favorites($request) {
+ $user_id = get_current_user_id();
+
+ global $wpdb;
+ $table_name = $wpdb->prefix . 'user_favorites';
+
+ // Ensure table exists
+ $this->ensure_table_exists();
+
+ $favorites = $wpdb->get_col($wpdb->prepare(
+ "SELECT post_id FROM $table_name WHERE user_id = %d ORDER BY created_at DESC",
+ $user_id
+ ));
+
+ return array(
+ 'success' => true,
+ 'favorites' => $favorites
+ );
+ }
+
+ /**
+ * Initialize assets
+ */
+ private function init_assets() {
+ require_once WP_FAVORITES_PLUGIN_PATH . 'includes/class-wp-favorites-assets.php';
+ WP_Favorites_Assets::init();
+ }
+
+ /**
+ * Initialize template functions
+ */
+ private function init_templates() {
+ require_once WP_FAVORITES_PLUGIN_PATH . 'includes/class-wp-favorites-helpers.php';
+ require_once WP_FAVORITES_PLUGIN_PATH . 'includes/class-wp-favorites-template.php';
+ WP_Favorites_Template::init();
+ }
+}
\ No newline at end of file
diff --git a/wp-favorites-plugin/includes/class-wp-favorites-template.php b/wp-favorites-plugin/includes/class-wp-favorites-template.php
new file mode 100644
index 00000000..a06e6eb3
--- /dev/null
+++ b/wp-favorites-plugin/includes/class-wp-favorites-template.php
@@ -0,0 +1,148 @@
+ get_the_ID(),
+ 'show_count' => false,
+ 'button_text' => __('Favorite', 'wp-favorites-plugin')
+ );
+
+ $args = wp_parse_args($args, $defaults);
+
+ // Load template
+ $template_path = WP_FAVORITES_PLUGIN_PATH . 'templates/favorite-button.php';
+ if (file_exists($template_path)) {
+ include $template_path;
+ }
+ }
+
+ /**
+ * Favorite button shortcode
+ *
+ * @param array $atts Shortcode attributes
+ * @return string
+ */
+ public static function favorite_button_shortcode($atts) {
+ $atts = shortcode_atts(array(
+ 'post_id' => get_the_ID(),
+ 'show_count' => 'false',
+ 'button_text' => __('Favorite', 'wp-favorites-plugin')
+ ), $atts);
+
+ $atts['show_count'] = filter_var($atts['show_count'], FILTER_VALIDATE_BOOLEAN);
+
+ ob_start();
+ self::favorite_button($atts);
+ return ob_get_clean();
+ }
+
+ /**
+ * Favorites list shortcode
+ *
+ * @param array $atts Shortcode attributes
+ * @return string
+ */
+ public static function favorites_list_shortcode($atts) {
+ if (!is_user_logged_in()) {
+ return '
' . __('Please log in to view your favorites.', 'wp-favorites-plugin') . '
';
+ }
+
+ $atts = shortcode_atts(array(
+ 'user_id' => get_current_user_id(),
+ 'limit' => 10,
+ 'show_excerpt' => 'false',
+ 'show_date' => 'false'
+ ), $atts);
+
+ $favorites = WP_Favorites_Helpers::get_user_favorites($atts['user_id']);
+
+ if (empty($favorites)) {
+ return '
' . __('No favorite posts found.', 'wp-favorites-plugin') . '
';
+ }
+
+ // Limit results
+ $favorites = array_slice($favorites, 0, (int) $atts['limit']);
+
+ $output = '
';
+ $output .= '
' . __('Your Favorite Posts', 'wp-favorites-plugin') . '
';
+ $output .= '
';
+
+ foreach ($favorites as $post_id) {
+ $post = get_post($post_id);
+ if (!$post) continue;
+
+ $output .= '- ';
+ $output .= '' . get_the_title($post_id) . '';
+
+ if (filter_var($atts['show_date'], FILTER_VALIDATE_BOOLEAN)) {
+ $output .= ' (' . get_the_date('', $post_id) . ')';
+ }
+
+ if (filter_var($atts['show_excerpt'], FILTER_VALIDATE_BOOLEAN)) {
+ $excerpt = wp_trim_words(get_the_excerpt($post_id), 20);
+ $output .= '
' . $excerpt . '
';
+ }
+
+ $output .= ' ';
+ }
+
+ $output .= '
';
+ $output .= '
';
+
+ return $output;
+ }
+
+ /**
+ * Get template path
+ *
+ * @param string $template_name Template name
+ * @return string
+ */
+ public static function get_template_path($template_name) {
+ return WP_FAVORITES_PLUGIN_PATH . 'templates/' . $template_name . '.php';
+ }
+
+ /**
+ * Load template
+ *
+ * @param string $template_name Template name
+ * @param array $args Template arguments
+ */
+ public static function load_template($template_name, $args = array()) {
+ $template_path = self::get_template_path($template_name);
+
+ if (file_exists($template_path)) {
+ extract($args);
+ include $template_path;
+ }
+ }
+}
\ No newline at end of file
diff --git a/wp-favorites-plugin/templates/favorite-button.php b/wp-favorites-plugin/templates/favorite-button.php
new file mode 100644
index 00000000..d2be9339
--- /dev/null
+++ b/wp-favorites-plugin/templates/favorite-button.php
@@ -0,0 +1,55 @@
+
+
+ ♡
+
+
+
+
+
\ No newline at end of file
diff --git a/wp-favorites-plugin/uninstall.php b/wp-favorites-plugin/uninstall.php
new file mode 100644
index 00000000..9f5184e5
--- /dev/null
+++ b/wp-favorites-plugin/uninstall.php
@@ -0,0 +1,23 @@
+prefix . 'user_favorites';
+$wpdb->query("DROP TABLE IF EXISTS $table_name");
+
+// Delete plugin options
+delete_option('wp_favorites_version');
+delete_option('wp_favorites_settings');
+
+// Clear any cached data that has been removed
+wp_cache_flush();
\ No newline at end of file
diff --git a/wp-favorites-plugin/wp-favorites-plugin.php b/wp-favorites-plugin/wp-favorites-plugin.php
new file mode 100644
index 00000000..06c18547
--- /dev/null
+++ b/wp-favorites-plugin/wp-favorites-plugin.php
@@ -0,0 +1,48 @@
+