diff --git a/admin/class-favorite-posts-admin.php b/admin/class-favorite-posts-admin.php new file mode 100644 index 00000000..781b5b5d --- /dev/null +++ b/admin/class-favorite-posts-admin.php @@ -0,0 +1,128 @@ +plugin_name = $plugin_name; + $this->version = $version; + $this->database = new Favorite_Posts_Database(); + } + + public function add_favorites_column( $columns ) { + $new_columns = array(); + foreach ( $columns as $key => $value ) { + $new_columns[ $key ] = $value; + if ( 'title' === $key ) { + $new_columns['favorite_count'] = 'Favoritos'; + } + } + return $new_columns; + } + + public function display_favorites_column_content( $column, $post_id ) { + if ( 'favorite_count' === $column ) { + global $wpdb; + $table_name = $wpdb->prefix . 'favorite_posts'; + $count = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$table_name} WHERE post_id = %d", $post_id ) ); + echo $count; + } + } + + public function register_favorites_sortable_column( $columns ) { + $columns['favorite_count'] = 'favorite_count_numeric'; + return $columns; + } + + public function custom_favorites_column_orderby( $query ) { + if ( ! is_admin() || ! $query->is_main_query() ) { + return; + } + + $orderby = $query->get( 'orderby' ); + + if ( 'favorite_count_numeric' === $orderby ) { + global $wpdb; + $table_name = $wpdb->prefix . 'favorite_posts'; + $query->set( 'orderby', "(SELECT COUNT(fp.post_id) FROM {$table_name} AS fp WHERE fp.post_id = {$wpdb->posts}.ID) " . $query->get( 'order' ) ); + } + } + + public function add_plugin_admin_menu() { + add_menu_page( + 'Posts Favoritos - Configurações', + 'Posts Favoritos', + 'manage_options', + $this->plugin_name . '_settings', + array( $this, 'display_plugin_setup_page' ), + 'dashicons-star-filled', + 60 + ); + } + + public function display_plugin_setup_page() { + ?> +
+

Posts Favoritos - Configurações

+ +

Como usar o botão de Favoritar

+

Para exibir o botão "Favoritar" em qualquer lugar do seu site, utilize o shortcode [favorite_button].

+ +

Opções do Shortcode:

+ + +

O botão só será exibido para usuários logados.

+
+ plugin_name . '-deactivation-modal', + plugin_dir_url( __FILE__ ) . '../public/js/favorite-posts-admin-deactivate-modal.js', + array( 'jquery', 'sweetalert2' ), + $this->version, + true + ); + + wp_localize_script( + $this->plugin_name . '-deactivation-modal', + 'favoritePostsDeactivationData', + array( + 'plugin_slug' => $this->plugin_name, + 'modal_title' => 'Desativar Posts Favoritos?', + 'modal_text' => 'Você deseja manter os dados de posts favoritos no banco de dados?', + 'confirm_text' => 'Sim, manter dados', + 'cancel_text' => 'Não, excluir tudo', + 'deny_text' => 'Cancelar desativação', + 'keep_data_value' => 'no', + 'delete_data_value' => 'yes', + 'is_rtl' => is_rtl(), + ) + ); + } + } +} \ No newline at end of file diff --git a/favorite-posts.php b/favorite-posts.php new file mode 100644 index 00000000..5ce72b30 --- /dev/null +++ b/favorite-posts.php @@ -0,0 +1,29 @@ +run(); +} +run_favorite_posts(); \ No newline at end of file diff --git a/includes/class-favorite-posts-activator.php b/includes/class-favorite-posts-activator.php new file mode 100644 index 00000000..c3f86b0c --- /dev/null +++ b/includes/class-favorite-posts-activator.php @@ -0,0 +1,26 @@ +prefix . 'favorite_posts'; + $charset_collate = $wpdb->get_charset_collate(); + + $sql = "CREATE TABLE $table_name ( + id bigint(20) NOT NULL AUTO_INCREMENT, + user_id bigint(20) NOT NULL, + post_id bigint(20) NOT NULL, + favorited_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY user_post_pair (user_id,post_id) + ) $charset_collate;"; + + require_once ABSPATH . 'wp-admin/includes/upgrade.php'; + dbDelta( $sql ); + + if ( get_option( 'favorite_posts_delete_data_on_uninstall' ) === false ) { + add_option( 'favorite_posts_delete_data_on_uninstall', 'no' ); + } + } +} \ No newline at end of file diff --git a/includes/class-favorite-posts-database.php b/includes/class-favorite-posts-database.php new file mode 100644 index 00000000..c2dfdb59 --- /dev/null +++ b/includes/class-favorite-posts-database.php @@ -0,0 +1,108 @@ +table_name = $wpdb->prefix . 'favorite_posts'; + $this->charset_collate = $wpdb->get_charset_collate(); + } + + public function create_table() { + if ( $this->table_exists() ) { + return; + } + + $sql = "CREATE TABLE {$this->table_name} ( + id bigint(20) NOT NULL AUTO_INCREMENT, + user_id bigint(20) NOT NULL, + post_id bigint(20) NOT NULL, + favorited_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY user_post_id (user_id,post_id) + ) {$this->charset_collate};"; + + require_once ABSPATH . 'wp-admin/includes/upgrade.php'; + dbDelta( $sql ); + } + + public function delete_table() { + global $wpdb; + $wpdb->query( "DROP TABLE IF EXISTS {$this->table_name}" ); + } + + private function table_exists() { + global $wpdb; + return $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $this->table_name ) ) === $this->table_name; + } + + public function add_favorite( $user_id, $post_id ) { + global $wpdb; + $wpdb->insert( + $this->table_name, + array( + 'user_id' => $user_id, + 'post_id' => $post_id, + 'favorited_at' => current_time( 'mysql' ), + ), + array( + '%d', + '%d', + '%s', + ) + ); + return $wpdb->insert_id; + } + + public function remove_favorite( $user_id, $post_id ) { + global $wpdb; + return $wpdb->delete( + $this->table_name, + array( + 'user_id' => $user_id, + 'post_id' => $post_id, + ), + array( + '%d', + '%d', + ) + ); + } + + public function is_favorited( $user_id, $post_id ) { + global $wpdb; + $count = $wpdb->get_var( + $wpdb->prepare( + "SELECT COUNT(*) FROM {$this->table_name} WHERE user_id = %d AND post_id = %d", + $user_id, + $post_id + ) + ); + return (bool) $count; + } + + public function get_favorite_count( $post_id ) { + global $wpdb; + $count = $wpdb->get_var( + $wpdb->prepare( + "SELECT COUNT(*) FROM {$this->table_name} WHERE post_id = %d", + $post_id + ) + ); + return (int) $count; + } + + public function get_user_favorites( $user_id ) { + global $wpdb; + $results = $wpdb->get_col( + $wpdb->prepare( + "SELECT post_id FROM {$this->table_name} WHERE user_id = %d", + $user_id + ) + ); + return array_map( 'absint', $results ); + } +} \ No newline at end of file diff --git a/includes/class-favorite-posts-deactivator.php b/includes/class-favorite-posts-deactivator.php new file mode 100644 index 00000000..e9d593b3 --- /dev/null +++ b/includes/class-favorite-posts-deactivator.php @@ -0,0 +1,14 @@ +delete_table(); + } + } +} \ No newline at end of file diff --git a/includes/class-favorite-posts-loader.php b/includes/class-favorite-posts-loader.php new file mode 100644 index 00000000..7bd06f20 --- /dev/null +++ b/includes/class-favorite-posts-loader.php @@ -0,0 +1,41 @@ +actions = array(); + $this->filters = array(); + } + + public function add_action( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) { + $this->actions = $this->add( $this->actions, $hook, $component, $callback, $priority, $accepted_args ); + } + + public function add_filter( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) { + $this->filters = $this->add( $this->filters, $hook, $component, $callback, $priority, $accepted_args ); + } + + private function add( $hooks, $hook, $component, $callback, $priority, $accepted_args ) { + $hooks[] = array( + 'hook' => $hook, + 'component' => $component, + 'callback' => $callback, + 'priority' => $priority, + 'accepted_args' => $accepted_args + ); + return $hooks; + } + + public function run() { + foreach ( $this->filters as $hook ) { + add_filter( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] ); + } + + foreach ( $this->actions as $hook ) { + add_action( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] ); + } + } +} \ No newline at end of file diff --git a/includes/class-favorite-posts-public.php b/includes/class-favorite-posts-public.php new file mode 100644 index 00000000..dcb15201 --- /dev/null +++ b/includes/class-favorite-posts-public.php @@ -0,0 +1,120 @@ +plugin_name = $plugin_name; + $this->version = $version; + } + + public function enqueue_scripts() { + wp_enqueue_style( + 'sweetalert2', + 'https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css', + array(), + '11.0.0', + 'all' + ); + + wp_enqueue_script( + 'sweetalert2', + 'https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.all.min.js', + array(), + '11.0.0', + true + ); + + wp_enqueue_style( + 'font-awesome-free', + 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css', + array(), + '6.5.2', + 'all' + ); + + wp_enqueue_style( + $this->plugin_name, + plugin_dir_url( __FILE__ ) . '../public/css/favorite-posts-public.css', + array(), + $this->version, + 'all' + ); + + wp_enqueue_script( + $this->plugin_name, + plugin_dir_url( __FILE__ ) . '../public/js/favorite-posts-public.js', + array( 'jquery', 'sweetalert2' ), + $this->version, + true + ); + + wp_localize_script( + $this->plugin_name, + 'favoritePostsData', + array( + 'root' => esc_url_raw( rest_url() ), + 'nonce' => wp_create_nonce( 'wp_rest' ), + 'namespace' => 'favorite-posts/v1', + 'is_user_logged_in' => is_user_logged_in(), + 'i18n' => array( + 'favorite' => 'Favoritar', + 'unfavorite' => 'Desfavoritar', + 'success_title' => 'Sucesso!', + 'error_title' => 'Erro!', + 'confirm_button' => 'Ok', + 'login_required_title' => 'Atenção!', + 'login_required_text' => 'Para favoritar posts, você precisa estar logado. Que tal criar uma conta ou fazer login agora?', // Nova string + ), + ) + ); + } + + public function register_favorite_button_shortcode() { + add_shortcode( 'favorite_button', array( $this, 'favorite_button_shortcode' ) ); + } + + public function favorite_button_shortcode( $atts ) { + global $post; + + $atts = shortcode_atts( array( + 'post_id' => 0, + ), $atts, 'favorite_button' ); + + $post_id = (int) $atts['post_id']; + + if ( $post_id === 0 && is_singular() && isset( $post->ID ) ) { + $post_id = $post->ID; + } + + if ( $post_id === 0 ) { + return ''; + } + + $is_logged_in = is_user_logged_in(); + $button_classes = 'favorite-post-button'; + $wrapper_classes = 'favorite-post-wrapper'; + $data_attributes = 'data-post-id="' . esc_attr( $post_id ) . '"'; + + if ( ! $is_logged_in ) { + $button_classes .= ' is-logged-out'; + $wrapper_classes .= ' is-logged-out-wrapper'; + } + + ob_start(); + ?> +
+ + + Faça login para favoritar! + +
+ database = $database; + } + + public function register_routes() { + register_rest_route( $this->namespace, '/favorite/(?P\d+)', array( + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'favorite_post' ), + 'permission_callback' => array( $this, 'user_logged_in_permission' ), + 'args' => array( + 'post_id' => array( + 'validate_callback' => function( $param, $request, $key ) { + return is_numeric( $param ) && get_post_status( (int) $param ); + }, + ), + ), + ) ); + + register_rest_route( $this->namespace, '/unfavorite/(?P\d+)', array( + 'methods' => WP_REST_Server::DELETABLE, + 'callback' => array( $this, 'unfavorite_post' ), + 'permission_callback' => array( $this, 'user_logged_in_permission' ), + 'args' => array( + 'post_id' => array( + 'validate_callback' => function( $param, $request, $key ) { + return is_numeric( $param ) && get_post_status( (int) $param ); + }, + ), + ), + ) ); + + register_rest_route( $this->namespace, '/is-favorited/(?P\d+)', array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'is_post_favorited' ), + 'permission_callback' => array( $this, 'user_logged_in_permission' ), + 'args' => array( + 'post_id' => array( + 'validate_callback' => function( $param, $request, $key ) { + return is_numeric( $param ) && get_post_status( (int) $param ); + }, + ), + ), + ) ); + + register_rest_route( $this->namespace, '/favorites', array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_user_favorites' ), + 'permission_callback' => array( $this, 'user_logged_in_permission' ), + ) ); + } + + public function favorite_post( WP_REST_Request $request ) { + $post_id = (int) $request['post_id']; + $user_id = get_current_user_id(); + + if ( $this->database->is_favorited( $user_id, $post_id ) ) { + return new WP_REST_Response( array( 'message' => 'Post já favoritado.', 'favorited' => true ), 200 ); + } + + $result = $this->database->add_favorite( $user_id, $post_id ); + + if ( $result ) { + return new WP_REST_Response( array( 'message' => 'Post favoritado com sucesso.', 'favorited' => true, 'post_id' => $post_id ), 200 ); + } else { + return new WP_Error( 'favorite_failed', 'Não foi possível favoritar o post.', array( 'status' => 500 ) ); + } + } + + public function unfavorite_post( WP_REST_Request $request ) { + $post_id = (int) $request['post_id']; + $user_id = get_current_user_id(); + + if ( ! $this->database->is_favorited( $user_id, $post_id ) ) { + return new WP_REST_Response( array( 'message' => 'Post não está favoritado.', 'favorited' => false ), 200 ); + } + + $result = $this->database->remove_favorite( $user_id, $post_id ); + + if ( $result ) { + return new WP_REST_Response( array( 'message' => 'Post desfavoritado com sucesso.', 'favorited' => false, 'post_id' => $post_id ), 200 ); + } else { + return new WP_Error( 'unfavorite_failed', 'Não foi possível desfavoritar o post.', array( 'status' => 500 ) ); + } + } + + public function is_post_favorited( WP_REST_Request $request ) { + $post_id = (int) $request['post_id']; + $user_id = get_current_user_id(); + + $is_favorited = $this->database->is_favorited( $user_id, $post_id ); + + return new WP_REST_Response( array( 'is_favorited' => $is_favorited ), 200 ); + } + + public function get_user_favorites( WP_REST_Request $request ) { + $user_id = get_current_user_id(); + $favorite_post_ids = $this->database->get_user_favorites( $user_id ); + + $favorited_posts_data = array(); + if ( ! empty( $favorite_post_ids ) ) { + $args = array( + 'post_type' => 'post', + 'post__in' => $favorite_post_ids, + 'posts_per_page' => -1, + 'orderby' => 'post__in', + 'fields' => 'ids', + ); + $query = new WP_Query( $args ); + + if ( $query->have_posts() ) { + foreach ( $query->posts as $post_id ) { + $post = WP_Post::get_instance( $post_id ); + if ( $post ) { + $favorited_posts_data[] = array( + 'id' => $post->ID, + 'title' => $post->post_title, + 'link' => get_permalink( $post->ID ), + 'date' => $post->post_date, + ); + } + } + } + wp_reset_postdata(); + } + + return new WP_REST_Response( array( 'favorites' => $favorited_posts_data ), 200 ); + } + + public function user_logged_in_permission( WP_REST_Request $request ) { + return is_user_logged_in(); + } +} \ No newline at end of file diff --git a/includes/class-favorite-posts.php b/includes/class-favorite-posts.php new file mode 100644 index 00000000..0881f67e --- /dev/null +++ b/includes/class-favorite-posts.php @@ -0,0 +1,75 @@ +plugin_name = 'favorite-posts'; + $this->version = '1.0.0'; + + $this->load_dependencies(); + $this->define_admin_hooks(); + $this->define_public_hooks(); + $this->define_rest_api_hooks(); + } + + private function load_dependencies() { + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-favorite-posts-loader.php'; + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-favorite-posts-database.php'; + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-favorite-posts-rest-controller.php'; + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-favorite-posts-public.php'; + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-favorite-posts-admin.php'; + + $this->loader = new Favorite_Posts_Loader(); + } + + private function define_admin_hooks() { + $plugin_admin = new Favorite_Posts_Admin( $this->get_plugin_name(), $this->get_version() ); + + $post_types = get_post_types( array( 'public' => true ), 'names' ); + foreach ( $post_types as $post_type ) { + if ( in_array( $post_type, array( 'attachment', 'revision', 'nav_menu_item', 'custom_css', 'customize_changeset' ) ) ) { + continue; + } + $this->loader->add_filter( "manage_{$post_type}_posts_columns", $plugin_admin, 'add_favorites_column' ); + $this->loader->add_action( "manage_{$post_type}_posts_custom_column", $plugin_admin, 'display_favorites_column_content', 10, 2 ); + $this->loader->add_filter( "manage_edit-{$post_type}_sortable_columns", $plugin_admin, 'register_favorites_sortable_column' ); + $this->loader->add_action( 'pre_get_posts', $plugin_admin, 'custom_favorites_column_orderby' ); + } + + $this->loader->add_action( 'admin_menu', $plugin_admin, 'add_plugin_admin_menu' ); + + $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_deactivation_modal_scripts' ); + } + + private function define_public_hooks() { + $plugin_public = new Favorite_Posts_Public( $this->get_plugin_name(), $this->get_version() ); + $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' ); + $this->loader->add_action( 'init', $plugin_public, 'register_favorite_button_shortcode' ); + } + + private function define_rest_api_hooks() { + $database = new Favorite_Posts_Database(); + $rest_controller = new Favorite_Posts_REST_Controller( $database ); + $this->loader->add_action( 'rest_api_init', $rest_controller, 'register_routes' ); + } + + public function run() { + $this->loader->run(); + } + + public function get_plugin_name() { + return $this->plugin_name; + } + + public function get_loader() { + return $this->loader; + } + + public function get_version() { + return $this->version; + } +} \ No newline at end of file diff --git a/public/css/favorite-posts-public.css b/public/css/favorite-posts-public.css new file mode 100644 index 00000000..5c71918f --- /dev/null +++ b/public/css/favorite-posts-public.css @@ -0,0 +1,45 @@ +.favorite-post-wrapper { + display: flex; + align-items: center; + gap: 10px; + margin-left: 10px; +} + +.favorite-post-button { + background: none; + border: none; + cursor: pointer; + font-size: 1.5em; + padding: 0; + line-height: 1; + color: #ccc; + display: flex; + align-items: center; + justify-content: center; +} + +.favorite-post-button.is-logged-out { + opacity: 0.7; + cursor: help; +} + +.favorite-post-button .favorite-icon-outline, +.favorite-post-button .favorite-icon-filled { + display: none; + line-height: 1; +} + +.favorite-post-button:not(.is-favorited) .favorite-icon-outline { + display: inline-block; +} + +.favorite-post-button.is-favorited .favorite-icon-filled { + display: inline-block; + color: #e74c3c; +} + +.favorite-login-message { + font-size: 0.9em; + color: #555; + white-space: nowrap; +} \ No newline at end of file diff --git a/public/js/favorite-posts-admin-deactivate-modal.js b/public/js/favorite-posts-admin-deactivate-modal.js new file mode 100644 index 00000000..9f4de181 --- /dev/null +++ b/public/js/favorite-posts-admin-deactivate-modal.js @@ -0,0 +1,38 @@ +jQuery(document).ready(function($) { + const data = window.favoritePostsDeactivationData; + + if (!data || !data.plugin_slug) { + return; + } + + const deactivateLink = $(`tr[data-slug="${data.plugin_slug}"] .deactivate a`); + + if (deactivateLink.length === 0) { + return; + } + + const originalDeactivateUrl = deactivateLink.attr('href'); + + deactivateLink.on('click', function(e) { + e.preventDefault(); + + Swal.fire({ + title: data.modal_title, + text: data.modal_text, + icon: 'question', + showDenyButton: true, + showCancelButton: true, + confirmButtonText: data.confirm_text, + cancelButtonText: data.cancel_text, + denyButtonText: data.deny_text, + reverseButtons: data.is_rtl + }).then((result) => { + if (result.isConfirmed) { + window.location.href = originalDeactivateUrl + '&_favorite_posts_delete_data=' + data.keep_data_value; + } else if (result.isDismissed && result.dismiss === Swal.DismissReason.cancel) { + window.location.href = originalDeactivateUrl + '&_favorite_posts_delete_data=' + data.delete_data_value; + } else if (result.isDenied) { + } + }); + }); +}); \ No newline at end of file diff --git a/public/js/favorite-posts-public.js b/public/js/favorite-posts-public.js new file mode 100644 index 00000000..81ad37ed --- /dev/null +++ b/public/js/favorite-posts-public.js @@ -0,0 +1,145 @@ +jQuery(document).ready(function($) { + const favoritePostsData = window.favoritePostsData; + + if (!favoritePostsData || !favoritePostsData.root || !favoritePostsData.nonce || !favoritePostsData.namespace) { + console.error('Dados do plugin Favorite Posts não inicializados corretamente.'); + return; + } + + const restRoot = favoritePostsData.root; + const restNonce = favoritePostsData.nonce; + const namespace = favoritePostsData.namespace; + const isUserLoggedIn = favoritePostsData.is_user_logged_in; + const i18n = favoritePostsData.i18n; + + function updateButtonState($button, isFavorited) { + const $outlineIcon = $button.find('.favorite-icon-outline'); + const $filledIcon = $button.find('.favorite-icon-filled'); + + if (isFavorited) { + $button.addClass('is-favorited'); + $outlineIcon.hide(); + $filledIcon.show(); + } else { + $button.removeClass('is-favorited'); + $outlineIcon.show(); + $filledIcon.hide(); + } + } + + function checkFavoriteStatus(postId, $button) { + if (!isUserLoggedIn) { + updateButtonState($button, false); + return; + } + + $.ajax({ + url: `${restRoot}${namespace}/is-favorited/${postId}`, + method: 'GET', + beforeSend: function(xhr) { + xhr.setRequestHeader('X-WP-Nonce', restNonce); + }, + success: function(response) { + updateButtonState($button, response.is_favorited); + }, + error: function(jqXHR, textStatus, errorThrown) { + console.error('Erro ao verificar status de favorito:', textStatus, errorThrown, jqXHR.responseJSON); + Swal.fire({ + icon: 'error', + title: i18n.error_title, + text: 'Não foi possível verificar o status de favorito.', + confirmButtonText: i18n.confirm_button + }); + } + }); + } + + $('.favorite-post-button').each(function() { + const $this = $(this); + const postId = $this.data('post-id'); + if (postId) { + checkFavoriteStatus(postId, $this); + } + }); + + $(document).on('click', '.favorite-post-button', function(e) { + e.preventDefault(); + const $button = $(this); + const postId = $button.data('post-id'); + + if (!isUserLoggedIn) { + Swal.fire({ + icon: 'info', + title: i18n.login_required_title, + text: i18n.login_required_text, + confirmButtonText: i18n.confirm_button + }); + return; + } + + if (!postId) { + console.error('ID do post não disponível.'); + Swal.fire({ + icon: 'error', + title: i18n.error_title, + text: 'ID do post não encontrado.', + confirmButtonText: i18n.confirm_button + }); + return; + } + + let method; + let endpoint; + let successMessage; + + if ($button.hasClass('is-favorited')) { + method = 'DELETE'; + endpoint = `${restRoot}${namespace}/unfavorite/${postId}`; + successMessage = 'Post desfavoritado com sucesso!'; + } else { + method = 'POST'; + endpoint = `${restRoot}${namespace}/favorite/${postId}`; + successMessage = 'Post favoritado com sucesso!'; + } + + $.ajax({ + url: endpoint, + method: method, + beforeSend: function(xhr) { + xhr.setRequestHeader('X-WP-Nonce', restNonce); + $button.prop('disabled', true); + }, + success: function(response) { + if (response.favorited !== undefined) { + updateButtonState($button, response.favorited); + } + Swal.fire({ + icon: 'success', + title: i18n.success_title, + text: response.message || successMessage, + showConfirmButton: false, + timer: 1500 + }); + }, + error: function(jqXHR, textStatus, errorThrown) { + console.error('API Error:', textStatus, errorThrown, jqXHR.responseJSON); + let errorMessage = i18n.error_title; + if (jqXHR.responseJSON && jqXHR.responseJSON.message) { + errorMessage = jqXHR.responseJSON.message; + } else if (textStatus) { + errorMessage = `Erro: ${textStatus}`; + } + + Swal.fire({ + icon: 'error', + title: i18n.error_title, + text: errorMessage, + confirmButtonText: i18n.confirm_button + }); + }, + complete: function() { + $button.prop('disabled', false); + } + }); + }); +}); \ No newline at end of file