WordPress插件:使用AJAX调用仅呈现页面内容

时间:2014-03-24 作者:Pietro

我正在编写一个插件来呈现API请求中的json数据,我需要在内容页中实现无限滚动。

问题是,当我使用ajax调用呈现内容时,它会呈现所有页面。

这就是我目前所做的:

function enable_pagination() {
    jQuery(function($) {
        $(\'#show-more-button a\').click( function(e) {
            e.preventDefault();
            $.ajax( {
                url: document.URL,
                data: { \'page\': 2 },
                type: \'POST\',
                dataType: \'html\',
                error: errorHandler
            }).done( function( response ) {
                $(\'.list\').append( response );
            });
        });
    });
}

EDIT: ADDING EVENTS_CONTROLLER CODE

public function festival( Array $shortcode_params ) {
            $collection_edition = $shortcode_params[\'collection_edition_id\'];
            $festival_name = $shortcode_params[\'name\'];

            if ( is_numeric( $collection_edition ) && $collection_edition > 0 ) {
                $this->initialize_params();
                $this->initialize_api_client();
                $date = array_key_exists( \'date\', $this->params ) ? $this->params[\'date\'] : date( \'Y-m-d\' );
                $category = $this->params[\'category\'];
                $page = isset( $this->params[\'page\'] ) ? $this->params[\'page\'] : 1;
                $events_by_festival = $this->api_client->from_day( $date, $collection_edition, $category, $page );

                // pagination
                if( $this->isAjax() )
                    return View::render( "events/partials/_list.php", array( \'events\' => $events_by_festival ) );
                else
                    return View::render( "events/festival.html.php", array( \'date\' => $date, \'category\' => $category, \'festival\' => $festival_name, \'events_by_festival\' => $events_by_festival ) );
            }
            return false;
        }


private function isAjax() {
            return !empty($_SERVER[\'HTTP_X_REQUESTED_WITH\']) && strtolower($_SERVER[\'HTTP_X_REQUESTED_WITH\']) == \'xmlhttprequest\';
        }
View是一个自定义类,包含一些辅助对象,例如:用于渲染。

/**
         * Render the template, returning it\'s content.
         * @param $data array Data made available to the view.
         * @param $template string view file name to render
         * @return string The rendered template.
         */
        public static function render( $template, $data ) {
            extract( $data );
            ob_start();
            include( "views/$template" );
            $content = ob_get_contents();
            ob_end_clean();
            return $content;
        }
文档。URL指的是events\\u控制器操作,当ajax请求时,该操作仅返回events\\u list部分视图。

如前所述,在本例中,ajax响应除了包含内容外,还包含页眉、提要栏、页脚等。。。。

有一个干净的方法来实现这一点吗?

提前谢谢你

3 个回复
最合适的回答,由SO网友:gmazzap 整理而成

你的代码有点复杂,所以我不能发布一个完整的工作代码,但概念验证,然后适应你的代码取决于你。

因此,WordPress中的Ajax应该通过Ajax API, 相反,要将请求发送到相同的url(当然是打印头)和其他内容,只需通过Ajax Api发送请求并输出所需内容即可。

我假设您有如下代码:

add_shortcode( \'festival\' , array( new Events_Controller, \'festival\' ) );
以及festival() 方法Events_Controller 将其归类为您发布的内容。似乎从shortcode获得的仅有2个参数是\'collection_edition_id\'\'name\' 所有其他参数(我猜)都是由Events_Controller::initialize_params() 方法(可能基于请求)。

所以,如果你的Events_Controller::festival() 方法可以从shortcode以外的其他源获取参数,而不是以相同的方式执行其工作。查看此代码:

public function festival( Array $params = array() ) {

  if ( ! $this->isAjax() ) ) {
    $collection = isset( $params[\'collection_edition_id\'] )
      ? $params[\'collection_edition_id\']
      : 0;
    $festival = isset( $params[\'name\'] ) ? $params[\'name\'] : \'\' ;
  } elseif ( empty( $params ) ) {
    $collection = filter_input(INPUT_POST, \'collid\', FILTER_SANITIZE_NUMBER_INT);
    $festival = filter_input(INPUT_POST, \'festival_name\', FILTER_SANITIZE_STRING);
  }

  if ( empty($collection) || ! is_numeric($collection) ) {
    // WordPress Ajax API need to die() on end or will append a 0 to the response
    if ( $this->isAjax() ) die();
    return;
  }

  $this->initialize_params();
  $this->initialize_api_client();
  $date = array_key_exists( \'date\', $this->params )
    ? $this->params[\'date\']
    : date( \'Y-m-d\' );
  $category = $this->params[\'category\'];
  $page = isset( $this->params[\'page\'] ) ? $this->params[\'page\'] : 1;
  $events_by_festival = $this->api_client->from_day(
    $date, $collection_edition, $category, $page 
  );

  if ( ! $this->isAjax() ) ) {
    wp_enqueue_script(
      \'my_ajax_script\',
      plugins_url( \'js/my_ajax.js\', __FILE__ ),
      array(\'jquery\'), NULL, TRUE
    );
    $data = array( \'ajax_url\' => admin_url( \'admin-ajax.php\' ) );
    wp_localize_script( \'my_ajax_script\', \'MyScriptData\', $data );
  }

  if( $this->isAjax() ) {
     View::render(
       "events/partials/_list.php", array( \'events\' => $events_by_festival )
     );
     // WordPress Ajax API need to die() on end or will append a 0 to the response
     die();
  } else {
    return View::render(
      "events/festival.html.php",
      array(
        \'date\' => $date,
        \'category\' => $category,
        \'festival\' => $festival,
        \'collection\' => $collection, // <-- pass also the collection
        \'page\' => $page, // <-- pass the page
        \'events_by_festival\' => $events_by_festival
      )
    );
  }

}
正如你所看到的,我$params 参数可选,我可以通过POST ajax请求而不是通过短代码ATT发送到方法集合id和节日名称,结果是您可以在短代码之外运行该方法。

我也用过wp_enqueue_script 要在页脚中添加javascript文件,并且在该文件中(我假设是相对于插件文件夹的“js/my\\u ajax.js”),您应该放置代码来触发ajax调用。

最终使用wp_localize_script 我向该脚本发送了一个变量:MyScriptData 将包含在ajax_url 属性的正确url\'admin-ajax.php\' (即,在该脚本中,您可以使用MyScriptData.ajax_url 访问url)。

这种方法现在变得非常“简单”;“大型”;而且可能最好将其拆分为多个部分,例如javascript内容可以放在另一个方法中,就像渲染内容一样。

现在,您必须创建ajax api调用来运行该方法:

add_action( \'wp_ajax_myplugin_festival\', array( new Events_Controller, \'festival\' ) );
add_action( \'wp_ajax_nopriv_myplugin_festival\', array( new Events_Controller, \'festival\' ) );
前面的代码表示当您将请求发送到admin-ajax.php 哪里$_REQUEST[\'action\'] 等于\'myplugin_festival\' (位于“wp\\u ajax\\u”和“wp\\u ajax\\u nopriv”之后的部分)然后Events_Controller::festival 由WordPress调用。

因此,您唯一需要做的就是向发送POST请求admin-ajax.php 哪里\'action\', \'collid\'\'festival_name\' POST变量设置正确。

然而,“action”必须硬编码为“myplugin\\u festival”,但是“collid”和“festival\\u name”应该根据短代码显示的内容进行设置:最简单的方法是设置一个data- 由快捷码打印的html标记内的参数。

在OP中,您没有发布模板,因此我不知道它是如何构造的,但是作为概念证明,我假设有一个容器div,您可以在其中设置数据:

<div class="festival-container" id="festival-container-<?php echo $collection; ?>"
   data-collid="<?php echo $collection; ?>"
   data-festival="<?php echo $festival; ?>"
   data-page="<?php echo $page; ?>">
当然,您需要传递到模板$festival,$collection$page 变量。

因此,您的js文件(我在前面的代码中假设是\'js/my_ajax.js\' 插件文件夹中的文件)写入:

jQuery(document).ready( function($) {

  $( document ).on( \'click\', \'.festival-container .show-more-button a\', function(e) {  
    e.preventDefault();
    var $container = $(this).closest(\'.festival-container\');
    var collection = $container.data(\'collid\');
    var festival = $container.data(\'festival\');
    var paged = $container.data(\'page\') + 1;
    $.ajax( {
      url: MyScriptData.ajaxurl,
      data: {
        action: \'myplugin_festival\',
        page: paged,
        coll_id: collection,
        festival_name: festival
      },
      type: \'POST\',
      dataType: \'html\',
      error: errorHandler
    }).done( function( response ) {
      $container.find(\'.list\').append( response );
    });
  });

});
一些注意事项请查看页面源代码以确保javascript url插入正确,因为如果文件路径js/my_ajax.js 是相对于插件根的,则需要作为第二个参数传递给plugins_url 插件主目录中的文件路径,我在其中使用__FILE__, 但是如果你的Events_Controller 类位于url用于js/my_ajax.js 将是错误的。

此外,在js中,您使用的是$(\'.list\').append( response ); 但也许你应该选择一个比$(\'.list\') 另外,如果同一短代码被多次插入,您需要一种方法来识别响应附加到哪个短代码。我使用了容器的引用,使我的代码适应您的需要。

在countrary上,在\'#show-more-button a\' 但您可能应该使用html类而不是html id,因为您可以有多个按钮。我使用了一个使用container类的类来缩小与页面中其他内容冲突的可能性,再次调整我的代码以满足您的需要。

SO网友:xiidea

正如您所知,您可以使用wp_ajax_*wp_ajax_nopriv_* 钩子来处理ajax请求。让我们用一个例子来看看它是如何工作的。

首先,我们需要为ajax请求选择一个唯一的动作键。现在说my_action. 最好在键前加上插件名称,这样就不会与其他插件冲突。现在定义两个挂钩。wp\\U ajax_my_action 和wp\\U ajax\\U nopriv_my_action

if ( is_admin() ) {
    add_action( \'wp_ajax_my_action\', \'my_action_callback\' );
    add_action( \'wp_ajax_nopriv_my_action\', \'my_action_callback\' );
}

Why two hook:

Thewp_ajax_my_action 仅对登录用户调用hook,仅在其中,wp_ajax_nopriv_my_action 钩子在用户未登录时触发。所以你可以选择你需要的。如果无论用户是否登录,都需要允许ajax请求,则必须同时注册这两者。

对于管理端,有一个javascript全局变量ajaxurl. 但对于正面页面ajaxurl javascript global不会自动为您定义,除非您安装了BuddyPress或其他依赖Ajax的插件。因此,我们声明全局变量,而不是依赖全局javascript变量。与默认ajaxurl的唯一区别是,我们将添加唯一的操作参数(my_action) 到此为止。

addAction(\'wp_print_scripts\', \'init_ajax_url_variable\');
function init_ajax_url_variable()
{
    $url = admin_url("admin-ajax.php?action=my_action");
    echo \'<script type="text/javascript">\';
    echo "var my_action_ajax_url = \'{$url}\'";
    echo \'</script>\';
}
现在定义ajax调用

function enable_pagination() {
    jQuery(function($) {
        $(\'#show-more-button a\').click( function(e) {
            e.preventDefault();
            $.ajax( {
                url: my_action_ajax_url,
                data: { \'page\': 2 },
                type: \'POST\',
                dataType: \'html\',
                error: errorHandler
            }).done( function( response ) {
                $(\'.list\').append( response );
            });
        });
    });
}


function my_action_callback() { //Your function to handle ajax request;

   // Here is all your code

    exit; //stop further processing
}
希望你现在清楚这是怎么回事

解决问题的另一个最短解决方案是在ajax处理之后添加模具/出口。如果您不需要处理festival function 您可以这样做:

$viewContent = View::render( "events/partials/_list.php", array( \'events\' => $events_by_festival ) );
die($viewContent);
享受吧!

对于资源Click Here

SO网友:Marc Dingena

当前代码请求整个页面,该页面返回为response.

.done( function( response ) {
    $(\'.list\').append( response );
})
而不是将响应附加到.list 元素,你应该把response, 找到所需的区块,然后只将区块附加到.list.

你可以用jQuery\'s .find(). 下面的代码分析response 并搜索.list 元素。通过使用jQuery\'s .html(), 我们可以提取.list 元素的HTML代码,并将其传递给.append() 从原始代码。

.done(function( response ) {
    $( \'.list\' ).append( $( response ).find( \'.list\' ).html() );
})
如果你想要一个无休止的卷轴,你可能应该记住paged 索引,并在每次成功的AJAX调用后递增,以便下次调用将尝试检索下一页的.list 要素

结束

相关推荐

如何在子主题中停止运行PHP代码

我知道您可以在父主题的顶部添加额外的CSS,但如何从函数中删除PHP代码。php?我想删除Masonry plugin 在里面twentyfourteen 主题,并在line 254. if ( is_active_sidebar( \'sidebar-3\' ) ) { wp_enqueue_script( \'jquery-masonry\' ); } 如果我正在编辑父主题,我可以将此块注释掉/* */.但我不知道有什么方法可以改变这是我的孩子的主题。