custom river menu for blogs based on api call response

Hi,

I'm using Elgg 2.3.14 and I've added a custom menu handler in my start.php:

elgg_plugin_hook_handler('register', 'menu:river', 'river_menu_handler');

And the block of code in my handler that calls a rest endpoint and displays a menu icon based on the response: 

function river_menu_handler($hook, $type, $items, $params) { 
    $authString = 'fakeauthorization';
    $item = $params['item'];
    $entity = $item->getObjectEntity();
    $auth_id = $entity->auth_id;
    $env_id = $entity->env_id;
    $hash = $entity->hash;
    if (elgg_instanceof($entity, 'object', 'blog')) {
        // call endpoint
        $response = validateSignature(auth_id, $hash, $env_id, $authString);
        $response_json = json_decode($response, true);
        if (isset($response_json['errorCode'])) {
            $errorCode = $response_json['errorCode'];
            if (errorCode == 0) {
                $items[] = \ElggMenuItem::factory([
                    'name' => 'verify',
                    'href' => 'http://mytestapi.com',
                    'text' => elgg_view_icon('round_checkmark'),
                    'title' => 'This post has been verified',
                    'priority' => 200,
                ]);
                return $items;
            } else {
                $items[] = \ElggMenuItem::factory([
                    'name' => 'verify',
                    'text' => elgg_view_icon('ban'),
                    'title' => 'This post has not been verified',
                    'priority' => 200,
                ]);
                return $items;
            }  
.
.
.

​

And the service where the curl executes to get the response:

function validateSignature($auth_id, $content_hash, $envelope_id, $authString) {
    $ch = curl_init();
    $authorization = 'Authorization: Basic ' . base64_encode($authString);
    $validate_url = 'https://myfakeapi/api/envelopes/validate/' . $auth_id .'/' . $content_hash . '/' . $envelope_id;
    curl_setopt($ch, CURLOPT_URL, $validate_url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_VERBOSE, 1);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array($authorization ));
    curl_setopt($ch, CURLINFO_HEADER_OUT, 1);
    $response = curl_exec($ch);
    $json = json_decode($response, true);
    $err = curl_error($ch);
    if($err) {
        echo "cURL Error: " . $err;
    }
    // Check HTTP status code
    if (!curl_errno($ch)) {
        switch ($http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE)) {
            case 200:  # OK
                //echo 'response is: ', $sigVer, "\n";
                break;
            case 502:  # server error
                system_message('Received 500 Error from Server');
                break;
            case 400:  # bad request
                $jsonResponse = json_decode($response, true);
                $message = $jsonResponse['message'];
                break;
            default:
                break;
        }
    }
    curl_close($ch);
    return $response;
}

So.. my question i probably more of a php (which I'm still learning) question than Elgg, but I've noticed that my activity page is taking a really long time to render and of course that's probably due to the fact that it is now making a call to my rest endpoint for every instance of a blog post in the river list.  I've been reading up on how to make this an asynchronous call but have yet to figure out a solution for this case where the rendering of the menu is dependent upon the response of the api call.  Then the page doesn't display until all of the menus for each post has completed. Is there a way to render the page without waiting for the response from the api calls to render the menus.. or even better, display some type of spinner where the icon is supposed to render when the response returns.

 

Any ideas?

 

Thanks.

  • Quickly answer is validate it using your API call once, e.g. when blog is published/edited, or using separate action by admin/moderators.

    Make hook using entity events for this.

    After validating add metadata's name/value to the published blog, e.g.:

    $entity->verify = true;

    Now you can just check this metadata's value on your river menu:

    if((bool) $entity->verify )  {
    
         //value is TRUE
    
           $items[] = \ElggMenuItem::factory([
               'name' => 'verify',
               'href' => 'http://mytestapi.com',
                'text' => elgg_view_icon('round_checkmark'),
                'title' => 'This post has been verified',
                'priority' => 200,
           ]);
           return $items;
    
    } else {
    
         //value is FALSE
    
         $items[] = \ElggMenuItem::factory([
                'name' => 'verify',
                'text' => elgg_view_icon('ban'),
                'title' => 'This post has not been verified',
                'priority' => 200,
         ]);
        return $items;
    
    }
  • Thanks RvR,

    First.. let me say that I appreciate your quick responses to my questions.. you are extremely knowledgeable!  

    So your solution would work if I didn't have the requirement to get "real-time" verification status.  We want to always check to make sure that the value of the data in the blog stored with Elgg has not changed when comparing it to the data that is stored in a remote distributed ledger when the post is created... so setting the verify attribute to true would not enforce those real-time checks.  We will always store an original version of the post with an outside source first and then run the comparison whenever the page renders for blogs.

Beginning Developers

Beginning Developers

This space is for newcomers, who wish to build a new plugin or to customize an existing one to their liking