从Personal API更新插件

时间:2011-05-29 作者:Simon

我现在正在开发一个wordpress插件,我不想在wordpress插件库中使用它。然而,我仍然希望能够从我自己的API存储库向我的客户推送更新。

我已经读了很多关于这方面的书,其中一件事似乎是关于pre_set_site_transient_update_plugins 过滤器,但是我找不到关于这个的很多信息。我试过这个教程(http://konstruktors.com/blog/wordpress/2538-automatic-updates-for-plugins-and-themes-hosted-outside-wordpress-extend/) 我没法工作。我可以从评论中看出,其他人实际上可以使用几乎是当前版本的WP(最新回复,4月22日)。

我尝试从站点安装插件,并将API文件夹放在第二个域中,但我通常在更新可用时收到的更新通知根本没有显示。

我不确定是否真的可以让自定义插件从其他存储库运行自动更新,所以我想听听这里是否有人对这些东西有任何经验?本教程中的解决方案似乎是一个简单的解决方案-我想知道是否有可能以更高级的方式实现它?

如果您能从我自己的存储库中获得此自动更新,我们将不胜感激!

(附言:我正在运行WP版本3.1.3)

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

为了让找到此页面的其他人受益,我建议那些希望在官方WP存储库之外提供自己更新的人在GitHub上查看此项目,它展示了以下功能:

https://github.com/jeremyclark13/automatic-theme-plugin-update

SO网友:EAMann

是的,这是可能的。里面有整整一章Professional WordPress Plugin Development 致力于此。如果您还没有,请拿起一份副本。这肯定会有帮助。

SO网友:Todd Lahman

WooCommerce有一个商业插件和主题更新API管理器,如果插件或主题没有托管在wordpress上,它可以特别工作。组织。它旨在为自托管插件和主题提供更新。这个插件是为那些不想自己写的人设计的,他们需要很多功能,以及正在销售的插件和主题的工作示例。

http://www.toddlahman.com/shop/wordpress-automatic-update-api-manager/

SO网友:cwd

还有一个整洁的服务http://wp-updates.com/ - 你可以免费获得一个主题或插件。仅供参考-这不是我的网站,但我已经尝试了一段时间,它似乎很好。

SO网友:Nathan Johnson

对于单站点安装(我没有在多站点上测试),您只需要从外部服务(如github或gitlab)更新两个挂钩。在下面的代码中,我使用gitlab,因为这就是我现在用来托管代码的地方。我可能应该把gitlab的部分提取出来。。。

你需要使用的第一个钩子是pre_set_site_transient_update_themes. 这是WordPress用来设置site\\u transient以显示是否有可用更新的过滤器。使用此挂钩连接到远程版本,并查看是否有可用的更新。如果有,则修改瞬态,以便WordPress知道有更新,并可以向用户显示通知。

你需要使用的另一个钩子是upgrader_source_selection. 无论如何,gitlab都需要这个过滤器,因为下载文件夹的名称与主题不同,所以我们使用这个钩子将其重命名为正确的名称。如果远程存储库提供了具有正确名称的zip,那么您甚至不需要这个挂钩。

您可以使用的第三个可选挂钩是auto_update_theme 如果要自动更新主题。在下面的示例中,我使用此挂钩仅自动更新此特定主题。

此代码仅使用WordPress 4.9进行了测试。x、 它需要PHP>7.0。

功能。php

//* Load the updater.
require PATH_TO . \'updater.php\';
$updater = new updater();
\\add_action( \'init\', [ $updater, \'init\' ] );
更新程序。php

/**
 * @package StackExchange\\WordPress
 */
declare( strict_types = 1 );
namespace StackExchange\\WordPress;

/**
 * Class for updating the theme.
 */
class updater {

  /**
   * @var Theme slug.
   */
  protected $theme = \'theme\';

  /**
   * @var Theme repository name.
   */
  protected $repository = \'project/theme\';

  /**
   * @var Repository domain.
   */
  protected $domain = \'https://gitlab.com/\';

  /**
   * @var CSS endpoint for repository.
   */
  protected $css_endpoint = \'/raw/master/style.css\';

  /**
   * @var ZIP endpoint for repository.
   */
  protected $zip_endpoint = \'/repository/archive.zip\';

  /**
   * @var Remote CSS URI.
   */
  protected $remote_css_uri;

  /**
   * @var Remote ZIP URI.
   */
  protected $remote_zip_uri;

  /**
   * @var Remote version.
   */
  protected $remote_version;

  /**
   * @var Local version.
   */
  protected $local_version;

  /**
   * Method called from the init hook to initiate the updater
   */
  public function init() {
    \\add_filter( \'auto_update_theme\', [ $this, \'auto_update_theme\' ], 20, 2 );
    \\add_filter( \'upgrader_source_selection\', [ $this, \'upgrader_source_selection\' ], 10, 4 );
    \\add_filter( \'pre_set_site_transient_update_themes\', [ $this, \'pre_set_site_transient_update_themes\' ] );
  }

  /**
   * Method called from the auto_update_theme hook.
   * Only auto update this theme.
   * This hook and method are only needed if you want to auto update the theme.
   *
   * @return bool Whether to update the theme.
   */
  public function auto_update_theme( bool $update, \\stdClass $item ) : bool {
    return $this->theme === $item->theme;
  }

  /**
   * Rename the unzipped folder to be the same as the existing folder
   *
   * @param string       $source        File source location
   * @param string       $remote_source Remote file source location
   * @param \\WP_Upgrader $upgrader      \\WP_Upgrader instance
   * @param array        $hook_extra    Extra arguments passed to hooked filters
   *
   * @return string | \\WP_Error The updated source location or a \\WP_Error object on failure
   */
  public function upgrader_source_selection( string $source, string $remote_source, \\WP_Upgrader $upgrader, array $hook_extra ) {
    global $wp_filesystem;

    $update = [ \'update-selected\', \'update-selected-themes\', \'upgrade-theme\' ];

    if( ! isset( $_GET[ \'action\' ] ) || ! in_array( $_GET[ \'action\' ], $update, true ) ) {
      return $source;
    }

    if( ! isset( $source, $remote_source ) ) {
      return $source;
    }

    if( false === stristr( basename( $source ), $this->theme ) ) {
      return $source;
    }

    $basename = basename( $source );
    $upgrader->skin->feedback( esc_html_e( \'Renaming theme directory.\', \'bootstrap\' ) );
    $corrected_source = str_replace( $basename, $this->theme, $source );

    if( $wp_filesystem->move( $source, $corrected_source, true ) ) {
      $upgrader->skin->feedback( esc_html_e( \'Rename successful.\', \'bootstrap\' ) );
      return $corrected_source;
    }

    return new \\WP_Error();
  }

  /**
   * Add respoinse to update transient if theme has an update.
   *
   * @param $transient
   *
   * @return
   */
  public function pre_set_site_transient_update_themes( $transient ) {
    require_once ABSPATH . \'wp-admin/includes/class-wp-upgrader.php\';
    $this->local_version = ( \\wp_get_theme( $this->theme ) )->get( \'Version\' );

    if( $this->hasUpdate() ) {
      $response = [
        \'theme\'       => $this->theme,
        \'new_version\' => $this->remote_version,
        \'url\'         => $this->construct_repository_uri(),
        \'package\'     => $this->construct_remote_zip_uri(),
        \'branch\'      => \'master\',
      ];
      $transient->response[ $this->theme ] = $response;
    }

    return $transient;
  }

  /**
   * Construct and return the URI to the remote stylesheet
   *
   * @return string The remote stylesheet URI
   */
  protected function construct_remote_stylesheet_uri() : string {
    return $this->remote_css_uri = $this->domain . $this->repository . $this->css_endpoint;
  }

  /**
   * Construct and return the URI to the remote ZIP file
   *
   * @return string The remote ZIP URI
   */
  protected function construct_remote_zip_uri() : string {
    return $this->remote_zip_uri = $this->domain . $this->repository . $this->zip_endpoint;
  }

  /**
   * Construct and return the URI to remote repository
   *
   * @access protected
   * @since  1.0
   *
   * @return string The remote repository URI
   */
  protected function construct_repository_uri() : string {
    return $this->repository_uri = $this->domain . \\trailingslashit( $this->repository );
  }

  /**
   * Get and return the remote version
   *
   * @return string The remote version
   */
  protected function get_remote_version() : string {
    $this->remote_stylesheet_uri = $this->construct_remote_stylesheet_uri();
    $response = $this->remote_get( $this->remote_stylesheet_uri );
    $response = str_replace( "\\r", "\\n", \\wp_remote_retrieve_body( $response ) );
    $headers = [ \'Version\' => \'Version\' ];

    foreach( $headers as $field => $regex ) {
      if( preg_match( \'/^[ \\t\\/*#@]*\' . preg_quote( $regex, \'/\' ) . \':(.*)$/mi\', $response, $match ) && $match[1] ) {
        $headers[ $field ] = _cleanup_header_comment( $match[1] );
      }
      else {
        $headers[ $field ] = \'\';
      }
    }

    return $this->remote_version = ( \'\' === $headers[ \'Version\' ] ) ? \'\' : $headers[ \'Version\' ];
  }

  /**
   * Return whether the theme has an update
   *
   * @return bool Whether the theme has an update
   */
  protected function hasUpdate() : bool {
    if( ! $this->remote_version ) $this->remote_version = $this->get_remote_version();
    return version_compare( $this->remote_version, $this->local_version, \'>\' );
  }

  /**
   * Wrapper for \\wp_remote_get()
   *
   * @param string $url  The URL to get
   * @param array  $args Array or arguments to pass through to \\wp_remote_get()
   *
   * @return array|WP_Error Return the request or an error object
   */
  protected function remote_get( string $url, array $args = [] ) {
    return \\wp_remote_get( $url, $args );
  }
}

结束

相关推荐

Hooking in to plugins

我正在开发一个插件,理想情况下,当用户通过一个不同的插件做某事时,它能够做一些事情。我可以在这些插件中添加自定义挂钩,但很明显,当我想要分发插件时,这不会很好地工作。有没有一个好方法可以从我自己的插件中为其他人的插件添加钩子?唯一真正的解决方案是要求作者包含自定义挂钩,以便其他开发人员可以根据他们的工作进行构建吗?示例:当有人转发文章时,我想在插件中做一些事情。如果在流行的retweet插件中有一个自定义的钩子,我可以钩住它,然后启动它,那就太好了。没有,所以我可以修改他们的插件以包含它,但这只适用于我的