Encoding de caracteres especiais no exposer

Olá, estou trabalhando em um exposer IIIF para o Tainacan. Já consigo criar um manifesto básico (com uma imagem estática) e carregá-lo em um visualizador compatível:

O id do manifesto deve ser a URL em que ele é servido, por exemplo https://wordpress.dvl.to/wp-json/tainacan/v2/collection/7/items/?&exposer=iiif&mapper=dublin-core&id=48. Estou construindo essa string assim:

'id' => get_bloginfo('url') . '/wp-json/tainacan/v2/collection/' . $item_data['collection_id'] . 'items/?exposer=iiif&mapper=dublin-core&id=' . $item_data['id'],
...
$response->set_data(json_encode($manifest, JSON_UNESCAPED_UNICODE));

mas o JSON parece estar sendo encodado por alguma função do WP após a criação no exposer, porque o resultado é "id": "https://wordpress.dvl.to/wp-json/tainacan/v2/collection/7/items/?exposer=iiif&mapper=dublin-core&id=48". Tentei usar funções como htmlspecialchars_decode, sem sucesso. Vocês sabem se é possível evitar isso de alguma maneira? Obrigado!

P.S.: PHP/WP não é minha especialidade (muito pelo contrário). Se tiverem sugestões de como determinar a URL de resposta do exposer de maneira mais elegante (por exemplo com alguma função do WP como get_bloginfo, etc) por favor me digam :slight_smile:

1 curtida

Salve @martimpassos! Cara que massa isso do integrador IFFF tô bastante empolgado pra ver isso aí rodando…

Sobre a questão do encode… pra ser sincero eu não tenho certeza. Dei aquela investigada no ChatGPT e o retorno foi o seguinte, me diga se algum deles resolve…

O problema é causado pelo fato de o WordPress automaticamente escapar caracteres especiais como & ao construir a resposta JSON. Isso é um comportamento comum no WordPress para evitar problemas de segurança e garantir que a saída seja segura para uso em HTML.

Aqui está como ele pode resolver isso:

Solução 1: Use wp_specialchars_decode

Ao invés de usar htmlspecialchars_decode, ele pode tentar usar a função wp_specialchars_decode antes de passar o JSON ao set_data. Essa função foi projetada para lidar com o escaping feito pelo WordPress:

$response->set_data(json_encode($manifest, JSON_UNESCAPED_UNICODE));
$response->set_data(wp_specialchars_decode($response->get_data()));

Solução 2: Modificar o valor diretamente no manifesto

Se o problema ocorrer durante a criação do manifesto (antes de passar para set_data), ele pode usar html_entity_decode ou wp_specialchars_decode diretamente no campo id antes de encodar o JSON:

$manifest['id'] = wp_specialchars_decode($manifest['id'], ENT_QUOTES);
$response->set_data(json_encode($manifest, JSON_UNESCAPED_UNICODE));

Solução 3: Usar o parâmetro ENT_NOQUOTES em htmlspecialchars_decode

Se nenhuma das opções acima funcionar, vale a pena testar com o parâmetro ENT_NOQUOTES:

$manifest['id'] = htmlspecialchars_decode($manifest['id'], ENT_NOQUOTES);
$response->set_data(json_encode($manifest, JSON_UNESCAPED_UNICODE));

Solução 4: Retornar o JSON como string na resposta

Caso nenhuma das opções funcione e ele tenha controle total sobre a resposta, pode-se evitar que o WordPress escape automaticamente os caracteres ao definir o cabeçalho da resposta como application/json e retornar o JSON como uma string bruta:

$response = new WP_REST_Response();
$response->set_headers(['Content-Type' => 'application/json']);
$response->set_data(json_encode($manifest, JSON_UNESCAPED_UNICODE));
return $response;

Oi @mateus.m.luna, agradeço a empolgação. Acho que pode ser algo benéfico para toda a comunidade Tainacan!

Engraçado, quando você sugeriu essa função achei que tinha resolvido o problema, porque ela parece exatamente o que preciso. Mas tentei incluí-la em vários momentos do código (antes de set_data, depois de set_data, etc) e nada.

Tentando a solução 4 tive um problema com stripcslashes() no exposers-handler:

$response = new \WP_REST_Response();
$response->set_headers(['Content-Type' => 'application/ld+json']);
$response->set_data(json_encode($manifest, JSON_UNESCAPED_UNICODE));
stripcslashes() expects parameter 1 to be string, array given

Achei estranho, porque teoricamente a função json_encode() já retorna uma string… Tentei forçar o tipo mas o erro persiste:

$response_data = (string) json_encode($manifest, JSON_UNESCAPED_UNICODE);
$response = new \WP_REST_Response();
$response->set_headers(['Content-Type' => 'application/ld+json']);
$response->set_data($response_data);

A solução sugerida pelo ChatGPT envolve modificar a chamada de stripcslashes, mas não me parece uma boa ideia.

Acabei “resolvendo” com uma regra de rewrite de

/wp-json/tainacan/v2/collection/7/items/?&exposer=iiif&mapper=dublin-core&id=139

para

/iiif/139/manifest

Assim não preciso de caracteres especiais no id. Existe alguma maneira de fazer esse rewrite ser parte do exposer? Eu fiz incluindo em functions.php, mas idealmente o usuário não precisaria fazer isso manualmente.

Outra opção, como estou tendo que criar um outro plugin para a parte da API de imagens, seria fazer com que esse plugin

  • Implementasse a API de imagem
  • Adicionasse o exposer IIIF (isso é possível?)
  • Criasse a regra de rewrite

E, claro, existe a opção de shipar ‘tudo’ isso com o Tainacan. Qual caminho você acha que faz mais sentido?