Coder Social home page Coder Social logo

Comments (20)

alordiel avatar alordiel commented on June 21, 2024

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.

from annotator.

ANONIMNIQ avatar ANONIMNIQ commented on June 21, 2024

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 И аз съм българин, може да ми отговаряш на български, ако ще се разберем по-добре! :)

from annotator.

alordiel avatar alordiel commented on June 21, 2024

Здрасти, предпочитам на английски да го караме, че може да е от полза на някой друг с подобен пробле.
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.

from annotator.

ANONIMNIQ avatar ANONIMNIQ commented on June 21, 2024

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.

from annotator.

alordiel avatar alordiel commented on June 21, 2024

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.

from annotator.

ANONIMNIQ avatar ANONIMNIQ commented on June 21, 2024

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.)

from annotator.

alordiel avatar alordiel commented on June 21, 2024

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.

from annotator.

ANONIMNIQ avatar ANONIMNIQ commented on June 21, 2024

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?

from annotator.

alordiel avatar alordiel commented on June 21, 2024

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.

from annotator.

ANONIMNIQ avatar ANONIMNIQ commented on June 21, 2024
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();
    })

});

from annotator.

alordiel avatar alordiel commented on June 21, 2024

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.

from annotator.

alordiel avatar alordiel commented on June 21, 2024

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.

from annotator.

ANONIMNIQ avatar ANONIMNIQ commented on June 21, 2024

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.

from annotator.

alordiel avatar alordiel commented on June 21, 2024

What is your use case of the annotation tool? I can past my callback here but may be you need something else.

from annotator.

ANONIMNIQ avatar ANONIMNIQ commented on June 21, 2024

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.

from annotator.

alordiel avatar alordiel commented on June 21, 2024

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.

from annotator.

ANONIMNIQ avatar ANONIMNIQ commented on June 21, 2024

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.

from annotator.

alordiel avatar alordiel commented on June 21, 2024

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.

from annotator.

ANONIMNIQ avatar ANONIMNIQ commented on June 21, 2024
<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.

from annotator.

alordiel avatar alordiel commented on June 21, 2024

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 );
}

from annotator.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.