Default search json output

Public

Creating a json endpoint for drupal default search module

Get raw version
php
  1. <?php
  2. // custom module to generate a json endpoint for drupal default search
  3. // json endpoint address [site:url]/search-json/[search_query]
  4. // module will restrict normal http request to json endpint
  5. // module precents normal http request to access endpint it only works with xmlhttprequest
  6. // coded by reza.sh on 06-01-2014
  7.  
  8. // create json endpoint
  9. /**
  10. * implements hook_menu
  11. */
  12. function grooch_json_search_menu (){
  13. $items = array();
  14. $items['search-json/%'] = array(
  15. 'page callback' => '_grooch_json_custom_search',
  16. 'access arguments' => array('access content'),
  17. 'page arguments' => array(1),
  18. 'type' => MENU_CALLBACK,
  19. );
  20. return $items;
  21. }
  22.  
  23. // @important this should be only used when you want to disable drupal default search page
  24. /**
  25. * implements hook_init()
  26. */
  27. function grooch_json_search_init(){
  28. if (arg(0) == 'search'){
  29. drupal_not_found();
  30. exit();
  31. }
  32. }
  33.  
  34. /**
  35. * custom function to perform and output search results in json
  36. */
  37. function _grooch_json_custom_search($search_keyword){
  38. // make sure that request is xmlhttprequest
  39. if (!_request_is_ajax()){
  40. return MENU_NOT_FOUND;
  41. }
  42. // list of allowed content types
  43. //search module exclude all other content types from the result automatically
  44. $content_types = "type:page,bullion_coins,collectible,collection,news,product_castbars,product_images,product,product_page,distributor,unesco_product";
  45. global $user;
  46. // join search keyword with allowed content types
  47. $final_keywords = $search_keyword . " " . $content_types;
  48. //perform search with search_data($key,$implementing_module,$conditions)
  49. $results = search_data($final_keywords,'node');
  50. $total_pages = ($GLOBALS['pager_total'][0]?$GLOBALS['pager_total'][0]:0);
  51. $current_page = (isset($_REQUEST['page']) ? $_REQUEST['page'] : 0) + 1;
  52. $next_page = (($total_pages == $current_page || $total_pages == 0)?false:true);
  53. $results = $results['#results'];
  54. // make a clean output of the results to be converted to the json array
  55. $clean_output = array();
  56. $clean_output['search_info']['total_pages'] = $total_pages;
  57. $clean_output['search_info']['current_page'] = $current_page;
  58. $clean_output['search_info']['next_page'] = $next_page;
  59. foreach ($results as $id => $result){
  60. if ($result['type'] == "Distributor"){
  61. $result['link'] = url('wheretobuy');
  62. }elseif ($result['type'] == "Bullion Coins"){
  63. $result['link'] = url('services/bullioncoins');
  64. }
  65. $clean_output['items'][$id] = array();
  66. $clean_output['items'][$id]['title'] = $result['title'];
  67. $clean_output['items'][$id]['link'] = $result['link'];
  68. $clean_output['items'][$id]['desc'] = strip_tags($result['snippet']);
  69. }
  70. // convert the php array to json array
  71. $clean_output = json_encode($clean_output);
  72. // print it to user and exit execution because of this no normal httprequest is allowed
  73. print $clean_output;exit();
  74. //return '';
  75. }
  76.  
  77. /**
  78. * custom function to check if the request is ajax or not
  79. */
  80. function _request_is_ajax (){
  81. if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
  82. return true;
  83. }
  84. return false;
  85. }

Example fetcher for the endpoing

Get raw version
javascript
  1. (function ($) {
  2. // to make it true only when each time user hits Enter on search input
  3. var first_search = false;
  4. var search_phrase;
  5. // this is fetched from json endpoint
  6. var total_pages;
  7. //next page to be parsed and then injected
  8. var page_to_inject = 1;
  9. // to perform search on next page query paramter or not (?page=) it is also needed for first hit
  10. var next_page = true;
  11. //lock connection if an active ajax request is sent, this will be unlocked on ajax complete
  12. var lock_connection = false;
  13. var loading_div = '<div class="smLoading" style="text-align:center;float:right;display:none;width:100%;padding-top:10px;color:#676E79;background-image:url(/sites/all/themes/pampTheme/img/smLoading.gif);background-repeat:no-repeat;background-position:top;position:relative;height:100px;">Loading search results...</div>'
  14. $(document).ready(function(){
  15. $('#mod_search_searchword').keypress(function(event) {
  16. if (event.which == 13){
  17. //we make next page true to switch to new search status
  18. next_page = true;
  19. // we make first search false to tell the functions that is a new search
  20. // functions will make it true if needed
  21. first_search = false;
  22. search_phrase = $(this).val();
  23. // revert page_to_inject to it's default becasuse of new search status
  24. page_to_inject = 1;
  25. //perform search
  26. cseSearchAjax(search_phrase);
  27. }
  28. });
  29. //function which handles ajax search results
  30. function cseSearchAjax($val) {
  31. // stop if there is no next_page or there is already another connection
  32. if (!next_page && lock_connection){
  33. return;
  34. }
  35. // do not send ?page=0 parameter if it's first page
  36. if (page_to_inject == 1){
  37. // show loading on page it will be auto displayed to "none" on ajax complete callback
  38. $('.contentHolder').html('<div class="searchWrapper">' + loading_div + '</div>');
  39. page_query = '';
  40. }else{
  41. page_query = '?page=' + (page_to_inject - 1);
  42. }
  43. $.ajax({
  44. url: '/search-json/' + $val + page_query,
  45. type: "GET",
  46. dataType: "json",
  47. beforeSend: function(){
  48. //lock connection to prevent ferequent request
  49. lock_connection = true;
  50. $('.smLoading').css('display','block');
  51. },
  52. success: function(data,status){
  53. //handle incoming data
  54. handle_drupal_json_search(data);
  55. },
  56. complete: function (){
  57. // unlock connection to allow next requests
  58. lock_connection = false;
  59. // hiding loading image
  60. $('.smLoading').css('display','none');
  61. }
  62. });
  63. }
  64. //use this function if you are retrieving data from google json custom search
  65. function cseSearchGenerate(data) {
  66. if (data.searchInformation.totalResults == 0){
  67. $('.searchWrapper .inSearching').html('<div class="inSearching text-center">Your search yielded no results!</div>');
  68. return
  69. }
  70. $('.searchWrapper').prepend('<ul class="searchResults"></ul>')
  71. if(data.items){
  72. searchData = data.items;
  73. superObj = new Array();
  74. $.each(searchData,function(index,inner){
  75. result = '<a class="searchTitle" href="' + inner.link + '">' + inner.title + '</a><br><div class="resultText">' + inner.snippet + '</div>';
  76. $('ul.searchResults').append('<li>' + result +'</li>');
  77. });
  78. }
  79. }
  80. // use this function if you are using drupal internal search ( grooch json custom search must be enabled)
  81. function handle_drupal_json_search(data){
  82. // stop if there is NO result for the search phrase (search_count = 0)
  83. if(data.search_info.total_pages == 0 && !first_search){
  84. // throw noting matched error
  85. $('.searchWrapper').html('<div class="inSearching text-center">Your search yielded no results!</div>');
  86. return
  87. }
  88. // inject wrapper only for first page (on scrolling we just append the ul below)
  89. if (page_to_inject == 1){
  90. $('.searchWrapper').html('<ul class="searchResults"></ul>');
  91. $('div.searchWrapper').append(loading_div);
  92. }
  93. //illiterate through result items
  94. $.each(data.items,function(index,inner){
  95. result = '<a class="searchTitle" href="' + inner.link + '">' + inner.title + '</a><br><div class="resultText">' + inner.desc + '</div>';
  96. $('ul.searchResults').append('<li>' + result +'</li>');
  97. });
  98. //make it true to check that first request is sent for current search phrase on next actions
  99. first_search = true;
  100. // increase next page number for further requests (for injecting on scroll)
  101. page_to_inject = data.search_info.current_page + 1;
  102. //get total pages from json endpoint it will be 0 if no results
  103. total_pages = data.search_info.total_pages;
  104. // next_page is used to check whether make next request by infinite scroll or not
  105. if (data.search_info.next_page){
  106. next_page = true;
  107. }else {
  108. next_page = false;
  109. }
  110. }
  111. // inject with infinite scroll
  112. $(window).scroll(function () {
  113. if (first_search && next_page && !lock_connection){
  114. if ($(window).scrollTop() >= $(document).height() - $(window).height() - 10) {
  115. cseSearchAjax(search_phrase,page_to_inject);
  116. }
  117. }
  118. });
  119. });
  120. })(jQuery);