diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5657f6e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +vendor \ No newline at end of file diff --git a/assets/css/style.css b/assets/css/style.css new file mode 100644 index 0000000..5ccbca0 --- /dev/null +++ b/assets/css/style.css @@ -0,0 +1,28 @@ +.like-button { + padding: 10px; + cursor: pointer; + border-radius: 5px; + transition: all 0.4s ease; + display: flex; + justify-content: center; +} + +.like-button:not(.liked){ + border: 1px solid green!important; + color: green; +} + +.like-button:not(.liked):hover { + background: green; + color: white; +} + +.like-button.liked { + color: red; + border: 1px solid red!important; +} + +.like-button.liked:hover { + background: red; + color: white; +} diff --git a/assets/js/script.js b/assets/js/script.js new file mode 100644 index 0000000..a56a4fb --- /dev/null +++ b/assets/js/script.js @@ -0,0 +1,40 @@ +document.addEventListener('DOMContentLoaded', function () { + const buttons = document.querySelectorAll('.like-button'); + + buttons.forEach(button => { + button.addEventListener('click', function () { + const postId = this.getAttribute('data-post-id'); + const isLiked = this.classList.contains('liked'); + + const method = isLiked ? 'DELETE' : 'POST'; + const endpoint = isLiked ? 'delete' : 'add'; + const url = `/wp-json/like/v1/${endpoint}`; + + fetch(url, { + method: method, + headers: { + 'Content-Type': 'application/json', + 'X-WP-Nonce': wpApiSettings.nonce + }, + body: JSON.stringify({ + post_id: postId + }) + }) + .then(response => { + console.log(response); + if (!response.ok) { + throw new Error('Erro na requisição'); + } + return response.json(); + }) + .then(data => { + console.log(data.message); + this.classList.toggle('liked', !isLiked); + this.textContent = isLiked ? 'Favoritar' : 'Desfavoritar'; + }) + .catch(error => { + alert('Erro: ' + error.message); + }); + }); + }); +}); diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..1842150 --- /dev/null +++ b/composer.json @@ -0,0 +1,13 @@ +{ + "name": "andre-nascimento/favoritar-posts", + "description": "Plugin para favoritar posts no WordPress.", + "type": "wordpress-plugin", + "autoload": { + "psr-4": { + "LikePosts\\": "includes/" + } + }, + "require": { + "php": ">=7.4" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..04347f9 --- /dev/null +++ b/composer.lock @@ -0,0 +1,20 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "071d1dd3227aff23eba292ecd8b541f8", + "packages": [], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.4" + }, + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/includes/Controllers/LikePostsController.php b/includes/Controllers/LikePostsController.php new file mode 100644 index 0000000..53681e1 --- /dev/null +++ b/includes/Controllers/LikePostsController.php @@ -0,0 +1,93 @@ +model = new LikePostsModel(); + $this->model->create_table(); + $this->view = new LikePostsView(); + + add_action('rest_api_init', [$this, 'register_rest_routes']); + add_action('the_content', [$this, 'add_like_button']); + add_action('wp_enqueue_scripts', [$this, 'enqueue_assets']); + } + + public function register_rest_routes() { + register_rest_route('like/v1', '/add', [ + 'methods' => 'POST', + 'callback' => [$this, 'like_post'], + 'permission_callback' => [$this, 'is_user_logged_in'] + ]); + + register_rest_route('like/v1', '/delete', [ + 'methods' => 'DELETE', + 'callback' => [$this, 'dislike_post'], + 'permission_callback' => [$this, 'is_user_logged_in'] + ]); + } + + public function is_user_logged_in() { + return is_user_logged_in(); + } + + public function like_post($request) { + $user_id = get_current_user_id(); + $post_id = intval($request['post_id']); + + if (!$this->is_valid_post($post_id)) { + return new WP_REST_Response(['message' => 'Post inválido!'], 400); + } + + $this->model->like($user_id, $post_id); + return new WP_REST_Response(['message' => 'Post favoritado!'], 200); + } + + public function dislike_post($request) { + $user_id = get_current_user_id(); + $post_id = intval($request['post_id']); + + if (!$this->is_valid_post($post_id)) { + return new WP_REST_Response(['message' => 'Post inválido!'], 400); + } + + $this->model->dislike($user_id, $post_id); + return new WP_REST_Response(['message' => 'Post desfavoritado!'], 200); + } + + + public function add_like_button($content) { + if (!is_single()) { + return $content; + } + + ob_start(); + $this->view->render(get_the_ID()); + $button = ob_get_clean(); + + return $content . $button; + } + + public function enqueue_assets() { + wp_enqueue_style('like-posts-style', plugin_dir_url(__FILE__) . '../../assets/css/style.css'); + wp_enqueue_script('like-posts-script', plugin_dir_url(__FILE__) . '../../assets/js/script.js', [], time(), true); + wp_localize_script('like-posts-script', 'wpApiSettings', [ + 'nonce' => wp_create_nonce('wp_rest') + ]); + } + + public function has_liked_post($user_id, $post_id){ + return $this->model->user_has_liked_post($user_id, $post_id); + } + + private function is_valid_post($post_id) { + return get_post($post_id) !== null; + } +} diff --git a/includes/Models/LikePostsModel.php b/includes/Models/LikePostsModel.php new file mode 100644 index 0000000..96bbf88 --- /dev/null +++ b/includes/Models/LikePostsModel.php @@ -0,0 +1,68 @@ +table_name = $wpdb->prefix . 'most_liked'; + } + + public function create_table() + { + global $wpdb; + + $charset_collate = $wpdb->get_charset_collate(); + $sql = "CREATE TABLE IF NOT EXISTS $this->table_name ( + id mediumint(9) NOT NULL AUTO_INCREMENT, + user_id bigint(20) NOT NULL, + post_id bigint(20) NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY user_post (user_id, post_id) + ) $charset_collate;"; + + require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); + dbDelta($sql); + } + + public function like($user_id, $post_id) + { + global $wpdb; + $wpdb->insert($this->table_name, [ + 'user_id' => $user_id, + 'post_id' => $post_id + ]); + } + + public function dislike($user_id, $post_id) + { + global $wpdb; + $wpdb->delete($this->table_name, [ + 'user_id' => $user_id, + 'post_id' => $post_id + ]); + } + + public function user_has_liked_post($user_id, $post_id) + { + global $wpdb; + + if (!$user_id || !$post_id) { + return false; + } + + $query = $wpdb->prepare( + "SELECT COUNT(*) FROM $this->table_name WHERE user_id = %d AND post_id = %d", + $user_id, + $post_id + ); + + $like_count = $wpdb->get_var($query); + + return $like_count > 0; + } +} diff --git a/includes/Views/AnotherView/.gitkeep b/includes/Views/AnotherView/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/includes/Views/LikePostsView/LikePostsView.php b/includes/Views/LikePostsView/LikePostsView.php new file mode 100644 index 0000000..faa58db --- /dev/null +++ b/includes/Views/LikePostsView/LikePostsView.php @@ -0,0 +1,15 @@ +has_liked_post(get_current_user_id(), $post_id); + include plugin_dir_path(__FILE__) . 'template.php'; + } +} diff --git a/includes/Views/LikePostsView/template.php b/includes/Views/LikePostsView/template.php new file mode 100644 index 0000000..5684f77 --- /dev/null +++ b/includes/Views/LikePostsView/template.php @@ -0,0 +1,9 @@ + + + +
Você precisa estar logado para curtir este post. + Clique aqui para fazer login. +
+ diff --git a/wordpress-back-end-challenge.php b/wordpress-back-end-challenge.php new file mode 100644 index 0000000..be49e5e --- /dev/null +++ b/wordpress-back-end-challenge.php @@ -0,0 +1,18 @@ +