PluginUpdateChecker.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <?php
  2. if ( !class_exists('Puc_v4p11_Vcs_PluginUpdateChecker') ):
  3. class Puc_v4p11_Vcs_PluginUpdateChecker extends Puc_v4p11_Plugin_UpdateChecker implements Puc_v4p11_Vcs_BaseChecker {
  4. /**
  5. * @var string The branch where to look for updates. Defaults to "master".
  6. */
  7. protected $branch = 'master';
  8. /**
  9. * @var Puc_v4p11_Vcs_Api Repository API client.
  10. */
  11. protected $api = null;
  12. /**
  13. * Puc_v4p11_Vcs_PluginUpdateChecker constructor.
  14. *
  15. * @param Puc_v4p11_Vcs_Api $api
  16. * @param string $pluginFile
  17. * @param string $slug
  18. * @param int $checkPeriod
  19. * @param string $optionName
  20. * @param string $muPluginFile
  21. */
  22. public function __construct($api, $pluginFile, $slug = '', $checkPeriod = 12, $optionName = '', $muPluginFile = '') {
  23. $this->api = $api;
  24. $this->api->setHttpFilterName($this->getUniqueName('request_info_options'));
  25. parent::__construct($api->getRepositoryUrl(), $pluginFile, $slug, $checkPeriod, $optionName, $muPluginFile);
  26. $this->api->setSlug($this->slug);
  27. }
  28. public function requestInfo($unusedParameter = null) {
  29. //We have to make several remote API requests to gather all the necessary info
  30. //which can take a while on slow networks.
  31. if ( function_exists('set_time_limit') ) {
  32. @set_time_limit(60);
  33. }
  34. $api = $this->api;
  35. $api->setLocalDirectory($this->package->getAbsoluteDirectoryPath());
  36. $info = new Puc_v4p11_Plugin_Info();
  37. $info->filename = $this->pluginFile;
  38. $info->slug = $this->slug;
  39. $this->setInfoFromHeader($this->package->getPluginHeader(), $info);
  40. //Pick a branch or tag.
  41. $updateSource = $api->chooseReference($this->branch);
  42. if ( $updateSource ) {
  43. $ref = $updateSource->name;
  44. $info->version = $updateSource->version;
  45. $info->last_updated = $updateSource->updated;
  46. $info->download_url = $updateSource->downloadUrl;
  47. if ( !empty($updateSource->changelog) ) {
  48. $info->sections['changelog'] = $updateSource->changelog;
  49. }
  50. if ( isset($updateSource->downloadCount) ) {
  51. $info->downloaded = $updateSource->downloadCount;
  52. }
  53. } else {
  54. //There's probably a network problem or an authentication error.
  55. do_action(
  56. 'puc_api_error',
  57. new WP_Error(
  58. 'puc-no-update-source',
  59. 'Could not retrieve version information from the repository. '
  60. . 'This usually means that the update checker either can\'t connect '
  61. . 'to the repository or it\'s configured incorrectly.'
  62. ),
  63. null, null, $this->slug
  64. );
  65. return null;
  66. }
  67. //Get headers from the main plugin file in this branch/tag. Its "Version" header and other metadata
  68. //are what the WordPress install will actually see after upgrading, so they take precedence over releases/tags.
  69. $mainPluginFile = basename($this->pluginFile);
  70. $remotePlugin = $api->getRemoteFile($mainPluginFile, $ref);
  71. if ( !empty($remotePlugin) ) {
  72. $remoteHeader = $this->package->getFileHeader($remotePlugin);
  73. $this->setInfoFromHeader($remoteHeader, $info);
  74. }
  75. //Try parsing readme.txt. If it's formatted according to WordPress.org standards, it will contain
  76. //a lot of useful information like the required/tested WP version, changelog, and so on.
  77. if ( $this->readmeTxtExistsLocally() ) {
  78. $this->setInfoFromRemoteReadme($ref, $info);
  79. }
  80. //The changelog might be in a separate file.
  81. if ( empty($info->sections['changelog']) ) {
  82. $info->sections['changelog'] = $api->getRemoteChangelog($ref, $this->package->getAbsoluteDirectoryPath());
  83. if ( empty($info->sections['changelog']) ) {
  84. $info->sections['changelog'] = __('There is no changelog available.', 'plugin-update-checker');
  85. }
  86. }
  87. if ( empty($info->last_updated) ) {
  88. //Fetch the latest commit that changed the tag or branch and use it as the "last_updated" date.
  89. $latestCommitTime = $api->getLatestCommitTime($ref);
  90. if ( $latestCommitTime !== null ) {
  91. $info->last_updated = $latestCommitTime;
  92. }
  93. }
  94. $info = apply_filters($this->getUniqueName('request_info_result'), $info, null);
  95. return $info;
  96. }
  97. /**
  98. * Check if the currently installed version has a readme.txt file.
  99. *
  100. * @return bool
  101. */
  102. protected function readmeTxtExistsLocally() {
  103. return $this->package->fileExists($this->api->getLocalReadmeName());
  104. }
  105. /**
  106. * Copy plugin metadata from a file header to a Plugin Info object.
  107. *
  108. * @param array $fileHeader
  109. * @param Puc_v4p11_Plugin_Info $pluginInfo
  110. */
  111. protected function setInfoFromHeader($fileHeader, $pluginInfo) {
  112. $headerToPropertyMap = array(
  113. 'Version' => 'version',
  114. 'Name' => 'name',
  115. 'PluginURI' => 'homepage',
  116. 'Author' => 'author',
  117. 'AuthorName' => 'author',
  118. 'AuthorURI' => 'author_homepage',
  119. 'Requires WP' => 'requires',
  120. 'Tested WP' => 'tested',
  121. 'Requires at least' => 'requires',
  122. 'Tested up to' => 'tested',
  123. 'Requires PHP' => 'requires_php',
  124. );
  125. foreach ($headerToPropertyMap as $headerName => $property) {
  126. if ( isset($fileHeader[$headerName]) && !empty($fileHeader[$headerName]) ) {
  127. $pluginInfo->$property = $fileHeader[$headerName];
  128. }
  129. }
  130. if ( !empty($fileHeader['Description']) ) {
  131. $pluginInfo->sections['description'] = $fileHeader['Description'];
  132. }
  133. }
  134. /**
  135. * Copy plugin metadata from the remote readme.txt file.
  136. *
  137. * @param string $ref GitHub tag or branch where to look for the readme.
  138. * @param Puc_v4p11_Plugin_Info $pluginInfo
  139. */
  140. protected function setInfoFromRemoteReadme($ref, $pluginInfo) {
  141. $readme = $this->api->getRemoteReadme($ref);
  142. if ( empty($readme) ) {
  143. return;
  144. }
  145. if ( isset($readme['sections']) ) {
  146. $pluginInfo->sections = array_merge($pluginInfo->sections, $readme['sections']);
  147. }
  148. if ( !empty($readme['tested_up_to']) ) {
  149. $pluginInfo->tested = $readme['tested_up_to'];
  150. }
  151. if ( !empty($readme['requires_at_least']) ) {
  152. $pluginInfo->requires = $readme['requires_at_least'];
  153. }
  154. if ( !empty($readme['requires_php']) ) {
  155. $pluginInfo->requires_php = $readme['requires_php'];
  156. }
  157. if ( isset($readme['upgrade_notice'], $readme['upgrade_notice'][$pluginInfo->version]) ) {
  158. $pluginInfo->upgrade_notice = $readme['upgrade_notice'][$pluginInfo->version];
  159. }
  160. }
  161. public function setBranch($branch) {
  162. $this->branch = $branch;
  163. return $this;
  164. }
  165. public function setAuthentication($credentials) {
  166. $this->api->setAuthentication($credentials);
  167. return $this;
  168. }
  169. public function getVcsApi() {
  170. return $this->api;
  171. }
  172. public function getUpdate() {
  173. $update = parent::getUpdate();
  174. if ( isset($update) && !empty($update->download_url) ) {
  175. $update->download_url = $this->api->signDownloadUrl($update->download_url);
  176. }
  177. return $update;
  178. }
  179. public function onDisplayConfiguration($panel) {
  180. parent::onDisplayConfiguration($panel);
  181. $panel->row('Branch', $this->branch);
  182. $panel->row('Authentication enabled', $this->api->isAuthenticationEnabled() ? 'Yes' : 'No');
  183. $panel->row('API client', get_class($this->api));
  184. }
  185. }
  186. endif;