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
171 changes: 155 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,166 @@
# WordPress Back-end Challenge
# Apiki Favorites Plugin

Desafio para os futuros programadores back-end em WordPress da Apiki.
Plugin WordPress para permitir que usuários logados favoritem posts usando a WP REST API.

## Introdução
## Instalação

Desenvolva um Plugin em WordPress que implemente a funcionalidade de favoritar posts para usuários logados usando a [WP REST API](https://developer.wordpress.org/rest-api/).
1. Faça o download ou clone este repositório.
2. Copie a pasta do plugin para o diretório `wp-content/plugins/` do seu WordPress.
3. Ative o plugin através do menu "Plugins" no WordPress.

**Especifícações**:
## Estrutura de Arquivos

* Possibilidade de favoritar e desfavoritar um post;
* Persistir os dados em uma [tabela a parte](https://codex.wordpress.org/Creating_Tables_with_Plugins);
```
apiki-favorites/
├── apiki-favorites.php # Arquivo principal do plugin
├── README.md # Este arquivo
└── includes/
├── class-activator.php # Classe de ativação (cria a tabela)
├── class-favorites-repository.php # Repositório (persistência no banco)
├── class-favorites-rest-controller.php # Controlador REST API
└── class-plugin.php # Classe principal do plugin
```

## Instruções
## Endpoints da API

1. Efetue o fork deste repositório e crie um branch com o seu nome e sobrenome. (exemplo: fulano-dasilva)
2. Após finalizar o desafio, crie um Pull Request.
3. Aguarde algum contribuidor realizar o code review.
### Favoritar um Post

## Pré-requisitos
- **Endpoint:** `POST /wp-json/apiki/v1/favorites/{post_id}`
- **Autenticação:** Necessária (usuário logado)
- **Exemplo de requisição:**

```
bash
curl -X POST https://seusite.com.br/wp-json/apiki/v1/favorites/123 \
-H "Authorization: Basic base64_encode(username:application_password)"

```

* PHP >= 5.6
* Orientado a objetos
- **Resposta de sucesso (201):**

```
json
{
"message": "Post favoritado com sucesso.",
"data": {
"post_id": 123,
"user_id": 1
}
}

```

## Dúvidas
- **Resposta de erro - Post não encontrado (404):**

```
json
{
"code": "apiki_favorites_post_not_found",
"message": "Post não encontrado.",
"data": {
"status": 404
}
}

```

Em caso de dúvidas, crie uma issue.
- **Resposta de erro - Já favoritado (422):**

```
json
{
"code": "apiki_favorites_already_exists",
"message": "Este post já está favoritado.",
"data": {
"status": 422
}
}

```

### Desfavoritar um Post

- **Endpoint:** `DELETE /wp-json/apiki/v1/favorites/{post_id}`
- **Autenticação:** Necessária (usuário logado)
- **Exemplo de requisição:**

```
bash
curl -X DELETE https://seusite.com.br/wp-json/apiki/v1/favorites/123 \
-H "Authorization: Basic base64_encode(username:application_password)"

```

- **Resposta de sucesso (200):**

```
json
{
"message": "Post desfavoritado com sucesso.",
"data": {
"post_id": 123,
"user_id": 1
}
}

```

- **Resposta de erro - Post não encontrado (404):**

```
json
{
"code": "apiki_favorites_post_not_found",
"message": "Post não encontrado.",
"data": {
"status": 404
}
}

```

- **Resposta de erro - Não favoritado (404):**

```json
{
"code": "apiki_favorites_not_found",
"message": "Este post não está favoritado.",
"data": {
"status": 404
}
}

```

## Tabela do Banco de Dados

O plugin cria uma tabela chamada `{prefix}apiki_favorites` com a seguinte estrutura:

| Coluna | Tipo | Descrição |
|------------|-------------------|---------------------|
| id | bigint(20) | ID único |
| user_id | bigint(20) | ID do usuário |
| post_id | bigint(20) | ID do post |
| created_at | datetime | Data de criação |

A tabela possui uma chave única na combinação (user_id, post_id) para evitar duplicatas.

## Requisitos

- PHP >= 5.6
- WordPress 4.7 ou superior (para REST API)
- Usuário logado para favoritar/desfavoritar

## Autenticação

A API requer autenticação. Você pode usar:

- **Application Passwords** (recomendado para WordPress 5.6+)
- **Cookie Authentication** (para testes locais)
- **JWT Authentication** (se instalado)

Exemplo com Application Password:
```
bash
curl -X POST https://seusite.com.br/wp-json/apiki/v1/favorites/123 \
-u "username:application_password"
42 changes: 42 additions & 0 deletions apiki-favorites.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
/**
* Plugin Name: Apiki Favorites
* Description: Plugin to allow logged-in users to favorite posts using WP REST API.
* Version: 1.0.0
* Author: Apiki
* License: GPL2
* Text Domain: apiki-favorites
*/

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

// Define plugin constants.
define( 'APIKI_FAVORITES_VERSION', '1.0.0' );
define( 'APIKI_FAVORITES_PATH', plugin_dir_path( __FILE__ ) );
define( 'APIKI_FAVORITES_INCLUDES_PATH', APIKI_FAVORITES_PATH . 'includes/' );

/**
* Code that runs during plugin activation.
*/
function apiki_favorites_activate() {
require_once APIKI_FAVORITES_INCLUDES_PATH . 'class-activator.php';
Apiki_Favorites_Activator::activate();
}

register_activation_hook( __FILE__, 'apiki_favorites_activate' );

/**
* Load plugin classes.
*/
function apiki_favorites_load() {
require_once APIKI_FAVORITES_INCLUDES_PATH . 'class-favorites-repository.php';
require_once APIKI_FAVORITES_INCLUDES_PATH . 'class-favorites-rest-controller.php';
require_once APIKI_FAVORITES_INCLUDES_PATH . 'class-plugin.php';

$plugin = new Apiki_Favorites_Plugin();
$plugin->run();
}

add_action( 'plugins_loaded', 'apiki_favorites_load' );
49 changes: 49 additions & 0 deletions includes/class-activator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
/**
* Class to handle plugin activation and database table creation.
*
* @package Apiki_Favorites
*/

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

/**
* Apiki Favorites Activator Class.
*/
class Apiki_Favorites_Activator {

/**
* Run activation tasks.
*
* @return void
*/
public static function activate() {
self::create_table();
}

/**
* Create the favorites table in the database.
*
* @return void
*/
private static function create_table() {
global $wpdb;

$table_name = $wpdb->prefix . 'apiki_favorites';
$charset_collate = $wpdb->get_charset_collate();

$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 DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (id),
UNIQUE KEY unique_user_post (user_id, post_id)
) {$charset_collate};";

require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
}
}
123 changes: 123 additions & 0 deletions includes/class-favorites-repository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?php
/**
* Class to handle favorites database operations.
*
* @package Apiki_Favorites
*/

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

/**
* Apiki Favorites Repository Class.
*/
class Apiki_Favorites_Repository {

/**
* Database table name.
*
* @var string
*/
private $table_name;

/**
* Constructor.
*/
public function __construct() {
global $wpdb;
$this->table_name = $wpdb->prefix . 'apiki_favorites';
}

/**
* Add a favorite for a user and post.
*
* @param int $user_id User ID.
* @param int $post_id Post ID.
* @return bool True on success, false on failure.
*/
public function add_favorite( $user_id, $post_id ) {
global $wpdb;

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

return $result !== false;
}

/**
* Remove a favorite for a user and post.
*
* @param int $user_id User ID.
* @param int $post_id Post ID.
* @return bool True on success, false on failure.
*/
public function remove_favorite( $user_id, $post_id ) {
global $wpdb;

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

return $result !== false;
}

/**
* Check if a post is already favorited by a user.
*
* @param int $user_id User ID.
* @param int $post_id Post ID.
* @return bool True if already favorited, false otherwise.
*/
public function is_favorited( $user_id, $post_id ) {
global $wpdb;

$query = $wpdb->prepare(
"SELECT COUNT(*) FROM {$this->table_name} WHERE user_id = %d AND post_id = %d",
$user_id,
$post_id
);

$count = $wpdb->get_var( $query );

return (int) $count > 0;
}

/**
* Get favorite ID by user and post.
*
* @param int $user_id User ID.
* @param int $post_id Post ID.
* @return int|null Favorite ID or null if not found.
*/
public function get_favorite_id( $user_id, $post_id ) {
global $wpdb;

$query = $wpdb->prepare(
"SELECT id FROM {$this->table_name} WHERE user_id = %d AND post_id = %d",
$user_id,
$post_id
);

return $wpdb->get_var( $query );
}
}
Loading