guage-html">- <ion-button type="submit" color="danger" expand="block" (click)="logout()">Log Out</ion-button> 44
+              <!-- <ion-button type="submit" color="danger" expand="block" (click)="logout()">Log Out</ion-button> -->
39 45
             </div>
40 46
           </form>
41 47
         </div>
42 48
       </ion-col>
43 49
     </ion-row>
44
-  <!-- </div> -->
45
-  <!-- <ng-template #loading>
50
+    <!-- </div> -->
51
+    <!-- <ng-template #loading>
46 52
     Loading stuff...
47 53
   </ng-template> -->
54
+  </ion-grid>
48 55
 </ion-content>

+ 1 - 0
src/app/profile/profile.page.ts

@@ -8,6 +8,7 @@ import { Component, OnInit } from '@angular/core';
8 8
 export class ProfilePage implements OnInit {
9 9
 
10 10
   user2: any;
11
+  user: any;
11 12
   
12 13
   constructor() { }
13 14
 

+ 28 - 29
src/app/province/province.page.html

@@ -6,34 +6,33 @@
6 6
     <ion-title>Wellnewss Route</ion-title>
7 7
   </ion-toolbar>
8 8
 </ion-header>
9
-
10 9
 <ion-content>
11
-  <img src="/assets/images/welcome_drone.jpeg" alt="">
12
-  <div class="holidaycard">
13
-    <ion-grid>
14
-      <ion-row>
15
-        <ion-col size="12">
16
-          <div class="txt-place-title">Province Name</div>
17
-        </ion-col>
18
-      </ion-row>
19
-      <ion-row>
20
-        <ion-col>
21
-          <ion-toolbar class="search">
22
-            <ion-searchbar placeholder="ค้นหา"></ion-searchbar>
23
-          </ion-toolbar>
24
-        </ion-col>
25
-      </ion-row>
26
-      <ion-card *ngFor="let provlist of provicelist">
27
-        <div *ngIf="$any(provlist).better_featured_image != null">
28
-          <img src="{{$any(provlist).better_featured_image.source_url}}" alt="">
29
-        </div>
30
-        <div *ngIf="$any(provlist).better_featured_image == null">
31
-          <img src="/assets/images/temp.png" />
32
-        </div>
33
-        <ion-card-header>
34
-          <a [routerLink]="['/tabs/place/', provlist.id]"><ion-card-title [innerHTML]="provlist.title.rendered"></ion-card-title></a>
35
-        </ion-card-header>
36
-      </ion-card>
37
-    </ion-grid>
38
-  </div>
10
+  <img src="/assets/images/image-004.jpg" alt="">
11
+  <ion-grid>
12
+    <ion-row>
13
+      <ion-col size="12">
14
+        <div class="txt-place-title">Province Name</div>
15
+      </ion-col>
16
+    </ion-row>
17
+    <ion-row>
18
+      <ion-col>
19
+        <ion-toolbar class="search">
20
+          <ion-searchbar placeholder="ค้นหา"></ion-searchbar>
21
+        </ion-toolbar>
22
+      </ion-col>
23
+    </ion-row>
24
+    <ion-card *ngFor="let provlist of provicelist">
25
+      <div *ngIf="$any(provlist).better_featured_image != null">
26
+        <img src="{{$any(provlist).better_featured_image.source_url}}" alt="">
27
+      </div>
28
+      <div *ngIf="$any(provlist).better_featured_image == null">
29
+        <img src="/assets/images/temp.png" />
30
+      </div>
31
+      <ion-card-header>
32
+        <a [routerLink]="['/tabs/place/', provlist.id]">
33
+          <ion-card-title [innerHTML]="provlist.title.rendered"></ion-card-title>
34
+        </a>
35
+      </ion-card-header>
36
+    </ion-card>
37
+  </ion-grid>
39 38
 </ion-content>

+ 12 - 12
src/app/province/province.page.scss

@@ -1,16 +1,16 @@
1 1
 
2
-.holidaycard {
3
-  position: absolute;
4
-  left: 0px;
5
-  // bottom: 0px;
6
-  top:200px;
7
-  min-height: 48%;
8
-  width: 100%;
9
-  padding: 5px;
10
-  border-radius: 15px ;
11
-  background: white;
12
-  --background: white;
13
-}
2
+// .holidaycard {
3
+//   position: absolute;
4
+//   left: 0px;
5
+//   // bottom: 0px;
6
+//   top:200px;
7
+//   min-height: 48%;
8
+//   width: 100%;
9
+//   padding: 5px;
10
+//   border-radius: 15px ;
11
+//   background: white;
12
+//   --background: white;
13
+// }
14 14
 
15 15
 ion-card-title {
16 16
   font-family: "IBM Plex Sans Thai", sans-serif !important;

+ 10 - 7
src/app/register-form/register-form.page.html

@@ -1,10 +1,13 @@
1 1
 <ion-header>
2
-  <ion-toolbar>
2
+  <ion-toolbar class="new-background-color">
3
+    <ion-buttons slot="start" color="light">
4
+      <ion-back-button></ion-back-button>
5
+    </ion-buttons>
3 6
     <ion-title>Wellness Route</ion-title>
4 7
   </ion-toolbar>
5 8
 </ion-header>
6
-
7 9
 <ion-content>
10
+  <div><img src="/assets/images/image-001.jpg"></div>
8 11
   <ion-row>
9 12
     <ion-col>
10 13
       <div class="ion-text-center">
@@ -13,9 +16,9 @@
13 16
     </ion-col>
14 17
   </ion-row>
15 18
   <ion-row>
16
-    <ion-col>      
19
+    <ion-col>
17 20
       <form>
18
-        <ion-text *ngIf="errorText" color="primary" style='background-color:#fff'>
21
+        <ion-text *ngIf="errorText" color="primary">
19 22
           {{ errorText }}
20 23
         </ion-text>
21 24
         <ion-item lines="full">
@@ -45,9 +48,9 @@
45 48
         </ion-item>
46 49
 
47 50
         <div class="ion-padding-vertical">
48
-          <ion-button type="submit" color="success" expand="block" (click)="register()">ลงทะเบียน</ion-button>
51
+          <ion-button type="submit" color="success" expand="block">ลงทะเบียน</ion-button>
49 52
         </div>
50 53
       </form>
51 54
     </ion-col>
52
-  </ion-row>  
53
-</ion-content>
55
+  </ion-row>
56
+</ion-content>

+ 10 - 7
src/app/register/register.page.html

@@ -1,20 +1,23 @@
1 1
 <ion-header>
2
-  <ion-toolbar>
3
-    <ion-title>ลงทะเบียน</ion-title>
2
+  <ion-toolbar class="new-background-color">
3
+    <ion-buttons slot="start" color="light">
4
+      <ion-back-button></ion-back-button>
5
+    </ion-buttons>
6
+    <ion-title>Wellness Route</ion-title>
4 7
   </ion-toolbar>
5 8
 </ion-header>
6
-
7 9
 <ion-content class="auth-form">
10
+  <div><img src="/assets/images/image-001.jpg"></div>
8 11
   <ion-grid>
9 12
     <ion-row>
10 13
       <ion-col align-self-center>
11
-        <ion-button [routerLink]="['/registration']" expand="block" color="primary">Register</ion-button>
14
+        <ion-button [routerLink]="['/register-form']" expand="block" color="primary">ลงทะเบียนผู้ใช้งาน</ion-button>
12 15
 
13
-        <span class="divider line one-line">or</span>
16
+        <span class="divider line one-line">หรือ</span>
14 17
 
15
-        <span class="already">Already a user?</span>
18
+        <span class="already">มีชื่อผู้ใช้งานแล้ว</span>
16 19
 
17
-        <ion-button [routerLink]="['/login']" expand="block" color="danger">Sign In</ion-button>
20
+        <ion-button [routerLink]="['/login']" expand="block" color="danger">เข้าสู่ระบบ</ion-button>
18 21
       </ion-col>
19 22
     </ion-row>
20 23
   </ion-grid>

+ 2 - 2
src/app/register/register.page.scss

@@ -12,7 +12,7 @@
12 12
   .line {
13 13
     align-items: center;
14 14
     margin: 1em -1em;
15
-    color: #cccccc;
15
+    color: #5f5e5e;
16 16
     
17 17
     &:before,
18 18
     &:after {
@@ -24,7 +24,7 @@
24 24
   .one-line {
25 25
     &:before,
26 26
     &:after {
27
-       background: #cccccc;
27
+       background: #5f5e5e;
28 28
     }
29 29
   }
30 30
   

+ 29 - 24
src/app/reset-password/reset-password.page.html

@@ -1,33 +1,38 @@
1 1
 <ion-header>
2
-  <ion-toolbar>
2
+  <ion-toolbar class="new-background-color">
3
+    <ion-buttons slot="start" color="light">
4
+      <ion-back-button></ion-back-button>
5
+    </ion-buttons>
3 6
     <ion-title>Wellness Route</ion-title>
4 7
   </ion-toolbar>
5 8
 </ion-header>
6
-
7 9
 <ion-content>
8
-  <ion-row>
9
-    <ion-col class="ion-text-center">
10
-      <h1>กรุณาใส่รหัสผ่านใหม่</h1>
11
-    </ion-col>
12
-  </ion-row>
13
-  <form>
14
-    <ion-row>
15
-      <ion-col>
16
-        <ion-item lines="full">
17
-          <ion-label position="floating">รหัสผ่าน</ion-label>
18
-          <ion-input type="password" required></ion-input>
19
-        </ion-item>
20
-
21
-        <ion-item lines="full">
22
-          <ion-label position="floating">ยืนยัน รหัสผ่าน</ion-label>
23
-          <ion-input type="password" required></ion-input>
24
-        </ion-item>
25
-      </ion-col>
26
-    </ion-row>
10
+  <div><img src="/assets/images/image-007.jpg"></div>
11
+  <ion-grid>
27 12
     <ion-row>
28
-      <ion-col>
29
-        <ion-button type="submit" color="success" expand="block">ส่ง</ion-button>
13
+      <ion-col class="ion-text-center">
14
+        <h1>กรุณาใส่รหัสผ่านใหม่</h1>
30 15
       </ion-col>
31 16
     </ion-row>
32
-  </form>
17
+    <form>
18
+      <ion-row>
19
+        <ion-col>
20
+          <ion-item lines="full">
21
+            <ion-label position="floating">รหัสผ่าน</ion-label>
22
+            <ion-input type="password" required></ion-input>
23
+          </ion-item>
24
+
25
+          <ion-item lines="full">
26
+            <ion-label position="floating">ยืนยัน รหัสผ่าน</ion-label>
27
+            <ion-input type="password" required></ion-input>
28
+          </ion-item>
29
+        </ion-col>
30
+      </ion-row>
31
+      <ion-row>
32
+        <ion-col>
33
+          <ion-button type="submit" color="success" expand="block">ส่ง</ion-button>
34
+        </ion-col>
35
+      </ion-row>
36
+    </form>
37
+  </ion-grid>
33 38
 </ion-content>

+ 2 - 2
src/app/tabs/tabs.page.html

@@ -1,9 +1,9 @@
1 1
 <ion-tabs>
2
-  <ion-fab vertical="bottom" horizontal="center" translucent="true">
2
+  <!-- <ion-fab vertical="bottom" horizontal="center" translucent="true">
3 3
     <ion-fab-button routerLink="nearme" routerDirection="forward">
4 4
     <ion-icon name="navigate"></ion-icon>
5 5
     </ion-fab-button>
6
-  </ion-fab>
6
+  </ion-fab> -->
7 7
   <ion-tab-bar slot="bottom">
8 8
     <ion-tab-button tab="home">
9 9
       <ion-icon name="home"></ion-icon>

+ 2 - 1
src/app/wp-service.service.ts

@@ -31,7 +31,8 @@ export class WpServiceService {
31 31
 
32 32
   getPlaceDetail(id) {
33 33
     return this.http.get(
34
-      "http://tamtime.iamarray.xyz/wp-json/wp/v2/place/"+id+"/?_embed"
34
+      // "http://tamtime.iamarray.xyz/wp-json/wp/v2/place/"+id+"/?_embed"
35
+      "/assets/json/place173.json"
35 36
     );
36 37
   }
37 38
 

BIN
src/assets/images/image-001.jpg


BIN
src/assets/images/image-002.jpg


BIN
src/assets/images/image-003.jpg


BIN
src/assets/images/image-004.jpg


BIN
src/assets/images/image-005.jpg


BIN
src/assets/images/image-006.jpg


BIN
src/assets/images/image-007.jpg


BIN
src/assets/images/image-008.jpg


BIN
src/assets/images/image-009.jpg


BIN
src/assets/images/image-010.jpg


BIN
src/assets/images/image-011.jpg


BIN
src/assets/images/image-012.jpg


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 0
src/assets/json/place173.json


+ 18 - 7
src/global.scss

@@ -116,6 +116,17 @@
116 116
   --color: #ffffff;
117 117
 }
118 118
 
119
+// ion-content {
120
+//   --background: linear-gradient(
121
+//     to bottom,
122
+//     #a7e9ff,
123
+//     #8fd8fd,
124
+//     #7ec7fb,
125
+//     #78b4f6,
126
+//     #7c9fee
127
+//   );
128
+// }
129
+
119 130
 ion-title {
120 131
   font-family: "Kanit", sans-serif !important;
121 132
   font-weight: 500;
@@ -160,12 +171,12 @@ ion-button {
160 171
 
161 172
 a {
162 173
   text-decoration: none;
163
- }
164
- 
165
-// ion-content {
166
-//   --background: url(/assets/images/wnr-bg.jpg) no-repeat center/cover fixed;
167
-// }
174
+}
175
+
176
+.image-page-cover {
177
+  height: 200px;
178
+}
168 179
 .ios ion-fab-button {
169
-  position:absolute;
180
+  position: absolute;
170 181
   bottom: 25px;
171
-}
182
+}

tum/whitesports - Gogs: Simplico Git Service

Bez popisu

copy-post.php 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. <?php
  2. /**
  3. * Module Name: Copy Post
  4. * Module Description: Enable the option to copy entire posts and pages, including tags and settings
  5. * Sort Order: 15
  6. * First Introduced: 7.0
  7. * Requires Connection: No
  8. * Auto Activate: No
  9. * Module Tags: Writing
  10. * Feature: Writing
  11. * Additional Search Queries: copy, duplicate
  12. */
  13. /**
  14. * Copy Post class.
  15. */
  16. class Jetpack_Copy_Post {
  17. /**
  18. * Jetpack_Copy_Post_By_Param constructor.
  19. * Add row actions to post/page/CPT listing screens.
  20. * Process any `?copy` param if on a create new post/page/CPT screen.
  21. *
  22. * @return void
  23. */
  24. public function __construct() {
  25. if ( 'edit.php' === $GLOBALS['pagenow'] ) {
  26. add_filter( 'post_row_actions', array( $this, 'add_row_action' ), 10, 2 );
  27. add_filter( 'page_row_actions', array( $this, 'add_row_action' ), 10, 2 );
  28. return;
  29. }
  30. if ( ! empty( $_GET['jetpack-copy'] ) && 'post-new.php' === $GLOBALS['pagenow'] ) {
  31. add_action( 'wp_insert_post', array( $this, 'update_post_data' ), 10, 3 );
  32. add_filter( 'pre_option_default_post_format', '__return_empty_string' );
  33. }
  34. }
  35. /**
  36. * Update the new (target) post data with the source post data.
  37. *
  38. * @param int $target_post_id Target post ID.
  39. * @param WP_Post $post Target post object (not used).
  40. * @param bool $update Whether this is an existing post being updated or not.
  41. * @return void
  42. */
  43. public function update_post_data( $target_post_id, $post, $update ) {
  44. global $wp_version;
  45. // This `$update` check avoids infinite loops of trying to update our updated post.
  46. if ( $update ) {
  47. return;
  48. }
  49. $source_post = get_post( $_GET['jetpack-copy'] );
  50. if ( ! $source_post instanceof WP_Post ||
  51. ! $this->user_can_access_post( $source_post->ID ) ||
  52. ! $this->validate_post_type( $source_post ) ) {
  53. return;
  54. }
  55. $update_results = array(
  56. 'update_content' => $this->update_content( $source_post, $target_post_id ),
  57. 'update_featured_image' => $this->update_featured_image( $source_post, $target_post_id ),
  58. 'update_post_format' => $this->update_post_format( $source_post, $target_post_id ),
  59. 'update_likes_sharing' => $this->update_likes_sharing( $source_post, $target_post_id ),
  60. 'update_post_type_terms' => $this->update_post_type_terms( $source_post, $target_post_id ),
  61. );
  62. // Required to satisfy get_default_post_to_edit(), which has these filters after post creation.
  63. add_filter( 'default_title', array( $this, 'filter_title' ), 10, 2 );
  64. add_filter( 'default_content', array( $this, 'filter_content' ), 10, 2 );
  65. add_filter( 'default_excerpt', array( $this, 'filter_excerpt' ), 10, 2 );
  66. /*
  67. * Required to avoid the block editor from adding default blocks according to post format.
  68. * @todo: simplify once WordPress 5.8 is the minimum required version.
  69. */
  70. if ( version_compare( $wp_version, '5.8', '>=' ) ) {
  71. add_filter( 'block_editor_settings_all', array( $this, 'remove_post_format_template' ) );
  72. } else {
  73. add_filter( 'block_editor_settings', array( $this, 'remove_post_format_template' ) );
  74. }
  75. /**
  76. * Fires after all updates have been performed, and default content filters have been added.
  77. * Allows for any cleanup or post operations, and default content filters can be removed or modified.
  78. *
  79. * @module copy-post
  80. *
  81. * @since 7.0.0
  82. *
  83. * @param WP_Post $source_post Post object that was copied.
  84. * @param int $target_post_id Target post ID.
  85. * @param array $update_results Results of all update operations, allowing action to be taken.
  86. */
  87. do_action( 'jetpack_copy_post', $source_post, $target_post_id, $update_results );
  88. }
  89. /**
  90. * Determine if the current user has edit access to the source post.
  91. *
  92. * @param int $post_id Source post ID (the post being copied).
  93. * @return bool True if user has the meta cap of `edit_post` for the given post ID, false otherwise.
  94. */
  95. protected function user_can_access_post( $post_id ) {
  96. return current_user_can( 'edit_post', $post_id );
  97. }
  98. /**
  99. * Update the target post's title, content, excerpt, categories, and tags.
  100. *
  101. * @param WP_Post $source_post Post object to be copied.
  102. * @param int $target_post_id Target post ID.
  103. * @return int 0 on failure, or the updated post ID on success.
  104. */
  105. protected function update_content( $source_post, $target_post_id ) {
  106. $data = array(
  107. 'ID' => $target_post_id,
  108. 'post_title' => $source_post->post_title,
  109. 'post_content' => $source_post->post_content,
  110. 'post_excerpt' => $source_post->post_excerpt,
  111. 'comment_status' => $source_post->comment_status,
  112. 'ping_status' => $source_post->ping_status,
  113. 'post_category' => wp_get_post_categories( $source_post->ID ),
  114. 'post_password' => $source_post->post_password,
  115. 'tags_input' => $source_post->tags_input,
  116. );
  117. /**
  118. * Fires just before the target post is updated with its new data.
  119. * Allows for final data adjustments before updating the target post.
  120. *
  121. * @module copy-post
  122. *
  123. * @since 7.0.0
  124. *
  125. * @param array $data Post data with which to update the target (new) post.
  126. * @param WP_Post $source_post Post object being copied.
  127. * @param int $target_post_id Target post ID.
  128. */
  129. $data = apply_filters( 'jetpack_copy_post_data', $data, $source_post, $target_post_id );
  130. return wp_update_post( $data );
  131. }
  132. /**
  133. * Update terms for post types.
  134. *
  135. * @param WP_Post $source_post Post object to be copied.
  136. * @param int $target_post_id Target post ID.
  137. * @return array Results of attempts to set each term to the target (new) post.
  138. */
  139. protected function update_post_type_terms( $source_post, $target_post_id ) {
  140. $results = array();
  141. $bypassed_post_types = apply_filters( 'jetpack_copy_post_bypassed_post_types', array( 'post', 'page' ), $source_post, $target_post_id );
  142. if ( in_array( $source_post->post_type, $bypassed_post_types, true ) ) {
  143. return $results;
  144. }
  145. $taxonomies = get_object_taxonomies( $source_post, 'objects' );
  146. foreach ( $taxonomies as $taxonomy ) {
  147. $terms = wp_get_post_terms( $source_post->ID, $taxonomy->name, array( 'fields' => 'ids' ) );
  148. $results[] = wp_set_post_terms( $target_post_id, $terms, $taxonomy->name );
  149. }
  150. return $results;
  151. }
  152. /**
  153. * Update the target post's featured image.
  154. *
  155. * @param WP_Post $source_post Post object to be copied.
  156. * @param int $target_post_id Target post ID.
  157. * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
  158. */
  159. protected function update_featured_image( $source_post, $target_post_id ) {
  160. $featured_image_id = get_post_thumbnail_id( $source_post );
  161. return update_post_meta( $target_post_id, '_thumbnail_id', $featured_image_id );
  162. }
  163. /**
  164. * Update the target post's post format.
  165. *
  166. * @param WP_Post $source_post Post object to be copied.
  167. * @param int $target_post_id Target post ID.
  168. * @return array|WP_Error|false WP_Error on error, array of affected term IDs on success.
  169. */
  170. protected function update_post_format( $source_post, $target_post_id ) {
  171. $post_format = get_post_format( $source_post );
  172. return set_post_format( $target_post_id, $post_format );
  173. }
  174. /**
  175. * Ensure the block editor doesn't modify the source post content for non-standard post formats.
  176. *
  177. * @param array $settings Settings to be passed into the block editor.
  178. * @return array Settings with any `template` key removed.
  179. */
  180. public function remove_post_format_template( $settings ) {
  181. unset( $settings['template'] );
  182. return $settings;
  183. }
  184. /**
  185. * Update the target post's Likes and Sharing statuses.
  186. *
  187. * @param WP_Post $source_post Post object to be copied.
  188. * @param int $target_post_id Target post ID.
  189. * @return array Array with the results of each update action.
  190. */
  191. protected function update_likes_sharing( $source_post, $target_post_id ) {
  192. $likes = get_post_meta( $source_post->ID, 'switch_like_status', true );
  193. $sharing = get_post_meta( $source_post->ID, 'sharing_disabled', true );
  194. if ( '' !== $likes ) {
  195. $likes_result = update_post_meta( $target_post_id, 'switch_like_status', $likes );
  196. } else {
  197. $likes_result = null;
  198. }
  199. if ( '' !== $sharing ) {
  200. $sharing_result = update_post_meta( $target_post_id, 'sharing_disabled', $sharing );
  201. } else {
  202. $sharing_result = null;
  203. }
  204. return array(
  205. 'likes' => $likes_result,
  206. 'sharing' => $sharing_result,
  207. );
  208. }
  209. /**
  210. * Update the target post's title.
  211. *
  212. * @param string $post_title Post title determined by `get_default_post_to_edit()`.
  213. * @param WP_Post $post Post object of newly-inserted post.
  214. * @return string Updated post title from source post.
  215. */
  216. public function filter_title( $post_title, $post ) {
  217. return $post->post_title;
  218. }
  219. /**
  220. * Update the target post's content (`post_content`).
  221. *
  222. * @param string $post_content Post content determined by `get_default_post_to_edit()`.
  223. * @param WP_Post $post Post object of newly-inserted post.
  224. * @return string Updated post content from source post.
  225. */
  226. public function filter_content( $post_content, $post ) {
  227. return $post->post_content;
  228. }
  229. /**
  230. * Update the target post's excerpt.
  231. *
  232. * @param string $post_excerpt Post excerpt determined by `get_default_post_to_edit()`.
  233. * @param WP_Post $post Post object of newly-inserted post.
  234. * @return string Updated post excerpt from source post.
  235. */
  236. public function filter_excerpt( $post_excerpt, $post ) {
  237. return $post->post_excerpt;
  238. }
  239. /**
  240. * Validate the post type to be used for the target post.
  241. *
  242. * @param WP_Post $post Post object of current post in listing.
  243. * @return bool True if the post type is in a list of supported psot types; false otherwise.
  244. */
  245. protected function validate_post_type( $post ) {
  246. /**
  247. * Fires when determining if the "Copy" row action should be made available.
  248. * Allows overriding supported post types.
  249. *
  250. * @module copy-post
  251. *
  252. * @since 7.0.0
  253. *
  254. * @param array Post types supported by default.
  255. * @param WP_Post $post Post object of current post in listing.
  256. */
  257. $valid_post_types = apply_filters(
  258. 'jetpack_copy_post_post_types',
  259. array(
  260. 'post',
  261. 'page',
  262. 'jetpack-testimonial',
  263. 'jetpack-portfolio',
  264. ),
  265. $post
  266. );
  267. return in_array( $post->post_type, $valid_post_types, true );
  268. }
  269. /**
  270. * Add a "Copy" row action to supported posts/pages/CPTs on list views.
  271. *
  272. * @param array $actions Existing actions.
  273. * @param WP_Post $post Post object of current post in list.
  274. * @return array Array of updated row actions.
  275. */
  276. public function add_row_action( $actions, $post ) {
  277. if ( ! $this->user_can_access_post( $post->ID ) ||
  278. ! $post instanceof WP_Post ||
  279. ! $this->validate_post_type( $post ) ) {
  280. return $actions;
  281. }
  282. $edit_url = add_query_arg(
  283. array(
  284. 'post_type' => $post->post_type,
  285. 'jetpack-copy' => $post->ID,
  286. ),
  287. admin_url( 'post-new.php' )
  288. );
  289. $edit_action = array(
  290. 'jetpack-copy' => sprintf(
  291. '<a href="%s" aria-label="%s">%s</a>',
  292. esc_url( $edit_url ),
  293. esc_attr__( 'Copy this post.', 'jetpack' ),
  294. esc_html__( 'Copy', 'jetpack' )
  295. ),
  296. );
  297. // Insert the Copy action before the Trash action.
  298. $edit_offset = array_search( 'trash', array_keys( $actions ), true );
  299. $updated_actions = array_merge(
  300. array_slice( $actions, 0, $edit_offset ),
  301. $edit_action,
  302. array_slice( $actions, $edit_offset )
  303. );
  304. /**
  305. * Fires after the new Copy action has been added to the row actions.
  306. * Allows changes to the action presentation, or other final checks.
  307. *
  308. * @module copy-post
  309. *
  310. * @since 7.0.0
  311. *
  312. * @param array $updated_actions Updated row actions with the Copy Post action.
  313. * @param array $actions Original row actions passed to this filter.
  314. * @param WP_Post $post Post object of current post in listing.
  315. */
  316. return apply_filters( 'jetpack_copy_post_row_actions', $updated_actions, $actions, $post );
  317. }
  318. }
  319. /**
  320. * Instantiate an instance of Jetpack_Copy_Post on the `admin_init` hook.
  321. */
  322. function jetpack_copy_post_init() {
  323. new Jetpack_Copy_Post();
  324. }
  325. add_action( 'admin_init', 'jetpack_copy_post_init' );