├── dev
├── dockerfile
├── .env
├── install.md
├── .htaccess
└── docker-compose.yml
├── WordPressPCL
├── Images
│ └── icon.png
├── Interfaces
│ ├── ICountOperation.cs
│ ├── IDeleteOperation.cs
│ ├── ICreateOperation.cs
│ ├── IUpdateOperation.cs
│ ├── IQueryOperation.cs
│ └── IReadOperation.cs
├── Models
│ ├── CommentThreaded.cs
│ ├── AuthMethod.cs
│ ├── Base.cs
│ ├── JWTPlugin.cs
│ ├── BadRequest.cs
│ ├── AvatarURL.cs
│ ├── JWTResponse.cs
│ ├── JWTData.cs
│ ├── JWTUser.cs
│ ├── MediaSize.cs
│ ├── MediaDetails.cs
│ ├── Embedded.cs
│ ├── Tag.cs
│ ├── ApplicationPassword.cs
│ ├── Category.cs
│ ├── Term.cs
│ ├── Exceptions
│ │ ├── WPException.cs
│ │ └── WPUnexpectedException.cs
│ ├── ImageMeta.cs
│ ├── Links.cs
│ ├── PostStatus.cs
│ ├── PostType.cs
│ ├── Taxonomy.cs
│ ├── Theme.cs
│ ├── Settings.cs
│ └── Plugin.cs
├── Utility
│ ├── TaxonomiesQueryBuilder.cs
│ ├── ThemesQueryBuilder.cs
│ ├── PluginsQueryBuilder.cs
│ ├── QueryTextAttribute.cs
│ ├── ExcludeQueryTextAttribute.cs
│ ├── CustomCapabilitiesJsonConverter.cs
│ ├── UrlHelper.cs
│ ├── TagsQueryBuilder.cs
│ ├── UsersQueryBuilder.cs
│ └── CategoriesQueryBuilder.cs
└── Client
│ ├── Tags.cs
│ ├── Categories.cs
│ ├── Settings.cs
│ ├── Themes.cs
│ ├── Pages.cs
│ ├── PostRevisions.cs
│ ├── PostTypes.cs
│ ├── PostStatuses.cs
│ ├── Comments.cs
│ ├── CustomRequest.cs
│ └── Taxonomies.cs
├── mkdocs.yml
├── WordPressPCL.Tests.Selfhosted
├── Assets
│ ├── cat.jpg
│ └── img_exif_error.jpg
├── jwt.runsettings
├── jwtauth.runsettings
├── Utility
│ ├── ApiCredentials.cs
│ ├── UrlHelper_Tests.cs
│ ├── ClientHelper.cs
│ └── HttpHelper_Tests.cs
├── MimeTypeHelper_Tests.cs
├── Settings_Tests.cs
├── QueryBuilder_Tests.cs
├── WordPressPCL.Tests.Selfhosted.csproj
├── PostStatuses_Tests.cs
├── PostTypes_Tests.cs
├── Themes_Tests.cs
├── Taxonomies_Tests.cs
├── HttpClient_Tests.cs
├── ListPosts_QueryBuilder_Tests.cs
├── ApplicationPasswords_Tests.cs
├── PostRevisions_Tests.cs
├── Exception_Unexpected_Tests.cs
├── Plugins_Tests.cs
├── ExceptionTests.cs
├── CustomRequests_Tests.cs
├── Pages_Tests.cs
├── Tag_Tests.cs
└── Categories_Tests.cs
├── WordPressPCL.Tests.Hosted
├── Utility
│ ├── ClientHelper.cs
│ ├── ApiCredentials.cs
│ └── HttpHelper_Tests.cs
├── WordPressPCL.Tests.Hosted.csproj
└── Basic_Tests.cs
├── docs
├── II version 1.x
│ ├── entities
│ │ ├── settings.md
│ │ ├── posttypes.md
│ │ ├── taxonomies.md
│ │ ├── poststatuses.md
│ │ ├── customPostType.md
│ │ ├── tags.md
│ │ ├── pages.md
│ │ ├── categories.md
│ │ ├── posts.md
│ │ ├── users.md
│ │ ├── comments.md
│ │ └── media.md
│ ├── customization
│ │ ├── customHttpClient.md
│ │ ├── customJsonSerializationSettings.md
│ │ ├── customRequest.md
│ │ └── httpResponsePreProcessing.md
│ └── troubleshooting.md
├── I version 2.x
│ ├── entities
│ │ ├── settings.md
│ │ ├── posttypes.md
│ │ ├── taxonomies.md
│ │ ├── poststatuses.md
│ │ ├── customPostType.md
│ │ ├── tags.md
│ │ ├── pages.md
│ │ ├── categories.md
│ │ ├── media.md
│ │ ├── comments.md
│ │ ├── posts.md
│ │ └── users.md
│ ├── breaking-changes.md
│ ├── customization
│ │ ├── customHttpClient.md
│ │ ├── customJsonSerializationSettings.md
│ │ ├── customRequest.md
│ │ └── httpResponsePreProcessing.md
│ └── troubleshooting.md
└── index.md
├── .github
├── FUNDING.yml
└── workflows
│ ├── publish-nuget.yml
│ ├── documentation.yml
│ ├── integration-tests.yml
│ └── codeql-analysis.yml
├── LICENSE
├── .gitattributes
└── CODE_OF_CONDUCT.md
/dev/dockerfile:
--------------------------------------------------------------------------------
1 | FROM wordpress:latest
2 |
3 | COPY ./.htaccess /var/www/html/
4 |
--------------------------------------------------------------------------------
/WordPressPCL/Images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wp-net/WordPressPCL/master/WordPressPCL/Images/icon.png
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: WordPressPCL
2 | site_url: https://wp-net.github.io/WordPressPCL/
3 | theme: readthedocs
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/Assets/cat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wp-net/WordPressPCL/master/WordPressPCL.Tests.Selfhosted/Assets/cat.jpg
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/Assets/img_exif_error.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wp-net/WordPressPCL/master/WordPressPCL.Tests.Selfhosted/Assets/img_exif_error.jpg
--------------------------------------------------------------------------------
/dev/.env:
--------------------------------------------------------------------------------
1 | MYSQL_ROOT_PASSWORD=wordpress
2 | MYSQL_DATABASE=wordpress
3 | MYSQL_USER=wordpress
4 | MYSQL_PASSWORD=wordpress
5 |
6 | WORDPRESS_DB_HOST=db:3306
7 | WORDPRESS_DB_USER=wordpress
8 | WORDPRESS_DB_PASSWORD=wordpress
9 | WORDPRESS_DB_NAME=wordpress
10 | WORDPRESS_DEBUG=1
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/jwt.runsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/jwtauth.runsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/Utility/ApiCredentials.cs:
--------------------------------------------------------------------------------
1 | namespace WordPressPCL.Tests.Selfhosted.Utility;
2 |
3 | public class ApiCredentials
4 | {
5 | public static string WordPressUri = "http://localhost:8080/wp-json/";
6 | public static string Username = "wordpress";
7 | public static string Password = "wordpress";
8 | }
9 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Hosted/Utility/ClientHelper.cs:
--------------------------------------------------------------------------------
1 | namespace WordPressPCL.Tests.Hosted.Utility;
2 |
3 | public static class ClientHelper
4 | {
5 | private static WordPressClient _client;
6 |
7 | public static WordPressClient GetWordPressClient()
8 | {
9 | if(_client == null)
10 | _client = new WordPressClient(ApiCredentials.WordPressUri, "");
11 | return _client;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Hosted/Utility/ApiCredentials.cs:
--------------------------------------------------------------------------------
1 | namespace WordPressPCL.Tests.Hosted.Utility
2 | {
3 | public class ApiCredentials
4 | {
5 | public static string SiteUri = "mysite.wordpress.com";
6 | public static string WordPressUri = $"https://public-api.wordpress.com/wp/v2/sites/{SiteUri}/";
7 | public static string Username = "Name";
8 | public static string Password = "password";
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/WordPressPCL/Interfaces/ICountOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace WordPressPCL.Interfaces {
4 |
5 | ///
6 | /// Interface for count of Wordpress items
7 | ///
8 | public interface ICountOperation
9 | {
10 | ///
11 | /// Get Count of Wordpress items
12 | ///
13 | /// Result of Operation
14 | Task GetCountAsync();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/docs/II version 1.x/entities/settings.md:
--------------------------------------------------------------------------------
1 | # Settings
2 |
3 | Here is a list of methods and examples of working with Settings
4 |
5 | ## GetSettings()
6 |
7 | ```C#
8 | // returns current settings
9 | var settings = await client.GetSettings();
10 | ```
11 |
12 | ## Update Settings
13 | ```C#
14 | //update settings
15 | var settings = await client.GetSettings();
16 | settings.Description = "New Site Description";
17 | var updatedSettings = await client.UpdateSettings(settings);
18 | ```
--------------------------------------------------------------------------------
/WordPressPCL/Models/CommentThreaded.cs:
--------------------------------------------------------------------------------
1 | namespace WordPressPCL.Models
2 | {
3 | ///
4 | /// An extension class for Comment that holds a depth property
5 | /// for displaying threaded comments
6 | ///
7 | public class CommentThreaded : Comment
8 | {
9 | ///
10 | /// The depth of a comment
11 | /// 0 is a top level comments without parent
12 | ///
13 | public int Depth { get; set; }
14 | }
15 | }
--------------------------------------------------------------------------------
/WordPressPCL/Utility/TaxonomiesQueryBuilder.cs:
--------------------------------------------------------------------------------
1 | namespace WordPressPCL.Utility
2 | {
3 | ///
4 | /// Taxonomies Query Builder class to construct queries with valid parameters
5 | ///
6 | public class TaxonomiesQueryBuilder : QueryBuilder
7 | {
8 | ///
9 | /// Limit results to taxonomies associated with a specific post type.
10 | ///
11 | [QueryText("type")]
12 | public string Type { get; set; }
13 | }
14 | }
--------------------------------------------------------------------------------
/WordPressPCL/Utility/ThemesQueryBuilder.cs:
--------------------------------------------------------------------------------
1 | using WordPressPCL.Models;
2 |
3 | namespace WordPressPCL.Utility
4 | {
5 | ///
6 | /// Themes Query Builder class to construct queries with valid parameters
7 | ///
8 | public class ThemesQueryBuilder : QueryBuilder
9 | {
10 | ///
11 | /// Limit results to specific status
12 | ///
13 | [QueryText("status")]
14 | public ActivationStatus Status { get; set; }
15 |
16 |
17 | }
18 | }
--------------------------------------------------------------------------------
/docs/I version 2.x/entities/settings.md:
--------------------------------------------------------------------------------
1 | # Settings
2 |
3 | Here is a list of methods and examples of working with Settings
4 |
5 | ## Get Settings
6 |
7 | ```C#
8 | // returns current settings
9 | var settings = await client.Settings.GetSettingsAsync();
10 | ```
11 |
12 | ## Update Settings
13 | ```C#
14 | //update settings
15 | var settings = await client.Settings.GetSettingsAsync();
16 | settings.Description = "New Site Description";
17 | var updatedSettings = await client.Settings.UpdateSettingsAsync(settings);
18 | ```
--------------------------------------------------------------------------------
/WordPressPCL/Interfaces/IDeleteOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace WordPressPCL.Interfaces
4 | {
5 | ///
6 | /// Interface with required Delete methods
7 | ///
8 | public interface IDeleteOperation
9 | {
10 | ///
11 | /// Delete object by Id
12 | ///
13 | /// ID ob object to delete
14 | /// Result of operation
15 | Task DeleteAsync(int ID);
16 | }
17 | }
--------------------------------------------------------------------------------
/WordPressPCL/Models/AuthMethod.cs:
--------------------------------------------------------------------------------
1 | namespace WordPressPCL.Models
2 | {
3 | ///
4 | /// Authentication Methods
5 | /// JWT - recommended AUTH method
6 | ///
7 | public enum AuthMethod
8 | {
9 | ///
10 | /// Bearer Authentication using token
11 | ///
12 | Bearer,
13 | ///
14 | /// Basic Authentication using Application Passwords introduced in Wordpress 5.6
15 | ///
16 | Basic
17 | }
18 | }
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/Utility/UrlHelper_Tests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using WordPressPCL.Utility;
3 |
4 | namespace WordPressPCL.Tests.Selfhosted.Utility;
5 |
6 | [TestClass]
7 | public class UrlHelper_Tests
8 | {
9 |
10 |
11 | [TestMethod]
12 | public void SetQueryParam_Test()
13 | {
14 | string test = "test";
15 | string result = test.SetQueryParam("param", "value");
16 |
17 | Assert.AreEqual("test", test);
18 | Assert.AreEqual("test?param=value", result);
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/WordPressPCL/Models/Base.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace WordPressPCL.Models
4 | {
5 | ///
6 | /// Base class for Models
7 | ///
8 | public class Base
9 | {
10 | ///
11 | /// Unique identifier for the object.
12 | ///
13 | ///
14 | /// Read only
15 | /// Context: view, edit, embed
16 | ///
17 | [JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Ignore)]
18 | public int Id { get; set; }
19 | }
20 | }
--------------------------------------------------------------------------------
/WordPressPCL/Interfaces/ICreateOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace WordPressPCL.Interfaces
4 | {
5 | ///
6 | /// Interface with required Create methods
7 | ///
8 | /// return class type
9 | public interface ICreateOperation
10 | {
11 | ///
12 | /// Create object
13 | ///
14 | /// object to create
15 | /// Created object
16 | Task CreateAsync(TClass Entity);
17 | }
18 | }
--------------------------------------------------------------------------------
/WordPressPCL/Models/JWTPlugin.cs:
--------------------------------------------------------------------------------
1 | namespace WordPressPCL.Models {
2 |
3 | ///
4 | /// JWT Plugins supported
5 | ///
6 | public enum JWTPlugin {
7 |
8 | ///
9 | /// JWT Authentication for WP REST API plugin
10 | /// Author - Enrique Chavez
11 | ///
12 | JWTAuthByEnriqueChavez,
13 | ///
14 | /// JWT Auth – WordPress JSON Web Token Authentication plugin
15 | /// Author - Useful Team
16 | ///
17 | JWTAuthByUsefulTeam
18 |
19 | }
20 | }
--------------------------------------------------------------------------------
/WordPressPCL/Interfaces/IUpdateOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace WordPressPCL.Interfaces
4 | {
5 | ///
6 | /// Interface with required Update methods
7 | ///
8 | /// return class type
9 | public interface IUpdateOperation
10 | {
11 | ///
12 | /// Update entity method
13 | ///
14 | /// object to update
15 | /// Updated entity
16 | Task UpdateAsync(TClass Entity);
17 | }
18 | }
--------------------------------------------------------------------------------
/docs/I version 2.x/breaking-changes.md:
--------------------------------------------------------------------------------
1 | # Breaking Changes in Version 2.x
2 |
3 | - Separate sub client for Authentication accessed via `client.Auth`
4 | - Separate sub client for Settings accessed via `client.Settings`
5 | - Default MIME type for media is **application/octet-stream** instead of text/plain
6 | - Async methods have an Async suffix as per naming C# naming guidelines e.g. `client.Posts.GetAllAsync()`
7 | - MediaQueryBuilder by default will return all types of media instead of just images.
8 | - Model properties that returned arrays are changed to List type e.g. `Tags` in `Post` class is now of type `List` instead of `int[]` type
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Hosted/WordPressPCL.Tests.Hosted.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/docs/I version 2.x/customization/customHttpClient.md:
--------------------------------------------------------------------------------
1 | # Custom HttpClient
2 |
3 | You can inject your own instance of an HttpClient into the WordPressClient. This allows you to re-use an existing instance, set desired headers etc.
4 |
5 | ```c#
6 | var httpClient = new HttpClient
7 | {
8 | BaseAddress = new Uri(ApiCredentials.WordPressUri)
9 | };
10 | httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0");
11 | httpClient.DefaultRequestHeaders.Add("Referer", "https://github.com/wp-net/WordPressPCL");
12 |
13 | var client = new WordPressClient(httpClient);
14 | var posts = await client.Posts.GetAllAsync();
15 | ```
--------------------------------------------------------------------------------
/docs/II version 1.x/customization/customHttpClient.md:
--------------------------------------------------------------------------------
1 | # Custom HttpClient
2 |
3 | You can inject your own instance of an HttpClient into the WordPressClient. This allows you to re-use an existing instance, set desired headers etc.
4 |
5 | ```csharp
6 | var httpClient = new HttpClient
7 | {
8 | BaseAddress = new Uri(ApiCredentials.WordPressUri)
9 | };
10 | httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0");
11 | httpClient.DefaultRequestHeaders.Add("Referer", "https://github.com/wp-net/WordPressPCL");
12 |
13 | var client = new WordPressClient(httpClient);
14 | var posts = await client.Posts.GetAll();
15 | ```
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/MimeTypeHelper_Tests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using WordPressPCL.Utility;
3 |
4 | namespace WordPressPCL.Tests.Selfhosted;
5 | [TestClass]
6 | public class MimeTypeHelper_Tests {
7 |
8 | [TestMethod]
9 | public void MimeType_Defaults_To_Application_Octet_Stream_For_Unknown_Extension() {
10 | const string unknownExtension = "unknown";
11 | const string expectedMimeType = "application/octet-stream";
12 |
13 | string resultMimeType = MimeTypeHelper.GetMIMETypeFromExtension(unknownExtension);
14 |
15 | Assert.AreEqual(expectedMimeType, resultMimeType);
16 | }
17 |
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/docs/II version 1.x/entities/posttypes.md:
--------------------------------------------------------------------------------
1 | # PostTypes
2 |
3 | Here is a list of methods and examples of working with PostTypes
4 |
5 | ## GetAll()
6 |
7 | ```C#
8 | // returns all posttypes
9 | var posttypes = await client.PostTypes.GetAll();
10 | ```
11 |
12 | ## GetByID
13 |
14 | ```C#
15 | // returns posttype by ID
16 | var posttype = await client.PostTypes.GetByID(123);
17 | ```
18 |
19 | ## Query
20 | Create parametrized request
21 | ```C#
22 | // returns result of query
23 | var queryBuilder = new PostTypesQueryBuilder();
24 | queryBuilder.PerPage = 40;
25 | queryBuilder.Page = 2;
26 | queryBuilder.Before = DateTime.Now;
27 | var posttypes = await client.PostTypes.Query(queryBuilder);
28 | ```
--------------------------------------------------------------------------------
/docs/II version 1.x/entities/taxonomies.md:
--------------------------------------------------------------------------------
1 | # Taxonomies
2 |
3 | Here is a list of methods and examples of working with Taxonomies
4 |
5 | ## GetAll()
6 |
7 | ```C#
8 | // returns all taxonomies
9 | var taxonomies = await client.Taxonomies.GetAll();
10 | ```
11 |
12 | ## GetByID
13 |
14 | ```C#
15 | // returns taxonomy by ID
16 | var taxonomy = await client.Taxonomies.GetByID(123);
17 | ```
18 |
19 | ## Query
20 | Create parametrized request
21 | ```C#
22 | // returns result of query
23 | var queryBuilder = new TaxonomiesQueryBuilder();
24 | queryBuilder.PerPage = 40;
25 | queryBuilder.Page = 2;
26 | queryBuilder.Before = DateTime.Now;
27 | var taxonomies = await client.Taxonomies.Query(queryBuilder);
28 | ```
--------------------------------------------------------------------------------
/docs/I version 2.x/entities/posttypes.md:
--------------------------------------------------------------------------------
1 | # PostTypes
2 |
3 | Here is a list of methods and examples of working with PostTypes
4 |
5 | ## Get All
6 |
7 | ```C#
8 | // returns all posttypes
9 | var posttypes = await client.PostTypes.GetAllAsync();
10 | ```
11 |
12 | ## Get By ID
13 |
14 | ```C#
15 | // returns posttype by ID
16 | var posttype = await client.PostTypes.GetByIDAsync(123);
17 | ```
18 |
19 | ## Query
20 | Create parametrized request
21 | ```C#
22 | // returns result of query
23 | var queryBuilder = new PostTypesQueryBuilder();
24 | queryBuilder.PerPage = 40;
25 | queryBuilder.Page = 2;
26 | queryBuilder.Before = DateTime.Now;
27 | var posttypes = await client.PostTypes.QueryAsync(queryBuilder);
28 | ```
--------------------------------------------------------------------------------
/docs/I version 2.x/entities/taxonomies.md:
--------------------------------------------------------------------------------
1 | # Taxonomies
2 |
3 | Here is a list of methods and examples of working with Taxonomies
4 |
5 | ## Get All
6 |
7 | ```C#
8 | // returns all taxonomies
9 | var taxonomies = await client.Taxonomies.GetAllAsync();
10 | ```
11 |
12 | ## Get By ID
13 |
14 | ```C#
15 | // returns taxonomy by ID
16 | var taxonomy = await client.Taxonomies.GetByIDAsync(123);
17 | ```
18 |
19 | ## Query
20 | Create parametrized request
21 | ```C#
22 | // returns result of query
23 | var queryBuilder = new TaxonomiesQueryBuilder();
24 | queryBuilder.PerPage = 40;
25 | queryBuilder.Page = 2;
26 | queryBuilder.Before = DateTime.Now;
27 | var taxonomies = await client.Taxonomies.QueryAsync(queryBuilder);
28 | ```
--------------------------------------------------------------------------------
/WordPressPCL/Utility/PluginsQueryBuilder.cs:
--------------------------------------------------------------------------------
1 | using WordPressPCL.Models;
2 |
3 | namespace WordPressPCL.Utility
4 | {
5 | ///
6 | /// Plugins Query Builder class to construct queries with valid parameters
7 | ///
8 | public class PluginsQueryBuilder : QueryBuilder
9 | {
10 | ///
11 | /// Limit results to those matching a string.
12 | ///
13 | [QueryText("search")]
14 | public string Search { get; set; }
15 |
16 | ///
17 | /// Limit results to specific status
18 | ///
19 | [QueryText("status")]
20 | public ActivationStatus Status { get; set; }
21 |
22 |
23 | }
24 | }
--------------------------------------------------------------------------------
/docs/II version 1.x/entities/poststatuses.md:
--------------------------------------------------------------------------------
1 | # PostStatuses
2 |
3 | Here is a list of methods and examples of working with PostStatuses
4 |
5 | ## GetAll()
6 |
7 | ```C#
8 | // returns all poststatuses
9 | var poststatuses = await client.PostStatuses.GetAll();
10 | ```
11 |
12 | ## GetByID
13 |
14 | ```C#
15 | // returns poststatus by ID
16 | var poststatus = await client.PostStatuses.GetByID(123);
17 | ```
18 |
19 | ## Query
20 | Create parametrized request
21 | ```C#
22 | // returns result of query
23 | var queryBuilder = new PostStatusesQueryBuilder();
24 | queryBuilder.PerPage = 40;
25 | queryBuilder.Page = 2;
26 | queryBuilder.Before = DateTime.Now;
27 | var poststatuses = await client.PostStatuses.Query(queryBuilder);
28 | ```
--------------------------------------------------------------------------------
/docs/I version 2.x/customization/customJsonSerializationSettings.md:
--------------------------------------------------------------------------------
1 |
2 | # Custom JsonSerializationSettings
3 |
4 | In some cases, it may be useful to change the default settings for the serialization / deserialization process of the Json.NET library
5 | You can do this in the following way:
6 | ```c#
7 | var client = new WordPressClient("https://site.com/wp-json/");
8 | client.JsonSerializationSettings = new JsonSerializationSettings()
9 | {
10 | DateFormatHandling=DateFormatHandling.IsoDateFormat,
11 | DateFormatString = "d MMMM YYYY"
12 | };
13 | // working with library
14 | ```
15 | For detailed information on the available settings, see the Json.NET documentation https://www.newtonsoft.com/json/help/html/SerializationSettings.htm
--------------------------------------------------------------------------------
/docs/I version 2.x/entities/poststatuses.md:
--------------------------------------------------------------------------------
1 | # PostStatuses
2 |
3 | Here is a list of methods and examples of working with PostStatuses
4 |
5 | ## Get All
6 |
7 | ```C#
8 | // returns all poststatuses
9 | var poststatuses = await client.PostStatuses.GetAllAsync();
10 | ```
11 |
12 | ## Get By ID
13 |
14 | ```C#
15 | // returns poststatus by ID
16 | var poststatus = await client.PostStatuses.GetByIDAsync(123);
17 | ```
18 |
19 | ## Query
20 | Create parametrized request
21 | ```C#
22 | // returns result of query
23 | var queryBuilder = new PostStatusesQueryBuilder();
24 | queryBuilder.PerPage = 40;
25 | queryBuilder.Page = 2;
26 | queryBuilder.Before = DateTime.Now;
27 | var poststatuses = await client.PostStatuses.QueryAsync(queryBuilder);
28 | ```
--------------------------------------------------------------------------------
/docs/II version 1.x/customization/customJsonSerializationSettings.md:
--------------------------------------------------------------------------------
1 |
2 | # Custom JsonSerializationSettings
3 |
4 | In some cases, it may be useful to change the default settings for the serialization / deserialization process of the Json.NET library
5 | You can do this in the following way:
6 | ```c#
7 | var client = new WordPressClient("https://site.com/wp-json/");
8 | client.JsonSerializationSettings = new JsonSerializationSettings()
9 | {
10 | DateFormatHandling=DateFormatHandling.IsoDateFormat,
11 | DateFormatString = "d MMMM YYYY"
12 | };
13 | // working with library
14 | ```
15 | For detailed information on the available settings, see the Json.NET documentation https://www.newtonsoft.com/json/help/html/SerializationSettings.htm
--------------------------------------------------------------------------------
/WordPressPCL/Utility/QueryTextAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace WordPressPCL.Utility
4 | {
5 | ///
6 | /// Attribute for set Text in querybuilder
7 | ///
8 | [AttributeUsage(AttributeTargets.Property)]
9 | public sealed class QueryTextAttribute : Attribute
10 | {
11 | ///
12 | /// Text property uses in HTTP query string
13 | ///
14 | public string Text { get; set; }
15 | ///
16 | /// Constructor
17 | ///
18 | /// text uses in HTTP query string
19 | public QueryTextAttribute(string text)
20 | {
21 | Text = text;
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/WordPressPCL/Models/BadRequest.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace WordPressPCL.Models
4 | {
5 | ///
6 | /// Model for unsuccessful request
7 | ///
8 | public class BadRequest
9 | {
10 | ///
11 | /// Error type
12 | ///
13 | [JsonProperty("code")]
14 | public string Name { get; set; }
15 |
16 | ///
17 | /// Error description
18 | ///
19 | [JsonProperty("message")]
20 | public string Message { get; set; }
21 |
22 | ///
23 | /// Additional info
24 | ///
25 | [JsonProperty("data")]
26 | public dynamic Data { get; set; }
27 | }
28 | }
--------------------------------------------------------------------------------
/WordPressPCL/Client/Tags.cs:
--------------------------------------------------------------------------------
1 | using WordPressPCL.Models;
2 | using WordPressPCL.Utility;
3 |
4 | namespace WordPressPCL.Client
5 | {
6 | ///
7 | /// Client class for interaction with Tags endpoint WP REST API
8 | ///
9 | public class Tags : CRUDOperation
10 | {
11 | #region Init
12 |
13 | private const string _methodPath = "tags";
14 |
15 | ///
16 | /// Constructor
17 | ///
18 | /// reference to HttpHelper class for interaction with HTTP
19 | public Tags(HttpHelper HttpHelper) : base(HttpHelper, _methodPath, true)
20 | {
21 | }
22 |
23 | #endregion Init
24 | }
25 | }
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [ThomasPe] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/dev/install.md:
--------------------------------------------------------------------------------
1 | Run `docker compose up` inside the `dev` folder and it will start a fully setup docker Wordpress instance on port 8080 to run tests.
2 |
3 | - The Wordpress instance will have following already configured plugins:
4 | - [JWT Auth – WordPress JSON Web Token Authentication](https://wordpress.org/plugins/jwt-auth/)
5 | - [Contact Form 7](https://wordpress.org/plugins/contact-form-7/)
6 | - https://github.com/wp-net/wordpress-docker-compose/raw/master/plugins/enable-application-passwords.1.0.zip
7 |
8 | - The "Permanlinks" link structure in Wordpress settings is set to "Post name"
9 |
10 | To destroy the containers simply run `docker compose down` in the terminal
11 |
12 | To run the tests in Visual Studio, make sure to use the `jwtauth.runsettings` test settings.
--------------------------------------------------------------------------------
/WordPressPCL/Client/Categories.cs:
--------------------------------------------------------------------------------
1 | using WordPressPCL.Models;
2 | using WordPressPCL.Utility;
3 |
4 | namespace WordPressPCL.Client
5 | {
6 | ///
7 | /// Client class for interaction with Categories endpoint WP REST API
8 | ///
9 | public class Categories : CRUDOperation
10 | {
11 | #region Init
12 |
13 | private const string _methodPath = "categories";
14 |
15 | ///
16 | /// Constructor
17 | ///
18 | /// reference to HttpHelper class for interaction with HTTP
19 | public Categories(HttpHelper HttpHelper) : base(HttpHelper, _methodPath, true)
20 | {
21 | }
22 |
23 | #endregion Init
24 | }
25 | }
--------------------------------------------------------------------------------
/WordPressPCL/Models/AvatarURL.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace WordPressPCL.Models
4 | {
5 | ///
6 | /// Avatar URLs for the users.
7 | ///
8 | /// Default sizes: 24, 48, 96
9 | public class AvatarURL
10 | {
11 | ///
12 | /// Avatar URL 24x24 pixels
13 | ///
14 | [JsonProperty("24")]
15 | public string Size24 { get; set; }
16 |
17 | ///
18 | /// Avatar URL 48x48 pixels
19 | ///
20 | [JsonProperty("48")]
21 | public string Size48 { get; set; }
22 |
23 | ///
24 | /// Avatar URL 96x96 pixels
25 | ///
26 | [JsonProperty("96")]
27 | public string Size96 { get; set; }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/WordPressPCL/Utility/ExcludeQueryTextAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace WordPressPCL.Utility {
4 | ///
5 | /// Attribute to exclude query text in querybuilder
6 | ///
7 | [AttributeUsage(AttributeTargets.Property)]
8 | public sealed class ExcludeQueryTextAttribute : Attribute {
9 |
10 | ///
11 | /// Value which determines if query text is excluded
12 | ///
13 | public string ExclusionValue { get; }
14 |
15 | ///
16 | /// Constructor
17 | ///
18 | /// value which determines if query text is excluded
19 | public ExcludeQueryTextAttribute(string exclusionValue) {
20 | ExclusionValue = exclusionValue;
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/Settings_Tests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System.Threading.Tasks;
3 | using WordPressPCL.Models;
4 | using WordPressPCL.Tests.Selfhosted.Utility;
5 |
6 | namespace WordPressPCL.Tests.Selfhosted;
7 |
8 | [TestClass]
9 | public class Settings_Tests
10 | {
11 | private static WordPressClient _clientAuth;
12 |
13 | [ClassInitialize]
14 | public static async Task Init(TestContext testContext)
15 | {
16 | _clientAuth = await ClientHelper.GetAuthenticatedWordPressClient(testContext);
17 | }
18 |
19 | [TestMethod]
20 | public async Task Get_Settings_Test()
21 | {
22 | Settings settings = await _clientAuth.Settings.GetSettingsAsync();
23 | Assert.IsNotNull(settings);
24 | Assert.IsNotNull(settings.Title);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/WordPressPCL/Models/JWTResponse.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.ComponentModel;
3 |
4 | namespace WordPressPCL.Models
5 | {
6 | ///
7 | /// Response class for the JWT Plugin
8 | ///
9 | public class JWTResponse
10 | {
11 | ///
12 | /// Indicates if the call was successful
13 | ///
14 | [JsonProperty("success")]
15 | public bool Success { get; set; }
16 |
17 | ///
18 | /// The response message
19 | ///
20 | [JsonProperty("message")]
21 | public string Message { get; set; }
22 |
23 | ///
24 | /// The JWT Content
25 | ///
26 | [JsonProperty("data")]
27 | [DefaultValue(null)]
28 | public JWTData Data { get; set; }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/WordPressPCL/Models/JWTData.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace WordPressPCL.Models
4 | {
5 | ///
6 | /// JWT Data
7 | ///
8 | public class JWTData
9 | {
10 | ///
11 | /// JWT Token
12 | ///
13 | [JsonProperty("token")]
14 | public string Token { get; set; }
15 |
16 | ///
17 | /// User Display Name
18 | ///
19 | [JsonProperty("displayName")]
20 | public string DisplayName { get; set; }
21 |
22 | ///
23 | /// User Email
24 | ///
25 | [JsonProperty("email")]
26 | public string Email { get; set; }
27 |
28 | ///
29 | /// User Nice Names
30 | ///
31 | [JsonProperty("nicename")]
32 | public string NiceName { get; set; }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/WordPressPCL/Interfaces/IQueryOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 | using WordPressPCL.Utility;
4 |
5 | namespace WordPressPCL.Interfaces
6 | {
7 | ///
8 | /// Interface with required Query methods
9 | ///
10 | /// return class type
11 | /// Query Builder class
12 | public interface IQueryOperation where TQueryClass : QueryBuilder
13 | {
14 | ///
15 | /// Execute query
16 | ///
17 | /// query builder with parameters for query
18 | /// Is use auth header
19 | /// list of filtered objects
20 | Task> QueryAsync(TQueryClass queryBuilder, bool useAuth = false);
21 | }
22 | }
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/QueryBuilder_Tests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 | using WordPressPCL.Models;
5 | using WordPressPCL.Utility;
6 |
7 | namespace WordPressPCL.Tests.Selfhosted;
8 |
9 | [TestClass]
10 | public class QueryBuilder_Tests
11 | {
12 | [TestMethod]
13 | public void Multi_Parameter_Query_Works_Test()
14 | {
15 | // Initialize
16 | PostsQueryBuilder builder = new() {
17 | Page = 1,
18 | PerPage = 15,
19 | OrderBy = PostsOrderBy.Title,
20 | Order = Order.ASC,
21 | Statuses = new List { Status.Publish },
22 | Embed = true
23 | };
24 | Console.WriteLine(builder.BuildQuery());
25 | Assert.AreEqual("?page=1&per_page=15&orderby=title&status=publish&order=asc&_embed=true&context=view", builder.BuildQuery());
26 | }
27 | }
28 |
29 |
30 |
--------------------------------------------------------------------------------
/dev/.htaccess:
--------------------------------------------------------------------------------
1 | # BEGIN WordPress
2 | # The directives (lines) between `BEGIN WordPress` and `END WordPress` are
3 | # dynamically generated, and should only be modified via WordPress filters.
4 | # Any changes to the directives between these markers will be overwritten.
5 |
6 |
7 | RewriteEngine On
8 | RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization}]
9 | RewriteBase /
10 | RewriteRule ^index\.php$ - [L]
11 | RewriteCond %{REQUEST_FILENAME} !-f
12 | RewriteCond %{REQUEST_FILENAME} !-d
13 | RewriteRule . /index.php [L]
14 |
15 |
16 | # END WordPress
17 |
18 | SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
19 |
20 | RewriteEngine On
21 | RewriteCond %{HTTP:Authorization} ^(.*)
22 | RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1]
23 | RewriteBase /
24 | RewriteRule ^index\.php$ - [L]
25 | RewriteCond %{REQUEST_FILENAME} !-f
26 | RewriteCond %{REQUEST_FILENAME} !-d
27 | RewriteRule . /index.php [L]
28 |
--------------------------------------------------------------------------------
/WordPressPCL/Models/JWTUser.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace WordPressPCL.Models
4 | {
5 | ///
6 | /// User class for working with the JWT plugin
7 | ///
8 | public class JWTUser
9 | {
10 | ///
11 | /// The JWT Token used to authorize requests
12 | ///
13 | [JsonProperty("token")]
14 | public string Token { get; set; }
15 |
16 | ///
17 | /// User Display Name
18 | ///
19 | [JsonProperty("user_display_name")]
20 | public string DisplayName { get; set; }
21 |
22 | ///
23 | /// User Email Address
24 | ///
25 | [JsonProperty("user_email")]
26 | public string Email { get; set; }
27 |
28 | ///
29 | /// User Nice Name
30 | ///
31 | [JsonProperty("user_nicename")]
32 | public string NiceName { get; set; }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/WordPressPCL.Tests.Selfhosted.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | Always
24 |
25 |
26 | Always
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/docs/II version 1.x/entities/customPostType.md:
--------------------------------------------------------------------------------
1 | # Custom Post Type
2 |
3 | To create post of custom post type you should do 2 things
4 | 1. Enable rest api support for custom post type [registering-a-custom-post-type-with-rest-api-support](https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-rest-api-support-for-custom-content-types/#registering-a-custom-post-type-with-rest-api-support)
5 | 2. This is a one of contrintuitive things in WP REST API, but for creating post with custom type you should send requests to custom endpoint. For this task you can use our [Custom Requests](https://github.com/wp-net/WordPressPCL/wiki/CustomRequests) feature
6 | Example:
7 | ```c#
8 | var post = new Post()
9 | {
10 | Title = new Title("Title 1"),
11 | Content = new Content("Content PostCreate"),
12 | Type = "portfolio" //your custom post type
13 | };
14 | //change portfolio to your custom post type
15 | var createdPost = await _clientAuth.CustomRequest.Create("wp/v2/portfolio",post);
16 | ```
--------------------------------------------------------------------------------
/docs/I version 2.x/entities/customPostType.md:
--------------------------------------------------------------------------------
1 | # Custom Post Type
2 |
3 | To create post of custom post type you should do 2 things
4 | 1. Enable rest api support for custom post type [registering-a-custom-post-type-with-rest-api-support](https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-rest-api-support-for-custom-content-types/#registering-a-custom-post-type-with-rest-api-support)
5 | 2. This is a one of the unintuitive things in WP REST API, but for creating post with custom type you should send requests to custom endpoint. For this task you can use our [Custom Requests](https://github.com/wp-net/WordPressPCL/wiki/CustomRequests) feature
6 |
7 |
8 | Example:
9 |
10 | ```c#
11 | var post = new Post()
12 | {
13 | Title = new Title("Title 1"),
14 | Content = new Content("Content PostCreate"),
15 | Type = "portfolio" //your custom post type
16 | };
17 | //change portfolio to your custom post type
18 | var createdPost = await _clientAuth.CustomRequest.CreateAsync("wp/v2/portfolio", post);
19 | ```
--------------------------------------------------------------------------------
/WordPressPCL/Models/MediaSize.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace WordPressPCL.Models
4 | {
5 | ///
6 | /// Info about Media Size
7 | ///
8 | ///
9 | public class MediaSize
10 | {
11 | ///
12 | /// File
13 | ///
14 | [JsonProperty("file")]
15 | public string File { get; set; }
16 | ///
17 | /// Media Width
18 | ///
19 | [JsonProperty("width")]
20 | public int? Width { get; set; }
21 | ///
22 | /// Media Height
23 | ///
24 | [JsonProperty("height")]
25 | public int? Height { get; set; }
26 | ///
27 | /// Mime Type
28 | ///
29 | [JsonProperty("mime_type")]
30 | public string MimeType { get; set; }
31 | ///
32 | /// Url of source media
33 | ///
34 | [JsonProperty("source_url")]
35 | public string SourceUrl { get; set; }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/WordPressPCL/Utility/CustomCapabilitiesJsonConverter.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Globalization;
4 |
5 | namespace WordPressPCL.Utility
6 | {
7 | ///
8 | /// Custom JSON converter to convert string values to boolean in capabilities and extra_capabilities properties
9 | ///
10 | ///
11 | ///
12 | public class CustomCapabilitiesJsonConverter : JsonConverter
13 | {
14 | ///
15 | public override bool ReadJson(JsonReader reader, Type objectType, bool existingValue, bool hasExistingValue, JsonSerializer serializer)
16 | {
17 | return Convert.ToBoolean(reader?.ValueType == typeof(string) ? Convert.ToByte(reader.Value, CultureInfo.InvariantCulture) : reader.Value, CultureInfo.InvariantCulture);
18 | }
19 |
20 | ///
21 | public override void WriteJson(JsonWriter writer, bool value, JsonSerializer serializer)
22 | {
23 | writer?.WriteValue(value);
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Thomas Pentenrieder
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/WordPressPCL/Models/MediaDetails.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.Collections.Generic;
3 |
4 | namespace WordPressPCL.Models
5 | {
6 | ///
7 | /// Details of media item
8 | ///
9 | ///
10 | public class MediaDetails
11 | {
12 | ///
13 | /// Media width
14 | ///
15 | [JsonProperty("width")]
16 | public int Width { get; set; }
17 | ///
18 | /// Media height
19 | ///
20 | [JsonProperty("height")]
21 | public int Height { get; set; }
22 | ///
23 | /// File
24 | ///
25 | [JsonProperty("file")]
26 | public string File { get; set; }
27 | ///
28 | /// Sizes
29 | ///
30 | [JsonProperty("sizes")]
31 | public IDictionary Sizes { get; set; }
32 | ///
33 | /// Meta info of Image
34 | ///
35 | [JsonProperty("image_meta")]
36 | public ImageMeta ImageMeta { get; set; }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/Utility/ClientHelper.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System;
3 | using System.Threading.Tasks;
4 | using WordPressPCL.Models;
5 |
6 | namespace WordPressPCL.Tests.Selfhosted.Utility;
7 |
8 | public static class ClientHelper
9 | {
10 | public static async Task GetAuthenticatedWordPressClient(TestContext context)
11 | {
12 | WordPressClient clientAuth = new(ApiCredentials.WordPressUri);
13 |
14 | Console.WriteLine($"Auth Plugin: {context?.Properties["authplugin"]}");
15 | if (context?.Properties["authplugin"]?.ToString() == "jwtAuthByUsefulTeam")
16 | {
17 | clientAuth.Auth.UseBearerAuth(JWTPlugin.JWTAuthByUsefulTeam);
18 | }
19 | else {
20 | clientAuth.Auth.UseBearerAuth(JWTPlugin.JWTAuthByEnriqueChavez);
21 | }
22 | await clientAuth.Auth.RequestJWTokenAsync(ApiCredentials.Username, ApiCredentials.Password);
23 |
24 | return clientAuth;
25 | }
26 |
27 | public static WordPressClient GetWordPressClient()
28 | {
29 | return new WordPressClient(ApiCredentials.WordPressUri);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/PostStatuses_Tests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using WordPressPCL.Models;
5 | using WordPressPCL.Tests.Selfhosted.Utility;
6 |
7 | namespace WordPressPCL.Tests.Selfhosted;
8 |
9 | [TestClass]
10 | public class PostStatuses_Tests
11 | {
12 | private static WordPressClient _clientAuth;
13 |
14 | [ClassInitialize]
15 | public static async Task Init(TestContext testContext)
16 | {
17 | _clientAuth = await ClientHelper.GetAuthenticatedWordPressClient(testContext);
18 | }
19 |
20 | [TestMethod]
21 | public async Task PostStatuses_Read()
22 | {
23 | List poststatuses = await _clientAuth.PostStatuses.GetAllAsync();
24 | Assert.IsNotNull(poststatuses);
25 | Assert.AreNotEqual(poststatuses.Count, 0);
26 | }
27 |
28 | [TestMethod]
29 | public async Task PostStatuses_Get()
30 | {
31 | List poststatuses = await _clientAuth.PostStatuses.GetAsync();
32 | Assert.IsNotNull(poststatuses);
33 | Assert.AreNotEqual(poststatuses.Count, 0);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/.github/workflows/publish-nuget.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: Build & Publish to NuGet
4 |
5 | # Controls when the action will run.
6 | on:
7 | # Allows you to run this workflow manually from the Actions tab
8 | workflow_dispatch:
9 |
10 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
11 | jobs:
12 | # This workflow contains a single job called "build"
13 | build:
14 | # The type of runner that the job will run on
15 | runs-on: ubuntu-latest
16 |
17 | # Steps represent a sequence of tasks that will be executed as part of the job
18 | steps:
19 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
20 | - uses: actions/checkout@v2
21 | - name: Setup .NET SDK
22 | uses: actions/setup-dotnet@v4
23 | with:
24 | dotnet-version: 8.x
25 | - name: Build & Package
26 | run: |
27 | cd WordPressPCL
28 | dotnet pack -c Release -o out
29 | - name: PushNuget
30 | run: dotnet nuget push "**/*.nupkg" --source https://api.nuget.org/v3/index.json --api-key ${{secrets.WORDPRESSPCLNUGET}} --skip-duplicate
31 |
--------------------------------------------------------------------------------
/WordPressPCL/Models/Embedded.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json;
3 |
4 | namespace WordPressPCL.Models
5 | {
6 | ///
7 | /// Embedded Information
8 | ///
9 | public class Embedded
10 | {
11 | ///
12 | /// Post Author
13 | ///
14 | [JsonProperty("author")]
15 | public List Author { get; set; }
16 |
17 | ///
18 | /// Comments on the post
19 | ///
20 | [JsonProperty("replies")]
21 | public List> Replies { get; set; }
22 |
23 | ///
24 | /// Featured images for the post
25 | ///
26 | [JsonProperty("wp:featuredmedia")]
27 | public List WpFeaturedmedia { get; set; }
28 |
29 | ///
30 | /// Terms for the post (categories, tags etc.)
31 | ///
32 | [JsonProperty("wp:term")]
33 | public List> WpTerm { get; set; }
34 | ///
35 | /// Parent page
36 | ///
37 | [JsonProperty("up")]
38 | public List Up { get; set; }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/PostTypes_Tests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using WordPressPCL.Models;
5 | using WordPressPCL.Tests.Selfhosted.Utility;
6 |
7 | namespace WordPressPCL.Tests.Selfhosted;
8 |
9 | [TestClass]
10 | public class PostTypes_Tests
11 | {
12 | private static WordPressClient _client;
13 | private static WordPressClient _clientAuth;
14 |
15 | [ClassInitialize]
16 | public static async Task Init(TestContext testContext)
17 | {
18 | _client = ClientHelper.GetWordPressClient();
19 | _clientAuth = await ClientHelper.GetAuthenticatedWordPressClient(testContext);
20 | }
21 |
22 | [TestMethod]
23 | public async Task PostTypes_Read()
24 | {
25 | List posttypes = await _clientAuth.PostTypes.GetAllAsync();
26 | Assert.IsNotNull(posttypes);
27 | Assert.AreNotEqual(posttypes.Count, 0);
28 | }
29 |
30 | [TestMethod]
31 | public async Task PostTypes_Get()
32 | {
33 | List posttypes = await _clientAuth.PostTypes.GetAsync();
34 | Assert.IsNotNull(posttypes);
35 | Assert.AreNotEqual(posttypes.Count, 0);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/.github/workflows/documentation.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: Docs
4 |
5 | # Controls when the workflow will run
6 | on:
7 | # Triggers the workflow on push or pull request events but only for the master branch
8 | push:
9 | branches: [ master ]
10 |
11 | # Allows you to run this workflow manually from the Actions tab
12 | workflow_dispatch:
13 |
14 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
15 | jobs:
16 | # This workflow contains a single job called "build"
17 | build:
18 | # The type of runner that the job will run on
19 | runs-on: ubuntu-latest
20 |
21 | # Steps represent a sequence of tasks that will be executed as part of the job
22 | steps:
23 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
24 | - uses: actions/checkout@v4
25 | with:
26 | fetch-depth: 0
27 | - uses: actions/setup-python@v2
28 | - run: pip install --upgrade pip && pip install mkdocs mkdocs-gen-files
29 | - run: git config user.name 'github-actions[bot]' && git config user.email 'github-actions[bot]@users.noreply.github.com'
30 | - name: Publish docs
31 | run: mkdocs gh-deploy
32 |
--------------------------------------------------------------------------------
/docs/II version 1.x/entities/tags.md:
--------------------------------------------------------------------------------
1 | # Tags
2 |
3 | Here is a list of methods and examples of working with Tags
4 |
5 | ## GetAll()
6 |
7 | ```C#
8 | // returns all tags
9 | var tags = await client.Tags.GetAll();
10 | ```
11 |
12 | ## GetByID
13 |
14 | ```C#
15 | // returns tag by ID
16 | var tag = await client.Tags.GetByID(123);
17 | ```
18 |
19 | ## Query
20 | Create parametrized request
21 | ```C#
22 | // returns result of query
23 | var queryBuilder = new TagsQueryBuilder();
24 | queryBuilder.PerPage = 40;
25 | queryBuilder.Page = 2;
26 | queryBuilder.Before = DateTime.Now;
27 | var tags = await client.Tags.Query(queryBuilder);
28 | ```
29 |
30 | ## Create new Tag
31 |
32 | ```C#
33 | // returns created tag
34 | var tag = new Tag()
35 | {
36 | Name = "Name",
37 | Description = "Tag"
38 | };
39 | if (await client.IsValidJWToken())
40 | {
41 | var createdtag = await client.Tags.Create(tag);
42 | }
43 | ```
44 |
45 | ## Update Tag
46 |
47 | ```C#
48 | // returns updated tag
49 | var tag = client.Tags.GetByID(123);
50 | tag.Name = "New Name";
51 | if (await client.IsValidJWToken())
52 | {
53 | var updatedTag = await client.Tags.Update(tag);
54 | }
55 | ```
56 |
57 | ## Delete Tag
58 |
59 | ```C#
60 | // returns result of deletion
61 | if (await client.IsValidJWToken())
62 | {
63 | var result = await client.Tags.Delete(123);
64 | }
65 | ```
--------------------------------------------------------------------------------
/docs/I version 2.x/entities/tags.md:
--------------------------------------------------------------------------------
1 | # Tags
2 |
3 | Here is a list of methods and examples of working with Tags
4 |
5 | ## Get All
6 |
7 | ```C#
8 | // returns all tags
9 | var tags = await client.Tags.GetAllAsync();
10 | ```
11 |
12 | ## Get By ID
13 |
14 | ```C#
15 | // returns tag by ID
16 | var tag = await client.Tags.GetByIDAsync(123);
17 | ```
18 |
19 | ## Query
20 | Create parametrized request
21 | ```C#
22 | // returns result of query
23 | var queryBuilder = new TagsQueryBuilder();
24 | queryBuilder.PerPage = 40;
25 | queryBuilder.Page = 2;
26 | queryBuilder.Before = DateTime.Now;
27 | var tags = await client.Tags.QueryAsync(queryBuilder);
28 | ```
29 |
30 | ## Create new Tag
31 |
32 | ```C#
33 | // returns created tag
34 | var tag = new Tag()
35 | {
36 | Name = "Name",
37 | Description = "Tag"
38 | };
39 | if (await client.IsValidJWTokenAsync())
40 | {
41 | var createdtag = await client.Tags.CreateAsync(tag);
42 | }
43 | ```
44 |
45 | ## Update Tag
46 |
47 | ```C#
48 | // returns updated tag
49 | var tag = client.Tags.GetByIDAsync(123);
50 | tag.Name = "New Name";
51 | if (await client.IsValidJWTokenAsync())
52 | {
53 | var updatedTag = await client.Tags.UpdateAsync(tag);
54 | }
55 | ```
56 |
57 | ## Delete Tag
58 |
59 | ```C#
60 | // returns result of deletion
61 | if (await client.IsValidJWTokenAsync())
62 | {
63 | var result = await client.Tags.DeleteAsync(123);
64 | }
65 | ```
--------------------------------------------------------------------------------
/docs/II version 1.x/entities/pages.md:
--------------------------------------------------------------------------------
1 | # Pages
2 |
3 | Here is a list of methods and examples of working with Pages
4 |
5 | ## GetAll()
6 |
7 | ```C#
8 | // returns all pages
9 | var pages = await client.Pages.GetAll();
10 | ```
11 |
12 | ## GetByID
13 |
14 | ```C#
15 | // returns page by ID
16 | var page = await client.Pages.GetByID(123);
17 | ```
18 |
19 | ## Query
20 | Create parametrized request
21 | ```C#
22 | // returns result of query
23 | var queryBuilder = new PagesQueryBuilder();
24 | queryBuilder.PerPage = 40;
25 | queryBuilder.Page = 2;
26 | queryBuilder.Before = DateTime.Now;
27 | var pages = await client.Pages.Query(queryBuilder);
28 | ```
29 |
30 | ## Create new Page
31 |
32 | ```C#
33 | // returns created page
34 | var page = new Page()
35 | {
36 | Title = new Title("Title 1"),
37 | Content = new Content("Content PageCreate")
38 | };
39 | if (await client.IsValidJWToken())
40 | {
41 | var createdPage = await client.Pages.Create(page);
42 | }
43 | ```
44 |
45 | ## Update Page
46 |
47 | ```C#
48 | // returns updated page
49 | var page= client.Pages.GetByID(123);
50 | page.Content.Raw = "New Content";
51 | if (await client.IsValidJWToken())
52 | {
53 | var updatedPage = await client.Pages.Update(page);
54 | }
55 | ```
56 |
57 | ## Delete Page
58 |
59 | ```C#
60 | // returns result of deletion
61 | if (await client.IsValidJWToken())
62 | {
63 | var result = await client.Pages.Delete(123);
64 | }
65 | ```
--------------------------------------------------------------------------------
/docs/II version 1.x/customization/customRequest.md:
--------------------------------------------------------------------------------
1 | # CustomRequest
2 |
3 | Here is a list of methods and examples of working with Custom Requests
4 |
5 | ## Overview
6 | WP REST Api can be modified and extended by plugins (Woocommerce, Contact Form 7, ACF and others), so Custom requests allow you to create non-standard requests.
7 | Before send requests you must create DTO Model of your request.
8 | Here is an example with Contact Form 7 plugin
9 |
10 | ## DTO Model
11 | ```C#
12 | public class ContactFormItem
13 | {
14 | public int? id;
15 | public string title;
16 | public string slug;
17 | public string locale;
18 | }
19 | ```
20 |
21 | ## Get
22 | ```C#
23 | var forms = client.CustomRequest.Get>("contact-form-7/v1/contact-forms");
24 | ```
25 |
26 | ## Create
27 | ```C#
28 | //requires two T parameters: first - input model, second - output model
29 | var forms = client.CustomRequest.Create("contact-form-7/v1/contact-forms",new ContactFormItem() { title = "test" });
30 | ```
31 |
32 | ## Update
33 | ```C#
34 | //requires two T parameters: first - input model, second - output model
35 | var forms = client.CustomRequest.Update("contact-form-7/v1/contact-forms/123",new ContactFormItem() { title = "test" });
36 | ```
37 |
38 | ## Delete
39 | ```C#
40 | var forms = client.CustomRequest.Delete("contact-form-7/v1/contact-forms/123");
41 | ```
--------------------------------------------------------------------------------
/docs/I version 2.x/customization/customRequest.md:
--------------------------------------------------------------------------------
1 | # CustomRequest
2 |
3 | Here is a list of methods and examples of working with Custom Requests
4 |
5 | ## Overview
6 | WP REST Api can be modified and extended by plugins (Woocommerce, Contact Form 7, ACF and others), so Custom requests allow you to create non-standard requests.
7 | Before send requests you must create DTO Model of your request.
8 | Here is an example with Contact Form 7 plugin
9 |
10 | ## DTO Model
11 | ```C#
12 | public class ContactFormItem
13 | {
14 | public int? id;
15 | public string title;
16 | public string slug;
17 | public string locale;
18 | }
19 | ```
20 |
21 | ## Get
22 | ```C#
23 | var forms = client.CustomRequest.GetAsync>("contact-form-7/v1/contact-forms");
24 | ```
25 |
26 | ## Create
27 | ```C#
28 | //requires two T parameters: first - input model, second - output model
29 | var forms = client.CustomRequest.CreateAsync("contact-form-7/v1/contact-forms", new ContactFormItem() { title = "test" });
30 | ```
31 |
32 | ## Update
33 | ```C#
34 | //requires two T parameters: first - input model, second - output model
35 | var forms = client.CustomRequest.UpdateAsync("contact-form-7/v1/contact-forms/123",new ContactFormItem() { title = "test" });
36 | ```
37 |
38 | ## Delete
39 | ```C#
40 | var forms = client.CustomRequest.DeleteAsync("contact-form-7/v1/contact-forms/123");
41 | ```
--------------------------------------------------------------------------------
/WordPressPCL/Models/Tag.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace WordPressPCL.Models
4 | {
5 | ///
6 | /// Terms of the type tag
7 | ///
8 | public class Tag : Term
9 | {
10 | ///
11 | /// Number of published posts for the term.
12 | ///
13 | ///
14 | /// Read only
15 | /// Context: view, edit
16 | ///
17 | [JsonProperty("count")]
18 | public int Count { get; set; }
19 |
20 | ///
21 | /// HTML description of the term.
22 | ///
23 | /// Context: view, edit
24 | [JsonProperty("description")]
25 | public string Description { get; set; }
26 | ///
27 | /// Meta object
28 | ///
29 | /// Context: view
30 | [JsonProperty("meta", DefaultValueHandling = DefaultValueHandling.Ignore)]
31 | public dynamic Meta { get; set; }
32 | ///
33 | /// Parameterless constructor
34 | ///
35 | public Tag():base()
36 | {
37 |
38 | }
39 | ///
40 | /// Constructor with required parameters
41 | ///
42 | /// Tag name
43 | public Tag(string name):this()
44 | {
45 | Name = name;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/docs/I version 2.x/entities/pages.md:
--------------------------------------------------------------------------------
1 | # Pages
2 |
3 | Here is a list of methods and examples of working with Pages
4 |
5 | ## Get All
6 |
7 | ```C#
8 | // returns all pages
9 | var pages = await client.Pages.GetAllAsync();
10 | ```
11 |
12 | ## Get By ID
13 |
14 | ```C#
15 | // returns page by ID
16 | var page = await client.Pages.GetByIDAsync(123);
17 | ```
18 |
19 | ## Query
20 | Create parametrized request
21 | ```C#
22 | // returns result of query
23 | var queryBuilder = new PagesQueryBuilder();
24 | queryBuilder.PerPage = 40;
25 | queryBuilder.Page = 2;
26 | queryBuilder.Before = DateTime.Now;
27 | var pages = await client.Pages.QueryAsync(queryBuilder);
28 | ```
29 |
30 | ## Create new Page
31 |
32 | ```C#
33 | // returns created page
34 | var page = new Page()
35 | {
36 | Title = new Title("Title 1"),
37 | Content = new Content("Content PageCreate")
38 | };
39 | if (await client.IsValidJWTokenAsync())
40 | {
41 | var createdPage = await client.Pages.CreateAsync(page);
42 | }
43 | ```
44 |
45 | ## Update Page
46 |
47 | ```C#
48 | // returns updated page
49 | var page= client.Pages.GetByIDAsync(123);
50 | page.Content.Raw = "New Content";
51 | if (await client.IsValidJWTokenAsync())
52 | {
53 | var updatedPage = await client.Pages.UpdateAsync(page);
54 | }
55 | ```
56 |
57 | ## Delete Page
58 |
59 | ```C#
60 | // returns result of deletion
61 | if (await client.IsValidJWTokenAsync())
62 | {
63 | var result = await client.Pages.DeleteAsync(123);
64 | }
65 | ```
--------------------------------------------------------------------------------
/.github/workflows/integration-tests.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: Integration Tests
4 |
5 | # Controls when the action will run.
6 | on:
7 | # Triggers the workflow on push or pull request events but only for the master branch
8 | push:
9 | branches: [ master ]
10 | pull_request:
11 | branches: [ master ]
12 |
13 | # Allows you to run this workflow manually from the Actions tab
14 | workflow_dispatch:
15 |
16 | env:
17 | solution: 'WordPressPCL.sln'
18 | buildPlatform: Any CPU
19 | buildConfiguration: Release
20 | jobs:
21 | build:
22 | runs-on: ubuntu-latest
23 | steps:
24 | - uses: actions/checkout@master
25 | - name: Setup .NET SDK
26 | uses: actions/setup-dotnet@v4
27 | with:
28 | dotnet-version: 8.x
29 | - name: Dotnet Restore
30 | run: dotnet restore ${{ env.solution }} --disable-parallel
31 | - name: Build Solution
32 | run: dotnet build ${{ env.solution }} -c Release --no-restore
33 |
34 | - name: Create dockerzied WordPress
35 | run: |
36 | cd dev
37 | docker compose up -d
38 | docker ps
39 | sleep 20s
40 | curl --fail http://localhost:8080/wp-json
41 |
42 | - name: 'Run Tests: Selfhosted WordPress with JWT-AUTH'
43 | run: dotnet test -l "console;verbosity=detailed" WordPressPCL.Tests.Selfhosted/WordPressPCL.Tests.Selfhosted.csproj -s WordPressPCL.Tests.Selfhosted/jwtauth.runsettings
44 |
--------------------------------------------------------------------------------
/WordPressPCL/Interfaces/IReadOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 |
4 | namespace WordPressPCL.Interfaces
5 | {
6 | ///
7 | /// Interface with required Get methods
8 | ///
9 | /// return class type
10 | public interface IReadOperation
11 | {
12 | ///
13 | /// Get latest
14 | ///
15 | /// Is use embed info
16 | /// Is use auth header
17 | /// requested object
18 | Task> GetAsync(bool embed = false, bool useAuth = false);
19 |
20 | ///
21 | /// Get object by Id
22 | ///
23 | /// Object Id
24 | /// Is use embed info
25 | /// Is use auth header
26 | /// requested object
27 | Task GetByIDAsync(object ID, bool embed = false, bool useAuth = false);
28 |
29 | ///
30 | /// Get all objects
31 | ///
32 | /// Is use embed info
33 | /// Is use auth header
34 | /// List of objects
35 | Task> GetAllAsync(bool embed = false, bool useAuth = false);
36 | }
37 | }
--------------------------------------------------------------------------------
/docs/I version 2.x/customization/httpResponsePreProcessing.md:
--------------------------------------------------------------------------------
1 | # HttpResponsePreProcessing
2 |
3 | Sometimes it's necessary to pre-process the HttpResponseMessage before deserializeing it.
4 |
5 | To do this, you can use the "HttpResponsePreProcessing" to pass a function to the WordPressClient.
6 | This function takes the HttpResponse content string as a parameter, and has to return a string that will be deserialized.
7 |
8 | ```C#
9 | // Add a HttpResponsePreProcessing function :
10 | client.HttpResponsePreProcessing = (response) =>
11 | {
12 | string updatedResponse = response;
13 |
14 | // Do something here on the updatedResponse
15 |
16 | return updatedResponse;
17 | };
18 | ```
19 |
20 | ## WordPress on Azure / ISS
21 |
22 | When deploying a WordPress website on Microsoft Azure, the REST API will add [unnecessary HTML before every POST request](https://social.msdn.microsoft.com/Forums/azure/en-US/8faac1fa-3d47-4149-aec0-f0a9a09f9744/php-wordpress-rest-api-prepending-html-with-location-header?forum=windowsazurewebsitespreview).
23 |
24 | In order to correct this, you can add a HttpResponsePreProcessing function that will delete the HTML code that is preventing the deserialization of the JSON content:
25 |
26 | ```C#
27 | client.HttpResponsePreProcessing = (responseString) =>
28 | {
29 | var clearedString = responseString.Replace("\n", "");
30 | var regex = @"\";
31 | return System.Text.RegularExpressions.Regex.Replace(clearedString, regex, "");
32 | };
33 | ```
34 |
--------------------------------------------------------------------------------
/docs/II version 1.x/customization/httpResponsePreProcessing.md:
--------------------------------------------------------------------------------
1 | # HttpResponsePreProcessing
2 |
3 | Sometimes it's necessary to pre-process the HttpResponseMessage before deserializeing it.
4 |
5 | To do this, you can use the "HttpResponsePreProcessing" to pass a function to the WordPressClient.
6 | This function takes the HttpResponse content string as a parameter, and has to return a string that will be deserialized.
7 |
8 | ```C#
9 | // Add a HttpResponsePreProcessing function :
10 | client.HttpResponsePreProcessing = (response) =>
11 | {
12 | string updatedResponse = response;
13 |
14 | // Do something here on the updatedResponse
15 |
16 | return updatedResponse;
17 | };
18 | ```
19 |
20 | ## WordPress on Azure / ISS
21 |
22 | When deploying a WordPress website on Microsoft Azure, the REST API will add [unnecessary HTML before every POST request](https://social.msdn.microsoft.com/Forums/azure/en-US/8faac1fa-3d47-4149-aec0-f0a9a09f9744/php-wordpress-rest-api-prepending-html-with-location-header?forum=windowsazurewebsitespreview).
23 |
24 | In order to correct this, you can add a HttpResponsePreProcessing function that will delete the HTML code that is preventing the deserialization of the JSON content:
25 |
26 | ```C#
27 | client.HttpResponsePreProcessing = (responseString) =>
28 | {
29 | var clearedString = responseString.Replace("\n", "");
30 | var regex = @"\";
31 | return System.Text.RegularExpressions.Regex.Replace(clearedString, regex, "");
32 | };
33 | ```
34 |
--------------------------------------------------------------------------------
/docs/II version 1.x/entities/categories.md:
--------------------------------------------------------------------------------
1 | # Categories
2 |
3 | Here is a list of methods and examples of working with Categories
4 |
5 | ## GetAll()
6 |
7 | ```C#
8 | // returns all categories
9 | var categories = await client.Categories.GetAll();
10 | ```
11 |
12 | ## GetByID
13 |
14 | ```C#
15 | // returns category by ID
16 | var category = await client.Categories.GetByID(123);
17 | ```
18 |
19 | ## Query
20 | Create parametrized request
21 | ```C#
22 | // returns result of query
23 | var queryBuilder = new CategoriesQueryBuilder();
24 | queryBuilder.PerPage = 40;
25 | queryBuilder.Page = 2;
26 | queryBuilder.Before = DateTime.Now;
27 | var categories = await client.Categories.Query(queryBuilder);
28 | ```
29 |
30 | ## Create new Category
31 |
32 | ```C#
33 | // returns created category
34 | var category = new Category()
35 | {
36 | Name = "Title 1",
37 | Description = "Content"
38 | };
39 | if (await client.IsValidJWToken())
40 | {
41 | var createdCategory = await client.Categories.Create(category);
42 | }
43 | ```
44 |
45 | ## Update Category
46 |
47 | ```C#
48 | // returns updated category
49 | var category = client.Categories.GetByID(123);
50 | category.Name = "New Name";
51 | if (await client.IsValidJWToken())
52 | {
53 | var updatedCategory = await client.Categories.Update(category);
54 | }
55 | ```
56 |
57 | ## Delete Category
58 |
59 | ```C#
60 | // returns result of deletion
61 | if (await client.IsValidJWToken())
62 | {
63 | var result = await client.Categories.Delete(123);
64 | }
65 | ```
--------------------------------------------------------------------------------
/docs/I version 2.x/entities/categories.md:
--------------------------------------------------------------------------------
1 | # Categories
2 |
3 | Here is a list of methods and examples of working with Categories
4 |
5 | ## Get All
6 |
7 | ```C#
8 | // returns all categories
9 | var categories = await client.Categories.GetAllAsync();
10 | ```
11 |
12 | ## Get by ID
13 |
14 | ```C#
15 | // returns category by ID
16 | var category = await client.Categories.GetByIDAsync(123);
17 | ```
18 |
19 | ## Query
20 | Create parametrized request
21 | ```C#
22 | // returns result of query
23 | var queryBuilder = new CategoriesQueryBuilder();
24 | queryBuilder.PerPage = 40;
25 | queryBuilder.Page = 2;
26 | queryBuilder.Before = DateTime.Now;
27 | var categories = await client.Categories.QueryAsync(queryBuilder);
28 | ```
29 |
30 | ## Create new Category
31 |
32 | ```C#
33 | // returns created category
34 | var category = new Category()
35 | {
36 | Name = "Title 1",
37 | Description = "Content"
38 | };
39 | if (await client.IsValidJWToken())
40 | {
41 | var createdCategory = await client.Categories.CreateAsync(category);
42 | }
43 | ```
44 |
45 | ## Update Category
46 |
47 | ```C#
48 | // returns updated category
49 | var category = client.Categories.GetByIDAsync(123);
50 | category.Name = "New Name";
51 | if (await client.IsValidJWTokenAsync())
52 | {
53 | var updatedCategory = await client.Categories.UpdateAsync(category);
54 | }
55 | ```
56 |
57 | ## Delete Category
58 |
59 | ```C#
60 | // returns result of deletion
61 | if (await client.IsValidJWTokenAsync())
62 | {
63 | var result = await client.Categories.DeleteAsync(123);
64 | }
65 | ```
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/Themes_Tests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using WordPressPCL.Models;
6 | using WordPressPCL.Tests.Selfhosted.Utility;
7 | using WordPressPCL.Utility;
8 |
9 | namespace WordPressPCL.Tests.Selfhosted;
10 |
11 | [TestClass]
12 | public class Themes_Tests
13 | {
14 | private static WordPressClient _clientAuth;
15 |
16 | [ClassInitialize]
17 | public static async Task Init(TestContext testContext)
18 | {
19 | _clientAuth = await ClientHelper.GetAuthenticatedWordPressClient(testContext);
20 | }
21 |
22 | [TestMethod]
23 | public async Task Themes_GetActive()
24 | {
25 | List themes = await _clientAuth.Themes.QueryAsync(new ThemesQueryBuilder { Status = ActivationStatus.Active }, useAuth:true);
26 | Assert.IsNotNull(themes);
27 | Assert.AreNotEqual(themes.Count, 0);
28 |
29 | }
30 | [TestMethod]
31 | public async Task Themes_Get()
32 | {
33 | List themes = await _clientAuth.Themes.GetAsync (useAuth: true);
34 | Assert.IsNotNull(themes);
35 | Assert.AreNotEqual(themes.Count, 0);
36 | CollectionAssert.AllItemsAreUnique(themes.Select(tag => tag.Stylesheet).ToList());
37 | }
38 |
39 | [TestMethod]
40 | public async Task Themes_GetByID()
41 | {
42 | Theme theme = await _clientAuth.Themes.GetByIDAsync("twentytwentyfour", useAuth: true);
43 | Assert.IsNotNull(theme);
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/docs/II version 1.x/entities/posts.md:
--------------------------------------------------------------------------------
1 | # Posts
2 |
3 | Here is a list of methods and examples of working with Posts
4 |
5 | ## GetAll()
6 |
7 | ```C#
8 | // returns all posts
9 | var posts = await client.Posts.GetAll();
10 | ```
11 |
12 | ## GetByID
13 |
14 | ```C#
15 | // returns post by ID
16 | var post = await client.Posts.GetByID(123);
17 | ```
18 |
19 | ## Query
20 | Create parametrized request
21 | ```C#
22 | // returns result of query
23 | var queryBuilder = new PostsQueryBuilder();
24 | queryBuilder.PerPage=40;
25 | queryBuilder.Page=2;
26 | queryBuilder.Categories= new int[]{1,2,3};
27 | var posts = await client.Posts.Query(queryBuilder);
28 | ```
29 |
30 | ## Create new Post
31 |
32 | ```C#
33 | // returns created post
34 | var post = new Post()
35 | {
36 | Title = new Title("Title 1"),
37 | Content = new Content("Content PostCreate")
38 | };
39 | if (await client.IsValidJWToken())
40 | {
41 | var createdPost = await client.Posts.Create(post);
42 | }
43 | ```
44 |
45 | ## Update Post
46 |
47 | ```C#
48 | // returns updated post
49 | var post = client.Posts.GetByID(123);
50 | post.Content.Raw = "New Content";
51 | if (await client.IsValidJWToken())
52 | {
53 | var updatedPost = await client.Posts.Update(post);
54 | }
55 | ```
56 |
57 | ## Delete Post
58 |
59 | ```C#
60 | // returns result of deletion
61 | if (await client.IsValidJWToken())
62 | {
63 | var result = await client.Posts.Delete(123);
64 | }
65 | ```
66 |
67 | ## Get Post Revisions
68 |
69 | ```C#
70 | // returns revisions of post
71 | var revisions = await client.Posts.Revisions(123);
72 | ```
--------------------------------------------------------------------------------
/WordPressPCL/Models/ApplicationPassword.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace WordPressPCL.Models
5 | {
6 | ///
7 | /// Application Password
8 | ///
9 | public class ApplicationPassword
10 | {
11 | ///
12 | /// Unique ID
13 | ///
14 | [JsonProperty("uuid")]
15 | public string Uuid { get; set; }
16 |
17 | ///
18 | /// App ID
19 | ///
20 | [JsonProperty("app_id")]
21 | public string AppId { get; set; }
22 |
23 | ///
24 | /// App Name
25 | ///
26 | [JsonProperty("name")]
27 | public string Name { get; set; }
28 |
29 | ///
30 | /// Created Timestamp
31 | ///
32 | [JsonProperty("created")]
33 | public DateTime Created { get; set; }
34 |
35 | ///
36 | /// Last Used
37 | ///
38 | [JsonProperty("last_used")]
39 | public object LastUsed { get; set; }
40 |
41 | ///
42 | /// Last IP
43 | ///
44 | [JsonProperty("last_ip")]
45 | public object LastIp { get; set; }
46 |
47 | ///
48 | /// Application Password
49 | ///
50 | [JsonProperty("password")]
51 | public string Password { get; set; }
52 |
53 | ///
54 | /// Links
55 | ///
56 | [JsonProperty("_links")]
57 | public Links Links { get; set; }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/docs/II version 1.x/troubleshooting.md:
--------------------------------------------------------------------------------
1 | # Troubleshooting
2 |
3 | ## WordPressClient throws WPException
4 | This happens when the rest api has received your request but for various reasons can not process it. You can catch this exception and in the additional information you can find out exactly what problems are with your request.
5 | To do this, you can access the **BadRequest** property, which contains the fields:
6 | * Name - the service name of the problem
7 | * Message - description of the problem
8 | * Data is a dynamic object that contains additional information about the exception
9 | Example:
10 | ```C#
11 | try
12 | {
13 | //create empty post is not allowed
14 | var post = await client.Posts.Create(new Post());
15 | }
16 | catch (WPException wpex)
17 | {
18 | wpex.BadRequest.Name //system name
19 | wpex.BadRequest.Message //description
20 | wpex.BadRequest.Data //dynamic object with any non-structured additional info
21 | }
22 | ```
23 |
24 | ### WordPressPCL.Models.Exceptions.WPException: No route was found matching the URL and request method
25 | This usually happens when a serverside redirect to retreive a new JWT Token changes the POST request into a GET request (e.g. on www-to-non-www or http-to-https redirects).
26 |
27 | ## WordPressClient returns `null`
28 | * Check your WordPress URL. It should look like this: `https://wordpress-site.com/wp-json/`
29 | * Check your request. If you're making a post query that requires the edit context, or for whatever reason requires auth headers, you need to tell the query method to include the auth headers using an additional parameter, as it will *not* by default. Ex: `_client.Posts.Query(query, true);`
--------------------------------------------------------------------------------
/docs/I version 2.x/troubleshooting.md:
--------------------------------------------------------------------------------
1 | # Troubleshooting
2 |
3 | ## WordPressClient throws WPException
4 | This happens when the rest api has received your request but for various reasons can not process it. You can catch this exception and in the additional information you can find out exactly what problems are with your request.
5 | To do this, you can access the **BadRequest** property, which contains the fields:
6 | * Name - the service name of the problem
7 | * Message - description of the problem
8 | * Data is a dynamic object that contains additional information about the exception
9 | Example:
10 | ```C#
11 | try
12 | {
13 | //create empty post is not allowed
14 | var post = await client.Posts.CreateAsync(new Post());
15 | }
16 | catch (WPException wpex)
17 | {
18 | wpex.BadRequest.Name //system name
19 | wpex.BadRequest.Message //description
20 | wpex.BadRequest.Data //dynamic object with any non-structured additional info
21 | }
22 | ```
23 |
24 | ### WordPressPCL.Models.Exceptions.WPException: No route was found matching the URL and request method
25 | This usually happens when a serverside redirect to retreive a new JWT Token changes the POST request into a GET request (e.g. on www-to-non-www or http-to-https redirects).
26 |
27 | ## WordPressClient returns `null`
28 | * Check your WordPress URL. It should look like this: `https://wordpress-site.com/wp-json/`
29 | * Check your request. If you're making a post query that requires the edit context, or for whatever reason requires auth headers, you need to tell the query method to include the auth headers using an additional parameter, as it will *not* by default. Ex: `_client.Posts.QueryAsync(query, true);`
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/Taxonomies_Tests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System.Threading.Tasks;
3 | using WordPressPCL.Utility;
4 | using WordPressPCL.Tests.Selfhosted.Utility;
5 | using WordPressPCL.Models;
6 | using System.Collections.Generic;
7 |
8 | namespace WordPressPCL.Tests.Selfhosted;
9 |
10 | [TestClass]
11 | public class Taxonomies_Tests
12 | {
13 | private static WordPressClient _clientAuth;
14 |
15 | [ClassInitialize]
16 | public static async Task Init(TestContext testContext)
17 | {
18 | _clientAuth = await ClientHelper.GetAuthenticatedWordPressClient(testContext);
19 | }
20 |
21 | [TestMethod]
22 | public async Task Taxonomies_Read()
23 | {
24 | List taxonomies = await _clientAuth.Taxonomies.GetAllAsync();
25 | Assert.IsNotNull(taxonomies);
26 | Assert.AreNotEqual(taxonomies.Count, 0);
27 | }
28 |
29 | [TestMethod]
30 | public async Task Taxonomies_Get()
31 | {
32 | List taxonomies = await _clientAuth.Taxonomies.GetAsync();
33 | Assert.IsNotNull(taxonomies);
34 | Assert.AreNotEqual(taxonomies.Count, 0);
35 | }
36 |
37 | [TestMethod]
38 | public async Task Taxonomies_Query()
39 | {
40 | TaxonomiesQueryBuilder queryBuilder = new()
41 | {
42 | Type = "post"
43 | };
44 | List queryresult = await _clientAuth.Taxonomies.QueryAsync(queryBuilder);
45 | Assert.AreEqual("?type=post&order=desc&context=view", queryBuilder.BuildQuery());
46 | Assert.IsNotNull(queryresult);
47 | Assert.AreNotSame(queryresult.Count, 0);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/WordPressPCL/Client/Settings.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http;
2 | using System.Text;
3 | using System.Threading.Tasks;
4 | using Newtonsoft.Json;
5 | using WordPressPCL.Utility;
6 |
7 | namespace WordPressPCL.Client {
8 | ///
9 | /// Client class for interaction with Settings endpoints of WP REST API
10 | ///
11 | public class Settings {
12 |
13 | private readonly HttpHelper _httpHelper;
14 |
15 | ///
16 | /// Constructor
17 | ///
18 | /// reference to HttpHelper class for interaction with HTTP
19 | public Settings(HttpHelper httpHelper) {
20 | _httpHelper = httpHelper;
21 | }
22 |
23 | ///
24 | /// Get site settings
25 | ///
26 | /// Site settings
27 | public Task GetSettingsAsync()
28 | {
29 | return _httpHelper.GetRequestAsync("settings", false, true);
30 | }
31 |
32 | ///
33 | /// Update site settings
34 | ///
35 | /// Settings object
36 | /// Updated settings
37 | public async Task UpdateSettingsAsync(Models.Settings settings)
38 | {
39 | using var postBody = new StringContent(JsonConvert.SerializeObject(settings), Encoding.UTF8, "application/json");
40 | var (setting, _) = await _httpHelper.PostRequestAsync("settings", postBody).ConfigureAwait(false);
41 | return setting;
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/docs/II version 1.x/entities/users.md:
--------------------------------------------------------------------------------
1 | # Users
2 |
3 | Here is a list of methods and examples of working with Users
4 |
5 | ## GetAll()
6 |
7 | ```C#
8 | // execute request users without credentials - returns only you
9 | var users = await client.Users.GetAll();
10 |
11 | // send credentials - list of all users
12 | var users = await client.Users.GetAll(useAuth:true);
13 | ```
14 |
15 | ## GetByID
16 |
17 | ```C#
18 | // returns user by ID
19 | var user = await client.Users.GetByID(123);
20 | ```
21 |
22 | ## GetCurrentUser
23 |
24 | ```C#
25 | // returns current user
26 | var user = await client.Users.GetCurrentUser();
27 | ```
28 |
29 | ## Query
30 | Create parametrized request
31 | ```C#
32 | // returns result of query
33 | var queryBuilder = new UsersQueryBuilder();
34 | queryBuilder.PerPage = 40;
35 | queryBuilder.Page = 2;
36 | queryBuilder.Before = DateTime.Now;
37 | var users = await client.Users.Query(queryBuilder);
38 | ```
39 |
40 | ## Create new User
41 |
42 | ```C#
43 | // returns created user
44 | var user = new User("username","email","password")
45 | {
46 | NickName= "nickname"
47 | };
48 | if (await client.IsValidJWToken())
49 | {
50 | var user = await client.Users.Create(user);
51 | }
52 | ```
53 |
54 | ## Update User
55 |
56 | ```C#
57 | // returns updated user
58 | var user = client.Users.GetByID(123);
59 | user.Name = "New Name";
60 | if (await client.IsValidJWToken())
61 | {
62 | var updatedUser = await client.Users.Update(user);
63 | }
64 | ```
65 |
66 | ## Delete User
67 |
68 | ```C#
69 | // returns result of deletion
70 | if (await client.IsValidJWToken())
71 | {
72 | //second param - user to reassign all content
73 | var result = await client.Users.Delete(123,321);
74 | }
75 | ```
--------------------------------------------------------------------------------
/WordPressPCL/Client/Themes.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 | using WordPressPCL.Models;
4 | using WordPressPCL.Utility;
5 |
6 | namespace WordPressPCL.Client
7 | {
8 | ///
9 | /// Client class for interaction with Themes endpoint WP REST API
10 | /// Date: 26 May 2023
11 | /// Creator: Gregory Liénard
12 | ///
13 | public class Themes : CRUDOperation
14 | {
15 | #region Init
16 |
17 | private const string _methodPath = "themes";
18 |
19 | ///
20 | /// Constructor
21 | ///
22 | /// reference to HttpHelper class for interaction with HTTP
23 | public Themes(HttpHelper HttpHelper) : base(HttpHelper, _methodPath)
24 | {
25 | }
26 |
27 | #endregion Init
28 |
29 | #region Custom
30 |
31 |
32 |
33 | ///
34 | /// Get themes by search term
35 | ///
36 | /// active or inactive
37 | /// include embed info
38 | /// List of posts
39 | public Task> GetThemesByActivationStatusAsync(ActivationStatus activationStatus, bool embed = false)
40 | {
41 | // default values
42 | // int page = 1, int per_page = 10, int offset = 0, Post.OrderBy orderby = Post.OrderBy.date
43 | return HttpHelper.GetRequestAsync>(_methodPath.SetQueryParam("status", activationStatus.ToString().ToLower()), embed, true);
44 | }
45 |
46 |
47 |
48 | #endregion Custom
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/WordPressPCL/Models/Category.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace WordPressPCL.Models
4 | {
5 | ///
6 | /// Terms of the type category
7 | ///
8 | public class Category : Term
9 | {
10 | ///
11 | /// Number of published posts for the term.
12 | ///
13 | ///
14 | /// Read only
15 | /// Context: view, edit
16 | ///
17 | [JsonProperty("count")]
18 | public int Count { get; set; }
19 |
20 | ///
21 | /// HTML description of the term.
22 | ///
23 | /// Context: view, edit
24 | [JsonProperty("description")]
25 | public string Description { get; set; }
26 |
27 | ///
28 | /// The parent term ID.
29 | ///
30 | /// Context: view, edit
31 | [JsonProperty("parent", NullValueHandling = NullValueHandling.Ignore)]
32 | public int Parent { get; set; }
33 |
34 | ///
35 | /// Meta fields.
36 | ///
37 | /// Context: view, edit
38 | [JsonProperty("meta", DefaultValueHandling = DefaultValueHandling.Ignore)]
39 | public dynamic Meta { get; set; }
40 |
41 | ///
42 | /// Parameterless constructor
43 | ///
44 | public Category() : base()
45 | {
46 | }
47 |
48 | ///
49 | /// Default constructor
50 | ///
51 | ///
52 | public Category(string name) : this()
53 | {
54 | Name = name;
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/HttpClient_Tests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Net.Http;
6 | using System.Threading.Tasks;
7 | using WordPressPCL.Models;
8 | using WordPressPCL.Tests.Selfhosted.Utility;
9 |
10 | namespace WordPressPCL.Tests.Selfhosted;
11 |
12 | [TestClass]
13 | public class HttpClient_Tests
14 | {
15 | [TestMethod]
16 | public async Task CustomHttpClient_WithBaseAddress()
17 | {
18 | // Initialize
19 | HttpClient httpClient = new()
20 | {
21 | BaseAddress = new Uri(ApiCredentials.WordPressUri)
22 | };
23 |
24 | await CustomHttpClientBase(httpClient, new WordPressClient(httpClient));
25 | }
26 |
27 | [TestMethod]
28 | public async Task CustomHttpClient_WithoutBaseAddress()
29 | {
30 | // Initialize
31 | HttpClient httpClient = new();
32 | WordPressClient wordPressClient = new(httpClient, uri: new Uri(ApiCredentials.WordPressUri));
33 | await CustomHttpClientBase(httpClient, wordPressClient);
34 | }
35 |
36 | private static async Task CustomHttpClientBase(HttpClient httpClient, WordPressClient client)
37 | {
38 | httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0");
39 | httpClient.DefaultRequestHeaders.Add("Referer", "https://github.com/wp-net/WordPressPCL");
40 |
41 | List posts = await client.Posts.GetAllAsync();
42 | Post post = await client.Posts.GetByIDAsync(posts.First().Id);
43 | Assert.IsTrue(posts.First().Id == post.Id);
44 | Assert.IsTrue(!string.IsNullOrEmpty(posts.First().Content.Rendered));
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/dev/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | db:
3 | image: mysql:5.7
4 | container_name: db
5 | environment:
6 | MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
7 | MYSQL_DATABASE: ${MYSQL_DATABASE}
8 | MYSQL_USER: ${MYSQL_USER}
9 | MYSQL_PASSWORD: ${MYSQL_PASSWORD}
10 | restart: unless-stopped
11 |
12 | wordpress:
13 | depends_on:
14 | - db
15 | build:
16 | context: .
17 | image: wordpress-custom
18 | volumes:
19 | - wp-volume:/var/www/html
20 | ports:
21 | - "8080:80"
22 | container_name: wordpress
23 | environment:
24 | WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST}
25 | WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
26 | WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
27 | WORDPRESS_DB_NAME: ${WORDPRESS_DB_NAME}
28 | WORDPRESS_DEBUG: ${WORDPRESS_DEBUG}
29 | WORDPRESS_CONFIG_EXTRA: define('JWT_AUTH_SECRET_KEY', '.|)WaUppb-a>Z;(%p,4~^|5jjWom6Gw{(2_lqJv9r&]p
44 | /bin/sh -c '
45 | sleep 10;
46 | wp core install --path="/var/www/html" --url="http://localhost:8080" --title="Test Instance" --admin_user=wordpress --admin_password=wordpress --admin_email=test@example.com;
47 | wp option update permalink_structure "/%postname%";
48 | wp plugin install application-passwords-enable --activate;
49 | wp plugin install contact-form-7 --activate;
50 | wp plugin install jwt-auth --activate;'
51 |
52 | volumes:
53 | wp-volume:
54 |
55 | networks:
56 | default:
57 | name: net1
--------------------------------------------------------------------------------
/WordPressPCL/Models/Term.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace WordPressPCL.Models
4 | {
5 | ///
6 | /// This is the base class for all terms, like categories and tags
7 | ///
8 | public class Term : Base
9 | {
10 | ///
11 | /// URL of the term.
12 | ///
13 | ///
14 | /// Read only
15 | /// Context: view, embed, edit
16 | ///
17 | [JsonProperty("link")]
18 | public string Link { get; set; }
19 |
20 | ///
21 | /// HTML title for the term.
22 | ///
23 | /// Context: view, embed, edit
24 | [JsonProperty("name")]
25 | public string Name { get; set; }
26 |
27 | ///
28 | /// An alphanumeric identifier for the term unique to its type.
29 | ///
30 | /// Context: view, embed, edit
31 | [JsonProperty("slug")]
32 | public string Slug { get; set; }
33 |
34 | ///
35 | /// Type attribution for the term.
36 | ///
37 | ///
38 | /// Read only
39 | /// Context: view, embed, edit
40 | /// One of: category, post_tag, nav_menu, link_category, post_format
41 | ///
42 | [JsonProperty("taxonomy")]
43 | public string Taxonomy { get; set; }
44 |
45 | ///
46 | /// Links to related resources
47 | ///
48 | [JsonProperty("_links", DefaultValueHandling = DefaultValueHandling.Ignore)]
49 | public Links Links { get; set; }
50 |
51 | ///
52 | /// parameterless constructor
53 | ///
54 | public Term()
55 | {
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/ListPosts_QueryBuilder_Tests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using WordPressPCL.Tests.Selfhosted.Utility;
3 | using System.Threading.Tasks;
4 | using WordPressPCL.Utility;
5 | using System.Linq;
6 | using System.Collections.Generic;
7 | using WordPressPCL.Models;
8 |
9 | namespace WordPressPCL.Tests.Selfhosted;
10 |
11 | [TestClass]
12 | public class ListPosts_QueryBuilder_Tests
13 | {
14 | private static WordPressClient _client;
15 |
16 | [ClassInitialize]
17 | public static void Init(TestContext testContext)
18 | {
19 | _client = ClientHelper.GetWordPressClient();
20 | }
21 |
22 | // TODO: initialize more test posts
23 | //[TestMethod]
24 | public async Task List_Posts_QueryBuilder_Test_Pagination()
25 | {
26 | // Posts
27 | List postsA = await _client.Posts.QueryAsync(new PostsQueryBuilder()
28 | {
29 | Page = 1,
30 | PerPage = 2
31 | });
32 | List postsB = await _client.Posts.QueryAsync(new PostsQueryBuilder()
33 | {
34 | Page = 2,
35 | PerPage = 2
36 | });
37 | Assert.IsNotNull(postsA);
38 | Assert.IsNotNull(postsB);
39 | Assert.AreNotEqual(postsA.Count, 0);
40 | Assert.AreNotEqual(postsB.Count, 0);
41 | CollectionAssert.AreNotEqual(postsA.Select(post => post.Id).ToList(), postsB.Select(post => post.Id).ToList());
42 | }
43 |
44 | [TestMethod]
45 | [Description("Test that the ListPosts method with the QueryBuilder set to list posts published After a specific date works.")]
46 | public async Task List_Posts_QueryBuilder_After()
47 | {
48 | // Posts
49 | List posts = await _client.Posts.QueryAsync(new PostsQueryBuilder { After = System.DateTime.Parse("2017-05-22T13:41:09") });
50 | Assert.IsNotNull(posts);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/docs/I version 2.x/entities/media.md:
--------------------------------------------------------------------------------
1 | # Media
2 |
3 | Here is a list of methods and examples of working with Media
4 |
5 | ## GetAll()
6 |
7 | ```C#
8 | // returns all media
9 | var media = await client.Media.GetAllAsync();
10 | ```
11 |
12 | ## GetByID
13 |
14 | ```C#
15 | // returns media by ID
16 | var media = await client.Media.GetByIDAsync(123);
17 | ```
18 |
19 | ## Query
20 | Create parametrized request
21 | ```C#
22 | // returns result of query
23 | var queryBuilder = new MediaQueryBuilder();
24 | queryBuilder.PerPage = 40;
25 | queryBuilder.Page = 2;
26 | queryBuilder.Before = DateTime.Now;
27 | var media = await client.Pages.QueryAsync(queryBuilder);
28 | ```
29 |
30 | ## Create new Media
31 | ### Create from Stream
32 |
33 | ```C#
34 | // returns created media
35 | // for create media item you must read them to Stream. Media items can be audio, video, image, pdf ot any othe type supported by wordpress
36 | Stream s = File.OpenRead("pathToMedia/media.jpg");
37 | if (await client.IsValidJWTokenAsync())
38 | {
39 | var createdMedia = await client.Media.CreateAsync(s,"media.jpg");
40 | }
41 | ```
42 | ### Create from file path
43 |
44 | ```C#
45 | // returns created media
46 | // for create media item you must read them to Stream. Media items can be audio, video, image, pdf ot any othe type supported by wordpress
47 | if (await client.IsValidJWToken())
48 | {
49 | var createdMedia = await client.Media.CreateAsync(@"C:\pathToFile\media.jpg","media.jpg");
50 | }
51 | ```
52 |
53 | ## Update Media
54 |
55 | ```C#
56 | // returns updated media
57 | var media= client.Media.GetByID(123);
58 | media.Title.Raw = "New Title";
59 |
60 | if (await client.IsValidJWTokenAsync())
61 | {
62 | var updatedMedia = await client.Media.UpdateAsync(media);
63 | }
64 | ```
65 |
66 | ## Delete Media
67 |
68 | ```C#
69 | // returns result of deletion
70 | if (await client.IsValidJWTokenAsync())
71 | {
72 | var result = await client.Media.DeleteAsync(123);
73 | }
74 | ```
--------------------------------------------------------------------------------
/docs/II version 1.x/entities/comments.md:
--------------------------------------------------------------------------------
1 | # Comments
2 |
3 | Here is a list of methods and examples of working with Comments
4 |
5 | ## GetAll()
6 |
7 | ```C#
8 | // returns all comments
9 | var comments = await client.Comments.GetAll();
10 | ```
11 |
12 | ## GetByID
13 |
14 | ```C#
15 | // returns comment by ID
16 | var comment = await client.Comments.GetByID(123);
17 | ```
18 |
19 | ## GetCommentsForPost
20 |
21 | ```C#
22 | // returns comments from post
23 | var comments = await client.Comments.GetCommentsForPost(123)
24 | ```
25 |
26 | ## Query
27 | Create parametrized request
28 | ```C#
29 | // returns result of query
30 | var queryBuilder = new CommentsQueryBuilder();
31 | queryBuilder.PerPage = 40;
32 | queryBuilder.Page = 2;
33 | queryBuilder.Before = DateTime.Now;
34 | var comments = await client.Comments.Query(queryBuilder);
35 | ```
36 |
37 | ## Get threaded comments
38 | If your blog supports threaded comments (comments with direct answers) you can order and get the right depth for them with this handy extension method:
39 |
40 | ```c#
41 | var comments = await client.Comments.GetCommentsForPost(123)
42 | var commentsThreaded = comments.ToThreaded();
43 | ```
44 |
45 | ## Create new Comment
46 |
47 | ```C#
48 | // returns created comment
49 | var comment = new Comment()
50 | {
51 | Content = new Content("Comment"),
52 | PostId = 123,
53 | AuthorId = 1,
54 | AuthorEmail = "test@test.com"
55 | };
56 | if (await client.IsValidJWToken())
57 | {
58 | var createdComment = await client.Comments.Create(comment);
59 | }
60 | ```
61 |
62 | ## Update Comment
63 |
64 | ```C#
65 | // returns updated comment
66 | var comment= client.Comments.GetByID(123);
67 | comment.Content.Raw = "New Content";
68 | if (await client.IsValidJWToken())
69 | {
70 | var updatedComment = await client.Comments.Update(comment);
71 | }
72 | ```
73 |
74 | ## Delete Comment
75 |
76 | ```C#
77 | // returns result of deletion
78 | if (await client.IsValidJWToken())
79 | {
80 | var result = await client.Comments.Delete(123);
81 | }
82 | ```
--------------------------------------------------------------------------------
/docs/I version 2.x/entities/comments.md:
--------------------------------------------------------------------------------
1 | Here is a list of methods and examples of working with Comments
2 |
3 | ## Get All
4 |
5 | ```C#
6 | // returns all comments
7 | var comments = await client.Comments.GetAllAsync();
8 | ```
9 |
10 | ## Get By ID
11 |
12 | ```C#
13 | // returns comment by ID
14 | var comment = await client.Comments.GetByIDAsync(123);
15 | ```
16 |
17 | ## Get Comments by Post ID
18 |
19 | ```C#
20 | // returns comments from post
21 | var comments = await client.Comments.GetCommentsForPostAsync(123)
22 | ```
23 |
24 | ## Query
25 | Create parametrized request
26 | ```C#
27 | // returns result of query
28 | var queryBuilder = new CommentsQueryBuilder();
29 | queryBuilder.PerPage = 40;
30 | queryBuilder.Page = 2;
31 | queryBuilder.Before = DateTime.Now;
32 | var comments = await client.Comments.Query(queryBuilder);
33 | ```
34 |
35 | ## Get threaded comments
36 | If your blog supports threaded comments (comments with direct answers) you can order and get the right depth for them with this handy extension method:
37 |
38 | ```c#
39 | var comments = await client.Comments.GetCommentsForPostAsync(123)
40 | var commentsThreaded = comments.ToThreaded();
41 | ```
42 |
43 | ## Create new Comment
44 |
45 | ```C#
46 | // returns created comment
47 | var comment = new Comment()
48 | {
49 | Content = new Content("Comment"),
50 | PostId = 123,
51 | AuthorId = 1,
52 | AuthorEmail = "test@test.com"
53 | };
54 | if (await client.IsValidJWTokenAsync())
55 | {
56 | var createdComment = await client.Comments.CreateAsync(comment);
57 | }
58 | ```
59 |
60 | ## Update Comment
61 |
62 | ```C#
63 | // returns updated comment
64 | var comment= client.Comments.GetByIDAsync(123);
65 | comment.Content.Raw = "New Content";
66 | if (await client.IsValidJWTokenAsync())
67 | {
68 | var updatedComment = await client.Comments.UpdateAsync(comment);
69 | }
70 | ```
71 |
72 | ## Delete Comment
73 |
74 | ```C#
75 | // returns result of deletion
76 | if (await client.IsValidJWToken())
77 | {
78 | var result = await client.Comments.DeleteAsync(123);
79 | }
80 | ```
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/ApplicationPasswords_Tests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using WordPressPCL.Models;
5 | using WordPressPCL.Tests.Selfhosted.Utility;
6 |
7 | namespace WordPressPCL.Tests.Selfhosted;
8 |
9 | [TestClass]
10 | public class ApplicationPasswords_Tests
11 | {
12 | private static WordPressClient _clientAuth;
13 |
14 | [ClassInitialize]
15 | public static async Task Init(TestContext testContext)
16 | {
17 | _clientAuth = await ClientHelper.GetAuthenticatedWordPressClient(testContext);
18 | }
19 |
20 | [TestMethod]
21 | public async Task Application_Passwords_Create()
22 | {
23 | ApplicationPassword password = await _clientAuth.Users.CreateApplicationPasswordAsync(System.Guid.NewGuid().ToString());
24 | Assert.IsNotNull(password.Password);
25 | }
26 |
27 | [TestMethod]
28 | public async Task Read()
29 | {
30 | await _clientAuth.Users.CreateApplicationPasswordAsync(System.Guid.NewGuid().ToString());
31 | List passwords = await _clientAuth.Users.GetApplicationPasswords();
32 |
33 | Assert.IsNotNull(passwords);
34 | Assert.AreNotEqual(0, passwords.Count);
35 | }
36 |
37 | [TestMethod]
38 | public async Task Application_Password_Auth()
39 | {
40 | ApplicationPassword appPassword = await _clientAuth.Users.CreateApplicationPasswordAsync(System.Guid.NewGuid().ToString());
41 | WordPressClient appPasswordClient = new(ApiCredentials.WordPressUri);
42 | appPasswordClient.Auth.UseBasicAuth(ApiCredentials.Username, appPassword.Password);
43 |
44 | Post post = new()
45 | {
46 | Title = new Title("Title 1"),
47 | Content = new Content("Content PostCreate")
48 | };
49 | Post postCreated = await appPasswordClient.Posts.CreateAsync(post);
50 | Assert.IsNotNull(postCreated);
51 | Assert.AreEqual("Title 1", postCreated.Title.Raw);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/WordPressPCL/Models/Exceptions/WPException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace WordPressPCL.Models.Exceptions
4 | {
5 | ///
6 | /// WordPress request exceptions
7 | ///
8 | public class WPException : Exception
9 | {
10 | ///
11 | /// Constructor
12 | ///
13 | public WPException()
14 | {
15 | }
16 |
17 | ///
18 | /// Constructor
19 | ///
20 | ///
21 | public WPException(string message) : base(message)
22 | {
23 | }
24 |
25 | ///
26 | /// Constructor
27 | ///
28 | ///
29 | ///
30 | public WPException(string message, Exception innerException) : base(message, innerException)
31 | {
32 | }
33 |
34 | ///
35 | /// Constructor
36 | ///
37 | /// additional request info
38 | public WPException(BadRequest request) : base() { RequestData = request; }
39 |
40 | ///
41 | /// Constructor
42 | ///
43 | /// additional message
44 | /// additional request info
45 | public WPException(string message, BadRequest request) : base(message) { RequestData = request; }
46 |
47 | ///
48 | /// Constructor
49 | ///
50 | /// additional message
51 | /// inner exception
52 | /// additional request info
53 | public WPException(string message, Exception inner, BadRequest request) : base(message, inner) { RequestData = request; }
54 |
55 | ///
56 | /// Bad request data info
57 | ///
58 | public BadRequest RequestData { get; set; }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ master ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ master ]
20 | schedule:
21 | - cron: '27 3 * * 1'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 | permissions:
28 | actions: read
29 | contents: read
30 | security-events: write
31 |
32 | strategy:
33 | fail-fast: false
34 | matrix:
35 | language: [ 'csharp' ]
36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support
38 |
39 | steps:
40 | - name: Checkout repository
41 | uses: actions/checkout@v4
42 |
43 | # Initializes the CodeQL tools for scanning.
44 | - name: Initialize CodeQL
45 | uses: github/codeql-action/init@v1
46 | with:
47 | languages: ${{ matrix.language }}
48 | # If you wish to specify custom queries, you can do so here or in a config file.
49 | # By default, queries listed here will override any specified in a config file.
50 | # Prefix the list here with "+" to use these queries and those in the config file.
51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
52 |
53 | - name: Setup .NET SDK
54 | uses: actions/setup-dotnet@v4
55 | with:
56 | dotnet-version: 8.x
57 | - name: Build Solution
58 | run: dotnet build ${{ env.solution }} -c Release
59 |
60 | - name: Perform CodeQL Analysis
61 | uses: github/codeql-action/analyze@v1
62 |
--------------------------------------------------------------------------------
/docs/II version 1.x/entities/media.md:
--------------------------------------------------------------------------------
1 | # Media
2 |
3 | Here is a list of methods and examples of working with Media
4 |
5 | ## GetAll()
6 |
7 | ```C#
8 | // returns all media
9 | var media = await client.Media.GetAll();
10 | ```
11 |
12 | ## GetByID
13 |
14 | ```C#
15 | // returns media by ID
16 | var media = await client.Media.GetByID(123);
17 | ```
18 |
19 | ## Query
20 | Create parametrized request
21 | ```C#
22 | // returns result of query
23 | var queryBuilder = new MediaQueryBuilder();
24 | queryBuilder.PerPage = 40;
25 | queryBuilder.Page = 2;
26 | queryBuilder.Before = DateTime.Now;
27 | var media = await client.Pages.Query(queryBuilder);
28 | ```
29 |
30 | ## Create new Media
31 | ### Create for .Net Standard 1.1+
32 | .Net Standard 1.1-1.3 doesn`t support file manipulation (read or write). So only way to send file content is to create Stream with file content manually.
33 | Applicable for .netcore 1.0 apps
34 | ```C#
35 | // returns created media
36 | // for create media item you must read them to Stream. Media items can be audio, video, image, pdf ot any othe type supported by wordpress
37 | Stream s = File.OpenRead("pathToMedia/media.jpg");
38 | if (await client.IsValidJWToken())
39 | {
40 | var createdMedia = await client.Media.Create(s,"media.jpg");
41 | }
42 | ```
43 | ### Create for .Net Standard 2.0+
44 | .Net Standard 2.0 supports files manipulation. You can send media files by passing its full path to file.
45 | Applicable for .netcore 2.0 apps
46 | ```C#
47 | // returns created media
48 | // for create media item you must read them to Stream. Media items can be audio, video, image, pdf ot any othe type supported by wordpress
49 | if (await client.IsValidJWToken())
50 | {
51 | var createdMedia = await client.Media.Create(@"C:\pathToFile\media.jpg","media.jpg");
52 | }
53 | ```
54 |
55 | ## Update Media
56 |
57 | ```C#
58 | // returns updated media
59 | var media= client.Media.GetByID(123);
60 | media.Title.Raw = "New Title";
61 |
62 | if (await client.IsValidJWToken())
63 | {
64 | var updatedMedia = await client.Media.Update(media);
65 | }
66 | ```
67 |
68 | ## Delete Media
69 |
70 | ```C#
71 | // returns result of deletion
72 | if (await client.IsValidJWToken())
73 | {
74 | var result = await client.Media.Delete(123);
75 | }
76 | ```
--------------------------------------------------------------------------------
/WordPressPCL/Utility/UrlHelper.cs:
--------------------------------------------------------------------------------
1 | namespace WordPressPCL.Utility
2 | {
3 | ///
4 | /// Helper clas for URL manipulation
5 | ///
6 | public static class UrlHelper
7 | {
8 | ///
9 | /// Creates a new string with queryParam & queryValue appended as query parameters
10 | /// Ensures values are appended correctly with & or ?
11 | ///
12 | /// Absolute or relative URL
13 | /// Query Parameter Name
14 | /// Query Parameter Value
15 | /// New URL as string
16 | public static string SetQueryParam(this string url, string paramName, string paramValue)
17 | {
18 | if(url == null)
19 | {
20 | return null;
21 | }
22 |
23 | if (url.Contains("?"))
24 | {
25 | url += '&';
26 | }
27 | else
28 | {
29 | url += '?';
30 | }
31 |
32 | url += CombineEnsureSingleSeparator(paramName, paramValue, '=');
33 | return url;
34 | }
35 |
36 | ///
37 | /// Creates a new string with queryParam & queryValue appended as query parameters
38 | /// Ensures values are appended correctly with & or ?
39 | ///
40 | /// Absolute or relative URL
41 | /// Query Parameter Name
42 | /// Query Parameter Value
43 | /// New URL as string
44 | public static string SetQueryParam(this string url, string paramName, int paramValue)
45 | {
46 | return SetQueryParam(url, paramName, $"{paramValue}");
47 | }
48 |
49 | private static string CombineEnsureSingleSeparator(string a, string b, char separator)
50 | {
51 | if (string.IsNullOrEmpty(a)) return b;
52 | if (string.IsNullOrEmpty(b)) return a;
53 | return a.TrimEnd(separator) + separator + b.TrimStart(separator);
54 | }
55 | }
56 |
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/docs/I version 2.x/entities/posts.md:
--------------------------------------------------------------------------------
1 | # Posts
2 |
3 | Here is a list of methods and examples of working with Posts
4 |
5 | ## Get All
6 |
7 | ```C#
8 | // returns all posts
9 | var posts = await client.Posts.GetAllAsync();```
10 |
11 | ## Get By ID
12 |
13 | ```C#
14 | // returns post by ID
15 | var post = await client.Posts.GetByIDAsync(123);
16 | ```
17 |
18 | ## Query
19 | Create parametrized request
20 | ```C#
21 | // returns result of query
22 | var queryBuilder = new PostsQueryBuilder();
23 | queryBuilder.PerPage = 40;
24 | queryBuilder.Page = 2;
25 | queryBuilder.Categories = new int[]{1,2,3};
26 | var posts = await client.Posts.QueryAsync(queryBuilder);
27 | ```
28 |
29 | ## Create new Post
30 |
31 | ```C#
32 | // returns created post
33 | var post = new Post()
34 | {
35 | Title = new Title("Title 1"),
36 | Content = new Content("Content PostCreate")
37 | };
38 | if (await client.IsValidJWTokenAsync())
39 | {
40 | var createdPost = await client.Posts.CreateAsync(post);
41 | }
42 | ```
43 |
44 | ## Update Post
45 |
46 | ```C#
47 | // returns updated post
48 | var post = client.Posts.GetByIDAsync(123);
49 | post.Content.Raw = "New Content";
50 | if (await client.IsValidJWTokenAsync())
51 | {
52 | var updatedPost = await client.Posts.UpdateAsync(post);
53 | }
54 | ```
55 |
56 | ## Update Custom Fields
57 |
58 | ```C#
59 | var post = new Post
60 | {
61 | Id = 123,
62 | Meta = new Dictionary
63 | {
64 | ["my-custom-key"] = "some value"
65 | },
66 | };
67 |
68 | await client.Posts.UpdateAsync(post);
69 | ```
70 |
71 | Please note that all meta keys need to be registered using [`register_post_meta()`](https://developer.wordpress.org/reference/functions/register_post_meta/) before you can use them, e.g. by using the following PHP snippet:
72 |
73 | ```php
74 | register_post_meta('post', 'my-custom-key', [
75 | 'type' => 'string',
76 | 'single' => true,
77 | 'show_in_rest' => true,
78 | ]);
79 | ```
80 |
81 | ## Delete Post
82 |
83 | ```C#
84 | // returns result of deletion
85 | if (await client.IsValidJWTokenAsync())
86 | {
87 | var result = await client.Posts.DeleteAsync(123);
88 | }
89 | ```
90 |
91 | ## Get Post Revisions
92 |
93 | ```C#
94 | // returns revisions of post
95 | var revisions = await client.Posts.RevisionsAsync(123);
96 | ```
--------------------------------------------------------------------------------
/WordPressPCL/Models/Exceptions/WPUnexpectedException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Http;
3 |
4 | namespace WordPressPCL.Models.Exceptions
5 | {
6 | ///
7 | /// An exception resulting from a malformed WP response from a
8 | /// WP REST call, where the response is still a valid (but not
9 | /// successful) HTTP response. For example, the response returned
10 | /// from an endpoint that is not a WP REST endpoint
11 | ///
12 | public class WPUnexpectedException : Exception
13 | {
14 | ///
15 | /// Constructor
16 | ///
17 | public WPUnexpectedException()
18 | {
19 | }
20 |
21 | ///
22 | /// Constructor
23 | ///
24 | ///
25 | public WPUnexpectedException(string message) : base(message)
26 | {
27 | }
28 |
29 | ///
30 | /// Constructor
31 | ///
32 | ///
33 | ///
34 | public WPUnexpectedException(string message, Exception innerException) : base(message, innerException)
35 | {
36 | }
37 |
38 | ///
39 | /// Construct a WPUnexpectedException from a response
40 | ///
41 | /// The raw response
42 | /// The response body, if any
43 | public WPUnexpectedException(HttpResponseMessage response, string resonseBody)
44 | : base(FormatExceptionMessage(response))
45 | {
46 | Response = response;
47 | ResponseBody = resonseBody;
48 | }
49 |
50 | ///
51 | /// The response that triggered the error
52 | ///
53 | public HttpResponseMessage Response { get; set; }
54 |
55 | ///
56 | /// The response body (if any) that was returned with the error status
57 | ///
58 | public string ResponseBody { get; set; }
59 |
60 | private static string FormatExceptionMessage(HttpResponseMessage response)
61 | {
62 | return $"Server returned HTTP status {response.StatusCode}";
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/WordPressPCL/Models/ImageMeta.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.Collections.Generic;
3 |
4 | namespace WordPressPCL.Models
5 | {
6 | ///
7 | /// Meta info (EXIF) of image media
8 | ///
9 | ///
10 | public class ImageMeta
11 | {
12 | ///
13 | /// Aperture
14 | ///
15 | [JsonProperty("aperture")]
16 | public string Aperture { get; set; }
17 | ///
18 | /// Credit
19 | ///
20 | [JsonProperty("credit")]
21 | public string Credit { get; set; }
22 | ///
23 | /// Camera Model
24 | ///
25 | [JsonProperty("camera")]
26 | public string Camera { get; set; }
27 | ///
28 | /// Image Caption
29 | ///
30 | [JsonProperty("caption")]
31 | public string Caption { get; set; }
32 | ///
33 | /// Created Date
34 | ///
35 | [JsonProperty("created_timestamp")]
36 | public string CreatedTimestamp { get; set; }
37 | ///
38 | /// Copyright
39 | ///
40 | [JsonProperty("copyright")]
41 | public string Copyright { get; set; }
42 | ///
43 | /// Focal Length
44 | ///
45 | [JsonProperty("focal_length")]
46 | public string FocalLength { get; set; }
47 | ///
48 | /// ISO
49 | ///
50 | [JsonProperty("iso")]
51 | public string Iso { get; set; }
52 | ///
53 | /// Shutter Speed
54 | ///
55 | [JsonProperty("shutter_speed")]
56 | public string ShutterSpeed { get; set; }
57 | ///
58 | /// Image Title
59 | ///
60 | [JsonProperty("title")]
61 | public string Title { get; set; }
62 | ///
63 | /// Orientation
64 | ///
65 | [JsonProperty("orientation")]
66 | public string Orientation { get; set; }
67 | ///
68 | /// Image keywords
69 | ///
70 | [JsonProperty("keywords")]
71 | public IList Keywords { get; set; }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/PostRevisions_Tests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using WordPressPCL.Models;
6 | using WordPressPCL.Tests.Selfhosted.Utility;
7 |
8 | namespace WordPressPCL.Tests.Selfhosted;
9 |
10 | [TestClass]
11 | public class PostRevisions_Tests
12 | {
13 | private static WordPressClient _clientAuth;
14 |
15 | [ClassInitialize]
16 | public static async Task Init(TestContext testContext)
17 | {
18 | _clientAuth = await ClientHelper.GetAuthenticatedWordPressClient(testContext);
19 | }
20 |
21 | [TestMethod]
22 | public async Task PostRevisions_Read()
23 | {
24 | int id = await CreatePostWithRevision();
25 | Client.PostRevisions revisionsclient = _clientAuth.Posts.Revisions(id);
26 | List revisions = await revisionsclient.GetAllAsync();
27 | Assert.AreNotEqual(revisions.Count, 0);
28 | }
29 |
30 | [TestMethod]
31 | public async Task PostRevisions_Get()
32 | {
33 | int id = await CreatePostWithRevision();
34 | Client.PostRevisions revisionsclient = _clientAuth.Posts.Revisions(id);
35 | List revisions = await revisionsclient.GetAsync();
36 | Assert.AreNotEqual(revisions.Count, 0);
37 | }
38 |
39 | // TODO: check why revision can't be deleted
40 | //[TestMethod]
41 | public async Task PostRevisions_Delete()
42 | {
43 | int id = await CreatePostWithRevision();
44 |
45 | Client.PostRevisions revisionsclient = _clientAuth.Posts.Revisions(id);
46 | List revisions = await revisionsclient.GetAllAsync();
47 | Assert.AreNotEqual(revisions.Count, 0);
48 | bool res = await revisionsclient.DeleteAsync(revisions.First().Id);
49 | Assert.IsTrue(res);
50 | }
51 |
52 | private async Task CreatePostWithRevision()
53 | {
54 | Post post = new()
55 | {
56 | Title = new Title("Title 1"),
57 | Content = new Content("Content PostCreate"),
58 | };
59 | Post createdPost = await _clientAuth.Posts.CreateAsync(post);
60 | createdPost.Content.Raw = "Updated Content";
61 | Post updatedPost = await _clientAuth.Posts.UpdateAsync(createdPost);
62 | return updatedPost.Id;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/WordPressPCL/Models/Links.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json;
3 |
4 | namespace WordPressPCL.Models
5 | {
6 | ///
7 | /// Links helper class
8 | ///
9 | public class Links
10 | {
11 | ///
12 | /// Self link
13 | ///
14 | [JsonProperty("self")]
15 | public List Self { get; set; }
16 |
17 | ///
18 | /// Collection of links
19 | ///
20 | ///
21 | [JsonProperty("collection")]
22 | public List Collection { get; set; }
23 |
24 | ///
25 | /// About info
26 | ///
27 | ///
28 | [JsonProperty("about")]
29 | public List About { get; set; }
30 |
31 | ///
32 | /// WordPress post Type
33 | ///
34 | [JsonProperty("wp:post_type")]
35 | public List WpPostType { get; set; }
36 |
37 | ///
38 | /// Curries
39 | ///
40 | [JsonProperty("curies")]
41 | public List Curies { get; set; }
42 |
43 | ///
44 | /// Author
45 | ///
46 | [JsonProperty("author")]
47 | public List Author { get; set; }
48 |
49 | ///
50 | /// Replies
51 | ///
52 | [JsonProperty("replies")]
53 | public List Replies { get; set; }
54 |
55 | ///
56 | /// Versions
57 | ///
58 | [JsonProperty("version-history")]
59 | public List Versions { get; set; }
60 |
61 | ///
62 | /// Attachment
63 | ///
64 | [JsonProperty("wp:attachment")]
65 | public List Attachment { get; set; }
66 |
67 | ///
68 | /// Featured media
69 | ///
70 | [JsonProperty("wp:featuredmedia")]
71 | public List FeaturedMedia { get; set; }
72 |
73 | ///
74 | /// Featured media
75 | ///
76 | [JsonProperty("wp:term")]
77 | public List Term { get; set; }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/Exception_Unexpected_Tests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading.Tasks;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 | using WordPressPCL.Models;
6 | using WordPressPCL.Models.Exceptions;
7 |
8 | namespace WordPressPCL.Tests.Selfhosted;
9 |
10 | [TestClass]
11 | public class Exception_Unexpected_Tests
12 | {
13 | private WordPressClient _badConnectionClient;
14 |
15 | [TestInitialize]
16 | public void Initialize()
17 | {
18 | _badConnectionClient = new WordPressClient("https://microsoft.com");
19 | }
20 |
21 | [TestMethod]
22 | public async Task Tags_Get_UnexpectedException()
23 | {
24 | await CheckForUnexpectedException(async () => await _badConnectionClient.Tags.GetAsync());
25 | }
26 |
27 | [TestMethod]
28 | public async Task Tags_Post_UnexpectedException()
29 | {
30 | await CheckForUnexpectedException(async () => await _badConnectionClient.Tags.UpdateAsync(new Tag()));
31 | }
32 |
33 | [TestMethod]
34 | public async Task Tags_Delete_UnexpectedException()
35 | {
36 | await CheckForUnexpectedException(async () => await _badConnectionClient.Tags.DeleteAsync(1), HttpStatusCode.NotImplemented);
37 | }
38 |
39 | private async Task CheckForUnexpectedException(Func task, HttpStatusCode expectedStatus = HttpStatusCode.NotFound)
40 | {
41 | bool exceptionCaught = false;
42 |
43 | try
44 | {
45 | await task();
46 | }
47 | catch (Exception ex)
48 | {
49 | exceptionCaught = true;
50 |
51 | if (!(ex is WPUnexpectedException typedException))
52 | {
53 | Assert.Fail($"Expected an exception of type WPUnexpectedException, but saw exception of type {ex.GetType()}");
54 | }
55 | else
56 | {
57 | Assert.AreEqual($"Server returned HTTP status {expectedStatus}", typedException.Message);
58 | Assert.IsNotNull(typedException.Response, "No HTTP response has been returned");
59 | Assert.AreEqual(expectedStatus, typedException.Response.StatusCode);
60 | Assert.IsFalse(string.IsNullOrEmpty(typedException.ResponseBody), "Expected a response body but didn't see one");
61 | }
62 | }
63 |
64 | Assert.IsTrue(exceptionCaught, "Exception was expected but none was seen");
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/WordPressPCL/Models/PostStatus.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace WordPressPCL.Models
4 | {
5 | ///
6 | /// Type represents Post Status Entity of WP REST API
7 | ///
8 | public class PostStatus
9 | {
10 | ///
11 | /// The title for the taxonomy.
12 | ///
13 | /// Context: view, edit, embed
14 | [JsonProperty("name")]
15 | public string Name { get; set; }
16 |
17 | ///
18 | /// Whether posts with this resource should be private.
19 | ///
20 | /// Context: edit
21 | [JsonProperty("private")]
22 | public bool Private { get; set; }
23 |
24 | ///
25 | /// Whether posts with this resource should be protected.
26 | ///
27 | /// Context: edit
28 | [JsonProperty("protected")]
29 | public bool Protected { get; set; }
30 |
31 | ///
32 | /// Whether posts with this resource should be public.
33 | ///
34 | /// Context: edit
35 | [JsonProperty("public")]
36 | public bool Public { get; set; }
37 |
38 | ///
39 | /// Whether posts with this resource should be publicly-queryable.
40 | ///
41 | /// Context: edit
42 | [JsonProperty("queryable")]
43 | public bool Queryable { get; set; }
44 |
45 | ///
46 | /// Whether to include posts in the edit listing for their post type.
47 | ///
48 | /// Context: edit
49 | [JsonProperty("show_in_list")]
50 | public bool ShowInList { get; set; }
51 |
52 | ///
53 | /// An alphanumeric identifier for the taxonomy.
54 | ///
55 | /// Context: view, edit, embed
56 | [JsonProperty("slug")]
57 | public string Slug { get; set; }
58 |
59 | ///
60 | /// Links to related resources
61 | ///
62 | [JsonProperty("_links", DefaultValueHandling = DefaultValueHandling.Ignore)]
63 | public Links Links { get; set; }
64 |
65 | ///
66 | /// Default constructor
67 | ///
68 | public PostStatus()
69 | {
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/docs/I version 2.x/entities/users.md:
--------------------------------------------------------------------------------
1 | # Users
2 |
3 | Here is a list of methods and examples of working with Users
4 |
5 | ## Get All
6 |
7 | ```C#
8 | // execute request users without credentials - returns only you
9 | var users = await client.Users.GetAllAsync();
10 |
11 | // send credentials - list of all users
12 | var users = await client.Users.GetAllAsync(useAuth:true);
13 | ```
14 |
15 | ## Get By ID
16 |
17 | ```C#
18 | // returns user by ID
19 | var user = await client.Users.GetByIDAsync(123);
20 | ```
21 |
22 | ## Get Current User
23 |
24 | ```C#
25 | // returns current user
26 | var user = await client.Users.GetCurrentUserAsync();
27 | ```
28 |
29 | ## Query
30 | Create parametrized request
31 | ```C#
32 | // returns result of query
33 | var queryBuilder = new UsersQueryBuilder();
34 | queryBuilder.PerPage = 40;
35 | queryBuilder.Page = 2;
36 | queryBuilder.Before = DateTime.Now;
37 | var users = await client.Users.QueryAsync(queryBuilder);
38 | ```
39 |
40 | ## Query with Roles
41 | To retreive users with roles, you'll need to set the `Context` property of the `UsersQueryBuilder` to `Context.Edit`.
42 | ```C#
43 | UsersQueryBuilder queryBuilder = new()
44 | {
45 | // required for roles to be loaded
46 | Context = Context.Edit
47 | };
48 |
49 | List users = await _clientAuth.Users.QueryAsync(queryBuilder, true);
50 | ```
51 |
52 | ## Create new User
53 |
54 | ```C#
55 | // returns created user
56 | var user = new User("username","email","password")
57 | {
58 | NickName= "nickname"
59 | };
60 | if (await client.IsValidJWTokenAsync())
61 | {
62 | var user = await client.Users.CreateAsync(user);
63 | }
64 | ```
65 |
66 | ## Update User
67 |
68 | ```C#
69 | // returns updated user
70 | var user = client.Users.GetByIDAsync(123);
71 | user.Name = "New Name";
72 | if (await client.IsValidJWTokenAsync())
73 | {
74 | var updatedUser = await client.Users.UpdateAsync(user);
75 | }
76 | ```
77 |
78 | ## Delete User
79 |
80 | ```C#
81 | // returns result of deletion
82 | if (await client.IsValidJWTokenAsync())
83 | {
84 | //second param - user to reassign all content
85 | var result = await client.Users.DeleteAsync(123,321);
86 | }
87 | ```
88 |
89 | ## Create Application Password
90 |
91 | ```C#
92 | // Create an application password for the current user
93 | var password = await client.Users.CreateApplicationPasswordAsync("application-name");
94 |
95 | // Create an application password for a specific user
96 | var password = await client.Users.CreateApplicationPasswordAsync("application-name", userId: "3");
97 | ```
98 |
--------------------------------------------------------------------------------
/WordPressPCL/Utility/TagsQueryBuilder.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using WordPressPCL.Models;
3 |
4 | namespace WordPressPCL.Utility
5 | {
6 | ///
7 | /// Tag Query Builder class to construct queries with valid parameters
8 | ///
9 | public class TagsQueryBuilder : QueryBuilder
10 | {
11 | ///
12 | /// Current page of the collection.
13 | ///
14 | /// Default: 1
15 | [QueryText("page")]
16 | public int Page { get; set; }
17 |
18 | ///
19 | /// Maximum number of items to be returned in result set (1-100).
20 | ///
21 | /// Default: 10
22 | [QueryText("per_page")]
23 | public int PerPage { get; set; }
24 |
25 | ///
26 | /// Limit results to those matching a string.
27 | ///
28 | [QueryText("search")]
29 | public string Search { get; set; }
30 |
31 | ///
32 | /// Ensure result set excludes specific IDs.
33 | ///
34 | [QueryText("exclude")]
35 | public List Exclude { get; set; }
36 |
37 | ///
38 | /// Limit result set to specific IDs.
39 | ///
40 | [QueryText("include")]
41 | public List Include { get; set; }
42 |
43 | ///
44 | /// Offset the result set by a specific number of items.
45 | ///
46 | [QueryText("offset")]
47 | public int Offset { get; set; }
48 |
49 | ///
50 | /// Sort collection by object attribute.
51 | ///
52 | /// Default: name
53 | /// One of: id, include, name, slug, term_group, description, count
54 | [QueryText("orderby")]
55 | public TermsOrderBy OrderBy { get; set; }
56 |
57 | ///
58 | /// Limit result set to users with a specific slug.
59 | ///
60 | [QueryText("slug")]
61 | public List Slugs { get; set; }
62 |
63 | ///
64 | /// Whether to hide terms not assigned to any posts.
65 | ///
66 | [QueryText("hide_empty")]
67 | public bool HideEmpty { get; set; }
68 |
69 | ///
70 | /// Limit result set to terms assigned to a specific post.
71 | ///
72 | [QueryText("post")]
73 | public int Post { get; set; }
74 | }
75 | }
--------------------------------------------------------------------------------
/WordPressPCL/Utility/UsersQueryBuilder.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using WordPressPCL.Models;
3 |
4 | namespace WordPressPCL.Utility
5 | {
6 | ///
7 | /// Users Query Builder class to construct queries with valid parameters
8 | ///
9 | public class UsersQueryBuilder : QueryBuilder
10 | {
11 | ///
12 | /// Current page of the collection.
13 | ///
14 | /// Default: 1
15 | [QueryText("page")]
16 | public int Page { get; set; }
17 |
18 | ///
19 | /// Maximum number of items to be returned in result set (1-100).
20 | ///
21 | /// Default: 10
22 | [QueryText("per_page")]
23 | public int PerPage { get; set; }
24 |
25 | ///
26 | /// Limit results to those matching a string.
27 | ///
28 | [QueryText("search")]
29 | public string Search { get; set; }
30 |
31 | ///
32 | /// Ensure result set excludes specific IDs.
33 | ///
34 | [QueryText("exclude")]
35 | public List Exclude { get; set; }
36 |
37 | ///
38 | /// Limit result set to specific IDs.
39 | ///
40 | [QueryText("include")]
41 | public List Include { get; set; }
42 |
43 | ///
44 | /// Offset the result set by a specific number of items.
45 | ///
46 | [QueryText("offset")]
47 | public int Offset { get; set; }
48 |
49 | ///
50 | /// Sort collection by object attribute.
51 | ///
52 | /// Default: name
53 | /// One of: id, include, name, registered_date, slug, email, url
54 | [QueryText("orderby")]
55 | public UsersOrderBy OrderBy { get; set; }
56 |
57 | ///
58 | /// Limit result set to users with a specific slug.
59 | ///
60 | [QueryText("slug")]
61 | public List Slugs { get; set; }
62 |
63 | //
64 | // Summary:
65 | // Limit result set to posts assigned one or more statuses.
66 | //
67 | // Remarks:
68 | // Default: publish
69 | [QueryText("status")]
70 | public List Statuses { get; set; }
71 |
72 | ///
73 | /// Limit result set to users matching at least one specific role provided. Accepts csv list or single role.
74 | ///
75 | [QueryText("roles")]
76 | public List Roles { get; set; }
77 | }
78 | }
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/WordPressPCL/Utility/CategoriesQueryBuilder.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using WordPressPCL.Models;
3 |
4 | namespace WordPressPCL.Utility
5 | {
6 | ///
7 | /// Category Query Builder class to construct queries with valid parameters
8 | ///
9 | public class CategoriesQueryBuilder : QueryBuilder
10 | {
11 | ///
12 | /// Current page of the collection.
13 | ///
14 | /// Default: 1
15 | [QueryText("page")]
16 | public int Page { get; set; }
17 |
18 | ///
19 | /// Maximum number of items to be returned in result set (1-100).
20 | ///
21 | /// Default: 10
22 | [QueryText("per_page")]
23 | public int PerPage { get; set; }
24 |
25 | ///
26 | /// Limit results to those matching a string.
27 | ///
28 | [QueryText("search")]
29 | public string Search { get; set; }
30 |
31 | ///
32 | /// Ensure result set excludes specific IDs.
33 | ///
34 | [QueryText("exclude")]
35 | public List Exclude { get; set; }
36 |
37 | ///
38 | /// Limit result set to specific IDs.
39 | ///
40 | [QueryText("include")]
41 | public List Include { get; set; }
42 |
43 | ///
44 | /// Offset the result set by a specific number of items.
45 | ///
46 | [QueryText("offset")]
47 | public int Offset { get; set; }
48 |
49 | ///
50 | /// Sort collection by object attribute.
51 | ///
52 | /// Default: name
53 | /// One of: id, include, name, slug, term_group, description, count
54 | [QueryText("orderby")]
55 | public TermsOrderBy OrderBy { get; set; }
56 |
57 | ///
58 | /// Limit result set to users with a specific slug.
59 | ///
60 | [QueryText("slug")]
61 | public List Slugs { get; set; }
62 |
63 | ///
64 | /// Whether to hide terms not assigned to any posts.
65 | ///
66 | [QueryText("hide_empty")]
67 | public bool HideEmpty { get; set; }
68 |
69 | ///
70 | /// Limit result set to terms assigned to a specific post.
71 | ///
72 | [QueryText("post")]
73 | public int Post { get; set; }
74 |
75 | ///
76 | /// Limit result set to terms assigned to a specific parent.
77 | ///
78 | [QueryText("parent")]
79 | public int Parent { get; set; }
80 | }
81 | }
--------------------------------------------------------------------------------
/WordPressPCL/Client/Pages.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Globalization;
3 | using System.Threading.Tasks;
4 | using WordPressPCL.Models;
5 | using WordPressPCL.Utility;
6 |
7 | namespace WordPressPCL.Client
8 | {
9 | ///
10 | /// Client class for interaction with Pages endpoint WP REST API
11 | ///
12 | public class Pages : CRUDOperation
13 | {
14 | #region Init
15 |
16 | private const string _methodPath = "pages";
17 |
18 | ///
19 | /// Constructor
20 | ///
21 | /// reference to HttpHelper class for interaction with HTTP
22 | public Pages(HttpHelper HttpHelper) : base(HttpHelper, _methodPath)
23 | {
24 | }
25 |
26 | #endregion Init
27 |
28 | #region Custom
29 |
30 | ///
31 | /// Get pages by its author
32 | ///
33 | /// Author id
34 | /// include embed info
35 | /// Send request with authentication header
36 | /// List of pages
37 | public Task> GetPagesByAuthorAsync(int authorId, bool embed = false, bool useAuth = false)
38 | {
39 | // default values
40 | // int page = 1, int per_page = 10, int offset = 0, Post.OrderBy orderby = Post.OrderBy.date
41 | return HttpHelper.GetRequestAsync>($"{_methodPath}?author={authorId}", embed, useAuth);
42 | }
43 |
44 | ///
45 | /// Get pages by search term
46 | ///
47 | /// Search term
48 | /// include embed info
49 | /// Send request with authentication header
50 | /// List of pages
51 | public Task> GetPagesBySearchAsync(string searchTerm, bool embed = false, bool useAuth = false)
52 | {
53 | // default values
54 | // int page = 1, int per_page = 10, int offset = 0, Post.OrderBy orderby = Post.OrderBy.date
55 | return HttpHelper.GetRequestAsync>($"{_methodPath}?search={searchTerm}", embed, useAuth);
56 | }
57 |
58 | ///
59 | /// Delete page with force deletion
60 | ///
61 | /// Page id
62 | /// force deletion
63 | /// Result of operation
64 | public Task Delete(int ID, bool force = false)
65 | {
66 | return HttpHelper.DeleteRequestAsync($"{_methodPath}/{ID}?force={force.ToString().ToLower(CultureInfo.InvariantCulture)}");
67 | }
68 |
69 | #endregion Custom
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/WordPressPCL/Client/PostRevisions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 | using WordPressPCL.Interfaces;
4 | using WordPressPCL.Models;
5 | using WordPressPCL.Utility;
6 |
7 | namespace WordPressPCL.Client
8 | {
9 | ///
10 | /// Client class for interaction with Post revisions endpoint WP REST API
11 | ///
12 | public class PostRevisions : IReadOperation, IDeleteOperation
13 | {
14 | private readonly HttpHelper _httpHelper;
15 | private const string _methodPath = "revisions";
16 | private readonly int _postId;
17 |
18 | ///
19 | /// Constructor
20 | ///
21 | /// reference to HttpHelper class for interaction with HTTP
22 | /// ID of post
23 | public PostRevisions(ref HttpHelper httpHelper, int postId)
24 | {
25 | _httpHelper = httpHelper;
26 | _postId = postId;
27 | }
28 | ///
29 | /// Delete Entity
30 | ///
31 | /// Entity Id
32 | /// Result of operation
33 | public Task DeleteAsync(int ID)
34 | {
35 | return _httpHelper.DeleteRequestAsync($"posts/{_postId}/{_methodPath}/{ID}?force=true");
36 | }
37 |
38 | ///
39 | /// Get latest
40 | ///
41 | /// include embed info
42 | /// Send request with authentication header
43 | /// Latest PostRevisions
44 | public Task> GetAsync(bool embed = false, bool useAuth = true)
45 | {
46 | return _httpHelper.GetRequestAsync>($"posts/{_postId}/{_methodPath}", embed, useAuth);
47 | }
48 |
49 | ///
50 | /// Get All
51 | ///
52 | /// Include embed info
53 | /// Send request with authentication header
54 | /// List of all result
55 | public Task> GetAllAsync(bool embed = false, bool useAuth = true)
56 | {
57 | return _httpHelper.GetRequestAsync>($"posts/{_postId}/{_methodPath}", embed, useAuth);
58 | }
59 |
60 | ///
61 | /// Get Entity by Id
62 | ///
63 | /// ID
64 | /// include embed info
65 | /// Send request with authentication header
66 | /// Entity by Id
67 | public Task GetByIDAsync(object ID, bool embed = false, bool useAuth = true)
68 | {
69 | return _httpHelper.GetRequestAsync($"posts/{_postId}/{_methodPath}/{ID}", embed, useAuth);
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/WordPressPCL/Models/PostType.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json;
3 |
4 | namespace WordPressPCL.Models
5 | {
6 | ///
7 | /// Type represents Post Type Entity of WP REST API
8 | ///
9 | public class PostType
10 | {
11 | ///
12 | /// All capabilities used by the taxonomy.
13 | ///
14 | /// Context: edit
15 | [JsonProperty("capabilities", DefaultValueHandling = DefaultValueHandling.Ignore)]
16 | public IDictionary Capabilities { get; set; }
17 |
18 | ///
19 | /// A human-readable description of the taxonomy.
20 | ///
21 | /// Context: view, edit
22 | [JsonProperty("description")]
23 | public string Description { get; set; }
24 |
25 | ///
26 | /// Whether or not the taxonomy should have children.
27 | ///
28 | /// Context: view, edit
29 | [JsonProperty("hierarchical")]
30 | public bool Hierarchical { get; set; }
31 |
32 | ///
33 | /// Human-readable labels for the taxonomy for various contexts.
34 | ///
35 | /// Context: edit
36 | [JsonProperty("labels")]
37 | public List Labels { get; set; }
38 |
39 | ///
40 | /// The title for the taxonomy.
41 | ///
42 | /// Context: view, edit, embed
43 | [JsonProperty("name")]
44 | public string Name { get; set; }
45 |
46 | ///
47 | /// An alphanumeric identifier for the taxonomy.
48 | ///
49 | /// Context: view, edit, embed
50 | [JsonProperty("slug")]
51 | public string Slug { get; set; }
52 |
53 | ///
54 | /// Whether or not the term cloud should be displayed.
55 | ///
56 | /// Context: edit
57 | [JsonProperty("show_cloud")]
58 | public bool ShowCloud { get; set; }
59 |
60 | ///
61 | /// List of taxonomies
62 | ///
63 | /// Context: edit
64 | [JsonProperty("taxonomies")]
65 | public List Taxonomies { get; set; }
66 |
67 | ///
68 | /// REST base route for the taxonomy.
69 | ///
70 | /// Context: view, edit, embed
71 | [JsonProperty("rest_base")]
72 | public string RestBase { get; set; }
73 |
74 | ///
75 | /// Links to related resources
76 | ///
77 | [JsonProperty("_links", DefaultValueHandling = DefaultValueHandling.Ignore)]
78 | public Links Links { get; set; }
79 |
80 | ///
81 | /// Default constructor
82 | ///
83 | public PostType()
84 | {
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/WordPressPCL/Models/Taxonomy.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json;
3 |
4 | namespace WordPressPCL.Models
5 | {
6 | ///
7 | /// Type represents Taxonomy Entity of WP REST API
8 | ///
9 | public class Taxonomy
10 | {
11 | ///
12 | /// All capabilities used by the taxonomy.
13 | ///
14 | /// Context: edit
15 | [JsonProperty("capabilities", DefaultValueHandling = DefaultValueHandling.Ignore)]
16 | public IDictionary Capabilities { get; set; }
17 |
18 | ///
19 | /// A human-readable description of the taxonomy.
20 | ///
21 | /// Context: view, edit
22 | [JsonProperty("description")]
23 | public string Description { get; set; }
24 |
25 | ///
26 | /// Whether or not the taxonomy should have children.
27 | ///
28 | /// Context: view, edit
29 | [JsonProperty("hierarchical")]
30 | public bool Hierarchical { get; set; }
31 |
32 | ///
33 | /// Human-readable labels for the taxonomy for various contexts.
34 | ///
35 | /// Context: edit
36 | [JsonProperty("labels")]
37 | public List Labels { get; set; }
38 |
39 | ///
40 | /// The title for the taxonomy.
41 | ///
42 | /// Context: view, edit, embed
43 | [JsonProperty("name")]
44 | public string Name { get; set; }
45 |
46 | ///
47 | /// An alphanumeric identifier for the taxonomy.
48 | ///
49 | /// Context: view, edit, embed
50 | [JsonProperty("slug")]
51 | public string Slug { get; set; }
52 |
53 | ///
54 | /// Whether or not the term cloud should be displayed.
55 | ///
56 | /// Context: edit
57 | [JsonProperty("show_cloud")]
58 | public bool ShowCloud { get; set; }
59 |
60 | ///
61 | /// Types associated with the taxonomy.
62 | ///
63 | /// Context: view, edit
64 | [JsonProperty("types")]
65 | public List Types { get; set; }
66 |
67 | ///
68 | /// REST base route for the taxonomy.
69 | ///
70 | /// Context: view, edit, embed
71 | [JsonProperty("rest_base")]
72 | public string RestBase { get; set; }
73 |
74 | ///
75 | /// Links to related resources
76 | ///
77 | [JsonProperty("_links", DefaultValueHandling = DefaultValueHandling.Ignore)]
78 | public Links Links { get; set; }
79 |
80 | ///
81 | /// Default constructor
82 | ///
83 | public Taxonomy()
84 | {
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/Plugins_Tests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using WordPressPCL.Models;
6 | using WordPressPCL.Tests.Selfhosted.Utility;
7 | using WordPressPCL.Utility;
8 |
9 | namespace WordPressPCL.Tests.Selfhosted;
10 |
11 | [TestClass]
12 | public class Plugins_Tests
13 | {
14 | private static WordPressClient _clientAuth;
15 | private static string PluginId= "wordpress-seo";
16 |
17 | [ClassInitialize]
18 | public static async Task Init(TestContext testContext)
19 | {
20 | _clientAuth = await ClientHelper.GetAuthenticatedWordPressClient(testContext);
21 | }
22 |
23 | [TestMethod]
24 | public async Task Plugins_Install_Activate_Deactivate_Delete()
25 | {
26 | Plugin plugin = await _clientAuth.Plugins.InstallAsync(PluginId);
27 | Assert.IsNotNull(plugin);
28 | Assert.AreEqual(PluginId, plugin.Id);
29 |
30 |
31 | //Activate plugin
32 | Plugin activePlugin = await _clientAuth.Plugins.ActivateAsync(plugin);
33 | Assert.AreEqual(activePlugin.Status, ActivationStatus.Active);
34 | Assert.AreEqual(activePlugin.Id, plugin.Id);
35 |
36 |
37 | //Deactivate plugin
38 | Plugin deactivatedPlugin = await _clientAuth.Plugins.DeactivateAsync(plugin);
39 | Assert.AreEqual(deactivatedPlugin.Status, ActivationStatus.Inactive);
40 | Assert.AreEqual(deactivatedPlugin.Id, plugin.Id);
41 |
42 | //Delete plugin
43 | bool response = await _clientAuth.Plugins.DeleteAsync(plugin);
44 | Assert.IsTrue(response);
45 | List plugins = await _clientAuth.Plugins.GetAllAsync(useAuth: true);
46 | List c = plugins.Where(x => x.Id == plugin.Id).ToList();
47 | Assert.AreEqual(c.Count, 0);
48 | }
49 |
50 | [TestMethod]
51 | public async Task Plugins_GetActive()
52 | {
53 | //Active plugin
54 | List plugins = await _clientAuth.Plugins.QueryAsync(new PluginsQueryBuilder { Status = ActivationStatus.Active }, useAuth:true);
55 | Assert.IsNotNull(plugins);
56 | Assert.AreNotEqual(plugins.Count, 0);
57 |
58 | }
59 | [TestMethod]
60 | public async Task Plugins_Search ()
61 | {
62 | //Active plugin
63 | List plugins = await _clientAuth.Plugins.QueryAsync(new PluginsQueryBuilder { Search="jwt" }, useAuth:true);
64 | Assert.IsNotNull(plugins);
65 | Assert.AreNotEqual(plugins.Count, 0);
66 |
67 | }
68 |
69 | [TestMethod]
70 | public async Task Plugins_Get()
71 | {
72 | List plugins = await _clientAuth.Plugins.GetAsync (useAuth: true);
73 | Assert.IsNotNull(plugins);
74 | Assert.AreNotEqual(plugins.Count, 0);
75 | CollectionAssert.AllItemsAreUnique(plugins.Select(tag => tag.Id).ToList());
76 | }
77 |
78 | [TestMethod]
79 | public async Task Plugins_GetByID()
80 | {
81 | Plugin plugin = await _clientAuth.Plugins.GetByIDAsync("jwt-auth/jwt-auth", useAuth: true);
82 | Assert.IsNotNull(plugin);
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/WordPressPCL/Client/PostTypes.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 | using WordPressPCL.Interfaces;
4 | using WordPressPCL.Models;
5 | using WordPressPCL.Utility;
6 |
7 | namespace WordPressPCL.Client
8 | {
9 | ///
10 | /// Client class for interaction with Post Types endpoint WP REST API
11 | ///
12 | public class PostTypes : IReadOperation
13 | {
14 | private HttpHelper _httpHelper;
15 | private const string _methodPath = "types";
16 |
17 | ///
18 | /// Constructor
19 | ///
20 | /// reference to HttpHelper class for interaction with HTTP
21 | public PostTypes(HttpHelper httpHelper)
22 | {
23 | _httpHelper = httpHelper;
24 | }
25 |
26 | ///
27 | /// Get latest
28 | ///
29 | /// Include embed info
30 | /// Send request with authentication header
31 | /// List of latest PostTypes
32 | public async Task> GetAsync(bool embed = false, bool useAuth = false)
33 | {
34 | List entities = new();
35 | Dictionary entities_page = (await _httpHelper.GetRequestAsync>($"{_methodPath}", embed, useAuth).ConfigureAwait(false));
36 | foreach (KeyValuePair ent in entities_page)
37 | {
38 | entities.Add(ent.Value);
39 | }
40 | return entities;
41 | }
42 |
43 | ///
44 | /// Get All
45 | ///
46 | /// Include embed info
47 | /// Send request with authentication header
48 | /// List of all PostTypes
49 | public async Task> GetAllAsync(bool embed = false, bool useAuth = false)
50 | {
51 | //100 - Max posts per page in WordPress REST API, so this is hack with multiple requests
52 | List entities = new();
53 | Dictionary entities_page = (await _httpHelper.GetRequestAsync>($"{_methodPath}", embed, useAuth).ConfigureAwait(false));
54 | foreach (KeyValuePair ent in entities_page)
55 | {
56 | entities.Add(ent.Value);
57 | }
58 | return entities;
59 | }
60 |
61 | ///
62 | /// Get Entity by Id
63 | ///
64 | /// ID
65 | /// include embed info
66 | /// Send request with authentication header
67 | /// Entity by Id
68 | public Task GetByIDAsync(object ID, bool embed = false, bool useAuth = false)
69 | {
70 | return _httpHelper.GetRequestAsync($"{_methodPath}/{ID}", embed, useAuth);
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/WordPressPCL/Client/PostStatuses.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 | using WordPressPCL.Interfaces;
4 | using WordPressPCL.Models;
5 | using WordPressPCL.Utility;
6 |
7 | namespace WordPressPCL.Client
8 | {
9 | ///
10 | /// Client class for interaction with Post Types endpoint WP REST API
11 | ///
12 | public class PostStatuses : IReadOperation
13 | {
14 | private readonly HttpHelper _httpHelper;
15 | private const string _methodPath = "statuses";
16 |
17 | ///
18 | /// Constructor
19 | ///
20 | /// reference to HttpHelper class for interaction with HTTP
21 | public PostStatuses(HttpHelper httpHelper)
22 | {
23 | _httpHelper = httpHelper;
24 | }
25 |
26 | ///
27 | /// Get latest Post Statuses
28 | ///
29 | /// include embed info
30 | /// Send request with authentication header
31 | /// Entity by Id
32 | public async Task> GetAsync(bool embed = false, bool useAuth = false)
33 | {
34 | List entities = new();
35 | Dictionary entities_page = await _httpHelper.GetRequestAsync>($"{_methodPath}", embed, useAuth).ConfigureAwait(false);
36 | foreach (KeyValuePair ent in entities_page)
37 | {
38 | entities.Add(ent.Value);
39 | }
40 | return entities;
41 | }
42 |
43 | ///
44 | /// Get All
45 | ///
46 | /// Include embed info
47 | /// Send request with authentication header
48 | /// List of all result
49 | public async Task> GetAllAsync(bool embed = false, bool useAuth = false)
50 | {
51 | //100 - Max posts per page in WordPress REST API, so this is hack with multiple requests
52 | List entities = new();
53 | Dictionary entities_page = await _httpHelper.GetRequestAsync>($"{_methodPath}", embed, useAuth).ConfigureAwait(false);
54 | foreach (KeyValuePair ent in entities_page)
55 | {
56 | entities.Add(ent.Value);
57 | }
58 | return entities;
59 | }
60 |
61 | ///
62 | /// Get Entity by Id
63 | ///
64 | /// ID
65 | /// include embed info
66 | /// Send request with authentication header
67 | /// Entity by Id
68 | public Task GetByIDAsync(object ID, bool embed = false, bool useAuth = false)
69 | {
70 | return _httpHelper.GetRequestAsync($"{_methodPath}/{ID}", embed, useAuth);
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/WordPressPCL/Models/Theme.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace WordPressPCL.Models
5 | {
6 | ///
7 | /// WordPress Themes
8 | /// Date: 8 June 2023
9 | /// Creator: Gregory Liénard
10 | ///
11 | public class Theme
12 | {
13 | ///
14 | /// The theme's stylesheet. This uniquely identifies the theme.
15 | ///
16 | [JsonProperty("stylesheet")]
17 | public string Stylesheet { get; set; }
18 |
19 | ///
20 | /// The theme's template. If this is a child theme, this refers to the parent theme.
21 | ///
22 | [JsonProperty("template")]
23 | public string Template { get; set; }
24 |
25 | ///
26 | /// The theme author.
27 | ///
28 | [JsonProperty("author")]
29 | public Rendered Author { get; set; }
30 |
31 | ///
32 | /// The website of the theme author.
33 | ///
34 | [JsonProperty("author_uri")]
35 | public Rendered AuthorUri { get; set; }
36 |
37 | ///
38 | /// A description of the theme.
39 | ///
40 | [JsonProperty("description")]
41 | public Description Description { get; set; }
42 |
43 | ///
44 | /// The name of the theme.
45 | ///
46 | [JsonProperty("name")]
47 | public Rendered Name { get; set; }
48 |
49 | ///
50 | /// The minimum PHP version required for the theme to work.
51 | ///
52 | [JsonProperty("requires_php")]
53 | public string RequiresPhp { get; set; }
54 |
55 | ///
56 | /// The minimum WordPress version required for the theme to work.
57 | ///
58 | [JsonProperty("requires_wp")]
59 | public string RequiresWp { get; set; }
60 |
61 | ///
62 | /// The theme's screenshot URL.
63 | ///
64 | [JsonProperty("screenshot")]
65 | public Uri Screenshot { get; set; }
66 |
67 | ///
68 | /// Tags indicating styles and features of the theme.
69 | ///
70 | [JsonProperty("tags")]
71 | public Tags Tags { get; set; }
72 |
73 | ///
74 | /// The theme's text domain.
75 | ///
76 | [JsonProperty("textdomain")]
77 | public string Textdomain { get; set; }
78 |
79 |
80 | ///
81 | /// The URI of the theme's webpage.
82 | ///
83 | [JsonProperty("theme_uri")]
84 | public Rendered ThemeUri { get; set; }
85 |
86 | ///
87 | /// The theme's current version.
88 | ///
89 | [JsonProperty("version")]
90 | public Version Version { get; set; }
91 |
92 | ///
93 | /// A named status for the theme.
94 | ///
95 | [JsonProperty("status")]
96 | public ActivationStatus Status { get; set; }
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/ExceptionTests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System.Threading.Tasks;
3 | using WordPressPCL.Models;
4 | using WordPressPCL.Models.Exceptions;
5 | using WordPressPCL.Tests.Selfhosted.Utility;
6 |
7 | namespace WordPressPCL.Tests.Selfhosted;
8 |
9 | [TestClass]
10 | public class ExceptionTests
11 | {
12 | private static WordPressClient _client;
13 | private static WordPressClient _clientAuth;
14 |
15 | [ClassInitialize]
16 | public static async Task Init(TestContext testContext)
17 | {
18 | _client = ClientHelper.GetWordPressClient();
19 | _clientAuth = await ClientHelper.GetAuthenticatedWordPressClient(testContext);
20 | }
21 |
22 | [TestMethod]
23 | public async Task Exception_JWTAuthExceptionTest()
24 | {
25 | // Initialize
26 | Assert.IsNotNull(_client);
27 | // Get settings without auth
28 |
29 | await Assert.ThrowsExceptionAsync(async () =>
30 | {
31 | Settings settings = await _client.Settings.GetSettingsAsync();
32 | });
33 | }
34 |
35 | [TestMethod]
36 | public async Task Exception_RequestJWTokenForBasicAuth()
37 | {
38 | //Initialize
39 | Assert.IsNotNull(_client);
40 | const string dummyUser = "dummy";
41 | const string dummyPassword = "dummy";
42 |
43 | _client.Auth.UseBasicAuth(dummyUser, dummyPassword);
44 |
45 | await Assert.ThrowsExceptionAsync(async () =>
46 | {
47 | await _client.Auth.RequestJWTokenAsync(dummyUser, dummyPassword);
48 | });
49 | }
50 |
51 | [TestMethod]
52 | public async Task Exception_IsValidJWTokenForBasicAuth()
53 | {
54 | //Initialize
55 | Assert.IsNotNull(_client);
56 | const string dummyUser = "dummy";
57 | const string dummyPassword = "dummy";
58 |
59 | _client.Auth.UseBasicAuth(dummyUser, dummyPassword);
60 |
61 | await Assert.ThrowsExceptionAsync(async () => {
62 | await _client.Auth.IsValidJWTokenAsync();
63 | });
64 | }
65 |
66 | [TestMethod]
67 | public async Task Exception_PostCreateExceptionTest()
68 | {
69 | // Initialize
70 | Assert.IsNotNull(_clientAuth);
71 | // Create empty post
72 | try
73 | {
74 | Post post = await _clientAuth.Posts.CreateAsync(new Post());
75 | }
76 | catch (WPException wpex)
77 | {
78 | Assert.IsNotNull(wpex.RequestData);
79 | Assert.AreEqual(wpex.RequestData.Name, "empty_content");
80 | }
81 | }
82 |
83 | [TestMethod]
84 | public async Task Exception_DeleteExceptionTest()
85 | {
86 | // Initialize
87 | Assert.IsNotNull(_clientAuth);
88 | // Delete nonexisted post
89 | try
90 | {
91 | bool result = await _clientAuth.Posts.DeleteAsync(int.MaxValue);
92 | }
93 | catch (WPException wpex)
94 | {
95 | Assert.IsNotNull(wpex.RequestData);
96 | Assert.AreEqual(wpex.RequestData.Name, "rest_post_invalid_id");
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/Utility/HttpHelper_Tests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 | using WordPressPCL.Models;
7 |
8 | namespace WordPressPCL.Tests.Selfhosted.Utility;
9 |
10 | [TestClass]
11 | public class HttpHelper_Tests
12 | {
13 | private static WordPressClient _clientAuth;
14 |
15 | [ClassInitialize]
16 | public static async Task Init(TestContext testContext)
17 | {
18 | _clientAuth = await ClientHelper.GetAuthenticatedWordPressClient(testContext);
19 | }
20 |
21 |
22 | [TestMethod]
23 | public async Task HttpHelper_InvalidPreProcessing()
24 | {
25 | // Create a random tag , must works:
26 | string tagname = $"Test {System.Guid.NewGuid()}";
27 | Tag tag = await _clientAuth.Tags.CreateAsync(new Tag()
28 | {
29 | Name = tagname,
30 | Description = "Test Description"
31 | });
32 | Assert.IsTrue(tag.Id > 0);
33 | Assert.IsNotNull(tag);
34 | Assert.AreEqual(tagname, tag.Name);
35 | Assert.AreEqual("Test Description", tag.Description);
36 |
37 | // We call Get tag list without pre processing
38 | List tags = await _clientAuth.Tags.GetAllAsync();
39 | Assert.IsNotNull(tags);
40 | Assert.AreNotEqual(tags.Count, 0);
41 | CollectionAssert.AllItemsAreUnique(tags.Select(e => e.Id).ToList());
42 |
43 | // Now we add a PreProcessing task
44 | _clientAuth.HttpResponsePreProcessing = (response) =>
45 | {
46 | throw new InvalidOperationException("PreProcessing must fail");
47 | };
48 | await Assert.ThrowsExceptionAsync(async () =>
49 | {
50 | await _clientAuth.Tags.GetAllAsync();
51 | });
52 | _clientAuth.HttpResponsePreProcessing = null;
53 | }
54 |
55 | [TestMethod]
56 | public async Task HttpHelper_ValidPreProcessing()
57 | {
58 | _clientAuth.HttpResponsePreProcessing = null;
59 |
60 | // Create a random tag
61 | Random random = new();
62 | string tagname = $"Test {System.Guid.NewGuid()}";
63 | Tag tag = await _clientAuth.Tags.CreateAsync(new Tag()
64 | {
65 | Name = tagname,
66 | Description = "Test Description"
67 | });
68 | Assert.IsTrue(tag.Id > 0);
69 | Assert.IsNotNull(tag);
70 | Assert.AreEqual(tagname, tag.Name);
71 | Assert.AreEqual("Test Description", tag.Description);
72 |
73 | // We call Get tag list without pre processing
74 | List tags = await _clientAuth.Tags.GetAllAsync();
75 | Assert.IsNotNull(tags);
76 | Assert.AreNotEqual(tags.Count, 0);
77 | CollectionAssert.AllItemsAreUnique(tags.Select(e => e.Id).ToList());
78 |
79 | // Now we add a PreProcessing task
80 | _clientAuth.HttpResponsePreProcessing = (response) =>
81 | {
82 | return response;
83 | };
84 |
85 | tags = await _clientAuth.Tags.GetAllAsync();
86 | Assert.IsNotNull(tags);
87 | Assert.AreNotEqual(tags.Count, 0);
88 | CollectionAssert.AllItemsAreUnique(tags.Select(e => e.Id).ToList());
89 | _clientAuth.HttpResponsePreProcessing = null;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/WordPressPCL/Models/Settings.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace WordPressPCL.Models
4 | {
5 | ///
6 | /// WordPress main settings
7 | ///
8 | public class Settings
9 | {
10 | ///
11 | /// Site title.
12 | ///
13 | [JsonProperty("title")]
14 | public string Title { get; set; }
15 |
16 | ///
17 | /// Site description.
18 | ///
19 | [JsonProperty("description")]
20 | public string Description { get; set; }
21 |
22 | ///
23 | /// Site URL.
24 | ///
25 | [JsonProperty("url")]
26 | public string Url { get; set; }
27 |
28 | ///
29 | /// This address is used for admin purposes. If you change this we will send you an email at your new address to confirm it. The new address will not become active until confirmed.
30 | ///
31 | [JsonProperty("email")]
32 | public string Email { get; set; }
33 |
34 | ///
35 | /// A city in the same timezone as you.
36 | ///
37 | [JsonProperty("timezone")]
38 | public string Timezone { get; set; }
39 |
40 | ///
41 | /// A date format for all date strings.
42 | ///
43 | [JsonProperty("date_format")]
44 | public string DateFormat { get; set; }
45 |
46 | ///
47 | /// A time format for all time strings.
48 | ///
49 | [JsonProperty("time_format")]
50 | public string TimeFormat { get; set; }
51 |
52 | ///
53 | /// A day number of the week that the week should start on.
54 | ///
55 | [JsonProperty("start_of_week")]
56 | public int StartOfWeek { get; set; }
57 |
58 | ///
59 | /// WordPress locale code.
60 | ///
61 | [JsonProperty("language")]
62 | public string Language { get; set; }
63 |
64 | ///
65 | /// Convert emoticons like :-) and :-P to graphics on display.
66 | ///
67 | [JsonProperty("use_smilies")]
68 | public bool UseSmilies { get; set; }
69 |
70 | ///
71 | /// Default category.
72 | ///
73 | [JsonProperty("default_category")]
74 | public int DefaultCategory { get; set; }
75 |
76 | ///
77 | /// Default post format.
78 | ///
79 | [JsonProperty("default_post_format")]
80 | public string DefaultPostFormat { get; set; }
81 |
82 | ///
83 | /// Blog pages show at most.
84 | ///
85 | [JsonProperty("posts_per_page")]
86 | public int PostsPerPage { get; set; }
87 |
88 | ///
89 | /// Default Ping Status
90 | ///
91 | [JsonProperty("default_ping_status")]
92 | public OpenStatus? DefaultPingStatus { get; set; }
93 |
94 | ///
95 | /// Default Comment Status
96 | ///
97 | [JsonProperty("default_comment_status")]
98 | public OpenStatus? DefaultCommentStatus { get; set; }
99 | }
100 | }
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Hosted/Utility/HttpHelper_Tests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 | using WordPressPCL.Models;
6 |
7 | namespace WordPressPCL.Tests.Hosted.Utility;
8 |
9 | [TestClass]
10 | public class HttpHelper_Tests
11 | {
12 |
13 | [ClassInitialize]
14 | public static void Init(TestContext testContext)
15 | {
16 | }
17 |
18 | [TestMethod]
19 | public async Task Hosted_HttpHelper_InvalidPreProcessing()
20 | {
21 | // AUTHENTICATION DOES NOT YET WORK FOR HOSTED SITES
22 | var client = new WordPressClient(ApiCredentials.WordPressUri);
23 | client.Auth.UseBearerAuth(JWTPlugin.JWTAuthByEnriqueChavez);
24 | await client.Auth.RequestJWTokenAsync(ApiCredentials.Username, ApiCredentials.Password);
25 |
26 | // Create a random tag , must works:
27 | var tagname = $"Test {System.Guid.NewGuid()}";
28 | var tag = await client.Tags.CreateAsync(new Tag()
29 | {
30 | Name = tagname,
31 | Description = "Test Description"
32 | });
33 | Assert.IsTrue(tag.Id > 0);
34 | Assert.IsNotNull(tag);
35 | Assert.AreEqual(tagname, tag.Name);
36 | Assert.AreEqual("Test Description", tag.Description);
37 |
38 | // We call Get tag list without pre processing
39 | var tags = await client.Tags.GetAllAsync();
40 | Assert.IsNotNull(tags);
41 | Assert.AreNotEqual(tags.Count, 0);
42 | CollectionAssert.AllItemsAreUnique(tags.Select(e => e.Id).ToList());
43 |
44 | // Now we add a PreProcessing task
45 | client.HttpResponsePreProcessing = (response) =>
46 | {
47 | throw new InvalidOperationException("PreProcessing must fail");
48 | };
49 | await Assert.ThrowsExceptionAsync(async () =>
50 | {
51 | await client.Tags.GetAllAsync();
52 | });
53 | }
54 |
55 | [TestMethod]
56 | public async Task Hosted_HttpHelper_ValidPreProcessing() {
57 | var client = new WordPressClient(ApiCredentials.WordPressUri);
58 | client.Auth.UseBearerAuth(JWTPlugin.JWTAuthByEnriqueChavez);
59 | await client.Auth.RequestJWTokenAsync(ApiCredentials.Username, ApiCredentials.Password);
60 |
61 | // Create a random tag
62 | var tagname = $"Test {System.Guid.NewGuid()}";
63 | var tag = await client.Tags.CreateAsync(new Tag()
64 | {
65 | Name = tagname,
66 | Description = "Test Description"
67 | });
68 | Assert.IsTrue(tag.Id > 0);
69 | Assert.IsNotNull(tag);
70 | Assert.AreEqual(tagname, tag.Name);
71 | Assert.AreEqual("Test Description", tag.Description);
72 |
73 | // We call Get tag list without pre processing
74 | var tags = await client.Tags.GetAllAsync();
75 | Assert.IsNotNull(tags);
76 | Assert.AreNotEqual(tags.Count, 0);
77 | CollectionAssert.AllItemsAreUnique(tags.Select(e => e.Id).ToList());
78 |
79 | // Now we add a PreProcessing task
80 | client.HttpResponsePreProcessing = (response) =>
81 | {
82 | return response;
83 | };
84 |
85 | tags = await client.Tags.GetAllAsync();
86 | Assert.IsNotNull(tags);
87 | Assert.AreNotEqual(tags.Count, 0);
88 | CollectionAssert.AllItemsAreUnique(tags.Select(e => e.Id).ToList());
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/WordPressPCL/Client/Comments.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Globalization;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using WordPressPCL.Models;
6 | using WordPressPCL.Utility;
7 |
8 | namespace WordPressPCL.Client
9 | {
10 | ///
11 | /// Client class for interaction with Comments endpoint WP REST API
12 | ///
13 |
14 | public class Comments : CRUDOperation
15 | {
16 | #region Init
17 |
18 | private const string _methodPath = "comments";
19 |
20 | ///
21 | /// Constructor
22 | ///
23 | /// reference to HttpHelper class for interaction with HTTP
24 | public Comments(HttpHelper HttpHelper) : base(HttpHelper, _methodPath)
25 | {
26 | }
27 |
28 | #endregion Init
29 |
30 | #region Custom
31 |
32 | ///
33 | /// Get comments for Post
34 | ///
35 | /// Post id
36 | /// include embed info
37 | /// Send request with authentication header
38 | /// List of comments for post
39 | public Task> GetCommentsForPostAsync(int PostID, bool embed = false, bool useAuth = false)
40 | {
41 | return HttpHelper.GetRequestAsync>($"{_methodPath}?post={PostID}", embed, useAuth);
42 | }
43 |
44 | ///
45 | /// Get all comments for Post
46 | ///
47 | /// Post id
48 | /// include embed info
49 | /// Send request with authentication header
50 | /// List of comments for post
51 | public async Task> GetAllCommentsForPostAsync(int PostID, bool embed = false, bool useAuth = false)
52 | {
53 | //100 - Max comments per page in WordPress REST API, so this is hack with multiple requests
54 | List comments = await HttpHelper.GetRequestAsync>($"{_methodPath}?post={PostID}&per_page=100&page=1", embed, useAuth).ConfigureAwait(false);
55 | if (HttpHelper.LastResponseHeaders.Contains("X-WP-TotalPages") &&
56 | int.TryParse(HttpHelper.LastResponseHeaders.GetValues("X-WP-TotalPages").FirstOrDefault(), out int totalPages) &&
57 | totalPages > 1)
58 | {
59 | for (int page = 2; page <= totalPages; page++)
60 | {
61 | comments.AddRange(await HttpHelper.GetRequestAsync>($"{_methodPath}?post={PostID}&per_page=100&page={page}", embed, useAuth).ConfigureAwait(false));
62 | }
63 | }
64 | return comments;
65 | }
66 |
67 | ///
68 | /// Force deletion of comments
69 | ///
70 | /// Comment Id
71 | /// force deletion
72 | /// Result of operation
73 | public Task DeleteAsync(int ID, bool force = false)
74 | {
75 | return HttpHelper.DeleteRequestAsync($"{_methodPath}/{ID}?force={force.ToString().ToLower(CultureInfo.InvariantCulture)}");
76 | }
77 |
78 | #endregion Custom
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/CustomRequests_Tests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 | using Newtonsoft.Json;
7 | using WordPressPCL.Tests.Selfhosted.Utility;
8 |
9 | namespace WordPressPCL.Tests.Selfhosted;
10 |
11 | [TestClass]
12 | public class CustomRequests_Tests
13 | {
14 | //Requires contact-form-7 plugin
15 | private class ContactFormItem
16 | {
17 | [JsonProperty("id")]
18 | public int? Id { get; set; }
19 | [JsonProperty("title")]
20 | public string Title { get; set; }
21 | [JsonProperty("slug")]
22 | public string Slug { get; set; }
23 | [JsonProperty("locale")]
24 | public string Locale { get; set; }
25 | }
26 |
27 | private static WordPressClient _clientAuth;
28 |
29 | [ClassInitialize]
30 | public static async Task Init(TestContext testContext)
31 | {
32 | _clientAuth = await ClientHelper.GetAuthenticatedWordPressClient(testContext);
33 | }
34 |
35 | [TestMethod]
36 | public async Task CustomRequests_Read()
37 | {
38 | List forms = await _clientAuth.CustomRequest.GetAsync>("contact-form-7/v1/contact-forms", false, true);
39 | Assert.IsNotNull(forms);
40 | Assert.AreNotEqual(forms.Count, 0);
41 | }
42 |
43 | // TODO: check why this isn't returning the form
44 | //[TestMethod]
45 | public async Task CustomRequests_Create()
46 | {
47 | string title = $"Test Form {Guid.NewGuid()}";
48 | ContactFormItem form = await _clientAuth.CustomRequest.CreateAsync("contact-form-7/v1/contact-forms", new ContactFormItem() { Title = title, Locale = "en-US" });
49 | Assert.IsNotNull(form);
50 | Assert.IsNotNull(form.Id);
51 | Assert.AreEqual(form.Title, title);
52 | }
53 |
54 | // TODO: make test not depend on other tests
55 | //[TestMethod]
56 | public async Task CustomRequests_Update()
57 | {
58 | string title = $"Test Form {Guid.NewGuid()}";
59 | ContactFormItem form = await _clientAuth.CustomRequest.CreateAsync("contact-form-7/v1/contact-forms", new ContactFormItem() { Title = title, Locale = "en-US" });
60 |
61 | List forms = await _clientAuth.CustomRequest.GetAsync>("contact-form-7/v1/contact-forms", false, true);
62 | Assert.IsNotNull(forms);
63 | Assert.AreNotEqual(forms.Count, 0);
64 | ContactFormItem editform = forms.First();
65 | editform.Title += "test";
66 | ContactFormItem form2 = await _clientAuth.CustomRequest.UpdateAsync($"contact-form-7/v1/contact-forms/{editform.Id.Value}", editform);
67 | Assert.IsNotNull(form2);
68 | Assert.AreEqual(form.Title, editform.Title);
69 | }
70 |
71 | // TODO: make test not depend on other tests
72 | //[TestMethod]
73 | public async Task CustomRequests_Delete()
74 | {
75 | List forms = await _clientAuth.CustomRequest.GetAsync>("contact-form-7/v1/contact-forms", false, true);
76 | Assert.IsNotNull(forms);
77 | Assert.AreNotEqual(forms.Count, 0);
78 | ContactFormItem deleteform = forms.First();
79 | bool result = await _clientAuth.CustomRequest.DeleteAsync($"contact-form-7/v1/contact-forms/{deleteform.Id.Value}");
80 | Assert.IsTrue(result);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/WordPressPCL/Models/Plugin.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace WordPressPCL.Models
4 | {
5 | ///
6 | /// WordPress Plugins
7 | /// Date: 26 May 2023
8 | /// Creator: Gregory Liénard
9 | ///
10 | public class Plugin
11 | {
12 | ///
13 | /// The plugin file. unique identifier.
14 | ///
15 | [JsonProperty("plugin")]
16 | public string PluginFile
17 | {
18 | get
19 | {
20 | return _PluginFile;
21 | }
22 | set
23 | {
24 | _PluginFile = value;
25 | if (value.Contains("/"))
26 | Id = value.Substring(0, value.IndexOf("/"));
27 | else
28 | Id = value;
29 | }
30 | }
31 | private string _PluginFile;
32 |
33 | ///
34 | /// First part of the pluginfile: wordpress-seo/wp-seo => wordpress-seo
35 | /// Id is needed to install, PluginFile is needed to activate, deactivate, delete
36 | ///
37 | public string Id { get ; set; }
38 |
39 | ///
40 | /// The plugin activation status.
41 | ///
42 | [JsonProperty("status")]
43 | public ActivationStatus Status { get; set; }
44 |
45 | ///
46 | /// The plugin name.
47 | ///
48 | [JsonProperty("name")]
49 | public string Name { get; set; }
50 |
51 | ///
52 | /// The plugin's website address.
53 | ///
54 | [JsonProperty("plugin_uri")]
55 | public string PluginUri { get; set; }
56 |
57 | ///
58 | /// The plugin author.
59 | ///
60 | [JsonProperty("author")]
61 | public string Author { get; set; }
62 |
63 | ///
64 | /// Plugin author's website address.
65 | ///
66 | [JsonProperty("author_uri")]
67 | public string AuthorUri { get; set; }
68 |
69 | ///
70 | /// The plugin description.
71 | ///
72 | [JsonProperty("description")]
73 | public Description Description { get; set; }
74 |
75 | ///
76 | /// The plugin version number.
77 | ///
78 | [JsonProperty("version")]
79 | public string Version { get; set; }
80 |
81 | ///
82 | /// Whether the plugin can only be activated network-wide.
83 | ///
84 | [JsonProperty("network_only")]
85 | public bool NetworkOnly { get; set; }
86 |
87 | ///
88 | /// Minimum required version of WordPress.
89 | ///
90 | [JsonProperty("requires_wp")]
91 | public string RequiresWordPress { get; set; }
92 |
93 | ///
94 | /// Minimum required version of PHP.
95 | ///
96 | [JsonProperty("requires_php")]
97 | public string RequiresPHP { get; set; }
98 |
99 | ///
100 | /// The plugin's text domain.
101 | ///
102 | [JsonProperty("textdomain")]
103 | public string TextDomain { get; set; }
104 |
105 | ///
106 | /// The plugin's links.
107 | ///
108 | [JsonProperty("_links")]
109 | public Links Links { get; set; }
110 | }
111 | }
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at pentenrieder@outlook.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/Pages_Tests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System.Threading.Tasks;
3 | using WordPressPCL.Models;
4 | using WordPressPCL.Tests.Selfhosted.Utility;
5 | using System.Linq;
6 | using WordPressPCL.Utility;
7 | using WordPressPCL.Models.Exceptions;
8 | using System.Collections.Generic;
9 |
10 | namespace WordPressPCL.Tests.Selfhosted;
11 |
12 | [TestClass]
13 | public class Pages_Tests
14 | {
15 | private static WordPressClient _client;
16 | private static WordPressClient _clientAuth;
17 |
18 | [ClassInitialize]
19 | public static async Task Init(TestContext testContext)
20 | {
21 | _client = ClientHelper.GetWordPressClient();
22 | _clientAuth = await ClientHelper.GetAuthenticatedWordPressClient(testContext);
23 | }
24 |
25 | [TestMethod]
26 | public async Task Pages_Create()
27 | {
28 | Page page = new()
29 | {
30 | Title = new Title("Title 1"),
31 | Content = new Content("Content PostCreate")
32 | };
33 | Page createdPage = await _clientAuth.Pages.CreateAsync(page);
34 |
35 | Assert.AreEqual(page.Content.Raw, createdPage.Content.Raw);
36 | Assert.IsTrue(createdPage.Content.Rendered.Contains(page.Content.Rendered));
37 | }
38 |
39 | [TestMethod]
40 | public async Task Pages_Read()
41 | {
42 | List pages = await _client.Pages.QueryAsync(new PagesQueryBuilder());
43 | Assert.IsNotNull(pages);
44 | Assert.AreNotEqual(pages.Count, 0);
45 | }
46 |
47 | [TestMethod]
48 | public async Task Pages_Get()
49 | {
50 | List pages = await _client.Pages.GetAsync();
51 | Assert.IsNotNull(pages);
52 | Assert.AreNotEqual(pages.Count, 0);
53 | }
54 |
55 | [TestMethod]
56 | public async Task Pages_Update()
57 | {
58 | string testContent = $"Test {System.Guid.NewGuid()}";
59 | List pages = await _client.Pages.GetAllAsync();
60 | Assert.IsTrue(pages.Count > 0);
61 |
62 | Page page = pages.FirstOrDefault();
63 | page.Content.Raw = testContent;
64 | Page updatedPage = await _clientAuth.Pages.UpdateAsync(page);
65 | Assert.AreEqual(testContent, updatedPage.Content.Raw);
66 | }
67 |
68 |
69 | [TestMethod]
70 | public async Task Pages_Delete()
71 | {
72 | Page page = new()
73 | {
74 | Title = new Title("Title 1"),
75 | Content = new Content("Content PostCreate")
76 | };
77 | Page createdPage = await _clientAuth.Pages.CreateAsync(page);
78 | Assert.IsNotNull(createdPage);
79 |
80 | bool response = await _clientAuth.Pages.Delete(createdPage.Id);
81 | Assert.IsTrue(response);
82 | await Assert.ThrowsExceptionAsync(async () =>
83 | {
84 | Page pageById = await _client.Pages.GetByIDAsync(createdPage.Id);
85 | });
86 | }
87 |
88 | [TestMethod]
89 | public async Task Pages_Query()
90 | {
91 | PagesQueryBuilder queryBuilder = new()
92 | {
93 | Page = 1,
94 | PerPage = 15,
95 | OrderBy = PagesOrderBy.Title,
96 | Order = Order.ASC,
97 | Statuses = new List { Status.Publish },
98 | Embed = true
99 | };
100 | List queryresult = await _client.Pages.QueryAsync(queryBuilder);
101 | Assert.AreEqual("?page=1&per_page=15&orderby=title&status=publish&order=asc&_embed=true&context=view", queryBuilder.BuildQuery());
102 | Assert.IsNotNull(queryresult);
103 | Assert.AreNotSame(queryresult.Count, 0);
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Hosted/Basic_Tests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using WordPressPCL.Tests.Hosted.Utility;
4 | using System.Threading.Tasks;
5 | using WordPressPCL.Models;
6 | using System.Linq;
7 |
8 | namespace WordPressPCL.Hosted;
9 |
10 | [TestClass]
11 | public class Basic_Tests
12 | {
13 | private static WordPressClient _client;
14 |
15 | [ClassInitialize]
16 | public static void Init(TestContext testContext)
17 | {
18 | _client = ClientHelper.GetWordPressClient();
19 | }
20 |
21 | [TestMethod]
22 | public async Task Hosted_BasicSetupTest()
23 | {
24 | // Initialize
25 | Assert.IsNotNull(_client);
26 | // Posts
27 | var posts = await _client.Posts.GetAllAsync();
28 | Assert.AreNotEqual(posts.Count, 0);
29 | Assert.IsNotNull(posts);
30 | }
31 |
32 | [TestMethod]
33 | public async Task Hosted_GetFirstPostTest()
34 | {
35 | // Initialize
36 | var posts = await _client.Posts.GetAllAsync();
37 | var post = await _client.Posts.GetByIDAsync(posts.First().Id);
38 | Assert.IsTrue(posts.First().Id == post.Id);
39 | Assert.IsTrue(!String.IsNullOrEmpty(posts.First().Content.Rendered));
40 | }
41 |
42 | [TestMethod]
43 | public async Task Hosted_GetStickyPosts()
44 | {
45 | // Initialize
46 | var posts = await _client.Posts.GetStickyPostsAsync();
47 |
48 | foreach (Post post in posts)
49 | {
50 | Assert.IsTrue(post.Sticky);
51 | }
52 | }
53 |
54 | [TestMethod]
55 | public async Task Hosted_GetPostsByCategory()
56 | {
57 | // This CategoryID MUST exists at ApiCredentials.WordPressUri
58 | int category = 1;
59 | // Initialize
60 | var posts = await _client.Posts.GetPostsByCategoryAsync(category);
61 |
62 | foreach (Post post in posts)
63 | {
64 | Assert.IsTrue(post.Categories.ToList().Contains(category));
65 | }
66 | }
67 |
68 | [TestMethod]
69 | public async Task Hosted_GetPostsByTag()
70 | {
71 | var tags = await _client.Tags.GetAsync();
72 | int tagId = tags.FirstOrDefault().Id;
73 |
74 | // Initialize
75 | var posts = await _client.Posts.GetPostsByTagAsync(tagId);
76 | Assert.AreNotEqual(0, posts.Count);
77 | foreach (Post post in posts)
78 | {
79 | Assert.IsTrue(post.Tags.ToList().Contains(tagId));
80 | }
81 | }
82 |
83 | [TestMethod]
84 | public async Task Hosted_GetPostsByAuthor()
85 | {
86 | // This AuthorID MUST exists at ApiCredentials.WordPressUri
87 | int author = 3722200;
88 | // Initialize
89 | var posts = await _client.Posts.GetPostsByAuthorAsync(author);
90 | Assert.AreNotEqual(0, posts.Count);
91 | foreach (Post post in posts)
92 | {
93 | Assert.IsTrue(post.Author == author);
94 | }
95 | }
96 |
97 | [TestMethod]
98 | public async Task Hosted_GetPostsBySearch()
99 | {
100 | // This search term MUST be used at least once
101 | string search = "hello";
102 | // Initialize
103 | var posts = await _client.Posts.GetPostsBySearchAsync(search);
104 | Assert.AreNotEqual(0, posts.Count);
105 | foreach (Post post in posts)
106 | {
107 | bool containsOnContentOrTitle = false;
108 |
109 | if (post.Content.Rendered.ToUpper().Contains(search.ToUpper()) || post.Title.Rendered.ToUpper().Contains(search.ToUpper()))
110 | {
111 | containsOnContentOrTitle = true;
112 | }
113 |
114 | Assert.IsTrue(containsOnContentOrTitle);
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/WordPressPCL/Client/CustomRequest.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http;
2 | using System.Text;
3 | using System.Threading.Tasks;
4 | using Newtonsoft.Json;
5 | using WordPressPCL.Utility;
6 |
7 | namespace WordPressPCL.Client
8 | {
9 | ///
10 | /// Class to create custom requests
11 | ///
12 | public class CustomRequest
13 | {
14 | private readonly HttpHelper _httpHelper;
15 |
16 | ///
17 | /// Constructor
18 | ///
19 | /// HttpHelper class to operate with Http methods
20 | public CustomRequest(HttpHelper httpHelper)
21 | {
22 | _httpHelper = httpHelper;
23 | }
24 |
25 | ///
26 | /// Create object
27 | ///
28 | /// type of input object
29 | /// type of result object
30 | /// path to exec request
31 | /// object for creation
32 | /// request should prepend default path to route, defaults to true
33 | /// Created object
34 | public async Task CreateAsync(string route, TInput Entity, bool ignoreDefaultPath = true) where TOutput : class
35 | {
36 | string entity = _httpHelper.JsonSerializerSettings == null ? JsonConvert.SerializeObject(Entity) : JsonConvert.SerializeObject(Entity, _httpHelper.JsonSerializerSettings);
37 | using StringContent sc = new(entity, Encoding.UTF8, "application/json");
38 | return (await _httpHelper.PostRequestAsync(route, sc, true, ignoreDefaultPath).ConfigureAwait(false)).Item1;
39 | }
40 |
41 | ///
42 | /// Delete object
43 | ///
44 | /// path to exec delete request
45 | /// request should prepend default path to route, defaults to true
46 | /// Result of deletion
47 | public Task DeleteAsync(string route, bool ignoreDefaultPath = true)
48 | {
49 | return _httpHelper.DeleteRequestAsync(route, true, ignoreDefaultPath);
50 | }
51 |
52 | ///
53 | /// Get object/s
54 | ///
55 | /// type of object
56 | /// path to exec request
57 | /// is get embed params
58 | /// i use auth
59 | /// request should prepend default path to route, defaults to true
60 | /// List of objects
61 | public Task GetAsync(string route, bool embed = false, bool useAuth = false, bool ignoreDefaultPath = true) where TClass : class
62 | {
63 | return _httpHelper.GetRequestAsync(route, embed, useAuth, ignoreDefaultPath);
64 | }
65 |
66 | ///
67 | /// Update object
68 | ///
69 | /// type of input object
70 | /// type of result object
71 | /// path to exec request
72 | /// object for update
73 | /// request should prepend default path to route, defaults to true
74 | /// Updated object
75 | public Task UpdateAsync(string route, TInput Entity, bool ignoreDefaultPath = true) where TOutput : class
76 | {
77 | return CreateAsync(route, Entity, ignoreDefaultPath);
78 | }
79 | }
80 | }
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/Tag_Tests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using WordPressPCL.Tests.Selfhosted.Utility;
3 | using System.Threading.Tasks;
4 | using WordPressPCL.Models;
5 | using WordPressPCL.Utility;
6 | using System.Linq;
7 | using System.Collections.Generic;
8 |
9 | namespace WordPressPCL.Tests.Selfhosted;
10 |
11 | [TestClass]
12 | public class Tag_Tests
13 | {
14 | private static WordPressClient _client;
15 | private static WordPressClient _clientAuth;
16 |
17 | [ClassInitialize]
18 | public static async Task Init(TestContext testContext)
19 | {
20 | _client = ClientHelper.GetWordPressClient();
21 | _clientAuth = await ClientHelper.GetAuthenticatedWordPressClient(testContext);
22 |
23 | string tagname = $"Test {System.Guid.NewGuid()}";
24 | await _clientAuth.Tags.CreateAsync(new Tag()
25 | {
26 | Name = tagname,
27 | Description = "Test Description"
28 | });
29 | }
30 |
31 | [TestMethod]
32 | public async Task Tags_Create()
33 | {
34 | string tagname = $"Test {System.Guid.NewGuid()}";
35 | Tag tag = await _clientAuth.Tags.CreateAsync(new Tag()
36 | {
37 | Name = tagname,
38 | Description = "Test Description"
39 | });
40 | Assert.IsNotNull(tag);
41 | Assert.AreEqual(tagname, tag.Name);
42 | Assert.AreEqual("Test Description", tag.Description);
43 | }
44 |
45 | [TestMethod]
46 | public async Task Tags_Read()
47 | {
48 | List tags = await _clientAuth.Tags.GetAllAsync();
49 | Assert.IsNotNull(tags);
50 | Assert.AreNotEqual(tags.Count, 0);
51 | CollectionAssert.AllItemsAreUnique(tags.Select(tag => tag.Id).ToList());
52 | }
53 |
54 | [TestMethod]
55 | public async Task Tags_Get()
56 | {
57 | List tags = await _client.Tags.GetAsync();
58 | Assert.IsNotNull(tags);
59 | Assert.AreNotEqual(tags.Count, 0);
60 | CollectionAssert.AllItemsAreUnique(tags.Select(tag => tag.Id).ToList());
61 | }
62 |
63 | [TestMethod]
64 | public async Task Tags_Update()
65 | {
66 | List tags = await _clientAuth.Tags.GetAllAsync();
67 | Tag tag = tags.FirstOrDefault();
68 | if(tag == null)
69 | {
70 | Assert.Inconclusive();
71 | }
72 | string tagname = $"Testname {System.Guid.NewGuid()}";
73 | string tagdesc = "Test Description";
74 | tag.Name = tagname;
75 | tag.Description = tagdesc;
76 | Tag tagUpdated = await _clientAuth.Tags.UpdateAsync(tag);
77 | Assert.AreEqual(tagname, tagUpdated.Name);
78 | Assert.AreEqual(tagdesc, tagUpdated.Description);
79 | }
80 |
81 | [TestMethod]
82 | public async Task Tags_Delete()
83 | {
84 | List tags = await _clientAuth.Tags.GetAllAsync();
85 | Tag tag = tags.FirstOrDefault();
86 | if (tag == null)
87 | {
88 | Assert.Inconclusive();
89 | }
90 | int tagId = tag.Id;
91 | bool response = await _clientAuth.Tags.DeleteAsync(tagId);
92 | Assert.IsTrue(response);
93 | tags = await _clientAuth.Tags.GetAllAsync();
94 | List tagsWithId = tags.Where(x => x.Id == tagId).ToList();
95 | Assert.AreEqual(tagsWithId.Count, 0);
96 | }
97 | [TestMethod]
98 | public async Task Tags_Query()
99 | {
100 | TagsQueryBuilder queryBuilder = new()
101 | {
102 | Page = 1,
103 | PerPage = 15,
104 | OrderBy = TermsOrderBy.Id,
105 | Order = Order.DESC,
106 | };
107 | List queryresult = await _clientAuth.Tags.QueryAsync(queryBuilder);
108 | Assert.AreEqual("?page=1&per_page=15&orderby=id&order=desc&context=view", queryBuilder.BuildQuery());
109 | Assert.IsNotNull(queryresult);
110 | Assert.AreNotSame(queryresult.Count, 0);
111 | }
112 |
113 | }
114 |
115 |
--------------------------------------------------------------------------------
/WordPressPCL.Tests.Selfhosted/Categories_Tests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using WordPressPCL.Models;
7 | using WordPressPCL.Tests.Selfhosted.Utility;
8 | using WordPressPCL.Utility;
9 |
10 | namespace WordPressPCL.Tests.Selfhosted;
11 |
12 | [TestClass]
13 | public class Categories_Tests
14 | {
15 | private static WordPressClient _client;
16 | private static WordPressClient _clientAuth;
17 |
18 | [ClassInitialize]
19 | public static async Task Init(TestContext testContext)
20 | {
21 | _client = ClientHelper.GetWordPressClient();
22 | _clientAuth = await ClientHelper.GetAuthenticatedWordPressClient(testContext);
23 | }
24 |
25 | [TestMethod]
26 | public async Task Categories_Create()
27 | {
28 | Random random = new();
29 | string name = $"TestCategory {random.Next(0, 10000)}";
30 | Category category = await _clientAuth.Categories.CreateAsync(new Category()
31 | {
32 | Name = name,
33 | Description = "Test"
34 | });
35 | Assert.IsNotNull(category);
36 | Assert.AreEqual(name, category.Name);
37 | Assert.AreEqual("Test", category.Description);
38 | }
39 |
40 | [TestMethod]
41 | public async Task Categories_Read()
42 | {
43 | List categories = await _client.Categories.GetAllAsync();
44 | Assert.IsNotNull(categories);
45 | Assert.AreNotEqual(categories.Count, 0);
46 | CollectionAssert.AllItemsAreUnique(categories.Select(tag => tag.Id).ToList());
47 | }
48 |
49 | [TestMethod]
50 | public async Task Categories_Get()
51 | {
52 | List categories = await _client.Categories.GetAsync();
53 | Assert.IsNotNull(categories);
54 | Assert.AreNotEqual(categories.Count, 0);
55 | CollectionAssert.AllItemsAreUnique(categories.Select(tag => tag.Id).ToList());
56 | }
57 |
58 | [TestMethod]
59 | public async Task Categories_Update()
60 | {
61 | List categories = await _clientAuth.Categories.GetAllAsync();
62 | Category category = categories.First();
63 | Random random = new();
64 | string name = $"UpdatedCategory {random.Next(0, 10000)}";
65 | category.Name = name;
66 | Category updatedCategory = await _clientAuth.Categories.UpdateAsync(category);
67 | Assert.AreEqual(updatedCategory.Name, name);
68 | Assert.AreEqual(updatedCategory.Id, category.Id);
69 | }
70 |
71 | [TestMethod]
72 | public async Task Categories_Delete()
73 | {
74 | Random random = new();
75 | string name = $"TestCategory {random.Next(0, 10000)}";
76 | Category category = await _clientAuth.Categories.CreateAsync(new Category()
77 | {
78 | Name = name,
79 | Description = "Test"
80 | });
81 |
82 | if (category == null)
83 | {
84 | Assert.Inconclusive();
85 | }
86 | bool response = await _clientAuth.Categories.DeleteAsync(category.Id);
87 | Assert.IsTrue(response);
88 | List categories = await _clientAuth.Categories.GetAllAsync();
89 | List c = categories.Where(x => x.Id == category.Id).ToList();
90 | Assert.AreEqual(c.Count, 0);
91 | }
92 |
93 | [TestMethod]
94 | public async Task Categories_Query()
95 | {
96 | CategoriesQueryBuilder queryBuilder = new()
97 | {
98 | Page = 1,
99 | PerPage = 15,
100 | OrderBy = TermsOrderBy.Id,
101 | Order = Order.DESC,
102 | };
103 | List queryresult = await _clientAuth.Categories.QueryAsync(queryBuilder);
104 | Assert.AreEqual("?page=1&per_page=15&orderby=id&order=desc&context=view", queryBuilder.BuildQuery());
105 | Assert.IsNotNull(queryresult);
106 | Assert.AreNotSame(queryresult.Count, 0);
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/WordPressPCL/Client/Taxonomies.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 | using WordPressPCL.Interfaces;
4 | using WordPressPCL.Models;
5 | using WordPressPCL.Utility;
6 |
7 | namespace WordPressPCL.Client
8 | {
9 | ///
10 | /// Client class for interaction with Taxonomies endpoint WP REST API
11 | ///
12 | public class Taxonomies : IReadOperation, IQueryOperation
13 | {
14 | private readonly HttpHelper _httpHelper;
15 | private const string _methodPath = "taxonomies";
16 |
17 | ///
18 | /// Constructor
19 | ///
20 | /// reference to HttpHelper class for interaction with HTTP
21 | public Taxonomies(HttpHelper httpHelper)
22 | {
23 | _httpHelper = httpHelper;
24 | }
25 | ///
26 | /// Get latest
27 | ///
28 | /// include embed info
29 | /// Send request with authentication header
30 | /// Get latest taxonomies
31 | public async Task> GetAsync(bool embed = false, bool useAuth = false)
32 | {
33 | List entities = new();
34 | Dictionary entities_page = await _httpHelper.GetRequestAsync>($"{_methodPath}", embed, useAuth).ConfigureAwait(false);
35 | foreach (KeyValuePair ent in entities_page)
36 | {
37 | entities.Add(ent.Value);
38 | }
39 | return entities;
40 | }
41 |
42 | ///
43 | /// Get All
44 | ///
45 | /// Include embed info
46 | /// Send request with authentication header
47 | /// List of all result
48 | public async Task> GetAllAsync(bool embed = false, bool useAuth = false)
49 | {
50 | //100 - Max posts per page in WordPress REST API, so this is hack with multiple requests
51 | List entities = new();
52 | Dictionary entities_page = (await _httpHelper.GetRequestAsync>($"{_methodPath}", embed, useAuth).ConfigureAwait(false));
53 | foreach (KeyValuePair ent in entities_page)
54 | {
55 | entities.Add(ent.Value);
56 | }
57 | return entities;
58 | }
59 |
60 | ///
61 | /// Get Entity by Id
62 | ///
63 | /// ID
64 | /// include embed info
65 | /// Send request with authentication header
66 | /// Entity by Id
67 | public Task GetByIDAsync(object ID, bool embed = false, bool useAuth = false)
68 | {
69 | return _httpHelper.GetRequestAsync($"{_methodPath}/{ID}", embed, useAuth);
70 | }
71 |
72 | ///
73 | /// Create a parametrized query and get a result
74 | ///
75 | /// Query builder with specific parameters
76 | /// Send request with authentication header
77 | /// List of filtered result
78 | public async Task> QueryAsync(TaxonomiesQueryBuilder queryBuilder, bool useAuth = false)
79 | {
80 | List entities = new();
81 | Dictionary entities_dict = await _httpHelper.GetRequestAsync>($"{_methodPath}{queryBuilder.BuildQuery()}", false, useAuth).ConfigureAwait(false);
82 | foreach (KeyValuePair ent in entities_dict)
83 | {
84 | entities.Add(ent.Value);
85 | }
86 | return entities;
87 | }
88 | }
89 | }
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # Home
2 |
3 | This is a portable library for consuming the WordPress REST-API in (almost) any C# application.
4 | If you find bugs or have any suggestions, feel free to create an issue.
5 |
6 | ## License
7 | WordPressPCL is published under the [MIT License](https://github.com/wp-net/WordPressPCL/blob/master/LICENSE)
8 |
9 | # Quickstart
10 |
11 | ## WordPress Requirements
12 | Since WordPress 4.7 the REST API has been integrated into the core so there's no need for any plugins to get basic functionality. If you want to access protected endpoints, this library supports authentication through JSON Web Tokens (JWT) (plugin required).
13 |
14 | * [WordPress 4.7 or newer](https://wordpress.org/)
15 | * [JWT Authentication for WP REST API](https://wordpress.org/plugins/jwt-authentication-for-wp-rest-api/)
16 |
17 | ## Including WordPressPCL
18 | The WordPressPCL API Wrapper is avaiable through [NuGet](https://www.nuget.org/packages/WordPressPCL/):
19 |
20 | ```
21 | > Install-Package WordPressPCL
22 | ```
23 |
24 | ## Supported Plattforms
25 | WordPressPCL is built on top of the new [.NET Standard](https://github.com/dotnet/standard) targeting netstandard versions 1.1 and 2.0 - therefore it should work on the following plaforms:
26 | * .NET Framework 4.5 and newer
27 | * .NET Core
28 | * Universal Windows Platform (uap)
29 | * Windows 8.0 and newer
30 | * Windows Phone (WinRT, not Silverlight)
31 | * Mono / Xamarin
32 |
33 | ## Quickstart: Using the API Wrapper
34 |
35 | ```c#
36 | // Initialize
37 | var client = new WordPressClient("http://demo.wp-api.org/wp-json/");
38 |
39 | // Posts
40 | var posts = await client.Posts.GetAll();
41 | var postbyid = await client.Posts.GetById(id);
42 |
43 | // Comments
44 | var comments = await client.Comments.GetAll();
45 | var commentbyid = await client.Comments.GetById(id);
46 | var commentsbypost = await client.Comments.GetCommentsForPost(postid, true, false);
47 |
48 | // Users
49 | // JWT authentication
50 | var client = new WordPressClient(ApiCredentials.WordPressUri);
51 | client.AuthMethod = AuthMethod.JWT;
52 | await client.RequestJWToken(ApiCredentials.Username,ApiCredentials.Password);
53 |
54 | // check if authentication has been successful
55 | var isValidToken = await client.IsValidJWToken();
56 |
57 | // now you can send requests that require authentication
58 | var response = client.Posts.Delete(postid);
59 | ```
60 |
61 | ## Supported REST Methods
62 |
63 | | | Create | Read | Update | Delete |
64 | |--------------------|---------|---------|---------|---------|
65 | | **Posts** | yes | yes | yes | yes |
66 | | **Pages** | yes | yes | yes | yes |
67 | | **Comments** | yes | yes | yes | yes |
68 | | **Categories** | yes | yes | yes | yes |
69 | | **Tags** | yes | yes | yes | yes |
70 | | **Users** | yes | yes | yes | yes |
71 | | **Media** | yes | yes | yes | yes |
72 | | **Post Revisions** | --- | yes | --- | yes |
73 | | **Taxonomies** | --- | yes | --- | --- |
74 | | **Post Types** | --- | yes | --- | --- |
75 | | **Post Statuses** | --- | yes | --- | --- |
76 | | **Settings** | --- | yes | yes | --- |
77 |
78 | ## Additional Features
79 |
80 | - Authentication using [JSON Web Tokens (JWT)](https://jwt.io/)
81 | - [HttpResponsePreProcessing](https://github.com/wp-net/WordPressPCL/wiki/HttpResponsePreProcessing): manipulate the API response before deserializing it
82 |
83 | ## Contribution Guidelines
84 | We're very happy to get input from the community on this project! To keep the code clean we ask you to follow a few simple contribution guidelines.
85 |
86 | First, create an issue describing what feature you want to add or what problem you're trying to solve, just to make sure no one is already working on that. That also gives us a chance to debate whether a feature is within the scope of this project.
87 |
88 | Second, please try to stick to the official C# coding guidelines. https://msdn.microsoft.com/en-us/library/ms229002(v=vs.110).aspx
89 |
90 | Also, make sure to write some tests covering your new or modified code.
91 |
--------------------------------------------------------------------------------