Practitioner-plugin (WordPress)

Uit De Vliegende Brigade
Naar navigatie springen Naar zoeken springen
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

De Practitioner-plugin is een maatwerk-plugin die eind 2017 is ontwikkeld voor een specifiek project. Het betreft een CPT - Custom Post Type. De achterliggende principes zijn echter vrij universeel, vandaar deze documentatie: Hoe maak je gebruik van CPT's?

Onderdelen

Er komt nogal wat bij kijken:

  • Plugin zelf
  • Child-theme van het gebruikte theme Hoshi
  • Advanced Custom Fields PRO-plugin
  • CPT-objectdefinitie (JSON- of PHP-bestand)
  • Ingevoerde data.

Deployment

Voorbeeld: Hoe migreer je de plugin naar een nieuwe locatie?

Bronlocatie

Exporteer de ACF (Advanced Custom Fields)-objectdefinitie

Doellocatie

Installeer de Advanced Custom Fields PRO-plugin
Plaats het child-theme
Importeer objectdefinitie
Voer een nieuwe Practitioner in
Alle Practitioner-objecten zijn beschikbaar op /practitioners. Hiervoor hoef je geen dummy-pagina-met-shortcode aan te maken
Losse objecten vind je op /practitioners/voornaam-tussenvoegsel-achternaam

Database-model

Practitioner-records worden in eerste instantie bijgehouden in de tabel wp_posts. Per practitioners worden er twee records aangemaakt
De waardes voor de custom-velden worden opgeslagen in tabel wp_meta Per veld (bv. Plaats van practitioner xyz) zijn er twee records

Tabel wp_posts - Publish-record

De belangrijkste tabel is wp_posts. Hier worden per posting twee records aangemaakt. Het belangrijkste van de twee, is vermoedelijk het publish-record. Een impressie:

  • ID - Dit is de primaire sleutel (bigint). Ik geloof dat-ie niet automatisch telt
  • Date- & timestamp
  • post_content: Wordt niet gebruikt
  • post_title: Titel van het practitioner-record
  • post_status: Published
  • comment_status: Closed - In dit geval
  • ping_status: Closed - In dit geval
  • post_password: Leeg
  • post_name: Gegenereerd door AFC. Wordt waarschijnlijk gebruikt voor de (interne?) URL
  • post_parent: 0
  • guid. Bv. http://bsp.dvb/?post_type=practitioners&p=797. De escape-string staat voor het '&'-symbool. Herschreven geeft dit http://bsp.dvb/?post_type=practitioners&p=797 - Dus de practitioner met ID 797 (ofzo). Dit is inderdaad de waarde van het ID-veld
  • post_type: practitioners.

Tabel wp_posts - Revision-record

Export van data

  • Ik weet niet hoe je CPT-gegevens gemakkelijk kunt exporteren - Ik heb het nog niet nodig gehad
  • Op database-niveau is dit in ieder geval flink wat werk, omdat de data verspreid staat over twee tabellen, in meerdere velden.

Importeren

Hoe importeer je practitioners vanaf een externe bron (bv. tekstbestand of db) naar de betreffende WordPress-site? De twee aangewezen manieren zijn via plugins en via API-toegang. Maar er zijn meer mogelijkheden.

Mocht er een programmeertaal aan te pas komen, dan graag Python, en geen PHP.

Import-plugins

Import-plugins, zoals Ultimtate CSV Importer (zie hieronder - Geen succes)

Op db-niveau

In oktober 2018 heb ik ca. twee uurtjes besteed om de import helemaal zelf op db-niveau te doen. Na die twee uurtjes gestopt: Ongetwijfeld kan ik dit voor elkaar krijgen, maar het kost gewoon te veel tijd om dit goed te doen: Je moet aan allerlei dingen denken, die anders de API voor je doet.

PHP WPDB-klasse

PHP wpdb-klasse [1] - Da's toegang op een lager niveau dan via een API. Dat sprak me aan, omdat ik geen zin heb om de API te leren gebruiken. Maar ik heb nog minder zin om PHP te leren programmeren.

API

Zie artikel WordPress API's en ihb. Database-API voor 'native' mogelijkheden. Dus allemaal in PHP

API - Python

Er zijn diverse manieren om API-toegang vanuit PHP te doen. Zo bestaat er een wrapper, maar die is niet compleet en alleen beschikbaar voor core en WooCommerce - Tricky.

API - XML-RPC

WordPress kent een XML-RPC-API. Da's programmeertaal-onafhankelijk, dus het kan ook in Python. Het werkt universeel, maar heeft beperkingen (je kunt bv. geen taxonomieën schrijvven) ⇒ Zie verderop in dit artikel.

Casus: Import mbv. Ultimate CSV Importer (zomer 2018)

  • Dit heeft gewerkt, al was er wel een bug: Als ik alle velden 'gewoon' invulde, kreeg ik een offset-foutmelding (zie verderop). Ik geloof dat als ik een bepaald veld leegliet, het wel goed ging
  • In de herfst van 2018, kon ik dit helaas niet hercreëren: Nu werden alleen de eerste letters van velden geïmporteerd + vage foutmeldingen.

Deze aanpak heb ik in de herfst van 2018 opgegeven: Het werkte niet en is om te kunnen werken, afhankelijk van diverse externe factoren (ihb.: deze plugin icm. met die advanced-nog-wat-plugin) die nog geld kosten ook → Zelf op db-niveau doen.

Opmaak importbestand

Dit betreft export vanuit LibreOffice Calc. Ongetwijfeld zijn er meer geldige mogelijkheden, maar dit werkt in ieder geval:

  • UTF-8
  • Tab-gescheiden of komma-gescheiden
  • Alle velden omsloten met dubbele aanhalingstekens, of juist niet

Twee voorbeelden:

"Title"	"firstname"	"lastname"	"description_short"	"description_long"	"city"	"province"	"website"	"photo"
"Jan1 Jan1 Achternaam"	"Jan1"	"Jan1 Achternaam"	"Jan1 korte omschrijving"	"Jan1 lange omschrijving"	"Jan1 – Plaats"	"Jan1 – Provincie"	"Jan1 – Site"	
"Jan2 Jan2 Achternaam"	"Jan2"	"Jan2 Achternaam"	"Jan2 korte omschrijving"	"Jan2 lange omschrijving"	"Jan2 – Plaats"	"Jan2 – Provincie"	"Jan2 – Site"	
"Jan3 Jan3 Achternaam"	"Jan3"	"Jan3 Achternaam"	"Jan3 korte omschrijving"	"Jan3 lange omschrijving"	"Jan3 – Plaats"	"Jan3 – Provincie"	"Jan3 – Site"	

en

Title	firstname	lastname	description_short	description_long	city	province	website	photo
Jan1 Jan1 Achternaam	Jan1	Jan1 Achternaam	Jan1 korte omschrijving	Jan1 lange omschrijving	Jan1 – Plaats	Jan1 – Provincie	Jan1 – Site	
Jan2 Jan2 Achternaam	Jan2	Jan2 Achternaam	Jan2 korte omschrijving	Jan2 lange omschrijving	Jan2 – Plaats	Jan2 – Provincie	Jan2 – Site	
Jan3 Jan3 Achternaam	Jan3	Jan3 Achternaam	Jan3 korte omschrijving	Jan3 lange omschrijving	Jan3 – Plaats	Jan3 – Provincie	Jan3 – Site	

Mapping - WordPress-velden

Cruciaal dat de kolom Title van een waarde is voorzien. Overige velden kun je negeren. Icm. de voorbeeldbestanden hierboven:

WP                  CSV
-----------------   -----------------
Title               Title
Content             --
Short Description   --

Mapping - WordPress-WordPress Custom Fields

Dit zijn de velden die daadwerkelijk gebruikt worden.

WP                               CSV
-----------------                -----------------
practitioner                     Title
practitioner_city                city
practitioner_description_long    description_long
practitioner_description_short   description_short
practitioner_firstname           firstname
practitioner_lastname            lastname
practitioner_province            province
practitioner_website             website

Image?

Geen idee.

Bug: Illegal string offset-error (zomer 2018)

Na import krijg ik bij alle velden (behalve titel) een illegal string offset-foutmelding:

  • Alleen het naam-veld importeren (dus het enige verplichte niet-custom-veld): Gaat goed
  • Naam-veld + customt naam-veld importeren: Foutmelding.

Casus: XML-RPC (okt. 2018)

Deze code maakt één record aan. Zie XML-RPC, WordPress & Python voor details:

#! /usr/bin/python
#####################################################################################
#
print(">>> 01.py")

#####################################################################################
# Import libraties
#####################################################################################

from wordpress_xmlrpc import Client, WordPressPost
from wordpress_xmlrpc.methods.posts import GetPosts, NewPost
from wordpress_xmlrpc.methods.users import GetUserInfo


#####################################################################################
# Instantiate object
#####################################################################################
#
wp = Client('http://example.com/xmlrpc.php', 'xxx', 'yyy')

#####################################################################################
# Create custom post type
#####################################################################################
#
# Initial stuff
##############################
#
practitioner 			= WordPressPost()
practitioner.post_type 		= "practitioners"
practitioner.title 		= "New practitioner (6)"
practitioner.custom_fields	= []



# Initialise custom fields
##############################
#
# All, except image
#
practitioner.custom_fields.append({
	'key': 'practitioner_firstname',
	'value': 'firstname_01'
})
practitioner.custom_fields.append({
	'key': 'practitioner_lastname',
	'value': 'lastname_01'
})
practitioner.custom_fields.append({
	'key': 'practitioner_description_short',
	'value': 'descr_short_01'
})
practitioner.custom_fields.append({
	'key': 'practitioner_description_long',
	'value': 'descr_long_01'
})
practitioner.custom_fields.append({
	'key': 'practitioner_city',
	'value': 'city_01'
})
practitioner.custom_fields.append({
	'key': 'practitioner_province',
	'value': 'province_01'
})
practitioner.custom_fields.append({
	'key': 'practitioner_website',
	'value': 'site_01'
})

wp.call(NewPost(practitioner))


#####################################################################################
#
print("<<< 01.py")

Storing: Content verschijnt pas na edit (eind 2018)

Probleem

Importeren is gelukt, maar de content wordt pas getoond als ik opnieuw Edit » Publish kies. Dat probleem is onafhankelijk van de wijze van impoteren. Het betreft zowel de pagina van individuele practitioners, als de archiefpagina met alle practitioners

Aanvullende gegevens

  • Een eventuele storing met aanmaken permalink [2] lijkt niet het geval te zijn: Na edit/publish verandert de permalink niet, en het probleem speelt ook voor de archiefpagina, en daar spelen permalinks geen rol, lijkt me. Aanpassen en weer terug-aanpassen van de permalink-settings, maakt geen verschil
  • Ik kon geen cash oid. vinden, die ik anders zou kunnen doorspoelen
  • WordFence-issue [3]: Maakt geen verschil + ligt niet voor de hand
  • In bulk postings aanpassen, werkt niet. Alleen als ik het één-voor-één doe.

Unregister CPT-definitie? (feb. 2019)

Ah: De practitioner-definitie zat in de prullenbak. Prullenbak legen maakte echter geen verschil: Nog steeds staat dat object in het linkermenu
CPT-objectdefinitie is in PHP en niet in de database! Deze map is een subtheme
CPT-objectdefinitie staat in subtheme » assets » cms » custom_posts.php

Een site met deze plugin heb ik geklooned. In de nieuwe site heb ik geen Practitioner-objecten nodig. Als ik Advanced Custom Fields PRO verwijder, blijft het Practitioners-object in het menu staan, en de content blijft ook behouden. Hoe verwijder ik deze?

  • Trash herhaaldelijk leegmaken: Nu is allle Practitioner-gerelateerde data verdwenen uit tabel wp_postmeta - Entiteit is er nog steeds
  • Custom Post Type Cleanup-plugin geïnstalleerd. Deze heeft 9 objecten verwijderd, maar het item in het linkermenu staat er nog steeds.
  • Op db-niveau wp_posts, wp_postmeta en wp_term_relationships opschonen [4]:
delete from example_com.wp_posts where  post_type like "practitioners";
delete from example_com.wp_postmeta where post_id not in (select id from wp_posts);
DELETE FROM wp_term_relationships WHERE object_id NOT IN (SELECT id FROM wp_posts);

Een paar items zijn verwijderd, maar niet het item in het linkermenu.

Gelukt: Zie laatste afbeelding hiernaast (verwijzing naar php-bestand met objectdefinitie).

Zie ook

Bronnen

Content verschijnt pas na edit/publish

Unregistering CPT

Appendix: CPT-objectdefinitie

Het betreffende field group-exportbestand vanuit de Advanced Custom Fields PRO-plugin:

[
    {
        "key": "group_5a44d8e93187a",
        "title": "Practitioners",
        "fields": [
            {
                "key": "field_5a44db1c303ab",
                "label": "Practitioner",
                "name": "practitioner",
                "type": "group",
                "instructions": "",
                "required": 0,
                "conditional_logic": 0,
                "wrapper": {
                    "width": "",
                    "class": "",
                    "id": ""
                },
                "layout": "block",
                "sub_fields": [
                    {
                        "key": "field_5a44d90110811",
                        "label": "Firstname",
                        "name": "firstname",
                        "type": "text",
                        "instructions": "",
                        "required": 0,
                        "conditional_logic": 0,
                        "wrapper": {
                            "width": "50",
                            "class": "",
                            "id": ""
                        },
                        "default_value": "",
                        "placeholder": "",
                        "prepend": "",
                        "append": "",
                        "maxlength": ""
                    },
                    {
                        "key": "field_5a44da3910812",
                        "label": "Lastname",
                        "name": "lastname",
                        "type": "text",
                        "instructions": "",
                        "required": 0,
                        "conditional_logic": 0,
                        "wrapper": {
                            "width": "50",
                            "class": "",
                            "id": ""
                        },
                        "default_value": "",
                        "placeholder": "",
                        "prepend": "",
                        "append": "",
                        "maxlength": ""
                    },
                    {
                        "key": "field_5a44da5110813",
                        "label": "Description (short)",
                        "name": "description_short",
                        "type": "textarea",
                        "instructions": "Displayed in the Overview\/table",
                        "required": 0,
                        "conditional_logic": 0,
                        "wrapper": {
                            "width": "",
                            "class": "",
                            "id": ""
                        },
                        "default_value": "",
                        "placeholder": "",
                        "maxlength": "",
                        "rows": "",
                        "new_lines": ""
                    },
                    {
                        "key": "field_5a44da70303a6",
                        "label": "Description (long)",
                        "name": "description_long",
                        "type": "wysiwyg",
                        "instructions": "Displayed on the single page",
                        "required": 0,
                        "conditional_logic": 0,
                        "wrapper": {
                            "width": "",
                            "class": "",
                            "id": ""
                        },
                        "default_value": "",
                        "tabs": "all",
                        "toolbar": "full",
                        "media_upload": 1,
                        "delay": 0
                    },
                    {
                        "key": "field_5a44daaa303a7",
                        "label": "City",
                        "name": "city",
                        "type": "text",
                        "instructions": "",
                        "required": 0,
                        "conditional_logic": 0,
                        "wrapper": {
                            "width": "50",
                            "class": "",
                            "id": ""
                        },
                        "default_value": "",
                        "placeholder": "",
                        "prepend": "",
                        "append": "",
                        "maxlength": ""
                    },
                    {
                        "key": "field_5a44dab4303a8",
                        "label": "Province",
                        "name": "province",
                        "type": "text",
                        "instructions": "",
                        "required": 0,
                        "conditional_logic": 0,
                        "wrapper": {
                            "width": "50",
                            "class": "",
                            "id": ""
                        },
                        "default_value": "",
                        "placeholder": "",
                        "prepend": "",
                        "append": "",
                        "maxlength": ""
                    },
                    {
                        "key": "field_5a44dad6303a9",
                        "label": "Website",
                        "name": "website",
                        "type": "text",
                        "instructions": "",
                        "required": 0,
                        "conditional_logic": 0,
                        "wrapper": {
                            "width": "50",
                            "class": "",
                            "id": ""
                        },
                        "default_value": "",
                        "placeholder": "",
                        "prepend": "",
                        "append": "",
                        "maxlength": ""
                    },
                    {
                        "key": "field_5a44daf7303aa",
                        "label": "Photo",
                        "name": "photo",
                        "type": "image",
                        "instructions": "",
                        "required": 0,
                        "conditional_logic": 0,
                        "wrapper": {
                            "width": "50",
                            "class": "",
                            "id": ""
                        },
                        "return_format": "array",
                        "preview_size": "thumbnail",
                        "library": "all",
                        "min_width": "",
                        "min_height": "",
                        "min_size": "",
                        "max_width": "",
                        "max_height": "",
                        "max_size": "",
                        "mime_types": ""
                    }
                ]
            }
        ],
        "location": [
            [
                {
                    "param": "post_type",
                    "operator": "==",
                    "value": "practitioners"
                }
            ]
        ],
        "menu_order": 0,
        "position": "normal",
        "style": "default",
        "label_placement": "top",
        "instruction_placement": "label",
        "hide_on_screen": [
            "the_content"
        ],
        "active": 1,
        "description": ""
    }
]