php – robfelty.com https://robfelty.com Wed, 10 Apr 2024 04:59:44 +0000 en-US hourly 1 https://wordpress.org/?v=7.1 89964869 Closures in PHPUnit dataProviders https://robfelty.com/2024/04/10/closures-in-phpunit-dataproviders Wed, 10 Apr 2024 04:59:41 +0000 https://robfelty.com/?p=2385 Today I was working on a PHPUnit test at work for testing Elasticsearch. In this case, I wanted to make sure that the data that I was indexing was findable. Basically I wanted to run a search for a given query and check that the results were as expected. I wanted to run this search and evaluate process for a number of different search terms. The only difference with each test would be the query and the expected result. Instead of having to create a custom function or loop to do this, PHPUnit provides a handy @dataProvider annotation that does just this. You define a function which will return an array of test cases, which then get run through your test function. You can give each test case a name. When you run the tests, PHPunit will report the results for each test case separately. It is very handy.

There is one tricky point though. In some of my tests, I am creating websites and indexing them on the fly. When I create a website or a post on that website’s blog, I am actually running production code with a real, local MySQL instance, and indexing into a real local Elasticsearch cluster. I am not simply mocking these calls. This is more of an integration test than a unit test. There are many configurations within MySQL and Elasticsearch which could cause failures or unexpected results. Testing this way allows me to have more confidence that my application is going to work the way I intend. When I write my test, I first create some test sites and content using the setUpBeforeClass method. That is a static method, which means that if I want to store the id of the website I created, I need to store that in a static variable, so I do that. However, this creates a minor issue with my data provider. If I try to access that static variable in my data provider, it will throw an error, because the code for the dataProvider function is compiled before the setUpBeforeClass function has run to initialize those variables. There is a workaround though – closures! A closure is simply an anonymous function. Instead of returning some data from my dataProvider, I return a function which will get evaluated when the test is run, which is after setUpBeforeClass has initialized the variables I need. Here is an example of a test I am running to test for searching for authors when a WordPress site is using the CoAuthorsPlus plugin. Notice how in order to use the closures, I must call them like a function using parentheses, like so: $main_author()

public function co_author_plus_sample_data() {
return array(
'regular_plus_guest_authors' => array(
'guest_authors' => array(
array(
'display_name' => 'mary smith',
'nicename' => 'cap-mary-smith',
),
array(
'display_name' => 'john smith',
'nicename' => 'cap-john-smith',
),
),
'regular_authors' => function () {
return array(
array(
'display_name' => self::$secondary_user->display_name,
'nicename' => self::$secondary_user->user_login,
),
array(
'display_name' => self::$tertiary_user->display_name,
'nicename' => self::$tertiary_user->user_nicename,
),
);
},
'main_author' => function () {
return false;
},
'expected_num_authors' => 4,
),
);
}
/**
* Tests that we can index co-author plus properly
* @dataProvider co_author_plus_sample_data
*/
public function test_co_authors_plus( $guest_authors, Closure $regular_authors, Closure $main_author, $expected_num_authors ) {
$guest_author_arr = wp_list_pluck( $guest_authors, 'nicename' );
$regular_author_arr = wp_list_pluck( $regular_authors(), 'nicename' );
$authors = array_merge( $guest_author_arr, $regular_author_arr );
$the_main_author = $main_author();
wp_set_post_terms( $post_id, $authors, 'author' );
// some more code here for actually indexing and querying data,
// which gets stored in $results
$this->assertFieldCount( $results, 0, 'author', $expected_num_authors, 1 );

When I run the test I get output like so:

phpunit --testdox --filter test_co_authors_plus suites/elasticsearch/Changes.php
✔ Co authors plus with data set "regular_plus_guest_authors"
]]>
2385
WordPress tip of the day: listing all filters https://robfelty.com/2021/12/02/wordpress-tip-of-the-day-listing-all-filters Thu, 02 Dec 2021 13:35:25 +0000 https://robfelty.com/?p=1875 One of the most interesting and powerful design components of the WordPress software are hooks. They are not unique to WordPress, but it is the main software I use that relies on them so heavily. There are two types of hooks – filters, and actions. The main difference is that a filter expects some sort of data as input, and will return some sort of data. For example, there is the classic capital_P_dangit filter, which makes sure that WordPress is always properly capitalized. The input is some text, and the output is some text, which has the P in WordPress capitalized, should you happen to forget to do so. Action hooks could be anything – for example, you could write one to send an email whenever the capital_P_dangit filter actually changes the output.

A tricky thing about filters is that any piece of code can add and remove filters at will. This can make debugging a bit difficult sometimes. You might be looking at a piece of code which contains a line like

 return apply_filters( 'foo', true );

And then you are surprise to see a lower case p come out. What gives? Well, maybe some piece of code has removed that filter (or maybe no filters were ever added to it to begin with). In these cases, it can be handy to know what filters are actually defined. I have duckduckgoed this several times recently, but keep forgetting the exact syntax, so I am writing it here for my future self. I can simply log all filters with:

error_log(json_encode($GLOBALS['wp_filter']));

Another very handy debugging tool in wordpress is wp_debug_backtrace_summary which prints out a brief stacktrace of all the functions that have been called to get to the current line of code

P.S. Too bad typewriters don’t have the capital_P_dangit function built in :)

]]>
1875
Photos, EXIF, IPTC oh my! https://robfelty.com/2021/10/04/photos-exif-iptc-oh-my Mon, 04 Oct 2021 06:42:28 +0000 https://robfelty.com/?p=1840 Today I wanted to make a post on my blog with a bunch of pictures. I used my Canon DSLR over the weekend, and I imported all the pictures into the Photos app on my Mac. My normal workflow is to first go through all the pictures and choose the best, which is usually somewhere around 30-40% of the photos, especially in cases where I am taking action shots, since I will frequently take several in a row. I use . shortcut key to quickly favorite the best pictures. Then I create a smart album based on the favorites and the date. Next, I go through all the pictures in the album and give them each a title/caption, so that I know what I am looking at. Finally, I export the pictures from Photos, so that I can upload them to my blog. It used to be the case that when I exported the pictures from Photos (or maybe it was iPhoto), that the titles would be stored in the IPTC captions information in the jpeg file. Several years ago I created a simple WordPress plugin called Image Meta to help with the import of this info, so that I can choose what I want to do with it. I used to have it set to use the filename of an image as the title in WordPress, and the IPTC caption as the caption, description, and alt text. I like this setup, because it works well with most themes and plugins.

This workflow has probably been broken for some time and I just ignored it, but today it really annoyed me when I took the time to label all of my photos, only to see them come up without captions in WordPress. Since I am lazy, I decided to finally try to fix the problem, rather than manually re-enter all the captions in the WordPress editor. It turned out that there were actually several issues. I did manage to figure it all out after a couple hours, but I don’t really like the solution I came up with.

Mac Photos title/caption exporting woes

Adding captions to my photos in the Mac Photos app

The first issue seems to be that the Photos app does not export the titles, descriptions and such that you assign in the app. After a fair amount of research on the unterwegs, I learned that there are two different export mechanisms in Photos

  1. Normal export (keyboard shortcut Cmd shift E) – this is what I usually use, and allows you to choose the size and quality and format and such. I frequently like to store the files using the option of the album name plus sequential number. This is much easier in my opinion for people who might download the pictures from my site later to know what they have just downloaded, rather than a file like IMG_13438.jpg.
  2. Original export (no keyboard shortcut) – this simply exports the original unedited file, but there is an option so also export the metadata into an XMP file.

Okay I thought. I can get out all the info I want, and then I can write a script to put it back together. Annoying, but doable. So I exported all my photos twice, and then I used the exiftool command to combine them.

It is actually a bit more complicated than that. When I export images using the album with sequential number, it produces file names like “album name – 11 of 30.jpg”. Being an old-school UNIX hacker, I hate this for a number of reasons.

  1. Please no spaces in file names
  2. This does not sort properly – image 11 comes before image 2.

So my first step is to run a quick BASH one liner with some perl regexes, like so

for file in *; do mv "$file" $(echo "$file" | perl -pe 's/ - ([0-9]{3}) /-$1/; s/ - ([0-9]{2}) /-0$1/; s/ - ([0-9]{1}) /-00$1/; s/(of|von) .*.(jpeg|JPG|xmp)/.$2/;s/ +/-/g;'); done

This gives me file names like “album-name-011.jpg”, which is much nicer in my opinion.

The next part was the tricky part. The exiftool program has a really great man page (UNIX manual), including lots of examples. It’s a good thing, because it falls into the same category of Swiss-army knife applications like ffmpeg, imagemagick, and sox, with literally hundreds of different options, and a style in which the order of the command-line options can matter. I quickly found what I wanted – the tagsFromFile option, which would read the XMP file, and then modify my jpg file. I verified that the title was added by using the “get information” option from the Finder (keyboard shortcut Cmd i). My modified jpeg showed that the title was now set.

WordPress woes

At this point I thought I was done, so I re-uploaded all my 52 images. But then I noticed that the captions still were not showing up, so I aborted. I then decided to start doing some debugging of my Image Meta program. I simply logged into my server via ssh (I host this blog on Dreamhost, and they give you ssh access). I added some logging statements in my code to see exactly what was happening during the upload. I discovered that the wp_read_image_metadata hook had added 2 more parameters since I originally developed my plugin, an IPTC array, and an EXIF array. I added those to my code as well, and did some more logging. I then discovered that the IPTC info did not contain the title field that I had added using exiftool . I confirmed again on my Mac that it was there using the Preview app, by another “get information” (cmd i). Then I started reading through the documentation of the wp_read_image_metadata function – and found some interesting details about the IPTC fields it looks for.

["title"] 
(string) Set to the first non-empty value found by looking through the following fields: 

  1. IPTC Headline field (2#105)
  2. IPTC Title field (2#005)
  3. IPTC Description field (2#120) but only if less than 80 characters
  4. EXIF Title field
  5. EXIF ImageDescription field but only if less than 80 characters

I noticed the IPTC array I was getting looked like this:

{"2#055":["20211002"],"2#000":["\\u0000\\u0004"]}

Aha! So I had a 055 field, but no 005 field. I couldn’t figure out how to more thoroughly inspect my images to see if there was something wrong with it. I might do that later if I find time. Instead, I decided to go the simple route, and just try some different fields. After a few more iterations of modifying with exiftool, re-uploading and examining my logs, I found that the headline field worked. Thus my exiftool command looks like this:

pushd album-name;
for file in *; do tags=../mannschaftsfahrt-2021-original/$file; tags=${tags/jpeg/xmp}; exiftool -tagsFromFile $tags '-caption<title' '-headline<title' $file; done

The -headline<title part says to use the title field from the source file (the XMP file), and add it to the headline field of the output file.

I also noticed that setting the alt text of the image was not working correctly in my plugin. I am going to leave that investigation for another day, and hopefully update the plugin, which I have not done in 11 years!

Summary

This should not be that hard! In fact, I am pretty certain it used to be easier. The worst part is the double-export from Photos. That is a travesty. I really wonder what other people are doing? Why bother have the ability to easily add titles and captions and such to your images in the Photos app, if it is so hard to export? Do most people just leave the photos in the application, and not export them?

]]>
1840
Forcing JPEG instead of WebP for images with Jetpack https://robfelty.com/2021/02/14/forcing-jpeg-instead-of-webp-for-images-with-jetpack Sun, 14 Feb 2021 10:58:53 +0000 https://robfelty.com/?p=1662 I use Jetpack on most of my WordPress websites, because it has some really great features, many of them free. I still can’t believe that Automattic gives away a CDN (content distribution network). If you don’t know what that is, it is a way of hosting static files like images, javascript, and css and the like separate from your dynamic content, which is generated on the fly with code (PHP) and a database (MySQL). In particular, files hosted on a CDN are distributed in a number of data centers around the world, so that a visitor to your site from France will get their content from a server in Europe, while a visitor from Australia will get the content from a server in Asia. This means faster page load times.

The way that this works with Jetpack is that when you add an image to your site, a copy of that image is sent to the Jetpack servers, and a number of different versions of the image are created, in order to serve up the best image possible, depending on the type of browser your visitor is using. While JPEG images were the standard for many years, the WebP format offers better compression, and thus loads faster in many instances. The default for Jetpack is to serve WebP whenever possible. This is great in many cases, but I noticed recently that if I try to download an image from my site, I get a WebP format instead of a JPEG format, even though the url says jpg in it. This is not really what I wanted, and in particular, it was very confusing for people like my mom, who like to download images from our family blog and print them out. WebP is not supported by most photo editing or printing programs. The only way I could figure out how to get around this was to add a bit of Javascript to hack my download urls. For example, when I use the Jetpack carousel to display galleries like on this picture – the “view full size” link would normally give me a WebP format. For my family website I am using a custom child theme from the 2017 theme. I added a little javascript file and load that from my functions.php file.

functions.js:

/* Photon is great, but when I want to download a full size image, I would rather download the original from my server, stored in jpg, and not in webp, so that I can then print it out */
jq2 = jQuery.noConflict();
jq2(function( $ ) {
  // Code using $ as usual goes here; the actual jQuery object is jq2
  $( 'body' ).on(
    'click',
    'a.jp-carousel-image-download',
    function( event ) {
      var photonHref = $( 'a.jp-carousel-image-download' ).attr( 'href' );
      if ( 'undefined' !== typeof(photonHref ) ) {
        var newHref = photonHref.replace( /i[0-9]+.wp\.com\//, '' ).replace( '-scaled', '' );
        $( 'a.jp-carousel-image-download' ).attr( 'href', newHref );
      }
    }
  );
});

functions.php:

function wp_fedibblety_enqueue_scripts() {
  wp_register_style(
      'fedibblety2017',
      get_stylesheet_directory_uri() . '/style.css'  ,
      array(),
      filemtime( get_stylesheet_directory() . '/style.css' )
  );
  wp_enqueue_style( 'fedibblety2017' );
  wp_register_script(
      'fedibblety2017js',
      get_stylesheet_directory_uri() . '/functions.js'  ,
      array(),
      filemtime( get_stylesheet_directory() . '/functions.js' )
  );
  wp_enqueue_script('fedibblety2017js');
}

I have the feeling that there are likely better ways to do this. Suggestions welcome :)

]]>
1662
UNIX Tip of the day: Strange behavior editing PHP files with vim https://robfelty.com/2020/10/25/unix-tip-of-the-day-strange-behavior-editing-php-files-with-vim Sun, 25 Oct 2020 11:19:49 +0000 https://robfelty.com/?p=1589 I have been struggling with this weird behavior in vim for the last month or so. I just re-joined Automattic in September. I have been using vim on many different computers and environments (linux, max, cygwin) for over 15 years, and I have never experienced this before. I only seem to have this issue when using vim on my development server. I tried searching the interwebs several times over the last month without avail. Today I finally decided to ask some colleagues if any of them had experienced the issue. As I was writing up the issue, I discovered the root cause, and a solution!

It is difficult to describe. Basically, when editing php files, if I try to type a method call of an object, the formatting gets messed up. For example, if I try to type $this->foo, it ends up displaying on the screen as $thi->foo – after typing the > character, the s disappears. However, if I write the buffer and reopen the file, I can see that it is actually there. As you can imagine, this is very annoying.

In order to fully document the issue, I wanted to also share my .vimrc file to help others debug. It also occurred to me that the issue could be due to GNU screen. I have experience other issues like that in the past. So I decided to see if I could replicate the behavior running outside of screen. It turns out that the behavior was also broken, but in a slightly different way. Instead of deleting the s character as above, a visual bell was triggered! I tried searching the interwebs again about this weird visual bell behavior, and ran across a Google groups posting with the answer. The issue is that the > character was trying to match to an opening < character, and probably not finding one, since I was deep inside a <?php block. This is controlled by the showmatch feature in vim. I was able to exclude matching of angle brackets <> by adding the following in my .vimrc file

" Disable matching of <> in PHP files because it causes strange behavior
" when trying to type method names of objects
autocmd BufRead *.php set  mps-=<:>

I hope that this can help others who may have had the same issue.

]]>
1589
Improving my coding efficiency in vim https://robfelty.com/2016/04/14/improving-my-coding-efficiency-in-vim Thu, 14 Apr 2016 18:43:12 +0000 http://robfelty.com/?p=1397 I have been using Vim for most editing for about 12 years now. I think I tried it for the first time in about 2003, and quickly gave up. Then in 2004 my roommate at the time convinced me to give it another try, and I quickly got hooked. I wrote my dissertation completely in vim. I have been coding in vim since then. I frequently find myself accidentally typing hjkl in non-vim editors. I feel I am pretty efficient in vim. For the most part, my .vimrc has always been relatively simple. Over the years, I have occasionally tried out some different plugins, but usually abandoned them, because they were buggy, or slowed things down, or used too much memory. I was at a meetup last week with colleagues, and my boss kept inquiring about how I can program efficiently without an IDE. This got me thinking the last couple days, as I found myself programming in PHP, and frequently looking up documentation on the net. I program in a lot of different languages. Currently, I am doing a lot of PHP and javascript, but from 2010-2015, I was mostly doing python, Java, and perl. I frequently forget the exact syntax of a lot of languages, which slows me down. Someone else at the meetup mentioned something about autocompletion in vim, so I decided to investigate a bit today. After about 2 hours or so of searching, installing plugins and such, I think I have something for PHP and JS now which should help improve my productivity.

Here are some pages on the web I found useful. Vim as an IDE has a lot of great info. I didn’t use all of the suggestions, but a number of them.

To make installing vim plugins easy, I used pathogen, which was itself easy to install, and seems fairly lightweight. You simple add 2 lines in your .vimrc, and then you can add vim plugins at will in your ~/.vim/bundle directory

A number of places recommended YouCompleteMe, which has completion for all sorts of different languages. I failed to get this installed, since my version of CMake was too old, and I am not currently in the position to upgrade it (using a shared host). I decided to stick with other options which were a little bit more specific.

I found some helpful general info about Omni completion

I installed this plugin with nicer php omni-completion

That plugin uses the default omnicompletion which Vim 7 supports out of the box. To use it, you start typing something, and then hit ctrl-x ctrl-o to show possible completions. This is a bit cumbersome, so instead I decided to try SuperTab, which automates a bunch of this for you, by simply pressing the TAB key, including looking both in omnicompletion, which includes built-in function names and such, as well as user completion, which is derived from the current file you are editing
I found a helpful comment for some .vimrc configuration to get supertab working nicely, with both user completion and omni completion.

Now if I start typing a function in a php file and hit tab, I get a little popup with several different options I might want (the coloring and highlighting is totally configurable – I played around with this a bit too – it’s in my .vimrc file below. At the top of the window, you get a brief synopsis of the function parameters, which is very helpful when trying to remember if you specify (needle, haystack) or (haystack,needle) for PHP functions. I configured the preview to stick around while I am still in insert mode, and then it goes away automatically. Unlike some IDEs, which will autocomplete the function parameters as well, this does not, which I prefer. I find that auto-inserting of quotes, parameters and such usually slows me down more than it speeds me up.

Screen Shot 2016-04-14 at 12.12.35

After all of this, I then decided to start looking around for javascript completion. For some reason, I was not able to find as nice of a solution. I looked at Tern for a bit, but it involves installing a lot of stuff, running a node server, and a bunch of configuration files. I wasn’t able to get it working really. YouCompleteMe probably would be a great solution for everything, if only I had a more recent OS. I did find a simple javascript completion vim plugin, which offers some decent code completion, although it doesn’t open a little preview with command arguments like the PHP one.

And finally, here is my updated .vimrc file with these new goodies.

" pathogen easy plugin management
execute pathogen#infect()
filetype plugin indent on
syntax on "highlight syntax
set bg=dark "use dark background
color desert "use this color scheme

"color marklar "use this color scheme
set shiftwidth=2 "indent equals two spaces
set tabstop=2 "tabstop equals two spaces
set expandtab "should make vim use spaces instead of tabs in autoindent
" use verymagic for searching
:nnoremap / /\v
:cnoremap '<,'>s/ '<,'>s/\v
:cnoremap %s/ %s/\v

set wildmenu
set wildmode=list:longest,full
"set mouse=a
" When editing a file, always jump to the last known cursor position.
" Don't do it when the position is invalid or when inside an event handler
" (happens when dropping a file on gvim).
" DF - Also do not do this if the file resides in the $TEMP directory,
" chances are it is a different file with the same name.
" This comes from the $VIMRUNTIME/vimrc_example.vim file
augroup JumpCursorOnEdit
au!
autocmd BufReadPost *
\ if expand(":p:h") !=? $TEMP |
\ if line("'\"") > 1 && line("'\"") <= line("$") | \ let JumpCursorOnEdit_foo = line("'\"") | \ let b:doopenfold = 1 | \ if (foldlevel(JumpCursorOnEdit_foo) > foldlevel(JumpCursorOnEdit_foo - 1)) |
\ let JumpCursorOnEdit_foo = JumpCursorOnEdit_foo - 1 |
\ let b:doopenfold = 2 |
\ endif |
\ exe JumpCursorOnEdit_foo |
\ endif |
\ endif
" Need to postpone using "zv" until after reading the modelines.
autocmd BufWinEnter *
\ if exists("b:doopenfold") |
\ exe "normal zv" |
\ if(b:doopenfold > 1) |
\ exe "+".1 |
\ endif |
\ unlet b:doopenfold |
\ endif
augroup END
set hlsearch "highlight searches
set backspace=2 "better backspacing
set nocompatible "use vim features not compatible with vi
set showmatch " match parentheses
set ruler "display line and column number at bottom of screen
set ignorecase "ignore case in search and replace
set smartcase "don't ignore case if Upper Case letters appear in search

"do word wrapping for txt and tex files
if has("autocmd")
autocmd BufRead *.tab,tsv,txt set tw=78 noexpandtab
autocmd BufRead *.tex set tw=78 ai spell spelllang=en_us
autocmd BufRead *.{groovy,m,pl,grxml,xml,r} set tw=78 ai
autocmd BufRead *.{grxml,xml,py} set foldenable foldmethod=indent foldlevel=0
autocmd BufRead *.py set tw=76 sts=4 sta tabstop=4 shiftwidth=4 smartindent cinwords=if,elif,else,for,while,try,except,finally,def,class
autocmd BufRead *.{php,js,css,scss,html} set foldenable foldmethod=indent foldlevel=0 tw=78 noexpandtab smartindent tabstop=2 shiftwidth=2
autocmd BufWritePre *.{php,js,css,scss,html} :%s/\s\+$//e
autocmd FileType javascript setlocal omnifunc=js#CompleteJS
endif

"control-t checks spelling with aspell
"map  :w!:!aspell check %:e! %

"control-l checks spelling with aspell with tex mode on
"map :w!:!aspell check -t %:e! %

set encoding=utf-8 "use UTF-8 encoding to display non ASCII characters

"the next line searches for the entire line wherever the cursor is
"first move to beginning of line with "0"
"then yank til the end of the line
"then start a search, and use ctrl-R which inserts something
"in this case '"' which is the contents of the latest yank
"map  0y$:/"
set spellfile=/home/robfelty/.vimspell.utf-8.add
" the next line is for the timepie todo list macro
"map  :wI!:%!$HOME/timepie/tskproc.pl
" copy tags from previous line to current line
""" mark b, search backwards for :, move to next space or end of line.
""" append a space, mark it a,
""" move to beginning of line, search forwards to :, yank to mark a
""" move to b, then paste
"map  mb?:/\(\s\\|$\)a ma0/:y`a`bp
"imap  
"replace tags on this timepie line with those from the prev line.
"map mzk0wmx/\([\\|$\)bea mc`x"vy`cj0wd/\([\\|$\)h"vpa `zj
map mzk0el"vy/\([\\|$\)jd/\([\\|$\)h"vp`zj
"cool stuff for python

"pyfile ~/bin/vim.py
"map ) :python pythonblockFind()
"map ( :python pythonblockFind(forward = 0)

"inflect german adjectives!
map "zyiwddOi "zpa"zpae"zpaes"zpaen"zpaem"zpaer
"delete current line along with the previous and next line
map k3dd

" --- Autocompletion stuff ---
" supertab (completefunc) + latex-box (omnifunc)
let g:SuperTabDefaultCompletionType = "context"
let g:SuperTabContextDefaultCompletionType = ""
let g:SuperTabCompletionContexts = ['s:ContextText', 's:ContextDiscover']
let g:SuperTabContextDiscoverDiscovery = ["&omnifunc:"]
autocmd FileType *
\ if &omnifunc != '' |
\ call SuperTabChain(&omnifunc, "") |
\ call SuperTabSetDefaultCompletionType("") |
\ endif

" If you prefer the Omni-Completion tip window to close when a selection is
" made, these lines close it on movement in insert mode or when leaving
" insert mode
"autocmd CursorMovedI * if pumvisible() == 0|pclose|endif
autocmd InsertLeave * if pumvisible() == 0|pclose|endif

hi Search term=reverse ctermbg=7 ctermfg=1
hi Pmenu guifg=#00ffff guibg=#000000 ctermbg=0 ctermfg=6
hi PmenuSel guifg=#ffff00 guibg=#000000 gui=bold ctermbg=7 cterm=bold
hi PmenuSbar guibg=#204d40 ctermbg=6
hi PmenuThumb guifg=#38ff56 ctermfg=3

]]>
1397
Random featured images in wordpress https://robfelty.com/2011/07/29/random-featured-images-in-wordpress Fri, 29 Jul 2011 22:29:21 +0000 http://robfelty.com/?p=1154 I’ve had random header images on the Fedibblety Family blog for quite some time. I originally implemented this by looking for images in a particular directory. However, I had to manually add pictures to this directory, which was a bit cumbersome. I started thinking, why not just select randomly from all the featured images I have for my posts? So I hacked up a quick function to do that. Here it is:

function get_random_header_images() {
global $wpdb;
$featured_image_query = "select id from wp_postmeta join wp_posts on wp_postmeta.meta_value=wp_posts.id where meta_key='_thumbnail_id' order by rand() limit 10";
$img1 = '';
$img2 = '';
$featured_images = $wpdb->get_results($featured_image_query);
foreach ($featured_images as $img) {
$img_src = wp_get_attachment_image_src( $img->id, 'medium');
$ratio = $img_src[1] / $img_src[2];
if ($ratio > 1.3 and $ratio < 1.6) { // make sure that the image isn't too big, and that it has been scaled by WordPress if ($img_src[1] > 250 or preg_match("/[0-9]+x[0-9]+/", $img_src[0]) == 0)
continue;
if ($img1=='') {
$img1=$img_src[0];
} elseif ($img2=='') {
$img2=$img_src[0];
break;
}
}
}
return (array($img1,$img2));
}

]]>
1154
Site redesign https://robfelty.com/2010/12/01/website-redesign https://robfelty.com/2010/12/01/website-redesign#comments Wed, 01 Dec 2010 16:50:39 +0000 http://robfelty.com/?p=848
robfelty.com 2.0
robfelty.com 2.0

I started my website in 2003. At the time it was hosted by the University of Michigan, where I was a graduate student. They gave all students some space for a personal website. It was really great, though it did come with some limitations, like no php or cgi allowed. I managed to kludge some server side includes and javascript together to get a fairly decent food website. I also had some other stuff on my site like some academic info. In 2006 I started a blog, and started learning wordpress. Since then, most of the new content on my site has been in my blog, and the rest of the site has kind of just been sitting there. I finally decided to try to integrate it all, for several reasons:

  1. Consistent style for all pages
  2. Get everything in a database (for better searching among other things)
  3. Learn some new technology

For that last reason, I had started to look at learning more about drupal, since I have seen a number of jobs looking for drupal developers recently. I spent a week or so looking at that in June, and got a little bit excited about a recipe module I found. However, I decided that I wasn’t crazy about drupal. I think WordPress is miles ahead of drupal in many ways. I was very surprised to find out that uploading pictures is not part of the core of drupal, but rather in a module (and not a very good one at that). Of course, up until WordPress 3.0, WP was mostly just a blogging platform. No longer! With version 3.0, WordPress can easily be used as a full-fledged content management system. So I decided to integrate the disparate portions of my website all into WordPress. During the conversion process I got to learn more about the new features in WordPress 3.0, especially custom post types.

robfelty.com 1.0 - food
robfelty.com 1.0 - food

The biggest challenge of the conversion was converting my recipes. Most of the old pages on my site simply became a WordPress page, but the recipes clearly needed special treatment. I thought I might use a custom post type for recipes, but after a little searching around, I quickly stumbled upon RecipePress, which basically does everything I was looking for (and does in fact use custom post types). RecipePress will work out of the box with any theme, but, upon my request, it also will let you use your own custom theme, which is the route I chose. One small dilemma I faced was that I had multiple pictures in some of my recipes, but I could not insert them into the post content, since RecipePress uses that for the recipe directions. Instead, what I ended up doing was using one image as a featured image, and then I wrote some custom code to display any additional images below the ingredients and contents, like so:


ID );
if (count($pics)>1): ?>


As I started to figure out how I wanted the navigation for the site to work, I also realized that I wanted to update some of the WordPress navigation plugins I have written – Collapsing Categories, Collapsing Archives, and Collapsing Pages. I added support for custom post types for the first two, and added an option for the pages plugin to only list subpages of the current page (this is how the navigation works for the academic, web design, and wordpress plugins portions of the new site). These features are all in the development versions of the respective plugins right now, but I should put out a new stable release soon.

While I was working on importing content from the old site, I also decided to make a new theme as well. I decided to try out the new child theme functionality in WordPress 3.0. It turned out to be quite easy. The only slightly confusing thing for me was how to disable some of the functionality of the parent theme. There are hints on how to to this in the TwentyTen functions.php file, but it took me awhile to actually figure it out. For example, I did not like how TwentyTen handles excerpts, so I wanted to remove the filters for the the except which TwentyTen adds. The way that WordPress handles child themes is that it first looks for the functions.php file in the child theme, and processes it all. Then it looks at the parent theme’s functions.php file and processes that. This means that if you try to simply remove a filter from the parent theme in your child theme, it won’t work, since the child theme is processed first. Instead, you have to do all of this in a function which is called in the after_setup_theme hook. Here is what I used in child theme functions.php file:


function robfelty_child_theme_setup() {
// We are providing our own filter for excerpt_length (or using the unfiltered value)
remove_filter( 'excerpt_length', 'twentyten_excerpt_length' );
remove_filter( 'excerpt_more', 'twentyten_auto_excerpt_more' );
remove_filter( 'get_the_excerpt', 'twentyten_custom_excerpt_more' );
}
add_action( 'after_setup_theme', 'robfelty_child_theme_setup' );

I also added in some CSS3 features, including rounded corners with border-radius, and gradients as well. As always, it is still a work in progress. Feedback is welcome.

]]>
https://robfelty.com/2010/12/01/website-redesign/feed 2 848
New WordPress plugin – Image Browser https://robfelty.com/2010/08/04/new-wordpress-plugin-image-browser Wed, 04 Aug 2010 21:55:03 +0000 http://robfelty.com/?p=687
Screenshot of image browser plugin in action
Screenshot of image browser plugin in action

Today I released my 8th wordpress plugin. This one is quite a bit different from all the other plugins I have written. A friend of mine was looking for a way to create a gallery on his family blog. “No problem!”, I told him, “there are lots of plugins for that”. But I then quickly realized that no plugins were available for what he was looking for. All of the other image gallery plugins for wordpress function by creating galleries manually, say a gallery of wedding photos, or a gallery of a trip to the zoo. My friend was looking for an easy way to browse all pictures he has ever posted on his blog. That is what the Image Browser plugin does. It allows you to browse through all of your pictures on your blog, and also allows you to restrict by year, month, category, and by caption text. It is easy to install and use. Simply install it, then create a new page, and insert the [[imagebrowser]] shortcode. That’s it. Options can be set either in the settings page, or by using shortcode parameters. If you would like a demo, please take a spin at my family blog gallery, or the image browser page on this site.

]]>
687
Showing total number of replies in bbpress https://robfelty.com/2010/04/09/showing-total-number-of-replies-in-bbpress Fri, 09 Apr 2010 21:36:59 +0000 http://robfelty.com/?p=662
showing total number of replies on a bbpress profile page
showing total number of replies on a bbpress profile page

For awhile now I have been wanting to show the total number of topics started and replies in a bbpress forum on the profile page. Today I finally figured out how. I like bbpress quite a bit, as it integrates very nicely into wordpress. The main downside of bbpress right now is that the documentation is still basically nonexistent. Maybe someday I will help out with it.

Anyways, to get the total number of replies, simply use the following little mysql query:

get_var("SELECT COUNT(post_id) FROM " .
$bbdb->prefix . "posts WHERE poster_id=$user->ID");
?>

To get the total number of topics started, use:

get_var("SELECT COUNT(topic_id) FROM " .
$bbdb->prefix . "topics WHERE topic_poster=$user->ID");
?>

]]>
662