Open ANONIMNIQ opened 4 years ago
Hi I'm successfully using this with WordPress. I will share some of my code here. First here is how I include the scripts (there are two scripts):
wp_enqueue_script(
'annotator',
THEME_REL . '/assets/annotator.min.js',
'jquery',
filemtime( THEME_ABS . '/assets/annotator.min.js' ),
true
);
wp_enqueue_script(
'e-edition-script',
THEME_REL . '/assets/e-edition.js',
jquery',
filemtime( THEME_ABS . '/assets/e-edition.js' ),
true
);
The e-edition.js
script contains the following script:
jQuery(function($) {
let app = new annotator.App();
app.include(annotator.ui.main);
app.include(annotator.storage.http, {
prefix: theme_l10n.siteURL +'/wp-json/annotation-notes/v1'
});
app.start().then(function () {
app.annotations.load();
})
});
Note: theme_l10n.siteURL is passed through wp_localize_script
function and actually this is site_url()
.
The last thing you will need is to build your API like so:
add_action( 'rest_api_init', 'annotation_note_api');
function annotation_note_api() {
register_rest_route( 'annotation-notes/v1', '/annotations/([\w-]+)', array(
// DELETE
array(
'methods' => WP_REST_Server::DELETABLE,
'callback' => 'delete_annotation_note'
),
// PUT
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => 'edit_annotation_note'
)
));
register_rest_route( 'annotation-notes/v1', '/annotations/', array(
// POST
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => 'add_annotation_note'
)
));
register_rest_route( 'annotation-notes/v1', '/search/', array(
// GET
array(
'methods' => WP_REST_Server::READABLE,
'callback' => 'get_all_notes'
)
));
}
Note: All the callback
are actually your functions that are going to be executed on the specific API call. You will need to code those on your own depending on what you want.
Thank you, I try it but now I have this errors:
Failed to load resource: the server responded with a status of 403 () You don't have permission to perform this operation! (Error 403)
Maybe I can't configure my api correctly, I don't know. Annotator loads correctly, but can't save anything. BTW И аз съм българин, може да ми отговаряш на български, ако ще се разберем по-добре! :)
Здрасти, предпочитам на английски да го караме, че може да е от полза на някой друг с подобен пробле.
So do you get 403 on the API calls from the annotator ? What is the URL that gets that forbidden
error?
I know few reasons - firewall on the server, or something like sucuri, or some security plugin. If you are using some plugin line iThemes Security, it is possible to have active setting from there for restrictions on the WP REST API.
I tried it on a blank test site, you can see it here:
https://tezi.tk
I don't have security plugins installed right now, but I'm not sure if I configured API correctly.
Thanks for the link. I've checked the site and found that even https://tezi.tk/wp-json returns 403 which means that error would be valid for any API call. I've checked the WP REST API documentation and found that the most possible problem for this is the permalink. Most probably they are in the standard (default) ugly format. Try to change them to Post name
and give it a try again (but my guess is that this time you will get 404 error). Also check the results of https://tezi.tk/wp-json in the routes
if you have the annotation-notes
route. Currently I'm not seeing it there (that is why I think you will get 404). So my guess is that there is problem with the registration of the endpoints (of the file where you have put them is not loaded). Also check the handbook for custom endpoints in WordPress for some debugging hints.
Can you check now? I get 404 could not connect to the annotation store, but I think https://tezi.tk/wp-json and annotation-notes are working now. btw I'm not realy sure how to make callback functions for this cases (add, edit, delete notes etc.)
The callbacks are easy to create. Check the code related to the add_action( 'rest_api_init', 'annotation_note_api');
There you have each method (DELETE, GET, PUT, POST). And each of them are having a callback
parameter. You need to create function with that names so once the API is called it will trigger that callback function. In this documentation you will see details on how to create the callback (as those function should receive some request data form the API).
Also where have you paste the API code (the PHP one). If you are adding thin into a theme it should be in the functions.php
file. Make sure your error login is on so you can see if there are any errors related to that functionality.
Ok, thank you! I previously put API code (without callback part, because I don't have functions right now) in ScriptsnStyles plugin, now I move it to functions.php, but it's the same result. I enabled debug and error log, but can't find any errors related to annotator. I will try to create callbacks but can't understand are they needed for annotation store to function properly? Is this 404 error related to this, or there is something else?
I think there is another problem here (for the 404) I can see in https://tezi.tk/wp-json the new api for the annotations. But their namespace is wp-json/annotation-notes/v1
which is wrong. Should be just annotation-notes/v1
. Can you paste the code for the registration of the endpoint.
I will try to create callbacks but can't understand are they needed for annotation store to function properly?
When an annotation is made it need to be stored some where, so next time the page is loaded it will check for the saved annotations and will fetch them if there is a match. Without the callback you can't save or search for the annotations. Basically your callback are going to do just that: save annotation, get annotation, delete annotation. And you will need to provide that functionality in the callbacks.
add_action( 'rest_api_init', 'annotation_note_api');
function annotation_note_api() {
register_rest_route( 'wp-json/annotation-notes/v1', '/annotations/([\w-]+)', array(
// DELETE
array(
'methods' => WP_REST_Server::DELETABLE
),
// PUT
array(
'methods' => WP_REST_Server::EDITABLE
)
));
register_rest_route( 'wp-json/annotation-notes/v1', '/annotations/', array(
// POST
array(
'methods' => WP_REST_Server::CREATABLE
)
));
register_rest_route( 'wp-json/annotation-notes/v1', '/search/', array(
// GET
array(
'methods' => WP_REST_Server::READABLE
)
));
}
jQuery(function($) {
let app = new annotator.App();
app.include(annotator.ui.main);
app.include(annotator.storage.http, {
prefix: 'https://tezi.tk/wp-json/annotation-notes/v1'
});
app.start().then(function () {
app.annotations.load();
})
});
On each place where you have 'wp-json/annotation-notes/v1'
in the php code, you should change to 'annotation-notes/v1'
. The prefix wp-json
is added by default.
The way you have registered the endpoints will point to https://tezi.tk/wp-json/wp-json/annotation-notes/v1
, in JS you are making request to different place: https://tezi.tk/wp-json/annotation-notes/v1
. And that is way you get 404.
Ah, and you are missing the callback parameter. This most probably will end in Fatal error (500 or 503). You need to add callback to make the annotation functional.
Ok, fix this but as you said now I have 500 error, even with callback parameter, maybe because I don't create the corresponding functions. Can you help me with some examples of how to make functions for read, add, edit and save annotations, I'm not really sure how my functions to looks like because I never used API calls before.
What is your use case of the annotation tool? I can past my callback here but may be you need something else.
What is your use case of the annotation tool? I can past my callback here but may be you need something else.
Sorry for the late response! For one of my sites I want to use annotator as comment tool, I want unregistered users to make annotations, and all annotations to be visible for all visitors, but only I as admin to have privileges to edit or delete them. I'm not sure how easy will be to manage all published annotations and if there is any way to prevent spam. For my other site I want only registered users to create annotations and to have privileges to edit or delete their own annotations, but I want all published annotations to be visible for all users, even non registered ones.
Ok, so my case is quite simpler. I needed to store annotations per user. And each annotation is visible only to the use that have created it. Any way, You might find my code useful and may be modify it to fit your needs. Here is the code:
dd_action( 'rest_api_init', 'aa_note_api' );
function aa_note_api() {
register_rest_route( 'annotation-notes/v1', '/annotations/([\w-]+)', array(
// DELETE
array(
'methods' => WP_REST_Server::DELETABLE,
'callback' => 'annotations_delete_annotation_note'
),
// PUT
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => 'annotations_edit_annotation_note'
)
) );
register_rest_route( 'annotation-notes/v1', '/annotations/', array(
// POST
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => 'annotations_add_annotation_note'
)
) );
register_rest_route( 'annotation-notes/v1', '/search/', array(
// GET
array(
'methods' => WP_REST_Server::READABLE,
'callback' => 'annotations_get_all_notes'
)
) );
}
function annotations_get_all_notes( WP_REST_Request $request ) {
$user_id = ! empty( $_COOKIE['uid'] ) ? $_COOKIE['uid'] : '';
$page_id = ! empty( $_COOKIE['pid'] ) ? $_COOKIE['pid'] : '';
if ( $user_id == '' || $page_id == '' ) {
return new WP_REST_Response( [], 200 );
}
global $wpdb;
$sql = "SELECT uid, ranges, note, quote FROM {$wpdb->prefix}annotations_notes WHERE user_id = %d AND page_id = %d";
$results = $wpdb->get_results( $wpdb->prepare( $sql, $user_id, $page_id ) );
if ( ! empty( $results ) ) {
$data = [ 'total' => count( $results ), 'rows' => [] ];
foreach ( $results as $note ) {
$data['rows'][] = [ 'id' => $note->uid, 'ranges' => unserialize( $note->ranges ), 'text' => $note->note, 'quote' => $note->quote ];
}
return new WP_REST_Response( $data, 200 );
}
return new WP_REST_Response( [], 200 );
}
function annotations_add_annotation_note( WP_REST_Request $request ) {
$json = $request->get_json_params();
$user_id = ! empty( $_COOKIE['uid'] ) ? $_COOKIE['uid'] : '';
$page_id = ! empty( $_COOKIE['pid'] ) ? $_COOKIE['pid'] : '';
if ( $user_id == '' || $page_id == '' ) {
return new WP_REST_Response( [], 200 );
}
$note_id = $user_id . '-' . uniqid() . '-' . $page_id;
$ranges = serialize( $json['ranges'] );
global $wpdb;
$sql = "INSERT INTO {$wpdb->prefix}annotations_notes (uid, user_id, page_id, ranges, note, quote) VALUES (%s, %d, %d, %s, %s, %s)";
$wpdb->query( $wpdb->prepare( $sql, $note_id, $user_id, $page_id, $ranges, $json['text'], $json['quote'] ) );
if ( $wpdb->insert_id ) {
$data = [ 'id' => $note_id, 'ranges' => $json['ranges'], 'text' => $json['text'], 'quote' => $json['quote'] ];
return new WP_REST_Response( $data, 200 );
}
return new WP_Error( 'cant-delete', __( 'Can\'t create!', 'cpotheme' ), array( 'status' => 404 ) );
}
function annotations_delete_annotation_note( WP_REST_Request $request ) {
$json = $request->get_json_params();
global $wpdb;
$sql = "DELETE FROM {$wpdb->prefix}annotations_notes WHERE uid LIKE '%s'";
$delete = $wpdb->query( $wpdb->prepare( $sql, $json['id'] ) );
if ( $delete !== false && $delete !== 0 ) {
$data = [];
return new WP_REST_Response( $data, 204 );
}
return new WP_Error( 'cant-edit', __( 'Note can\'t be deleted', 'cpotheme' ), array( 'status' => 404 ) );
}
function annotations_edit_annotation_note( WP_REST_Request $request ) {
$json = $request->get_json_params();
global $wpdb;
$sql = "UPDATE {$wpdb->prefix}annotations_notes SET note = '%s' WHERE uid LIKE '%s'";
$update = $wpdb->query( $wpdb->prepare( $sql, $json['text'], $json['id'] ) );
if ( $update !== false && $update !== 0 ) {
$data = [
'id' => $json['id'],
'ranges' => $json['ranges'],
'text' => $json['text'],
'quote' => $json['quote']
];
return new WP_REST_Response( $data, 200 );
}
return new WP_Error( 'cant-edit', __( 'Note can\'t be edited', 'cpotheme' ), array( 'status' => 400 ) );
}
Note that there is custom database where I store the annotations. It is called {$wpdb->prefix}annotations_notes and has the following columns: id, uid, user_id, page_id, ranges, note, quote.
Hope this helps.
Thank you! I use your code and create table annotations_notes with same prefix as my other tables in the database and add id, uid, user_id, page_id, ranges, note, quote columns to the table. Now I can't see any errors, but when I try to add annotation noting happened. The text is not highlighted and nothing is stored in database table.
Check the function annotations_add_annotation_note
. There is made a check for two cookies that represents the user_id and post_id. You need to set those in the code of the current page ( before get_header()
function). Or you can try use another way to get the current post ID and user ID from within that function as you will need that info for the database (even if you don't need the user ID, you still need the page ID, as this is the main parameter by which you will assign the annotations.
<script>
function setCookie1() {
global $wp_query;
if ($wp_query->have_posts()) {
$post_id = $wp_query->current_post;
setcookie('pid', $post_id);
}
$wp_query->rewind_posts();
return;
}
add_action( 'wp', 'setCookie1', 10);
function setCookie2() {
$user = wp_get_current_user();
if (!$user instanceof WP_User)
return;
setcookie('uid', $user->ID);
}
add_action('wp', 'setCookie2', 10);
</script>
I try to set cookies in single post template file but still not working.
This might be a mistake from the markdown but you don't set php code in <script>
tags.
And hooking that functions to wp
might be to early to get the post ID. I'm not sure when the wp
hook is executed in the work flow. Still you should be able to see if those two cookies exists from the browser's developer tool. If the cookies are empty, then nothing will be recorded because of that code from the function:
if ( $user_id == '' || $page_id == '' ) {
return new WP_REST_Response( [], 200 );
}
I test annotator on wordpress site, stable version works great, but can't understand how to use store plugin to save annotations. I use this code:
`jQuery(function ($) { $('.main-container').annotator() .annotator('addPlugin', 'Store', { prefix: 'http://mysite.com/api' , annotationData: { 'uri': '/annotations' },
}); }); ` the plugin gets error messeges and in the console i see this error:
I'm not sure how to make it work.