abrudtkuhl / WordPressSharp

A C# client to to interact with the WordPress XML-RPC API
abrudtkuhl.github.io/WordPressSharp/
GNU General Public License v3.0
103 stars 49 forks source link

Featured Images & Custom Fields #64

Closed bernhardgessler closed 7 years ago

bernhardgessler commented 7 years ago

Hey,

I'm proposing two changes:

Featured Image

This was a tricky one. I needed a possibility to check if a post had a featured image and compare its filename to a local file. So I added to Post.cs:

[XmlRpcMember("post_thumbnail")]
public MediaItem FeaturedImage { get; set; }

Unfortunately the value retrieved from the WP API is not consistent. If a post has no featured image, I get back:

{object[0]}

which can't be converted into MediaItem. So I went for object and later parsing via methods:

        [XmlRpcMember("post_thumbnail")]
        public object FeaturedImage { get; set; }

       MediaItem _parsedFeaturedImage;
        public bool HasFeaturedImage()
        {
            if (this._parsedFeaturedImage != null)
            {
                return true;
            }

            return this.GetFeaturedImage() != null;
        }

        public MediaItem GetFeaturedImage()
        {
            var image = this.FeaturedImage as XmlRpcStruct;
            if (image != null)
            {
                this._parsedFeaturedImage = image.ToObject<MediaItem>();
                return this._parsedFeaturedImage;
            }

            return null;
        }

and I introduced an extension method for XmlRpcStruct using reflection to populate MediaItem.

Custom Fields

I was trying to generate maps for the Google Maps Builder plugin. Internally all maps are stored as posts. Some of the custom fields required complex values though, such as:

a:4:{s:5:"width";s:3:"100";s:14:"map_width_unit";s:1:"%";s:6:"height";s:3:"600";s:15:"map_height_unit";s:2:"px";}

I could not find a way to create and pass this as a string. WP would just escape it and save it as a string, instead of the value intended. The only way I could find was to pass complex objects as custom field values, instead of strings. Example:

var customFields = new CustomField[]
{
    new CustomField() { Key = "gmb_double_click", Value = "true" },
    new CustomField() { Key = "gmb_draggable", Value = "default" }, //"none" },
    new CustomField() { Key = "gmb_lat_lng", Value = new MapMetaLatLng() { Latitude = centerLat, Longitude = centerLng } },
    new CustomField() { Key = "gmb_map_type_control", Value = "horizontal_bar" },
    new CustomField() { Key = "gmb_markers_group", Value = markers.ToArray() },
    new CustomField() { Key = "gmb_pan", Value = "true" },
    new CustomField() { Key = "gmb_search_radius", Value = "1000" },
    new CustomField() { Key = "gmb_show_places", Value = "no" },
    new CustomField() { Key = "gmb_street_view", Value = "true" },
    new CustomField() { Key = "gmb_theme", Value = "77" },
    new CustomField() { Key = "gmb_theme_json", Value = "[ { featureType: \"road\", elementType: \"geometry\", stylers: [ { lightness: 100 }, { visibility: \"simplified\" } ] },{ \"featureType\": \"water\", \"elementType\": \"geometry\", \"stylers\": [ { \"visibility\": \"on\" }, { \"color\": \"#C6E2FF\", } ] }, { \"featureType\": \"poi\", \"elementType\": \"geometry.fill\", \"stylers\": [ { \"color\": \"#C5E3BF\" } ] },{ \"featureType\": \"road\", \"elementType\": \"geometry.fill\", \"stylers\": [ { \"color\": \"#D1D1B8\" } ] } ]" },
    new CustomField() { Key = "gmb_type", Value = "RoadMap" },
    new CustomField() { Key = "gmb_wheel_zoom", Value = "none" },
    new CustomField() { Key = "gmb_width_height", Value = new MapMetaWidthHeight() { Width = "100", WidthUnit = "%", Height = "600", MapHeightUnit = "px" } },
    new CustomField() { Key = "gmb_zoom", Value = zoom.ToString() },
    new CustomField() { Key = "gmb_zoom_control", Value = "default" },
};

I created the classes with mapping accordingly:

[XmlRpcMissingMapping(MappingAction.Ignore)]
    class MapMetaWidthHeight
    {
        [XmlRpcMember("width")]
        public string Width { get; set; }

        [XmlRpcMember("map_width_unit")]
        public string WidthUnit { get; set; }

        [XmlRpcMember("height")]
        public string Height { get; set; }

        [XmlRpcMember("map_height_unit")]
        public string MapHeightUnit { get; set; }
    }

Works also with nested classes. WP receives the object, turns it into its string format and stores it. This is not only required for use with the plugin above but many plugins and themes.

Long story short: I propose changing the data type of the Custom Field value from string to object.

abrudtkuhl commented 7 years ago

These are great additions thank you @bernhardgessler and sorry for the delay