ajax_deliver returns json instead of content I have a panel with two columns. In the left is a views with teasers, in the right the full body text of a node.
If you click on a link in the views the content in the right panel should be replaced with the body text (and images).
Here the code of the module:

&lt;?php
function customNews_menu() {
        $items['customNews/%/%node'] = array(
                'access arguments' =&gt; array('access content'),
                'page callback' =&gt; 'customNews_ajax_callback',
                'access callback' =&gt; 'user_access',
                'page arguments' =&gt; array(1,2),
                'type' =&gt; MENU_CALLBACK,
        );
        return $items;
}

function customNews_ajax_callback($js, $node) {
    if ($js == 'nojs') {
        drupal_goto('node/' . $node-&gt;nid);
    }
        $div_id = 'customNewsContent';
        $vnode = node_view($node);
        $vnode['is_ajax'] = true;
        $output = '&lt;div class="panel-pane pane-node" id="'.$div_id.'"&gt;'.theme("node", $vnode).'&lt;/div&gt;';
        $commands = array();
        $commands[] = ajax_command_replace('#'.$div_id, $output);
        $page = array('#type' =&gt; 'ajax', '#commands' =&gt; $commands);
        ajax_deliver($page);
}
?&gt;


When I run it I get the following back in the browser:

[{"command":"settings","settings":{"basePath":"\/drupal\/","pathPrefix":"","ajaxPageState":{"theme":"seeleben","theme_token":"wdFHgqik_Sx4kvKrKXtT9tAndWxYgNr2-cO6lfT09gg"},"colorbox":{"opacity":"0.85","current":"{current} of {total}","previous":"\u00ab Prev","next":"Next \u00bb","close":"Schlie\u00dfen","maxWidth":"98%","maxHeight":"98%","fixed":true,"mobiledetect":true,"mobiledevicewidth":"480px"}},"merge":true},.........


What do I do wrong?
You are almost there!


You are opening a serious security hole in your site, allowing anyone who has access content permission to access all nodes bypassing node access system. 


Assuming you need to use ctools's Ajax framework extension, you obviously need to have ctools module enabled. 

1. Change your menu loader to this:

$items['customNews/%ctools_js/%node']

This will make Drupal pass the second %ctools_js argument to ctools_js_load function that returns TRUE if nojs was changed to ajax. 

2. The link.

Ctools won't change all "nojs" occurrences in the page. You need to create a special link using ctools_ajax_text_button function, or by adding classes to the link. 

&lt;?php 
  ctools_include('ajax');
  ctools_include('modal');
  ctools_modal_add_js();
  print ctools_ajax_text_button(t('Read more'), 'customNews/nojs/1'); //1 is the node ID. Replace accordingly. You need to use "nojs" here. 
?&gt;


3. Almost there!

Your code should work now. However, make sure you have proper node access checks before showing anything. SA-CORE-2-14-005 was touch enough. 

if ($js == 'nojs') {
        drupal_goto('node/' . $node-&gt;nid);
    }


Can be changed to:

if (!$js) {
  drupal_goto('node/' . $node-&gt;nid);
}


The importance of this "special link" is that ctools's JS registers all anchor tags in Drupal.ajax that follows the class name convention. For my own use, I have a small function that returns the proper link so I don't have to include ctools's ajax.inc file.