Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions apiki-favorites/apiki-favorites.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
/**
* Plugin Name: Apiki Favorites
* Plugin URI: https://apiki.com/
* Description: Plugin para favoritar e desfavoritar posts via WP REST API para usuários logados.
* Version: 1.0.0
* Author: Wilton Gomes
* Author URI: https://apiki.com/
* Text Domain: apiki-favorites
* Requires PHP: 7.4
*/

if (!defined('ABSPATH')) {
exit;
}

define('APIKI_FAVORITES_VERSION', '1.0.0');
define('APIKI_FAVORITES_FILE', __FILE__);
define('APIKI_FAVORITES_PATH', plugin_dir_path(__FILE__));
define('APIKI_FAVORITES_URL', plugin_dir_url(__FILE__));

require_once APIKI_FAVORITES_PATH . 'includes/class-apiki-favorites-installer.php';
require_once APIKI_FAVORITES_PATH . 'includes/class-apiki-favorites-repository.php';
require_once APIKI_FAVORITES_PATH . 'includes/class-apiki-favorites-rest-controller.php';
require_once APIKI_FAVORITES_PATH . 'includes/class-apiki-favorites-shortcode.php';
require_once APIKI_FAVORITES_PATH . 'includes/class-apiki-favorites-plugin.php';

register_activation_hook(APIKI_FAVORITES_FILE, array('Apiki_Favorites_Installer', 'activate'));

function apiki_favorites_run(): void
{
$plugin = new Apiki_Favorites_Plugin();
$plugin->initialize();
}

apiki_favorites_run();
60 changes: 60 additions & 0 deletions apiki-favorites/assets/apiki-favorites.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
(function () {
'use strict';

function updateButtonState(button, favorited, text) {
button.setAttribute('data-favorited', favorited ? 'true' : 'false');
button.setAttribute('aria-pressed', favorited ? 'true' : 'false');
button.disabled = false;
button.textContent = text;
}

function handleClick(event) {
var button = event.target;

if (!button.classList.contains('apiki-favorite-button')) {
return;
}

event.preventDefault();

if (!window.apikiFavorites || !window.apikiFavorites.isLoggedIn) {
window.alert(window.apikiFavorites.loginRequiredText);
return;
}

var postId = parseInt(button.getAttribute('data-post-id'), 10);
var favorited = button.getAttribute('data-favorited') === 'true';
var method = favorited ? 'DELETE' : 'POST';
var nextText = favorited ? window.apikiFavorites.favoriteText : window.apikiFavorites.unfavoriteText;

if (!postId) {
return;
}

button.disabled = true;
button.textContent = window.apikiFavorites.loadingText;

window.fetch(window.apikiFavorites.restUrl + postId, {
method: method, credentials: 'same-origin', headers: {
'X-WP-Nonce': window.apikiFavorites.nonce, 'Content-Type': 'application/json'
}
})
.then(function (response) {
if (!response.ok) {
throw new Error('Request failed');
}

return response.json();
})
.then(function () {
updateButtonState(button, !favorited, nextText);
})
.catch(function () {
button.disabled = false;
button.textContent = favorited ? window.apikiFavorites.unfavoriteText : window.apikiFavorites.favoriteText;
window.alert(window.apikiFavorites.errorText);
});
}

document.addEventListener('click', handleClick);
}());
46 changes: 46 additions & 0 deletions apiki-favorites/includes/class-apiki-favorites-installer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}

class Apiki_Favorites_Installer {

const DB_VERSION = '1.0.0';
const OPTION_DB_VERSION = 'apiki_favorites_db_version';

public static function activate(): void
{
self::createTable();
update_option( self::OPTION_DB_VERSION, self::DB_VERSION );
}

public static function getTableName(): string
{
global $wpdb;

return $wpdb->prefix . 'apiki_favorites';
}

private static function createTable(): void
{
global $wpdb;

$table_name = self::getTableName();
$charset_collate = $wpdb->get_charset_collate();

require_once ABSPATH . 'wp-admin/includes/upgrade.php';

$sql = "CREATE TABLE {$table_name} (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
user_id BIGINT(20) UNSIGNED NOT NULL,
post_id BIGINT(20) UNSIGNED NOT NULL,
created_at DATETIME NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY user_post_unique (user_id, post_id),
KEY user_id (user_id),
KEY post_id (post_id)
) {$charset_collate};";

dbDelta( $sql );
}
}
38 changes: 38 additions & 0 deletions apiki-favorites/includes/class-apiki-favorites-plugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php
if (!defined('ABSPATH')) {
exit;
}

class Apiki_Favorites_Plugin
{

/**
* @var Apiki_Favorites_Repository
*/
private $repository;

/**
* @var Apiki_Favorites_REST_Controller
*/
private $rest_controller;

/**
* @var Apiki_Favorites_Shortcode
*/
private $shortcode;

public function __construct()
{
$this->repository = new Apiki_Favorites_Repository();
$this->rest_controller = new Apiki_Favorites_REST_Controller($this->repository);
$this->shortcode = new Apiki_Favorites_Shortcode($this->repository);
}

public function initialize(): void
{
add_action('rest_api_init', array($this->rest_controller, 'register_routes'));
add_action('wp_enqueue_scripts', array($this->shortcode, 'registerAssets'));
add_shortcode('apiki_favorite_button', array($this->shortcode, 'showButton'));
add_shortcode('apiki_favorite_list', array($this->shortcode, 'showFavoriteList'));
}
}
119 changes: 119 additions & 0 deletions apiki-favorites/includes/class-apiki-favorites-repository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<?php
if (!defined('ABSPATH')) {
exit;
}

class Apiki_Favorites_Repository
{

/**
* @var string
*/
private $table_name;

public function __construct()
{
$this->table_name = Apiki_Favorites_Installer::getTableName();
}

/**
* @param int $user_id
* @param int $post_id
* @return bool
*/
public function favorite($user_id, $post_id): bool
{
global $wpdb;

$existing = $this->exists($user_id, $post_id);

if ($existing) {
return true;
}

$inserted = $wpdb->insert(
$this->table_name,
array(
'user_id' => (int)$user_id,
'post_id' => (int)$post_id,
'created_at' => current_time('mysql', true),
),
array(
'%d',
'%d',
'%s',
)
);

return false !== $inserted;
}

/**
* @param int $user_id
* @param int $post_id
* @return bool
*/
public function unfavorite($user_id, $post_id): bool
{
global $wpdb;

$deleted = $wpdb->delete(
$this->table_name,
array(
'user_id' => (int)$user_id,
'post_id' => (int)$post_id,
),
array(
'%d',
'%d',
)
);

return false !== $deleted;
}

/**
* @param int $user_id
* @param int $post_id
* @return bool
*/
public function exists($user_id, $post_id): bool
{
global $wpdb;

$sql = $wpdb->prepare(
"SELECT 1 FROM {$this->table_name} WHERE user_id = %d AND post_id = %d LIMIT 1",
(int)$user_id,
(int)$post_id
);

$result = $wpdb->get_var($sql);

return !empty($result);
}

/**
* @param int $user_id
* @return array
*/
public function get_user_favorites($user_id): array
{
global $wpdb;

$sql = $wpdb->prepare(
"SELECT post_id, created_at
FROM {$this->table_name}
WHERE user_id = %d
ORDER BY created_at DESC",
(int)$user_id
);

$results = $wpdb->get_results($sql, ARRAY_A);

if (empty($results)) {
return array();
}

return $results;
}
}
Loading