onsdag 16. september 2015

Er dine Wordpress innstikk og webmaler klare for WordPress 4.3 og PHP 7? Jeg viser deg vanlige feilmeldinger og sannsynlige løsninger!

For å unngå en total krasj når PHP 7 går i stabil lansering, har WordPress med versjon 4.3 lagt til rette for en mest mulig sømløs overgang. Dette høres bra ut og det er i praksis det.

I det stille vil derimot dine eksisterende nettsteder, innstikk og webmaler generere feil. Tilsynelatende fungerer nettstedet ditt gjerne som før, men hvis du ikke fikser feilene, vil det bli total krasj når webhotellet ditt oppgraderes til PHP 7.

Noen frustrerte lesere vil kanskje tenke: For noen slemme WordPress-utviklere, men den gang ei! Du har nå en utmerket mulighet for å gjøre klar nettstedet ditt for en sømløs overgang. PHP7 vil blant annet ikke støtte måten man definerte klasser eldre WordPress-versjoner, som baserte seg på PHP 4 kompabilitet. Denne kompabiliteten fungerer i PHP 5.5 og i WordPress 4.3, men er egentlig faset ut.

Hvis du velger å overse meldingene WordPress kan gi deg nå, ber du om trøbbel senere. Det hjelper ikke at du venter med å oppgradere WordPress, da webhotellet ditt nok oppgraderes før eller siden.

I artikkelen vil jeg ta for meg vanlige feil og vanlige fiks, samt hvordan du kommer kjapt i gang på 1-2-3.

1. Kom i gang med logging

Det er ikke så vanskelig å komme i gang med logging, selv om manualen til WordPress kanskje burde ha et mer nevenyttig eksempel enn det du finner her: Debugging_in_WordPress. Men fortvil ei, jeg skal hjelpe deg i gang!

Du må tenke gjennom et par ting
  • Gjør det noe at dine brukere ser masse feilmeldinger?
    • Hvis ja, må du logge til disk eller bare vise feil til deg selv
    • Hvis nei, kan du logge til skjerm og ev. disk
  • Har du tid til å sitte i timesvis med det?
    • Hvis nei, betal meg for å gjøre det!
  • Store logger tar stor plass, ikke start logging og glem den i noen år :)
  • Husk at loggene er hendelsstyrt, du må kjøre gjennom alle funksjoner og interaksjonsmuligheter for å avdekke feilene.
  • Logg til disk vil ikke differensiere alle feiltyper per site, i en multisiteløsning, dette er av den enkle årsaken at WordPress merger funksjonsfilen med sin egen funksjonsfil.
    • Feil på function.php vil du måtte identifisere gjennom visuell bekreftelse
    • Feil på selve temafilene (single.php, index, osv) vil du kunne lese direkte i loggen.
Når de tingene ovenfor er nevnt, står det ingen god måte å gjøre logging bare synlig for admin.
Hvis du sitter alene på din egen IP (din arbeidsplass eller ditt hjem), kan du gjøre det veldig enkelt:
if ($_SERVER['REMOTE_ADDR'] == '127.0.0.1') {
  // Slå på logging
define('WP_DEBUG', true);
// Aktiver loggfil til /wp-content/debug.log
define('WP_DEBUG_LOG', true);
// Slå av eller på feil og advarsler som vises på skjerm
define('WP_DEBUG_DISPLAY', true);
@ini_set('display_errors',1);
// Bruk utviklerversjoner av core JS og CSS-filer (bare nødvendig hvis du endrer kjernefilene)
define('SCRIPT_DEBUG', true);
}
else {
define('WP_DEBUG', false); // Slå av logging
}
Koden ovenfor legges inn i wp-config.php, over linjen /* That's all, stop editing! Happy blogging. */.
Man må legge inn sin egen public IP, med mindre man kjører mot localhost. IPen kan man finne på www.minip.no.

Noen tips:
Vil du bare logge til disk? Slå av WP_DEBUG_DISPLAY. Vil du bare logge til skjerm? Slå av WP_DEBUG_LOG.

Hvis du vil slå av all logging, kan du i praksis kommentere vekk alle linjene med:
/*
... koden her
*/

2. Identifiser feilene

Den kalte constructor-metoden for WP_Widget er foreldet

Feilen vil nok veldig mange støte på, av den enkle årsak at ikke alle utviklere av innstikk er klar over at de må oppdatere de for at de skal fungere på WordPress 4.3 og med kommende PHP 7. Mange innstikk har ikke blitt utviklet på lang tid. Hvis innstikket er ryddig kodet opp, bør det være relativt enkelt å fikse det.. Jeg kommer med to eksempler til samme innstikk her.

Feilmeldingen ser for eksempel slik ut
Notice: Den kalte constructor-metoden for WP_Widget er foreldet siden versjon 4.3.0! Bruk __construct() isteden. in ... on line ...

Konstruktøren fra instikket som gir trøbbel
function DTS_View_Full_Website() {
Set the new widget css class and description
$widget_ops = array(
'classname'   => 'dts_view_full_website',
'description' => 'Add a link for mobile users'
);

Build an instance of the new widget
$this->WP_Widget('dts_view_full_website', 'View Full Website', $widget_ops);

} // DTS_View_Full_Website 

Hvordan kode dette om til PHP7-støttet kode, som er det som bør brukes i WordPress 4.3?
Manualen sier hva som skal gjøres, men kanskje den er litt lite spesifikk.

Slik skal det se ut for å fungere
function __construct() {
$widget_ops = array( 'classname' => 'DTS_View_Full_Website', 'description' => 'Add a link for mobile users' );
parent::__construct( 'css-class', 'Title', $widget_ops );

Foreldede funksjoner i tema

Det er ikke uvanlig at man har et tema gjennom flere WordPress-versjoner, særlig ikke hvis det innehar en stor grad av skreddersøm. Da kan man oppleve feilkoder som dette:
PHP Notice:  add_custom_background er foreldet siden versjon 3.4! Bruk add_theme_support( 'custom-background', $args ) isteden. in ... on line ...
Det er jo logisk for alle som kan WordPress å lete i functions.php filen etter koden som gir feil og deretter kommentere den ut:
// This theme allows users to set a custom background
//add_custom_background();

Deretter kan man gå til [codex.wordpress.org/Function_Reference/add_theme_support] for å finne koden man trenger for sin utdaterte støttefunksjon:
$defaults = array(
'default-color'          => '',
'default-image'          => '',
'wp-head-callback'       => '_custom_background_cb',
'admin-head-callback'    => '',
'admin-preview-callback' => ''
);
add_theme_support( 'custom-background', $defaults );

Uforståelig feilmelding er ikke uvanlig

Hvordan skal man for eksempel skjønne denne feilmeldingen?
: Undefined variable: description in on line 
Ikke bare var den kryptisk, men den manglet linjenummer og litt annet. I dette tilfellet er det lurt å se i HTML-koden i nettleseren og se hva som ligger nært feilmeldingen. Meldingen sier riktignok at det er en udefinert variabel, men for å slippe å lete seg gjennom alle de modulære malfilene, er det lurt å vite sånn ca hvor det er eller hva det har tilknytning til.

Ved å se i HTML-koden, ser vi at det hører til menyen og vi ser da umiddelbart i alle fall en feil:
'walker'          => new description_walker
Det er en manglende parantes () som sier at det er en funksjon, derfor tror WordPress det er en konstant. Når det er fikset er fremdeles feilen der, derfor går inn i loggene på disken og finner følgende relatert feilmelding:
:  Declaration of description_walker::start_el() should be compatible with Walker_Nav_Menu::start_el(&$output, $item, $depth = 0, $args = Array, $id = 0) in 
What the bacon, tenkte du kanskje nå? Men det er egentlig ikke så mystisk.
Når vi extender en klasse fra WordPress, er det viktig at den ser lik ut i de ytre rammene.

Hvis temaet er godt bygd opp, skal det ligge en walker-kode i functions.php med navnet  vi kjenner
Walker, Texas Ranger!
til fra forrige feilmelding: description_walker. Etter denne koden er lokalisert, kan vi på samme måte som vi gjorde i et tidligere eksempel. endre syntaksen. Vi må gå inn i WordPress sin core trac for å se hvordan funksjonen start_el walker som utvider klassen Walker_Nav_Menu defineres i versjon 4.3. [ https://core.trac.wordpress.org/browser/tags/4.3/src//wp-includes/nav-menu-template.php ]

I dette spesifikke eksempelet må vi passe på at vår skreddersøm walkerkode har de samme parametrne som er i kjernen til WordPress, altså:
 &$output, $item, $depth = 0, $args = array(), $id = 0
Etter å ha oppdatert dette, forsvinner feilmeldingene ovenfor og menyen ser igjen fin ut.

Undefined index in...

Det kan være flere årsake for en undefined index in..., men ofte er det en matrise som brukes feil.

I dette tilfellet var det en enkel linje som skulle bort, det var litt spøkelseskode fra et innstikk som ikke lenger er i bruk:
wp_deregister_script('prettyphoto');

Undefined variable in..

Hvis du har fikset utallige feil og fremdeles ser følgende feil, ikke gi opp!
Notice:  Undefined variable: description in 
Hvordan vet vi hva dette er? Jo, vi kan se hvor den kommer fra ved å se i HTML-kilden:
<div data-role="panel" id="lPanel" data-display="overlay" data-position="left" data-position-fixed="true" data-theme="b">
Det sier oss at det er venstremenyen som gir problemer, den menyen vi allerede nå har fikset på to ganger og har fjernet mange feilmeldinger. Men vi er altså ikke helt ferdig med å mekke på den. Når vi ser i venstremenyen, ser vi at det ikke er så mye kode der. Dette er jo et bra tegn, siden den koden skal ligge i functions.php. Vi besøker derfor nok en gang walker-koden som vi måtte utbedre tidligere.

Denne gangen vet vi at vi leter etter en variabel med navn description.
Langt inne i vår walker-kode finner vi linjen:
$item_output .= $description.$args->link_after;
Problemet vårt er i de tilfeller hvor det ikke er lagt beskrivelse inn, da vil den prøve å bruke en variabel som ikke er initialisert. For å ordne det på en elegant måte, kan vi bruke en ternary operator. Det er viktig at denne legges tidligere i koden enn konkateneringen av variablene.

Ternary operators er egentlig ganske enkelt, den har syntaksen:
$variabel = (booleansk verdi ? sann : usann);

Vi lager derfor følgende kode som vi legger over den linjen hvor description konkateneres:
$description = (!isset($description) ? "" : $description);
Det den gjør, er å sette seg selv til en tom streng, hvis den ikke er definert. Ikke definert tilsvarer sånn ca. NULL i databasesammenheng, det er ikke det samme som 0 eller "", som de fleste IT-folk bør vite.

Undefined offset in,..

Denne meldingen slår seg gjerne ut som
Notice: Undefined offset: 8 in ... on line ...

Nok en intetsigende feil sier du og jeg kan godt være enig. Men i bunn og grunn betyr den at du er
Feil i koden gjør at hull i nummerserie
gir øunskede resultater og feil i logg.
utenfor matrisens definisjoner. Det vil mest sannsynlig være en bug/feil, av og til trenger den ikke krasje skriptet ditt, men kan gi uønskede resultater.

Det er en relativt enkel måte å fikse den bug'en der, det er nok å endre litt på løkken, slik at hull i nummerserien ikke påvirker resultatet. Fremfor å iterere over en heltallsverdi som øker med hver iterasjon, itererer vi over verdiene i en matrise og deretter bruker den som nøkkel.

Her er en linje fjernet, det er ny måte
å iterere løkken på og sjekk av numerisk
verdi er overflødig.

Deprecated: mysql_real_escape_string()

Lenge var mysql real escape string måten man unngikk sql-injeksjon, men denne skal ikke brukes sammen med WordPress 4.3. I vanlig PHP-kode skriver man i dag PDO eller bruker mysqli. I WordPress har man derimot innebygde funksjoner for å tilrettelegge for trygge sqlspørringer.

Feilmeldingene manifesteres som
Deprecated:  mysql_real_escape_string(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in...
og...
Warning:  mysql_real_escape_string(): Can't connect to local MySQL server through socket 
Man lurer gjerne på hvorfor dette skjer - siden alt virket før WordPress 4.3, men igjen er det WordPress som vil ha mest mulig sømløs overgang til PHP 7 og det betyr de må ha kontroll over funksjonskall i webmalene dine. Derfor må du inn der hvor du kjører  mysql_real_escape_string-kall og endre dette til innebygde funksjoner.

Eksempel på kode som måtte endres (skreddersøm søk):
$querystrToIndeks = sprintf("
SELECT post_title, ID, post_excerpt, post_content,
(post_title REGEXP '%s') as rIn ......
LIMIT 10", mysql_real_escape_string(strip_tags(trim($_REQUEST['term']))), ...........;
For å få den til å virke i WordPress 4.3 og fungere i PHP 7, må man gjøre små endringer
$querystrToIndeks = $wpdb->prepare("
SELECT post_title, ID, post_excerpt, post_content,
(post_title REGEXP '%s') as rIn ......
LIMIT 10", strip_tags(trim($_REQUEST['term'])), ...........;
Les gjerne mer om wpdb: codex.wordpress.org/Class_Reference/wpdb

Når du har kommet så langt, er du gjerne nesten i mål og kan glede deg til å spise en god hamburger dekket av bacon og ost. Men før den tiden er der, må du først fikse resten. Sannsynligheten er stor for at din gamle webmal også gir følgende feilmelding:
Notice:  Undefined property: stdClass::$post_author
Notice:  Undefined property: stdClass::$post_date
Fristelsen er kanskje nå stor for å rive ut håret, sende PC-en på gjenvinning og sparke ut vinduet. Men fortvil ei, dette er bare WordPress som sier til deg: heisann, du har ikke forfatter og dato! Så vi må bare legge de på spørringene mot databasen.

Gammel spørring
  SELECT post_title, ID, post_excerpt, post_content,
(post_title REGEXP '[(]%s[)]') as rIn ....
Ny spørring
  SELECT post_title, ID, post_excerpt, post_content, post_author, post_date,
(post_title REGEXP '[(]%s[)]') as rIn

3. Spis hamburger med bacon og ost

Nam nam!

Relaterte lenker:

Les mer om 4.3 oppgraderingen, som er en viktig mlepæl: make.wordpress.org/core/tag/4-3/